Switch away from string builtins

This commit is contained in:
greg 2019-08-12 14:10:07 -07:00
parent 24089da788
commit 7ae41e717d
3 changed files with 72 additions and 64 deletions

View File

@ -5,8 +5,8 @@ use std::str::FromStr;
use crate::tokenizing::TokenKind; use crate::tokenizing::TokenKind;
use crate::typechecking::{TypeConst, Type}; use crate::typechecking::{TypeConst, Type};
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
enum Builtin { pub enum Builtin {
Add, Add,
Subtract, Subtract,
Multiply, Multiply,

View File

@ -9,24 +9,16 @@ use itertools::Itertools;
use crate::util::ScopeStack; use crate::util::ScopeStack;
use crate::reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Subpattern}; use crate::reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Subpattern};
use crate::symbol_table::{SymbolSpec, Symbol, SymbolTable}; use crate::symbol_table::{SymbolSpec, Symbol, SymbolTable};
use crate::builtin::Builtin;
pub struct State<'a> { pub struct State<'a> {
values: ScopeStack<'a, Rc<String>, ValueEntry>, values: ScopeStack<'a, Rc<String>, ValueEntry>,
symbol_table_handle: Rc<RefCell<SymbolTable>>, symbol_table_handle: Rc<RefCell<SymbolTable>>,
} }
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> { impl<'a> State<'a> {
pub fn new(symbol_table_handle: Rc<RefCell<SymbolTable>>) -> State<'a> { pub fn new(symbol_table_handle: Rc<RefCell<SymbolTable>>) -> State<'a> {
let mut values = ScopeStack::new(Some(format!("global"))); let values = ScopeStack::new(Some(format!("global")));
builtin_binding!("print", values);
builtin_binding!("println", values);
builtin_binding!("getline", values);
State { values, symbol_table_handle } State { values, symbol_table_handle }
} }
@ -119,7 +111,7 @@ impl Expr {
StringLit(s) => format!("\"{}\"", s), StringLit(s) => format!("\"{}\"", s),
}, },
Expr::Func(f) => match f { Expr::Func(f) => match f {
BuiltIn(name) => format!("<built-in function '{}'>", name), BuiltIn(builtin) => format!("<built-in function '{:?}'>", builtin),
UserDefined { name: None, .. } => format!("<function>"), UserDefined { name: None, .. } => format!("<function>"),
UserDefined { name: Some(name), .. } => format!("<function '{}'>", name), UserDefined { name: Some(name), .. } => format!("<function '{}'>", name),
}, },
@ -257,7 +249,7 @@ impl<'a> State<'a> {
fn apply_function(&mut self, f: Func, args: Vec<Expr>) -> EvalResult<Node> { fn apply_function(&mut self, f: Func, args: Vec<Expr>) -> EvalResult<Node> {
match f { 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 } => { Func::UserDefined { params, body, name } => {
if params.len() != args.len() { if params.len() != args.len() {
@ -277,9 +269,11 @@ impl<'a> State<'a> {
} }
} }
fn apply_builtin(&mut self, name: Rc<String>, args: Vec<Expr>) -> EvalResult<Expr> { fn apply_builtin(&mut self, builtin: Builtin, args: Vec<Expr>) -> EvalResult<Expr> {
use self::Expr::*; use self::Expr::*;
use self::Lit::*; use self::Lit::*;
use Builtin::*;
let evaled_args: Result<Vec<Expr>, String> = args.into_iter().map(|arg| { let evaled_args: Result<Vec<Expr>, String> = args.into_iter().map(|arg| {
match self.expression(Node::Expr(arg)) { match self.expression(Node::Expr(arg)) {
Ok(Node::Expr(e)) => Ok(e), Ok(Node::Expr(e)) => Ok(e),
@ -290,65 +284,65 @@ impl<'a> State<'a> {
}).collect(); }).collect();
let evaled_args = evaled_args?; let evaled_args = evaled_args?;
Ok(match (name.as_str(), evaled_args.as_slice()) { Ok(match (builtin, evaled_args.as_slice()) {
/* binops */ /* binops */
("+", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l + r)), (Add, &[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)))), (Concatenate, &[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)), (Subtract, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l - r)),
("*", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l * r)), (Multiply, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l * r)),
("/", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Float((l as f64)/ (r as f64))), (Divide, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Float((l as f64)/ (r as f64))),
("quot", &[Lit(Nat(l)), Lit(Nat(r))]) => if r == 0 { (Quotient, &[Lit(Nat(l)), Lit(Nat(r))]) => if r == 0 {
return Err(format!("divide by zero")); return Err(format!("divide by zero"));
} else { } else {
Lit(Nat(l / 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)),
("^", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l ^ r)), (Exponentiation, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l ^ r)),
("&", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l & r)), (BitwiseAnd, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l & r)),
("|", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l | r)), (BitwiseOr, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Nat(l | r)),
/* comparisons */ /* comparisons */
("==", &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l == r)), (Equality, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l == r)),
("==", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l == r)), (Equality, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l == r)),
("==", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l == r)), (Equality, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l == r)),
("==", &[Lit(Bool(l)), Lit(Bool(r))]) => Lit(Bool(l == r)), (Equality, &[Lit(Bool(l)), Lit(Bool(r))]) => Lit(Bool(l == r)),
("==", &[Lit(StringLit(ref l)), Lit(StringLit(ref 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)), (LessThan, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l < r)),
("<", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l < r)), (LessThan, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l < r)),
("<", &[Lit(Float(l)), Lit(Float(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)), (LessThanOrEqual, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l <= r)),
("<=", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l <= r)), (LessThanOrEqual, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l <= r)),
("<=", &[Lit(Float(l)), Lit(Float(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)), (GreaterThan, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l > r)),
(">", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l > r)), (GreaterThan, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l > r)),
(">", &[Lit(Float(l)), Lit(Float(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)), (GreaterThanOrEqual, &[Lit(Nat(l)), Lit(Nat(r))]) => Lit(Bool(l >= r)),
(">=", &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l >= r)), (GreaterThanOrEqual, &[Lit(Int(l)), Lit(Int(r))]) => Lit(Bool(l >= r)),
(">=", &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l >= r)), (GreaterThanOrEqual, &[Lit(Float(l)), Lit(Float(r))]) => Lit(Bool(l >= r)),
/* prefix ops */ /* prefix ops */
("!", &[Lit(Bool(true))]) => Lit(Bool(false)), (BooleanNot, &[Lit(Bool(true))]) => Lit(Bool(false)),
("!", &[Lit(Bool(false))]) => Lit(Bool(true)), (BooleanNot, &[Lit(Bool(false))]) => Lit(Bool(true)),
("-", &[Lit(Nat(n))]) => Lit(Int(-1*(n as i64))), (Subtract, &[Lit(Nat(n))]) => Lit(Int(-1*(n as i64))),
("-", &[Lit(Int(n))]) => Lit(Int(-1*(n as i64))), (Subtract, &[Lit(Int(n))]) => Lit(Int(-1*(n as i64))),
("+", &[Lit(Int(n))]) => Lit(Int(n)), (Add, &[Lit(Int(n))]) => Lit(Int(n)),
("+", &[Lit(Nat(n))]) => Lit(Nat(n)), (Add, &[Lit(Nat(n))]) => Lit(Nat(n)),
/* builtin functions */ /* builtin functions */
("print", &[ref anything]) => { (IOPrint, &[ref anything]) => {
print!("{}", anything.to_repl()); print!("{}", anything.to_repl());
Expr::Unit Expr::Unit
}, },
("println", &[ref anything]) => { (IOPrintLn, &[ref anything]) => {
println!("{}", anything.to_repl()); println!("{}", anything.to_repl());
Expr::Unit Expr::Unit
}, },
("getline", &[]) => { (IOGetLine, &[]) => {
let mut buf = String::new(); let mut buf = String::new();
io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'"); io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'");
Lit(StringLit(Rc::new(buf.trim().to_string()))) Lit(StringLit(Rc::new(buf.trim().to_string())))

View File

@ -13,10 +13,11 @@
//! symbol table. But I think the former might make sense since ultimately the bytecode will be //! symbol table. But I think the former might make sense since ultimately the bytecode will be
//! built from the ReducedAST. //! built from the ReducedAST.
use std::rc::Rc; use std::rc::Rc;
use std::str::FromStr;
use crate::ast::*; use crate::ast::*;
use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable}; use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable};
use crate::builtin::{BinOp, PrefixOp}; use crate::builtin::{BinOp, PrefixOp, Builtin};
#[derive(Debug)] #[derive(Debug)]
pub struct ReducedAST(pub Vec<Stmt>); pub struct ReducedAST(pub Vec<Stmt>);
@ -98,7 +99,7 @@ pub enum Lit {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Func { pub enum Func {
BuiltIn(Rc<String>), BuiltIn(Builtin),
UserDefined { UserDefined {
name: Option<Rc<String>>, name: Option<Rc<String>>,
params: Vec<Rc<String>>, params: Vec<Rc<String>>,
@ -353,7 +354,7 @@ impl PatternLiteral {
_ => panic!("This should never happen") _ => panic!("This should never happen")
}); });
let guard = Some(Expr::Call { 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], args: vec![comparison, Expr::ConditionalTargetSigilValue],
}); });
Subpattern { Subpattern {
@ -365,7 +366,7 @@ impl PatternLiteral {
}, },
StringPattern(s) => { StringPattern(s) => {
let guard = Some(Expr::Call { 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] args: vec![Expr::Lit(Lit::StringLit(s.clone())), Expr::ConditionalTargetSigilValue]
}); });
@ -381,7 +382,7 @@ impl PatternLiteral {
Expr::ConditionalTargetSigilValue Expr::ConditionalTargetSigilValue
} else { } else {
Expr::Call { 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] args: vec![Expr::ConditionalTargetSigilValue]
} }
}); });
@ -429,21 +430,34 @@ impl Declaration {
impl BinOp { impl BinOp {
fn reduce(&self, symbol_table: &SymbolTable, lhs: &Box<Meta<Expression>>, rhs: &Box<Meta<Expression>>) -> Expr { fn reduce(&self, symbol_table: &SymbolTable, lhs: &Box<Meta<Expression>>, rhs: &Box<Meta<Expression>>) -> Expr {
if **self.sigil() == "=" { let operation = Builtin::from_str(self.sigil()).ok();
Expr::Assign { match operation {
Some(Builtin::Assignment) => Expr::Assign {
val: Box::new(lhs.node().reduce(symbol_table)), val: Box::new(lhs.node().reduce(symbol_table)),
expr: Box::new(rhs.node().reduce(symbol_table)), expr: Box::new(rhs.node().reduce(symbol_table)),
} },
} else { Some(op) => {
let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); let f = Box::new(Expr::Func(Func::BuiltIn(op)));
Expr::Call { f, args: vec![lhs.node().reduce(symbol_table), rhs.node().reduce(symbol_table)]} Expr::Call { f, args: vec![lhs.node().reduce(symbol_table), rhs.node().reduce(symbol_table)]}
},
None => {
//TODO handle a user-defined operation
Expr::UnimplementedSigilValue
}
} }
} }
} }
impl PrefixOp { impl PrefixOp {
fn reduce(&self, symbol_table: &SymbolTable, arg: &Box<Meta<Expression>>) -> Expr { fn reduce(&self, symbol_table: &SymbolTable, arg: &Box<Meta<Expression>>) -> Expr {
let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); 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)]} Expr::Call { f, args: vec![arg.node().reduce(symbol_table)]}
},
None => {
Expr::UnimplementedSigilValue
}
}
} }
} }