From 2477c1f9a242a2d47c51759af7ad2ab406d6874d Mon Sep 17 00:00:00 2001 From: Yazalde Filimone Date: Thu, 22 Aug 2024 17:57:08 +0200 Subject: [PATCH] feat: emit and exec lua code --- Cargo.toml | 3 +- src/ast/ast.rs | 390 +++++++++++++++++++++++++++++++++++++++++++++++ src/cli.rs | 3 + src/emit/mod.rs | 7 + src/lib.rs | 1 + src/main.rs | 86 ++++++++++- src/types/mod.rs | 15 +- 7 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 src/emit/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 35b32f6..37d859c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "stella_checker" description = "Rust-based, speedy Lua type checker" authors = ["Yazalde Filimone "] -version = "0.1.1" +version = "0.2.1" edition = "2021" keywords = ["lua", "checker", "typechecker", "compiler"] categories = ["compilers", "text-processing", "development-tools"] @@ -17,6 +17,7 @@ path = "src/main.rs" [dependencies] clap = { version = "4.5.9", features = ["derive"] } code_highlighter = "0.1.1" +rlua = "0.20.1" serde = { version = "1.0.204", features = ["derive"] } [dev-dependencies] diff --git a/src/ast/ast.rs b/src/ast/ast.rs index dac4074..352e76d 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -15,6 +15,14 @@ impl Program { pub fn new() -> Program { Program { statements: Vec::new() } } + + pub fn emit(&self, raw: &mut String) -> String { + for statement in &self.statements { + *raw = statement.emit(raw); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -58,6 +66,25 @@ impl Statement { pub fn new_function(function: FunctionStatement) -> Self { Statement::Function(function) } + + pub fn emit(&self, raw: &mut String) -> String { + match self { + Statement::Function(function) => function.emit(raw), + Statement::Return(return_) => return_.emit(raw), + Statement::If(if_) => if_.emit(raw), + Statement::While(while_) => while_.emit(raw), + Statement::Repeat(repeat) => repeat.emit(raw), + Statement::For(for_) => for_.emit(raw), + Statement::Break(break_) => break_.emit(raw), + Statement::Goto(goto) => goto.emit(raw), + Statement::Block(block) => block.emit(raw), + Statement::Empty(empty) => empty.emit(raw), + Statement::TypeDeclaration(declaration) => declaration.emit(raw), + Statement::Continue(continue_) => continue_.emit(raw), + Statement::Local(local) => local.emit(raw), + Statement::Expression(expression) => expression.emit(raw), + } + } } #[derive(Debug, Serialize, Deserialize)] @@ -75,6 +102,24 @@ impl AssignExpression { pub fn get_range(&self) -> Range { return self.range.clone(); } + + pub fn emit(&self, raw: &mut String) -> String { + for (index, variable) in self.left.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = variable.emit(raw); + } + raw.push_str(" = "); + for (index, initializer) in self.right.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = initializer.emit(raw); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -106,6 +151,27 @@ impl FunctionStatement { pub fn get_range(&self) -> Range { return self.range.clone(); } + + pub fn emit(&self, raw: &mut String) -> String { + if self.local { + raw.push_str("local "); + } + + raw.push_str(&format!("function {}", self.name.lexeme())); + raw.push_str("("); + for (index, argument) in self.arguments.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = argument.emit(raw); + } + raw.push_str(")"); + raw.push_str("\n"); + *raw = self.body.emit(raw); + raw.push_str("\nend"); + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -121,6 +187,18 @@ impl ReturnStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("return "); + for (index, value) in self.values.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = value.emit(raw); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -135,6 +213,11 @@ impl ContinueStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("continue\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -160,6 +243,15 @@ impl ElseIfStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("elseif "); + *raw = self.condition.emit(raw); + raw.push_str(" then\n"); + *raw = self.then_branch.emit(raw); + raw.push_str("\n"); + return raw.to_string(); + } } impl IfStatement { @@ -182,6 +274,22 @@ impl IfStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("if "); + *raw = self.condition.emit(raw); + raw.push_str(" then\n"); + *raw = self.then_body.emit(raw); + for else_if_branch in &self.else_if_branches { + *raw = else_if_branch.emit(raw); + } + if let Some(else_body) = &self.else_body { + *raw = else_body.emit(raw); + } + raw.push_str("end"); + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -198,6 +306,16 @@ impl WhileStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("while "); + *raw = self.condition.emit(raw); + raw.push_str(" do\n"); + *raw = self.body.emit(raw); + raw.push_str("end"); + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -215,6 +333,15 @@ impl RepeatStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("repeat\n"); + *raw = self.body.emit(raw); + raw.push_str("until "); + *raw = self.condition.emit(raw); + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -240,6 +367,23 @@ impl ForStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("for "); + *raw = self.init.emit(raw); + raw.push_str(" = "); + *raw = self.limit.emit(raw); + if let Some(step) = &self.step { + raw.push_str(", "); + *raw = step.emit(raw); + } + raw.push_str(" do\n"); + *raw = self.body.emit(raw); + raw.push_str("end"); + raw.push_str("\n"); + + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -254,6 +398,11 @@ impl BreakStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("break\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -270,6 +419,15 @@ impl GotoStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("goto "); + if let Some(label) = &self.label { + raw.push_str(&format!("{}\n", label)); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -289,6 +447,13 @@ impl BlockStatement { let last_statement = self.statements.last().unwrap(); create_middle_range(&first_statement.get_range(), &last_statement.get_range()) } + + pub fn emit(&self, raw: &mut String) -> String { + for statement in &self.statements { + *raw = statement.emit(raw); + } + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -298,6 +463,11 @@ impl EmptyStatement { pub fn get_range(&self) -> Range { Range::new() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -322,6 +492,11 @@ impl TypeDeclaration { // todo: check if it's correct create_middle_range(&self.range, &self.name.range) } + + pub fn emit(&self, raw: &mut String) -> String { + // don't emit type's + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -339,6 +514,11 @@ impl TypeFunction { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + // don't emit type's + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -354,6 +534,12 @@ impl Variable { pub fn get_range(&self) -> Range { return self.name.range.clone(); } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("{}", self.name.lexeme())); + // don't emit type's + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -370,6 +556,25 @@ impl LocalStatement { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("local "); + for (index, variable) in self.variables.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = variable.emit(raw); + } + raw.push_str(" = "); + for (index, initializer) in self.initializer.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = initializer.emit(raw); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -386,6 +591,24 @@ impl AssignExpresion { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + for (index, variable) in self.variables.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = variable.emit(raw); + } + raw.push_str(" = "); + for (index, initializer) in self.initializer.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = initializer.emit(raw); + } + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -493,6 +716,24 @@ impl Expression { pub fn is_literal(&self) -> bool { matches!(self, Expression::Literal(_)) } + + pub fn emit(&self, raw: &mut String) -> String { + match self { + Expression::Literal(literal) => literal.emit(raw), + Expression::Identifier(identifier) => identifier.emit(raw), + Expression::Call(call) => call.emit(raw), + Expression::Unary(unary) => unary.emit(raw), + Expression::Grouped(grouped) => grouped.emit(raw), + Expression::Binary(binary) => binary.emit(raw), + Expression::Require(require) => require.emit(raw), + Expression::Function(function) => function.emit(raw), + Expression::Table(table) => table.emit(raw), + Expression::Member(member) => member.emit(raw), + Expression::Index(index) => index.emit(raw), + Expression::Assign(assign) => assign.emit(raw), + Expression::Variable(variable) => variable.emit(raw), + } + } } #[derive(Debug, Serialize, Deserialize)] @@ -511,6 +752,13 @@ impl RequireExpression { let left_range = self.range.clone(); create_middle_range(&left_range, &right_range) } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("require "); + raw.push_str(&format!("\"{}\"", self.module_name.lexeme())); + raw.push_str("\n"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -527,6 +775,18 @@ impl GroupedExpression { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + // raw.push_str("("); + for (index, expression) in self.expressions.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = expression.emit(raw); + } + // raw.push_str(")"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -539,6 +799,11 @@ impl Identifier { pub fn new(name: String, range: Range) -> Self { Identifier { name, range } } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("{}", self.name)); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -557,6 +822,14 @@ impl CallExpression { let right_range = self.args.get_range(); create_middle_range(&left_range, &right_range) } + + pub fn emit(&self, raw: &mut String) -> String { + *raw = self.left.emit(raw); + raw.push_str("("); + *raw = self.args.emit(raw); + raw.push_str(")"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -580,6 +853,13 @@ impl UnaryExpression { pub fn get_operator_range(&self) -> Range { self.range.clone() } + + // !aaa + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("{}", self.operator.to_str())); + *raw = self.operand.emit(raw); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -597,6 +877,13 @@ impl MemberExpression { let right_range = self.identifier.range.clone(); create_middle_range(&left_range, &right_range) } + + pub fn emit(&self, raw: &mut String) -> String { + *raw = self.base.emit(raw); + raw.push_str("."); + *raw = self.identifier.emit(raw); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -615,6 +902,14 @@ impl IndexExpression { let right_range = self.index.get_range(); create_middle_range(&left_range, &right_range) } + + pub fn emit(&self, raw: &mut String) -> String { + *raw = self.base.emit(raw); + raw.push_str("["); + *raw = self.index.emit(raw); + raw.push_str("]"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] pub struct TableExpression { @@ -630,6 +925,21 @@ impl TableExpression { pub fn get_range(&self) -> Range { self.range.clone() } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("{"); + for (index, value) in self.values.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = value.0.emit(raw); + if let Some(value) = &value.1 { + raw.push_str(" = "); + *raw = value.emit(raw); + } + } + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -656,6 +966,20 @@ impl FunctionExpression { let left_range = self.range.clone(); return left_range; } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("function "); + for (index, argument) in self.arguments.iter().enumerate() { + if index > 0 { + raw.push_str(", "); + } + *raw = argument.emit(raw); + } + raw.push_str("\n"); + *raw = self.body.emit(raw); + raw.push_str("\nend"); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -675,6 +999,13 @@ impl BinaryExpression { let right_range = self.right.get_range(); create_middle_range(&left_range, &right_range) } + + pub fn emit(&self, raw: &mut String) -> String { + *raw = self.left.emit(raw); + *raw = self.operator.emit(raw); + *raw = self.right.emit(raw); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -710,6 +1041,15 @@ impl LiteralExpression { LiteralExpression::Nil(nil) => nil.range.clone(), } } + + pub fn emit(&self, raw: &mut String) -> String { + match self { + LiteralExpression::Number(number) => number.emit(raw), + LiteralExpression::String(string) => string.emit(raw), + LiteralExpression::Boolean(boolean) => boolean.emit(raw), + LiteralExpression::Nil(nil) => nil.emit(raw), + } + } } #[derive(Debug, Serialize, Deserialize)] @@ -722,6 +1062,11 @@ impl NumberLiteral { pub fn new(value: String, range: Range) -> Self { NumberLiteral { value, range } } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("{}", self.value)); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -734,6 +1079,11 @@ impl StringLiteral { pub fn new(value: String, range: Range) -> Self { StringLiteral { value, range } } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("\"{}\"", self.value)); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -746,6 +1096,11 @@ impl BooleanLiteral { pub fn new(value: bool, range: Range) -> Self { BooleanLiteral { value, range } } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str(&format!("{}", self.value)); + return raw.to_string(); + } } #[derive(Debug, Serialize, Deserialize)] @@ -757,6 +1112,11 @@ impl NilLiteral { pub fn new(range: Range) -> Self { NilLiteral { range } } + + pub fn emit(&self, raw: &mut String) -> String { + raw.push_str("nil"); + return raw.to_string(); + } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -789,6 +1149,15 @@ impl UnaryOperator { pub fn support_nil(&self) -> bool { matches!(self, UnaryOperator::Not) } + + pub fn emit(&self, raw: &mut String) -> String { + match self { + UnaryOperator::Negate => raw.push_str("-"), + UnaryOperator::Not => raw.push_str("not "), + UnaryOperator::Hash => raw.push_str("#"), + } + return raw.to_string(); + } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -841,6 +1210,27 @@ impl BinaryOperator { pub fn has_equal_precedence_to(&self, other: &BinaryOperator) -> bool { self.precedence() == other.precedence() } + + pub fn emit(&self, raw: &mut String) -> String { + match self { + BinaryOperator::Add => raw.push_str("+"), + BinaryOperator::Subtract => raw.push_str("-"), + BinaryOperator::Multiply => raw.push_str("*"), + BinaryOperator::Divide => raw.push_str("/"), + BinaryOperator::Modulus => raw.push_str("%"), + BinaryOperator::And => raw.push_str("and"), + BinaryOperator::Or => raw.push_str("or"), + BinaryOperator::Equal => raw.push_str("=="), + BinaryOperator::NotEqual => raw.push_str("~="), + BinaryOperator::LessThan => raw.push_str("<"), + BinaryOperator::GreaterThan => raw.push_str(">"), + BinaryOperator::LessThanOrEqual => raw.push_str("<="), + BinaryOperator::GreaterThanOrEqual => raw.push_str(">="), + BinaryOperator::DoubleDot => raw.push_str(".."), + BinaryOperator::DoubleSlash => raw.push_str("//"), + } + return raw.to_string(); + } } pub struct TypeExpression { diff --git a/src/cli.rs b/src/cli.rs index faa56ef..b807b5a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -16,6 +16,9 @@ pub fn command_line() -> clap::ArgMatches { .about("transform a lua file to a native executable.") .arg(Arg::new("file").help("the lua file to compile.").required(true)), ) + .subcommand( + Command::new("run").about("run stella code.").arg(Arg::new("file").help("the lua file to run.").required(true)), + ) .get_matches(); return matches; diff --git a/src/emit/mod.rs b/src/emit/mod.rs new file mode 100644 index 0000000..aba8bc8 --- /dev/null +++ b/src/emit/mod.rs @@ -0,0 +1,7 @@ +use crate::ast::ast; + +pub fn emit(progrma: &ast::Program, _path_name: &str) -> String { + println!("emitting lua code..."); + let raw = progrma.emit(&mut String::new()); + return raw; +} diff --git a/src/lib.rs b/src/lib.rs index c2a8725..1397e11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod checker; pub mod cli; pub mod context; pub mod diagnostics; +pub mod emit; pub mod formatting; pub mod lexer; pub mod modules; diff --git a/src/main.rs b/src/main.rs index ba7be59..16980f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod checker; mod cli; mod context; mod diagnostics; +mod emit; mod formatting; mod lexer; mod modules; @@ -11,8 +12,18 @@ mod stdlib; mod types; mod utils; +use std::{ + fs::{self, File}, + io::Write, + path::Path, +}; + use checker::Checker; use parser::parser::Parser; +use rlua::Lua; +use stella_checker::utils::highlight_text_with_red; + +const OUTPUT_DIRECTORY: &str = "build"; fn main() { let matches = cli::command_line(); @@ -22,9 +33,17 @@ fn main() { let path_name = matches.get_one::("file").unwrap(); run_check(path_name); } + Some(("compile", matches)) => { let path_name = matches.get_one::("file").unwrap(); - run_compile(path_name); + let result = run_compile(path_name); + if result.is_err() { + std::process::exit(1); + } + } + Some(("run", matches)) => { + let path_name = matches.get_one::("file").unwrap(); + run(path_name); } _ => panic!("No subcommand provided."), } @@ -41,11 +60,70 @@ fn run_check(path_name: &str) { return; } let type_ = type_result.unwrap(); - println!("Result: {}", type_.to_string()); + println!("Result Type: {}", type_); +} + +fn run_compile(path_name: &str) -> Result<(), std::io::Error> { + let raw = std::fs::read_to_string(path_name).unwrap(); + let mut parser = Parser::new(&raw, path_name); + let program = parser.parse_program(); + let mut checker = Checker::new(path_name, &raw); + let type_result = checker.check(&program); + + if type_result.is_err() || checker.diagnostics.error_count > 0 { + checker.diagnostics.emit_all(&raw, path_name); + std::process::exit(1); + } + + let output = create_output_directory(path_name); + let raw = emit::emit(&program, &path_name); + let path = Path::new(&output); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let mut file = File::create(path)?; + file.write_all(raw.as_bytes())?; + Ok(()) } -fn run_compile(path_name: &str) { + +fn run(path_name: &str) { let raw = std::fs::read_to_string(path_name).unwrap(); let mut parser = Parser::new(&raw, path_name); let program = parser.parse_program(); - println!("{:#?}", program); + let mut checker = Checker::new(path_name, &raw); + let type_result = checker.check(&program); + + if type_result.is_err() || checker.diagnostics.error_count > 0 { + checker.diagnostics.emit_all(&raw, path_name); + return; + } + let raw = emit::emit(&program, &path_name); + let lua = Lua::new(); + let result = lua.load(raw).exec(); + + match result { + Ok(_) => {} + Err(err) => { + println!("{}", highlight_text_with_red(remove_location(err.to_string().as_str()).as_str())); + } + } +} + +fn create_output_directory(path_name: &str) -> String { + let output_path = std::path::Path::new(OUTPUT_DIRECTORY); + if !output_path.exists() { + std::fs::create_dir(output_path).expect("failed to create output directory"); + } + let out_path = format!("{}/{}", OUTPUT_DIRECTORY, path_name.replace("./", "")); + return out_path; +} + +fn remove_location(error_message: &str) -> String { + if let Some(start) = error_message.find("[string \"") { + if let Some(end) = error_message[start..].find(": ") { + let clean_message = format!("{}{}", &error_message[..start], &error_message[start + end + 1..].trim()); + return clean_message.trim().to_string(); + } + } + error_message.to_string() } diff --git a/src/types/mod.rs b/src/types/mod.rs index 56af102..ff88eb9 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -244,8 +244,8 @@ impl Type { // math operators Add | Subtract | Multiply | Divide | Modulus | DoubleSlash => match (self, other) { (Type::Number, Type::Number) - | (Type::Unknown, Type::Number) | (Type::Number, Type::Unknown) + | (Type::Unknown, Type::Number) | (Type::Unknown, Type::Unknown) => Type::Number, _ => unreachable!("left: {:#?} {} right: {:#?}", self, operator, other), }, @@ -253,20 +253,19 @@ impl Type { // println!("comparison operators"); Equal | NotEqual | LessThan | GreaterThan | LessThanOrEqual | GreaterThanOrEqual => match (self, other) { (Type::Number, Type::Number) - | (Type::Unknown, Type::Number) - | (Type::Number, Type::Unknown) | (Type::String, Type::String) - | (Type::Unknown, Type::String) - | (Type::String, Type::Unknown) | (Type::Boolean, Type::Boolean) - | (Type::Unknown, Type::Boolean) - | (Type::Boolean, Type::Unknown) - | (Type::Unknown, Type::Unknown) => Type::Boolean, + | (Type::Nil, _) + | (_, Type::Nil) + | (_, Type::Unknown) + | (Type::Unknown, _) => Type::Boolean, _ => unreachable!("left: {:#?} {} right: {:#?}", self, operator, other), }, // logical operators And | Or => match (self, other) { (Type::Boolean, Type::Boolean) + | (_, Type::Nil) + | (Type::Nil, _) | (Type::Unknown, Type::Boolean) | (Type::Boolean, Type::Unknown) | (Type::Unknown, Type::Unknown) => Type::Boolean,