diff --git a/schala-lang/language/src/builtin.rs b/schala-lang/language/src/builtin.rs index 3927d99..6cc5577 100644 --- a/schala-lang/language/src/builtin.rs +++ b/schala-lang/language/src/builtin.rs @@ -5,8 +5,8 @@ use std::str::FromStr; use crate::tokenizing::TokenKind; use crate::typechecking::{TypeConst, Type}; -#[derive(Debug)] -enum Builtin { +#[derive(Debug, Clone, Copy)] +pub enum Builtin { Add, Subtract, Multiply, diff --git a/schala-lang/language/src/eval.rs b/schala-lang/language/src/eval.rs index 8f3fe88..73bd769 100644 --- a/schala-lang/language/src/eval.rs +++ b/schala-lang/language/src/eval.rs @@ -9,24 +9,16 @@ use itertools::Itertools; use crate::util::ScopeStack; use crate::reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Subpattern}; use crate::symbol_table::{SymbolSpec, Symbol, SymbolTable}; +use crate::builtin::Builtin; pub struct State<'a> { values: ScopeStack<'a, Rc, ValueEntry>, symbol_table_handle: Rc>, } -macro_rules! builtin_binding { - ($name:expr, $values:expr) => { - $values.insert(Rc::new(format!($name)), ValueEntry::Binding { constant: true, val: Node::Expr(Expr::Func(Func::BuiltIn(Rc::new(format!($name))))) }); - } -} - impl<'a> State<'a> { pub fn new(symbol_table_handle: Rc>) -> State<'a> { - let mut values = ScopeStack::new(Some(format!("global"))); - builtin_binding!("print", values); - builtin_binding!("println", values); - builtin_binding!("getline", values); + let values = ScopeStack::new(Some(format!("global"))); State { values, symbol_table_handle } } @@ -119,7 +111,7 @@ impl Expr { StringLit(s) => format!("\"{}\"", s), }, Expr::Func(f) => match f { - BuiltIn(name) => format!("", name), + BuiltIn(builtin) => format!("", builtin), UserDefined { name: None, .. } => format!(""), UserDefined { name: Some(name), .. } => format!("", name), }, @@ -257,7 +249,7 @@ impl<'a> State<'a> { fn apply_function(&mut self, f: Func, args: Vec) -> EvalResult { match f { - Func::BuiltIn(sigil) => Ok(Node::Expr(self.apply_builtin(sigil, args)?)), + Func::BuiltIn(builtin) => Ok(Node::Expr(self.apply_builtin(builtin, args)?)), Func::UserDefined { params, body, name } => { if params.len() != args.len() { @@ -277,9 +269,11 @@ impl<'a> State<'a> { } } - fn apply_builtin(&mut self, name: Rc, args: Vec) -> EvalResult { + fn apply_builtin(&mut self, builtin: Builtin, args: Vec) -> EvalResult { use self::Expr::*; use self::Lit::*; + use Builtin::*; + let evaled_args: Result, String> = args.into_iter().map(|arg| { match self.expression(Node::Expr(arg)) { Ok(Node::Expr(e)) => Ok(e), @@ -290,65 +284,65 @@ impl<'a> State<'a> { }).collect(); let evaled_args = evaled_args?; - Ok(match (name.as_str(), evaled_args.as_slice()) { + Ok(match (builtin, evaled_args.as_slice()) { /* binops */ - ("+", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l + r)), - ("++", &[Lit(StringLit(ref s1)), Lit(StringLit(ref s2))]) => Lit(StringLit(Rc::new(format!("{}{}", s1, s2)))), - ("-", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l - r)), - ("*", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l * r)), - ("/", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Float((l as f64)/ (r as f64))), - ("quot", &[Lit(Nat(l)), Lit(Nat(r))]) => if r == 0 { + (Add, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l + r)), + (Concatenate, &[Lit(StringLit(ref s1)), Lit(StringLit(ref s2))]) => Lit(StringLit(Rc::new(format!("{}{}", s1, s2)))), + (Subtract, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l - r)), + (Multiply, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l * r)), + (Divide, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Float((l as f64)/ (r as f64))), + (Quotient, &[Lit(Nat(l)), Lit(Nat(r))]) => if r == 0 { return Err(format!("divide by zero")); } else { Lit(Nat(l / r)) }, - ("%", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l % r)), - ("^", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l ^ r)), - ("&", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l & r)), - ("|", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l | r)), + (Modulo, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l % r)), + (Exponentiation, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l ^ r)), + (BitwiseAnd, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l & r)), + (BitwiseOr, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l | r)), /* comparisons */ - ("==", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l == r)), - ("==", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l == r)), - ("==", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l == r)), - ("==", &[Lit(Bool(l)), Lit(Bool(r))]) => Lit(Bool(l == r)), - ("==", &[Lit(StringLit(ref l)), Lit(StringLit(ref r))]) => Lit(Bool(l == r)), + (Equality, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l == r)), + (Equality, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l == r)), + (Equality, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l == r)), + (Equality, &[Lit(Bool(l)), Lit(Bool(r))]) => Lit(Bool(l == r)), + (Equality, &[Lit(StringLit(ref l)), Lit(StringLit(ref r))]) => Lit(Bool(l == r)), - ("<", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l < r)), - ("<", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l < r)), - ("<", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l < r)), + (LessThan, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l < r)), + (LessThan, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l < r)), + (LessThan, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l < r)), - ("<=", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l <= r)), - ("<=", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l <= r)), - ("<=", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l <= r)), + (LessThanOrEqual, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l <= r)), + (LessThanOrEqual, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l <= r)), + (LessThanOrEqual, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l <= r)), - (">", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l > r)), - (">", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l > r)), - (">", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l > r)), + (GreaterThan, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l > r)), + (GreaterThan, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l > r)), + (GreaterThan, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l > r)), - (">=", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l >= r)), - (">=", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l >= r)), - (">=", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l >= r)), + (GreaterThanOrEqual, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l >= r)), + (GreaterThanOrEqual, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l >= r)), + (GreaterThanOrEqual, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l >= r)), /* prefix ops */ - ("!", &[Lit(Bool(true))]) => Lit(Bool(false)), - ("!", &[Lit(Bool(false))]) => Lit(Bool(true)), - ("-", &[Lit(Nat(n))]) => Lit(Int(-1*(n as i64))), - ("-", &[Lit(Int(n))]) => Lit(Int(-1*(n as i64))), - ("+", &[Lit(Int(n))]) => Lit(Int(n)), - ("+", &[Lit(Nat(n))]) => Lit(Nat(n)), + (BooleanNot, &[Lit(Bool(true))]) => Lit(Bool(false)), + (BooleanNot, &[Lit(Bool(false))]) => Lit(Bool(true)), + (Subtract, &[Lit(Nat(n))]) => Lit(Int(-1*(n as i64))), + (Subtract, &[Lit(Int(n))]) => Lit(Int(-1*(n as i64))), + (Add, &[Lit(Int(n))]) => Lit(Int(n)), + (Add, &[Lit(Nat(n))]) => Lit(Nat(n)), /* builtin functions */ - ("print", &[ref anything]) => { + (IOPrint, &[ref anything]) => { print!("{}", anything.to_repl()); Expr::Unit }, - ("println", &[ref anything]) => { + (IOPrintLn, &[ref anything]) => { println!("{}", anything.to_repl()); Expr::Unit }, - ("getline", &[]) => { + (IOGetLine, &[]) => { let mut buf = String::new(); io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'"); Lit(StringLit(Rc::new(buf.trim().to_string()))) diff --git a/schala-lang/language/src/reduced_ast.rs b/schala-lang/language/src/reduced_ast.rs index 40669f7..20a44ef 100644 --- a/schala-lang/language/src/reduced_ast.rs +++ b/schala-lang/language/src/reduced_ast.rs @@ -13,10 +13,11 @@ //! symbol table. But I think the former might make sense since ultimately the bytecode will be //! built from the ReducedAST. use std::rc::Rc; +use std::str::FromStr; use crate::ast::*; use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable}; -use crate::builtin::{BinOp, PrefixOp}; +use crate::builtin::{BinOp, PrefixOp, Builtin}; #[derive(Debug)] pub struct ReducedAST(pub Vec); @@ -98,7 +99,7 @@ pub enum Lit { #[derive(Debug, Clone)] pub enum Func { - BuiltIn(Rc), + BuiltIn(Builtin), UserDefined { name: Option>, params: Vec>, @@ -353,7 +354,7 @@ impl PatternLiteral { _ => panic!("This should never happen") }); let guard = Some(Expr::Call { - f: Box::new(Expr::Func(Func::BuiltIn(Rc::new("==".to_string())))), + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::Equality))), args: vec![comparison, Expr::ConditionalTargetSigilValue], }); Subpattern { @@ -365,7 +366,7 @@ impl PatternLiteral { }, StringPattern(s) => { let guard = Some(Expr::Call { - f: Box::new(Expr::Func(Func::BuiltIn(Rc::new("==".to_string())))), + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::Equality))), args: vec![Expr::Lit(Lit::StringLit(s.clone())), Expr::ConditionalTargetSigilValue] }); @@ -381,7 +382,7 @@ impl PatternLiteral { Expr::ConditionalTargetSigilValue } else { Expr::Call { - f: Box::new(Expr::Func(Func::BuiltIn(Rc::new("!".to_string())))), + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::BooleanNot))), args: vec![Expr::ConditionalTargetSigilValue] } }); @@ -429,21 +430,34 @@ impl Declaration { impl BinOp { fn reduce(&self, symbol_table: &SymbolTable, lhs: &Box>, rhs: &Box>) -> Expr { - if **self.sigil() == "=" { - Expr::Assign { + let operation = Builtin::from_str(self.sigil()).ok(); + match operation { + Some(Builtin::Assignment) => Expr::Assign { val: Box::new(lhs.node().reduce(symbol_table)), expr: Box::new(rhs.node().reduce(symbol_table)), + }, + Some(op) => { + let f = Box::new(Expr::Func(Func::BuiltIn(op))); + Expr::Call { f, args: vec![lhs.node().reduce(symbol_table), rhs.node().reduce(symbol_table)]} + }, + None => { + //TODO handle a user-defined operation + Expr::UnimplementedSigilValue } - } else { - let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); - Expr::Call { f, args: vec![lhs.node().reduce(symbol_table), rhs.node().reduce(symbol_table)]} } } } impl PrefixOp { fn reduce(&self, symbol_table: &SymbolTable, arg: &Box>) -> Expr { - let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); - Expr::Call { f, args: vec![arg.node().reduce(symbol_table)]} + match Builtin::from_str(self.sigil()).ok() { + Some(op) => { + let f = Box::new(Expr::Func(Func::BuiltIn(op))); + Expr::Call { f, args: vec![arg.node().reduce(symbol_table)]} + }, + None => { + Expr::UnimplementedSigilValue + } + } } }