Skip to content

Commit

Permalink
Depth-first includes, closes #135
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkdp authored and David Peter committed Jul 27, 2023
1 parent d4297c0 commit d0da8ed
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 13 deletions.
3 changes: 3 additions & 0 deletions modules/units/imperial.nbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use units::si
use units::misc

### Imperial unit system

Expand Down Expand Up @@ -34,3 +35,5 @@ unit fathom: Length = 2 yard
unit league: Length = 3 mile

unit mph: Speed = miles per hour

unit inHg: Pressure = in Hg
75 changes: 62 additions & 13 deletions numbat/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ impl Resolver {
parse(code, code_source_index).map_err(|inner| ResolverError::ParseError(inner))
}

fn inlining_pass(&mut self, program: &[Statement]) -> Result<(Vec<Statement>, bool)> {
fn inlining_pass(&mut self, program: &[Statement]) -> Result<Vec<Statement>> {
let mut new_program = vec![];
let mut performed_imports = false;

for statement in program {
match statement {
Expand All @@ -95,10 +94,12 @@ impl Resolver {
CodeSource::Module(module_path.clone(), filesystem_path),
&code,
);
for statement in self.parse(&code, index)? {

let imported_program = self.parse(&code, index)?;
let inlined_program = self.inlining_pass(&imported_program)?;
for statement in inlined_program {
new_program.push(statement);
}
performed_imports = true;
} else {
return Err(ResolverError::UnknownModule(*span, module_path.clone()));
}
Expand All @@ -108,22 +109,16 @@ impl Resolver {
}
}

Ok((new_program, performed_imports))
Ok(new_program)
}

pub fn resolve(&mut self, code: &str, code_source: CodeSource) -> Result<Vec<Statement>> {
// TODO: handle cyclic dependencies & infinite loops

let index = self.add_code_source(code_source, code);
let mut statements = self.parse(code, index)?;
let statements = self.parse(code, index)?;

loop {
let result = self.inlining_pass(&statements)?;
statements = result.0;
if !result.1 {
return Ok(statements);
}
}
self.inlining_pass(&statements)
}
}

Expand Down Expand Up @@ -186,6 +181,13 @@ mod tests {
match path {
ModulePath(p) if p == &["foo", "bar"] => Some(("use foo::baz".into(), None)),
ModulePath(p) if p == &["foo", "baz"] => Some(("let a = 1".into(), None)),
// ----
ModulePath(p) if p == &["mod_a"] => Some(("use mod_b".into(), None)),
ModulePath(p) if p == &["mod_b"] => Some(("use mod_c\n let x = y".into(), None)),
ModulePath(p) if p == &["mod_c"] => Some(("let y = 1".into(), None)),
// ----
ModulePath(p) if p == &["cycle_a"] => Some(("use cycle_b".into(), None)),
ModulePath(p) if p == &["cycle_b"] => Some(("use cycle_a".into(), None)),
_ => None,
}
}
Expand Down Expand Up @@ -247,4 +249,51 @@ mod tests {
]
);
}

#[test]
fn resolver_depth_first_includes() {
use crate::ast::ReplaceSpans;

let program = "
use mod_a
use mod_c
";

let importer = TestImporter {};

let mut resolver = Resolver::new(importer);
let program_inlined = resolver.resolve(program, CodeSource::Text).unwrap();

assert_eq!(
&program_inlined.replace_spans(),
&[
Statement::DefineVariable {
identifier_span: Span::dummy(),
identifier: "y".into(),
expr: Expression::Scalar(Span::dummy(), Number::from_f64(1.0)),
type_annotation: None
},
Statement::DefineVariable {
identifier_span: Span::dummy(),
identifier: "x".into(),
expr: Expression::Identifier(Span::dummy(), "y".into()),
type_annotation: None
},
]
);
}

#[test]
fn resolved_cyclic_imports() {
let program = "
use cycle_a
";

let importer = TestImporter {};

let mut resolver = Resolver::new(importer);
let program_inlined = resolver.resolve(program, CodeSource::Text).unwrap();

assert_eq!(&program_inlined, &[]);
}
}

0 comments on commit d0da8ed

Please sign in to comment.