Switch away from string builtins
This commit is contained in:
parent
24089da788
commit
7ae41e717d
@ -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,
|
||||||
|
@ -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())))
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user