diff options
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 85 |
1 files changed, 75 insertions, 10 deletions
@@ -151,7 +151,7 @@ impl From<&Type> for Value { Type::String => Value::String(Rc::new("".to_string())), Type::Function(_, _) => Value::Function( Vec::new(), - Rc::new(RefCell::new(Block::empty_with_type(ty)))), + Rc::new(RefCell::new(Block::stubbed_block(ty)))), } } } @@ -626,35 +626,58 @@ mod op { } #[derive(Debug)] +enum BlockLinkState { + Linked, + Unlinked, + Nothing, +} + +#[derive(Debug)] pub struct Block { pub ty: Type, upvalues: Vec<(usize, bool, Type)>, + linking: BlockLinkState, pub name: String, pub file: PathBuf, ops: Vec<Op>, last_line_offset: usize, line_offsets: HashMap<usize, usize>, - line: usize, } impl Block { - fn new(name: &str, file: &Path, line: usize) -> Self { + fn new(name: &str, file: &Path) -> Self { Self { ty: Type::Void, upvalues: Vec::new(), + linking: BlockLinkState::Nothing, + name: String::from(name), file: file.to_owned(), ops: Vec::new(), last_line_offset: 0, line_offsets: HashMap::new(), - line, } } + fn mark_constant(&mut self) { + if self.upvalues.is_empty() { + return; + } + self.linking = BlockLinkState::Unlinked; + } + + fn link(&mut self) { + self.linking = BlockLinkState::Linked; + } + + fn needs_linking(&self) -> bool { + matches!(self.linking, BlockLinkState::Unlinked) + } + // Used to create empty functions. - fn empty_with_type(ty: &Type) -> Self { - let mut block = Block::new("/empty/", Path::new(""), 0); + fn stubbed_block(ty: &Type) -> Self { + let mut block = Block::new("/empty/", Path::new("")); block.ty = ty.clone(); block } @@ -865,7 +888,7 @@ mod tests { #[test] fn assign_to_constant_upvalue() { - assert_errs!(run_string("a :: 2\nq :: fn { a = 2 }\n", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); + assert_errs!(run_string("a :: 2\nq :: fn { a = 2 }\nq()\na", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); } #[test] @@ -873,6 +896,35 @@ mod tests { assert_errs!(run_string("a :: B()\n", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); } + #[test] + fn call_before_link() { + let prog = " +a := 1 +f() +c := 5 + +f :: fn { + c <=> 5 +} +a + "; + assert_errs!(run_string(prog, true, Vec::new()), [ErrorKind::InvalidProgram, ErrorKind::RuntimeTypeError(_, _)]); + } + + #[test] + fn unused_variable() { + assert_errs!(run_string("a := 1", true, Vec::new()), [ErrorKind::SyntaxError(1, _)]); + } + + #[test] + fn unused_upvalue() { + assert_errs!(run_string("a := 1\nf :: fn { a = 2 }\nf()", true, Vec::new()), [ErrorKind::SyntaxError(1, _)]); + } + + #[test] + fn unused_function() { + assert_errs!(run_string("a := 1\nf := fn { a }\n", true, Vec::new()), [ErrorKind::SyntaxError(2, _)]); + } macro_rules! test_multiple { ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => { @@ -1046,7 +1098,8 @@ a() <=> 4 blob, simple: "blob A {}", instantiate: "blob A {} - a := A()", + a := A() + a", field: "blob A { a: int }", field_assign: "blob A { a: int } a := A() @@ -1068,6 +1121,7 @@ a() <=> 4 blob_infer: " blob A { } a : A = A() +a ", ); @@ -1075,8 +1129,8 @@ a : A = A() add: "(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5)", sub: "(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5)", mul: "(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8)", - types: "a: (int, float, int) = (1, 1., 1)", - more_types: "a: (str, bool, int) = (\"abc\", true, 1)", + types: "a: (int, float, int) = (1, 1., 1)\na", + more_types: "a: (str, bool, int) = (\"abc\", true, 1)\na", ); test_file!(scoping, "progs/tests/scoping.sy"); @@ -1181,6 +1235,7 @@ a <=> 1 b := 2 { a <=> 1 + b <=> 2 }", ); @@ -1191,6 +1246,7 @@ a := 0 b := 99999 a += 1 a <=> 1 +b <=> 99999 ", simple_sub: " @@ -1198,6 +1254,7 @@ a := 0 b := 99999 a -= 1 a <=> -1 +b <=> 99999 ", strange: " @@ -1217,6 +1274,7 @@ a <=> -1 declaration_order, blob_simple: " a := A() +a blob A { a: int @@ -1229,6 +1287,11 @@ b := B() c := C() b2 := B() +a +b +c +b2 + blob A { c: C } @@ -1240,6 +1303,7 @@ blob B { } blob A { } a : A = A() +a ", @@ -1302,4 +1366,5 @@ q <=> 3 ", ); + } |
