diff options
| -rw-r--r-- | Cargo.lock | 119 | ||||
| -rw-r--r-- | README.md | 32 | ||||
| -rw-r--r-- | src/compiler.rs | 92 | ||||
| -rw-r--r-- | src/lib.rs | 924 | ||||
| -rw-r--r-- | src/vm.rs | 26 | ||||
| -rw-r--r-- | sylt_macro/src/lib.rs | 2 |
6 files changed, 628 insertions, 567 deletions
@@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" [[package]] name = "byteorder" @@ -64,12 +64,6 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" @@ -93,16 +87,16 @@ checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" [[package]] name = "criterion" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" +checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", - "itertools", + "itertools 0.10.0", "lazy_static", "num-traits", "oorandom", @@ -124,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" dependencies = [ "cast", - "itertools", + "itertools 0.9.0", ] [[package]] @@ -133,7 +127,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -143,7 +137,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -154,7 +148,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "const_fn", "crossbeam-utils", "lazy_static", @@ -169,7 +163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -209,15 +203,15 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "half" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" +checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -232,6 +226,15 @@ dependencies = [ ] [[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -239,9 +242,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" +checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" dependencies = [ "wasm-bindgen", ] @@ -254,17 +257,17 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" [[package]] name = "log" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -334,21 +337,37 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "owo-colors" version = "1.2.1" -source = "git+https://github.com/FredTheDino/owo-colors.git#4ca8cc3da368d17831af67b85fa33215deb4570f" +source = "git+https://github.com/FredTheDino/owo-colors.git#ccb9cf0cd41e21d1c7fa902f1475b84a5bfc01c8" [[package]] name = "plotters" -version = "0.2.15" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" +checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a" dependencies = [ - "js-sys", "num-traits", + "plotters-backend", + "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] +name = "plotters-backend" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" + +[[package]] +name = "plotters-svg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" +dependencies = [ + "plotters-backend", +] + +[[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -462,9 +481,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.119" +version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" [[package]] name = "serde_cbor" @@ -478,9 +497,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.119" +version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552954ce79a059ddd5fd68c271592374bd15cab2274970380c000118aeffe1cd" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2", "quote", @@ -518,9 +537,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ "proc-macro2", "quote", @@ -577,19 +596,19 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" dependencies = [ "bumpalo", "lazy_static", @@ -602,9 +621,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -612,9 +631,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" dependencies = [ "proc-macro2", "quote", @@ -625,15 +644,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" +checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" [[package]] name = "web-sys" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" +checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/README.md b/README.md new file mode 100644 index 0000000..ad6af5d --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Sylt-lang + +Sylt is a statically checked and dynamically typed reference counted programming +language made for game jams. + +## Why does this exist? Why use this instead of language X? + +Pfft! Why not? + +## Getting started + +Sylt is written entirely in Rust. There are two main ways of using it. + +1. Depend on this repository in your Cargo.toml. +2. Clone this repository and cargo build. You can then pass .sy-files to the + resulting binary. Currently this way won't give you any kind of game. + +## Basic Usage + +Currently, Sylt can only run single files. The last filename given is +run. + +The `-p` flag also lets you see a lot of debug output. If you want +to debug the compiler and runtime this might be helpful. + +## Endgame + +A language that has some form of static typechecking, is easy and fast to work +in. Performance should be good enough that you don't really have to worry about +it. + +Dreams also exist of automatically updating the game when files are changed. diff --git a/src/compiler.rs b/src/compiler.rs index 9a1d1e5..4988c4d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -152,15 +152,21 @@ macro_rules! push_scope { for var in $compiler.frame().stack[ss..$compiler.stack().len()].iter().rev() { if var.captured { - $block.add(Op::PopUpvalue, $compiler.line()); + add_op($compiler, $block, Op::PopUpvalue); } else { - $block.add(Op::Pop, $compiler.line()); + add_op($compiler, $block, Op::Pop); } } $compiler.stack_mut().truncate(ss); }; } +fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { + block.add(op, compiler.line()) +} + + + impl Compiler { pub fn new(current_file: &Path, tokens: TokenStream) -> Self { Self { @@ -330,7 +336,7 @@ impl Compiler { Token::String(s) => { Value::String(Rc::from(s)) } _ => { error!(self, "Cannot parse value."); Value::Bool(false) } }; - block.add(Op::Constant(value), self.line()); + add_op(self, block, Op::Constant(value)); } fn grouping_or_tuple(&mut self, block: &mut Block) { @@ -371,7 +377,7 @@ impl Compiler { } expect!(self, Token::RightParen, "Expected ')' after tuple."); - block.add(Op::Tuple(num_args), self.line()); + add_op(self, block, Op::Tuple(num_args)); Ok(()) } @@ -387,7 +393,7 @@ impl Compiler { expect!(self, Token::LeftBracket, "Expected '[' around index."); self.expression(block); - block.add(Op::Index, self.line()); + add_op(self, block, Op::Index); expect!(self, Token::RightBracket, "Expected ']' around index."); } @@ -399,7 +405,7 @@ impl Compiler { _ => { error!(self, "Invalid unary operator"); Op::Neg }, }; self.parse_precedence(block, Prec::Factor); - block.add(op, self.line()); + add_op(self, block, op); } fn binary(&mut self, block: &mut Block) { @@ -507,7 +513,7 @@ impl Compiler { } } - block.add(Op::Call(arity), self.line()); + add_op(self, block, Op::Call(arity)); } fn function(&mut self, block: &mut Block) { @@ -578,16 +584,16 @@ impl Compiler { Op::Pop | Op::PopUpvalue => {} Op::Return => { break; } , _ => { - function_block.add(Op::Constant(Value::Nil), self.line()); - function_block.add(Op::Return, self.line()); + add_op(self, &mut function_block, Op::Constant(Value::Nil)); + add_op(self, &mut function_block, Op::Return); break; } } } if function_block.ops.is_empty() { - function_block.add(Op::Constant(Value::Nil), self.line()); - function_block.add(Op::Return, self.line()); + add_op(self, &mut function_block, Op::Constant(Value::Nil)); + add_op(self, &mut function_block, Op::Return); } function_block.ty = Type::Function(args, Box::new(return_type)); @@ -596,7 +602,7 @@ impl Compiler { let func = Op::Constant(Value::Function(Vec::new(), Rc::clone(&function_block))); self.blocks[block_id] = function_block; - block.add(func, self.line()); + add_op(self, block, func); } fn variable_expression(&mut self, block: &mut Block) { @@ -606,16 +612,16 @@ impl Compiler { }; if let Some(var) = self.find_variable(&name) { if var.upvalue { - block.add(Op::ReadUpvalue(var.slot), self.line()); + add_op(self, block, Op::ReadUpvalue(var.slot)); } else { - block.add(Op::ReadLocal(var.slot), self.line()); + add_op(self, block, Op::ReadLocal(var.slot)); } loop { match self.peek() { Token::Dot => { self.eat(); if let Token::Identifier(field) = self.eat() { - block.add(Op::Get(String::from(field)), self.line()); + add_op(self, block, Op::Get(String::from(field))); } else { error!(self, "Expected fieldname after '.'."); break; @@ -628,12 +634,12 @@ impl Compiler { } } } else if let Some(blob) = self.find_blob(&name) { - block.add(Op::Constant(Value::Blob(blob)), self.line()); + add_op(self, block, Op::Constant(Value::Blob(blob))); if self.peek() == Token::LeftParen { self.call(block); } } else if let Some(slot) = self.find_extern_function(&name) { - block.add(Op::Constant(Value::ExternFunction(slot)), self.line()); + add_op(self, block, Op::Constant(Value::ExternFunction(slot))); self.call(block); } else { error!(self, format!("Using undefined variable {}.", name)); @@ -667,7 +673,7 @@ impl Compiler { fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { let slot = self.define_variable(name, typ.clone(), block); self.expression(block); - block.add(Op::Define(typ), self.line()); + add_op(self, block, Op::Define(typ)); if let Ok(slot) = slot { self.stack_mut()[slot].active = true; @@ -699,17 +705,17 @@ impl Compiler { if let Some(var) = self.find_variable(&name) { if let Some(op) = op { - block.add(Op::Copy, self.line()); + add_op(self, block, Op::Copy); self.expression(block); - block.add(op, self.line()); + add_op(self, block, op); } else { self.expression(block); } if var.upvalue { - block.add(Op::AssignUpvalue(var.slot), self.line()); + add_op(self, block, Op::AssignUpvalue(var.slot)); } else { - block.add(Op::AssignLocal(var.slot), self.line()); + add_op(self, block, Op::AssignLocal(var.slot)); } } else { error!(self, format!("Using undefined variable {}.", name)); @@ -738,13 +744,13 @@ impl Compiler { fn if_statment(&mut self, block: &mut Block) { expect!(self, Token::If, "Expected 'if' at start of if-statement."); self.expression(block); - let jump = block.add(Op::Illegal, self.line()); + let jump = add_op(self, block, Op::Illegal); self.scope(block); if Token::Else == self.peek() { self.eat(); - let else_jmp = block.add(Op::Illegal, self.line()); + let else_jmp = add_op(self, block, Op::Illegal); block.patch(Op::JmpFalse(block.curr()), jump); match self.peek() { @@ -781,20 +787,20 @@ impl Compiler { let cond = block.curr(); self.expression(block); - let cond_out = block.add(Op::Illegal, self.line()); - let cond_cont = block.add(Op::Illegal, self.line()); + let cond_out = add_op(self, block, Op::Illegal); + let cond_cont = add_op(self, block, Op::Illegal); expect!(self, Token::Comma, "Expect ',' between initalizer and loop expression."); let inc = block.curr(); push_scope!(self, block, { self.statement(block); }); - block.add(Op::Jmp(cond), self.line()); + add_op(self, block, Op::Jmp(cond)); // patch_jmp!(Op::Jmp, cond_cont => block.curr()); block.patch(Op::Jmp(block.curr()), cond_cont); self.scope(block); - block.add(Op::Jmp(inc), self.line()); + add_op(self, block, Op::Jmp(inc)); block.patch(Op::JmpFalse(block.curr()), cond_out); @@ -915,9 +921,9 @@ impl Compiler { }; if let Some(var) = self.find_variable(&name) { if var.upvalue { - block.add(Op::ReadUpvalue(var.slot), self.line()); + add_op(self, block, Op::ReadUpvalue(var.slot)); } else { - block.add(Op::ReadLocal(var.slot), self.line()); + add_op(self, block, Op::ReadLocal(var.slot)); } loop { match self.peek() { @@ -934,7 +940,7 @@ impl Compiler { Token::Equal => { self.eat(); self.expression(block); - block.add(Op::Set(field), self.line()); + add_op(self, block, Op::Set(field)); return Ok(()); } @@ -944,16 +950,16 @@ impl Compiler { Token::SlashEqual => Op::Div, _ => { - block.add(Op::Get(field), self.line()); + add_op(self, block, Op::Get(field)); continue; } }; - block.add(Op::Copy, self.line()); - block.add(Op::Get(field.clone()), self.line()); + add_op(self, block, Op::Copy); + add_op(self, block, Op::Get(field.clone())); self.eat(); self.expression(block); - block.add(op, self.line()); - block.add(Op::Set(field), self.line()); + add_op(self, block, op); + add_op(self, block, Op::Set(field)); return Ok(()); } Token::LeftParen => { @@ -979,7 +985,7 @@ impl Compiler { (Token::Print, ..) => { self.eat(); self.expression(block); - block.add(Op::Print, self.line()); + add_op(self, block, Op::Print); } (Token::Identifier(_), Token::Equal, ..) | @@ -1016,7 +1022,7 @@ impl Compiler { (Token::Yield, ..) => { self.eat(); - block.add(Op::Yield, self.line()); + add_op(self, block, Op::Yield); } (Token::Identifier(name), Token::ColonEqual, ..) => { @@ -1040,12 +1046,12 @@ impl Compiler { (Token::Ret, ..) => { self.eat(); self.expression(block); - block.add(Op::Return, self.line()); + add_op(self, block, Op::Return); } (Token::Unreachable, ..) => { self.eat(); - block.add(Op::Unreachable, self.line()); + add_op(self, block, Op::Unreachable); } (Token::LeftBrace, ..) => { @@ -1056,7 +1062,7 @@ impl Compiler { _ => { self.expression(block); - block.add(Op::Pop, self.line()); + add_op(self, block, Op::Pop); } } @@ -1086,8 +1092,8 @@ impl Compiler { self.statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); } - block.add(Op::Constant(Value::Nil), self.line()); - block.add(Op::Return, self.line()); + add_op(self, &mut block, Op::Constant(Value::Nil)); + add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); self.blocks.insert(0, Rc::new(RefCell::new(block))); @@ -57,303 +57,102 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String } } -#[cfg(test)] -mod tests { - use std::path::Path; - - use crate::error::ErrorKind; +pub type RustFunction = fn(&[Value], bool) -> Result<Value, ErrorKind>; - use super::{run_file, run_string}; +#[derive(Debug, Clone)] +pub enum Type { + Void, + UnknownType, + Int, + Float, + Bool, + String, + Tuple(Vec<Type>), + Function(Vec<Type>, Box<Type>), + Blob(usize), + BlobInstance(usize), +} - #[macro_export] - macro_rules! assert_errs { - ($result:expr, [ $( $kind:pat ),* ]) => { - eprintln!("{} => {:?}", stringify!($result), $result); - assert!(matches!( - $result.unwrap_err().as_slice(), - &[$($crate::error::Error { - kind: $kind, - file: _, - line: _, - message: _, - }, - )*] - )) - }; +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Type::Void, Type::Void) => true, + (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b, + (Type::Blob(a), Type::Blob(b)) => a == b, + (Type::Int, Type::Int) => true, + (Type::Float, Type::Float) => true, + (Type::Bool, Type::Bool) => true, + (Type::String, Type::String) => true, + (Type::Tuple(a), Type::Tuple(b)) => { + a.iter().zip(b.iter()).all(|(a, b)| a == b) + } + (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => + a_args == b_args && a_ret == b_ret, + _ => false, + } } +} - #[macro_export] - macro_rules! test_string { - ($fn:ident, $prog:literal) => { - #[test] - fn $fn() { - $crate::run_string($prog, true, Vec::new()).unwrap(); - } - }; - ($fn:ident, $prog:literal, $errs:tt) => { - #[test] - fn $fn() { - $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs); +impl From<&Value> for Type { + fn from(value: &Value) -> Type { + match value { + Value::BlobInstance(i, _) => Type::BlobInstance(*i), + Value::Blob(i) => Type::Blob(*i), + Value::Tuple(v) => { + Type::Tuple(v.iter().map(|x| Type::from(x)).collect()) } + Value::Int(_) => Type::Int, + Value::Float(_) => Type::Float, + Value::Bool(_) => Type::Bool, + Value::String(_) => Type::String, + Value::Function(_, block) => block.borrow().ty.clone(), + _ => Type::Void, } } +} - #[macro_export] - macro_rules! test_file { - ($fn:ident, $path:literal) => { - #[test] - fn $fn() { - let file = Path::new($path); - run_file(&file, true, Vec::new()).unwrap(); - } - }; +impl From<Value> for Type { + fn from(value: Value) -> Type { + Type::from(&value) } +} - #[test] - fn unreachable_token() { - assert_errs!(run_string("<!>\n", true, Vec::new()), [ErrorKind::Unreachable]); +impl Type { + pub fn is_unkown(&self) -> bool { + match self { + Type::UnknownType => true, + _ => false, + } } +} - macro_rules! test_multiple { - ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => { - mod $mod { - $( test_string!($fn, $prog); )+ +impl From<&Type> for Value { + fn from(ty: &Type) -> Self { + match ty { + Type::Void => Value::Nil, + Type::Blob(i) => Value::Blob(*i), + Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), + Type::Tuple(fields) => { + Value::Tuple(Rc::new(fields.iter().map(Value::from).collect())) } + Type::UnknownType => Value::Unkown, + Type::Int => Value::Int(1), + Type::Float => Value::Float(1.0), + Type::Bool => Value::Bool(true), + Type::String => Value::String(Rc::new("".to_string())), + Type::Function(_, _) => Value::Function( + Vec::new(), + Rc::new(RefCell::new(Block::empty_with_type(ty)))), } } +} - test_multiple!( - order_of_operations, - terms_and_factors: "1 + 1 * 2 <=> 3 - 1 * 2 + 3 <=> 5", - in_rhs: "5 <=> 1 * 2 + 3", - parenthesis: "(1 + 2) * 3 <=> 9", - negation: "-1 <=> 0 - 1 - -1 + 2 <=> 1 - -(1 + 2) <=> -3 - 1 + -1 <=> 0 - 2 * -1 <=> -2", - ); - - test_multiple!( - variables, - single_variable: "a := 1 - a <=> 1", - two_variables: "a := 1 - b := 2 - a <=> 1 - b <=> 2", - stack_ordering: "a := 1 - b := 2 - b <=> 2 - a <=> 1", - assignment: "a := 1 - b := 2 - a = b - a <=> 2 - b <=> 2", - ); - - test_multiple!( - if_, - compare_constants_equality: "if 1 == 2 { - <!> - }", - compare_constants_unequality: "if 1 != 1 { - <!> - }", - compare_variable: "a := 1 - if a == 0 { - <!> - } - if a != 1 { - <!> - }", - else_: "a := 1 - res := 0 - if a == 0 { - <!> - } else { - res = 1 - } - res <=> 1", - else_if: "a := 1 - res := 0 - if a == 0 { - <!> - } else if a == 1 { - res = 1 - } else { - <!> - } - res <=> 1", - ); - - test_multiple!( - fun, - simplest: "f := fn {} - f()", - param_1: "f := fn a: int {} - f(1)", - return_1: "f := fn -> int { - ret 1 - } - f() <=> 1", - param_and_return: "f := fn a: int -> int { - ret a * 2 - } - f(1) <=> 2 - f(5) <=> 10", - param_2: "add := fn a: int, b: int -> int { - ret a + b - } - add(1, 1) <=> 2 - add(10, 20) <=> 30", - calls_inside_calls: "one := fn -> int { - ret 1 - } - add := fn a: int, b: int -> int { - ret a + b - } - add(one(), one()) <=> 2 - add(add(one(), one()), one()) <=> 3 - add(one(), add(one(), one())) <=> 3", - passing_functions: "g := fn -> int { - ret 1 - } - f := fn inner: fn -> int -> int { - ret inner() - } - f(g) <=> 1", - passing_functions_mixed: "g := fn a: int -> int { - ret a * 2 - } - f := fn inner: fn int -> int, a: int -> int { - ret inner(a) - } - f(g, 2) <=> 4", - multiple_returns: "f := fn a: int -> int { - if a == 1 { - ret 2 - } else { - ret 3 - } - } - f(0) <=> 3 - f(1) <=> 2 - f(2) <=> 3", - precedence: "f := fn a: int, b: int -> int { - ret a + b - } - 1 + f(2, 3) <=> 6 - 2 * f(2, 3) <=> 10 - f(2, 3) - (2 + 3) <=> 0", - factorial: "factorial : fn int -> int = fn n: int -> int { - if n <= 1 { - ret 1 - } - ret n * factorial(n - 1) - } - factorial(5) <=> 120 - factorial(6) <=> 720 - factorial(12) <=> 479001600", - - returning_closures: " -f : fn -> fn -> int = fn -> fn -> int { - x : int = 0 - f := fn -> int { - x = x + 1 - ret x +impl From<Type> for Value { + fn from(ty: Type) -> Self { + Value::from(&ty) } - f() <=> 1 - ret f } -a := f() -b := f() - -a() <=> 2 -a() <=> 3 - -b() <=> 2 -b() <=> 3 - -a() <=> 4 -" - - //TODO this tests doesn't terminate in proper time if we print blocks and ops - /* - fibonacci: "fibonacci : fn int -> int = fn n: int -> int { - if n == 0 { - ret 0 - } else if n == 1 { - ret 1 - } else if n < 0 { - <!> - } - ret fibonacci(n - 1) + fibonacci(n - 2) - } - fibonacci(10) <=> 55 - fibonacci(20) <=> 6765" - */ - ); - - test_multiple!( - blob, - simple: "blob A {}", - instantiate: "blob A {} - a := A()", - field: "blob A { a: int }", - field_assign: "blob A { a: int } - a := A() - a.a = 2", - field_get: "blob A { a: int } - a := A() - a.a = 2 - a.a <=> 2 - 2 <=> a.a", - multiple_fields: "blob A { - a: int - b: int - } - a := A() - a.a = 2 - a.b = 3 - a.a + a.b <=> 5 - 5 <=> a.a + a.b" - ); - - test_multiple!(tuples, - 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)", - ); - - test_file!(scoping, "progs/tests/scoping.sy"); - test_file!(for_, "progs/tests/for.sy"); - - test_multiple!( - op_assign, - add: "a := 1\na += 1\na <=> 2", - sub: "a := 2\na -= 1\na <=> 1", - mul: "a := 2\na *= 2\na <=> 4", - div: "a := 2\na /= 2\na <=> 1", - cluster: " -blob A { a: int } -a := A() -a.a = 0 -a.a += 1 -a.a <=> 1 -a.a *= 2 -a.a <=> 2 -a.a /= 2 -a.a <=> 1 -a.a -= 1 -a.a <=> 0" - ); -} #[derive(Clone)] pub enum Value { @@ -370,6 +169,42 @@ pub enum Value { Nil, } +impl Debug for Value { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Blob(i) => write!(fmt, "(blob {})", i), + Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), + Value::Float(f) => write!(fmt, "(float {})", f), + Value::Int(i) => write!(fmt, "(int {})", i), + Value::Bool(b) => write!(fmt, "(bool {})", b), + Value::String(s) => write!(fmt, "(string \"{}\")", s), + Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty), + Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot), + Value::Unkown => write!(fmt, "(unkown)"), + Value::Nil => write!(fmt, "(nil)"), + Value::Tuple(v) => write!(fmt, "({:?})", v), + } + } +} + +impl Value { + fn identity(self) -> Self { + match self { + Value::Float(_) => Value::Float(1.0), + Value::Int(_) => Value::Int(1), + Value::Bool(_) => Value::Bool(true), + a => a, + } + } + + fn is_nil(&self) -> bool { + match self { + Value::Nil => true, + _ => false, + } + } +} + #[derive(Clone, Debug)] pub struct UpValue { slot: usize, @@ -411,24 +246,83 @@ impl UpValue { } } -impl Debug for Value { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Value::Blob(i) => write!(fmt, "(blob {})", i), - Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), - Value::Float(f) => write!(fmt, "(float {})", f), - Value::Int(i) => write!(fmt, "(int {})", i), - Value::Bool(b) => write!(fmt, "(bool {})", b), - Value::String(s) => write!(fmt, "(string \"{}\")", s), - Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty), - Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot), - Value::Unkown => write!(fmt, "(unkown)"), - Value::Nil => write!(fmt, "(nil)"), - Value::Tuple(v) => write!(fmt, "({:?})", v), +#[derive(Debug, Clone)] +pub struct Blob { + pub name: String, + + pub name_to_field: HashMap<String, (usize, Type)>, +} + +impl Blob { + pub fn new(name: &str) -> Self { + Self { + name: String::from(name), + name_to_field: HashMap::new(), + } + } + + pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { + let size = self.name_to_field.len(); + let entry = self.name_to_field.entry(String::from(name)); + if matches!(entry, Entry::Occupied(_)) { + Err(()) + } else { + entry.or_insert((size, ty)); + Ok(()) } } } +#[derive(Debug, Clone)] +pub enum Op { + Illegal, + + Pop, + PopUpvalue, + Copy, + Constant(Value), + Tuple(usize), + + Index, + Get(String), + Set(String), + + Add, + Sub, + Mul, + Div, + Neg, + + And, + Or, + Not, + + Jmp(usize), + JmpFalse(usize), + + Equal, // == + Less, // < + Greater, // > + + Assert, + Unreachable, + + ReadLocal(usize), + AssignLocal(usize), + + ReadUpvalue(usize), + AssignUpvalue(usize), + + Define(Type), + + Call(usize), + + Print, + + Return, + Yield, +} + mod op { use super::Value; use std::rc::Rc; @@ -528,80 +422,6 @@ mod op { _ => Value::Nil, } } - -} - - -impl Value { - fn identity(self) -> Self { - match self { - Value::Float(_) => Value::Float(1.0), - Value::Int(_) => Value::Int(1), - Value::Bool(_) => Value::Bool(true), - a => a, - } - } - - fn is_nil(&self) -> bool { - match self { - Value::Nil => true, - _ => false, - } - } - - fn as_type(&self) -> Type { - Type::from(self) - } -} - -#[derive(Debug, Clone)] -pub enum Op { - Illegal, - - Pop, - PopUpvalue, - Copy, - Constant(Value), - Tuple(usize), - - Index, - Get(String), - Set(String), - - Add, - Sub, - Mul, - Div, - Neg, - - And, - Or, - Not, - - Jmp(usize), - JmpFalse(usize), - - Equal, // == - Less, // < - Greater, // > - - Assert, - Unreachable, - - ReadLocal(usize), - AssignLocal(usize), - - ReadUpvalue(usize), - AssignUpvalue(usize), - - Define(Type), - - Call(usize), - - Print, - - Return, - Yield, } #[derive(Debug)] @@ -631,7 +451,7 @@ impl Block { } } - pub fn from_type(ty: &Type) -> Self { + pub fn empty_with_type(ty: &Type) -> Self { let mut block = Block::new("/empty/", Path::new(""), 0); block.ty = ty.clone(); block @@ -657,10 +477,6 @@ impl Block { (self.file.clone(), self.line) } - pub fn last_op(&self) -> Option<&Op> { - self.ops.last() - } - pub fn add_line(&mut self, token_position: usize) { if token_position != self.last_line_offset { self.line_offsets.insert(self.curr(), token_position); @@ -717,7 +533,6 @@ impl Block { } } - #[derive(Clone)] pub struct Prog { pub blocks: Vec<Rc<RefCell<Block>>>, @@ -725,111 +540,300 @@ pub struct Prog { pub functions: Vec<RustFunction>, } -#[derive(Debug, Clone)] -pub enum Type { - Void, - UnknownType, - Int, - Float, - Bool, - String, - Tuple(Vec<Type>), - Function(Vec<Type>, Box<Type>), - Blob(usize), - BlobInstance(usize), -} +#[cfg(test)] +mod tests { + use std::path::Path; -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Type::Void, Type::Void) => true, - (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b, - (Type::Blob(a), Type::Blob(b)) => a == b, - (Type::Int, Type::Int) => true, - (Type::Float, Type::Float) => true, - (Type::Bool, Type::Bool) => true, - (Type::String, Type::String) => true, - (Type::Tuple(a), Type::Tuple(b)) => { - a.iter().zip(b.iter()).all(|(a, b)| a == b) + use crate::error::ErrorKind; + + use super::{run_file, run_string}; + + #[macro_export] + macro_rules! assert_errs { + ($result:expr, [ $( $kind:pat ),* ]) => { + eprintln!("{} => {:?}", stringify!($result), $result); + assert!(matches!( + $result.unwrap_err().as_slice(), + &[$($crate::error::Error { + kind: $kind, + file: _, + line: _, + message: _, + }, + )*] + )) + }; + } + + #[macro_export] + macro_rules! test_string { + ($fn:ident, $prog:literal) => { + #[test] + fn $fn() { + $crate::run_string($prog, true, Vec::new()).unwrap(); + } + }; + ($fn:ident, $prog:literal, $errs:tt) => { + #[test] + fn $fn() { + $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs); } - (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => - a_args == b_args && a_ret == b_ret, - _ => false, } } -} -impl From<&Value> for Type { - fn from(value: &Value) -> Type { - match value { - Value::BlobInstance(i, _) => Type::BlobInstance(*i), - Value::Blob(i) => Type::Blob(*i), - Value::Tuple(v) => { - Type::Tuple(v.iter().map(|x| Type::from(x)).collect()) + #[macro_export] + macro_rules! test_file { + ($fn:ident, $path:literal) => { + #[test] + fn $fn() { + let file = Path::new($path); + run_file(&file, true, Vec::new()).unwrap(); } - Value::Int(_) => Type::Int, - Value::Float(_) => Type::Float, - Value::Bool(_) => Type::Bool, - Value::String(_) => Type::String, - Value::Function(_, block) => block.borrow().ty.clone(), - _ => Type::Void, - } + }; } -} -impl Type { - pub fn is_unkown(&self) -> bool { - match self { - Type::UnknownType => true, - _ => false, - } + #[test] + fn unreachable_token() { + assert_errs!(run_string("<!>\n", true, Vec::new()), [ErrorKind::Unreachable]); } - pub fn as_value(&self) -> Value { - match self { - Type::Void => Value::Nil, - Type::Blob(i) => Value::Blob(*i), - Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), - Type::Tuple(fields) => { - Value::Tuple(Rc::new(fields.iter().map(|x| x.as_value()).collect())) + macro_rules! test_multiple { + ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => { + mod $mod { + $( test_string!($fn, $prog); )+ } - Type::UnknownType => Value::Unkown, - Type::Int => Value::Int(1), - Type::Float => Value::Float(1.0), - Type::Bool => Value::Bool(true), - Type::String => Value::String(Rc::new("".to_string())), - Type::Function(_, _) => Value::Function( - Vec::new(), - Rc::new(RefCell::new(Block::from_type(self)))), } } -} -pub type RustFunction = fn(&[Value], bool) -> Result<Value, ErrorKind>; + test_multiple!( + order_of_operations, + terms_and_factors: "1 + 1 * 2 <=> 3 + 1 * 2 + 3 <=> 5", + in_rhs: "5 <=> 1 * 2 + 3", + parenthesis: "(1 + 2) * 3 <=> 9", + negation: "-1 <=> 0 - 1 + -1 + 2 <=> 1 + -(1 + 2) <=> -3 + 1 + -1 <=> 0 + 2 * -1 <=> -2", + ); -#[derive(Debug, Clone)] -pub struct Blob { - pub name: String, + test_multiple!( + variables, + single_variable: "a := 1 + a <=> 1", + two_variables: "a := 1 + b := 2 + a <=> 1 + b <=> 2", + stack_ordering: "a := 1 + b := 2 + b <=> 2 + a <=> 1", + assignment: "a := 1 + b := 2 + a = b + a <=> 2 + b <=> 2", + ); - pub name_to_field: HashMap<String, (usize, Type)>, -} + test_multiple!( + if_, + compare_constants_equality: "if 1 == 2 { + <!> + }", + compare_constants_unequality: "if 1 != 1 { + <!> + }", + compare_variable: "a := 1 + if a == 0 { + <!> + } + if a != 1 { + <!> + }", + else_: "a := 1 + res := 0 + if a == 0 { + <!> + } else { + res = 1 + } + res <=> 1", + else_if: "a := 1 + res := 0 + if a == 0 { + <!> + } else if a == 1 { + res = 1 + } else { + <!> + } + res <=> 1", + ); -impl Blob { - pub fn new(name: &str) -> Self { - Self { - name: String::from(name), - name_to_field: HashMap::new(), - } - } + test_multiple!( + fun, + simplest: "f := fn {} + f()", + param_1: "f := fn a: int {} + f(1)", + return_1: "f := fn -> int { + ret 1 + } + f() <=> 1", + param_and_return: "f := fn a: int -> int { + ret a * 2 + } + f(1) <=> 2 + f(5) <=> 10", + param_2: "add := fn a: int, b: int -> int { + ret a + b + } + add(1, 1) <=> 2 + add(10, 20) <=> 30", + calls_inside_calls: "one := fn -> int { + ret 1 + } + add := fn a: int, b: int -> int { + ret a + b + } + add(one(), one()) <=> 2 + add(add(one(), one()), one()) <=> 3 + add(one(), add(one(), one())) <=> 3", + passing_functions: "g := fn -> int { + ret 1 + } + f := fn inner: fn -> int -> int { + ret inner() + } + f(g) <=> 1", + passing_functions_mixed: "g := fn a: int -> int { + ret a * 2 + } + f := fn inner: fn int -> int, a: int -> int { + ret inner(a) + } + f(g, 2) <=> 4", + multiple_returns: "f := fn a: int -> int { + if a == 1 { + ret 2 + } else { + ret 3 + } + } + f(0) <=> 3 + f(1) <=> 2 + f(2) <=> 3", + precedence: "f := fn a: int, b: int -> int { + ret a + b + } + 1 + f(2, 3) <=> 6 + 2 * f(2, 3) <=> 10 + f(2, 3) - (2 + 3) <=> 0", + factorial: "factorial : fn int -> int = fn n: int -> int { + if n <= 1 { + ret 1 + } + ret n * factorial(n - 1) + } + factorial(5) <=> 120 + factorial(6) <=> 720 + factorial(12) <=> 479001600", - pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { - let size = self.name_to_field.len(); - let entry = self.name_to_field.entry(String::from(name)); - if matches!(entry, Entry::Occupied(_)) { - Err(()) - } else { - entry.or_insert((size, ty)); - Ok(()) - } + returning_closures: " +f : fn -> fn -> int = fn -> fn -> int { + x : int = 0 + f := fn -> int { + x = x + 1 + ret x } + f() <=> 1 + ret f +} + +a := f() +b := f() + +a() <=> 2 +a() <=> 3 + +b() <=> 2 +b() <=> 3 + +a() <=> 4 +" + + //TODO this tests doesn't terminate in proper time if we print blocks and ops + /* + fibonacci: "fibonacci : fn int -> int = fn n: int -> int { + if n == 0 { + ret 0 + } else if n == 1 { + ret 1 + } else if n < 0 { + <!> + } + ret fibonacci(n - 1) + fibonacci(n - 2) + } + fibonacci(10) <=> 55 + fibonacci(20) <=> 6765" + */ + ); + + test_multiple!( + blob, + simple: "blob A {}", + instantiate: "blob A {} + a := A()", + field: "blob A { a: int }", + field_assign: "blob A { a: int } + a := A() + a.a = 2", + field_get: "blob A { a: int } + a := A() + a.a = 2 + a.a <=> 2 + 2 <=> a.a", + multiple_fields: "blob A { + a: int + b: int + } + a := A() + a.a = 2 + a.b = 3 + a.a + a.b <=> 5 + 5 <=> a.a + a.b" + ); + + test_multiple!(tuples, + 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)", + ); + + test_file!(scoping, "progs/tests/scoping.sy"); + test_file!(for_, "progs/tests/for.sy"); + + test_multiple!( + op_assign, + add: "a := 1\na += 1\na <=> 2", + sub: "a := 2\na -= 1\na <=> 1", + mul: "a := 2\na *= 2\na <=> 4", + div: "a := 2\na /= 2\na <=> 1", + cluster: " +blob A { a: int } +a := A() +a.a = 0 +a.a += 1 +a.a <=> 1 +a.a *= 2 +a.a <=> 2 +a.a /= 2 +a.a <=> 1 +a.a -= 1 +a.a <=> 0" + ); } @@ -487,7 +487,7 @@ impl VM { if *is_up { types.push(ty.clone()); } else { - types.push(self.stack[*slot].as_type()); + types.push(Type::from(&self.stack[*slot])); } } @@ -517,7 +517,7 @@ impl VM { Op::Get(field) => { let inst = self.pop(); if let Value::BlobInstance(ty, _) = inst { - let value = self.blobs[ty].name_to_field.get(&field).unwrap().1.as_value(); + let value = Value::from(&self.blobs[ty].name_to_field.get(&field).unwrap().1); self.push(value); } else { self.push(Value::Nil); @@ -544,13 +544,13 @@ impl VM { } Op::ReadUpvalue(slot) => { - let value = self.frame().block.borrow().ups[slot].2.as_value(); + let value = Value::from(&self.frame().block.borrow().ups[slot].2); self.push(value); } Op::AssignUpvalue(slot) => { let var = self.frame().block.borrow().ups[slot].2.clone(); - let up = self.pop().as_type(); + let up = self.pop().into(); if var != up { error!(self, ErrorKind::TypeError(op, vec![var, up]), "Incorrect type for upvalue.".to_string()); @@ -561,8 +561,8 @@ impl VM { let a = self.pop(); let inner = self.frame().block.borrow(); let ret = inner.ret(); - if a.as_type() != *ret { - error!(self, ErrorKind::TypeError(op, vec![a.as_type(), + if Type::from(&a) != *ret { + error!(self, ErrorKind::TypeError(op, vec![a.into(), ret.clone()]), "Not matching return type.".to_string()); } @@ -573,7 +573,7 @@ impl VM { } Op::Define(ref ty) => { - let top_type = self.stack.last().unwrap().as_type(); + let top_type = self.stack.last().unwrap().into(); match (ty, top_type) { (Type::UnknownType, top_type) if top_type != Type::UnknownType => {} @@ -601,7 +601,7 @@ impl VM { } for (slot, ty) in blob.name_to_field.values() { - values[*slot] = ty.as_value(); + values[*slot] = ty.into(); } self.pop(); @@ -618,7 +618,7 @@ impl VM { } let stack_args = &self.stack[self.stack.len() - args.len()..]; - let stack_args: Vec<_> = stack_args.iter().map(|x| x.as_type()).collect(); + let stack_args: Vec<_> = stack_args.iter().map(|x| x.into()).collect(); if args != &stack_args { error!(self, ErrorKind::TypeError(op.clone(), vec![]), @@ -626,7 +626,7 @@ impl VM { args, stack_args)); } - self.stack[new_base] = block.borrow().ret().as_value(); + self.stack[new_base] = block.borrow().ret().into(); self.stack.truncate(new_base + 1); } @@ -645,7 +645,7 @@ impl VM { } _ => { error!(self, - ErrorKind::TypeError(op.clone(), vec![self.stack[new_base].as_type()]), + ErrorKind::TypeError(op.clone(), vec![Type::from(&self.stack[new_base])]), format!("Tried to call non-function {:?}", self.stack[new_base])); } } @@ -654,7 +654,7 @@ impl VM { Op::JmpFalse(_) => { match self.pop() { Value::Bool(_) => {}, - a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a.as_type()])) }, + a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a.into()])) }, } } _ => { @@ -672,7 +672,7 @@ impl VM { self.push(Value::Function(Vec::new(), Rc::clone(&block))); for arg in block.borrow().args() { - self.push(arg.as_value()); + self.push(arg.into()); } self.frames.push(Frame { diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 241ef7d..fc43b5c 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -51,7 +51,7 @@ pub fn extern_function(tokens: TokenStream) -> TokenStream { let pat = block.pattern.clone(); let ty = block.return_ty.clone(); quote! { - #pat => { Ok(#ty.as_value()) } + #pat => { Ok(sylt::Value::from(#ty)) } } }).collect(); |
