more pipeline, partial fns, block comments
This commit is contained in:
parent
19b7215234
commit
c5380e383e
9 changed files with 172 additions and 31 deletions
|
@ -11,12 +11,14 @@ fn count_by(delta, limit) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
# counter is an iterator
|
#{
|
||||||
# iterators are functions that:
|
counter is an iterator
|
||||||
# - take no arguments
|
iterators are functions that:
|
||||||
# - return nil once done
|
- take no arguments
|
||||||
# - once returned nil once, must do so for all subsequent calls
|
- return nil once done
|
||||||
# the interpreter only checks the first requirement
|
- once returned nil once, must do so for all subsequent calls
|
||||||
|
the interpreter only checks the first requirement
|
||||||
|
}#
|
||||||
let counter = count_by(2, 5);
|
let counter = count_by(2, 5);
|
||||||
println(counter()); # 0
|
println(counter()); # 0
|
||||||
println(counter()); # 2
|
println(counter()); # 2
|
||||||
|
|
1
complexpr/examples/quine.cxpr
Normal file
1
complexpr/examples/quine.cxpr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
let s="let s=;let p=print;for n:range(0,6){p(s[n]);}p(chr(34)+s+chr(34));for n:range(6,105){p(s[n]);}p(chr(10));";let p=print;for n:range(0,6){p(s[n]);}p(chr(34)+s+chr(34));for n:range(6,105){p(s[n]);}p(chr(10));
|
|
@ -130,7 +130,7 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
=> eval_assignment(lhs, rhs, op, env),
|
=> eval_assignment(lhs, rhs, op, env),
|
||||||
Some(OpType::Additive) | Some(OpType::Multiplicative) | Some(OpType::Exponential)
|
Some(OpType::Additive) | Some(OpType::Multiplicative) | Some(OpType::Exponential)
|
||||||
=> eval_arith(lhs, rhs, op, env),
|
=> eval_arith(lhs, rhs, op, env),
|
||||||
Some(OpType::Boolean)
|
Some(OpType::LogicalAnd) | Some(OpType::LogicalOr)
|
||||||
=> eval_boolean(lhs, rhs, op, env),
|
=> eval_boolean(lhs, rhs, op, env),
|
||||||
Some(OpType::Comparison)
|
Some(OpType::Comparison)
|
||||||
=> eval_comp(lhs, rhs, op, env),
|
=> eval_comp(lhs, rhs, op, env),
|
||||||
|
@ -138,6 +138,7 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
=> eval_pipeline(lhs, rhs, op, env),
|
=> eval_pipeline(lhs, rhs, op, env),
|
||||||
o => todo!("{:?}", o) // TODO other operations
|
o => todo!("{:?}", o) // TODO other operations
|
||||||
},
|
},
|
||||||
|
Expr::Ternary { .. } => todo!(),
|
||||||
Expr::Unary { arg, op } => eval_unary(arg, op, env),
|
Expr::Unary { arg, op } => eval_unary(arg, op, env),
|
||||||
Expr::List { items } => {
|
Expr::List { items } => {
|
||||||
let mut list = Vec::with_capacity(items.len());
|
let mut list = Vec::with_capacity(items.len());
|
||||||
|
@ -225,9 +226,9 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul
|
||||||
// plain assignment
|
// plain assignment
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
env.borrow_mut()
|
env.borrow_mut()
|
||||||
.set(name.clone(), r)
|
.set(name.clone(), r.clone())
|
||||||
.map_err(|_| RuntimeError::new("Variable not declared before assignment", op.pos.clone()))?;
|
.map_err(|_| RuntimeError::new("Variable not declared before assignment", op.pos.clone()))?;
|
||||||
Ok(Value::Nil)
|
Ok(r)
|
||||||
} else {
|
} else {
|
||||||
// compound assignment
|
// compound assignment
|
||||||
let prev_value = env.borrow_mut()
|
let prev_value = env.borrow_mut()
|
||||||
|
@ -371,6 +372,35 @@ fn eval_pipeline_inner(l: Value, r: Value, op: &Token) -> Result<Value, RuntimeE
|
||||||
func: pipequestion_inner,
|
func: pipequestion_inner,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
TokenType::PipeDoubleSlash => {
|
||||||
|
let mut result = Value::Nil;
|
||||||
|
let mut first_iter = true;
|
||||||
|
for v in l.iter().map_err(|e| RuntimeError::new(e, op.pos.clone()))? {
|
||||||
|
let v = v.map_err(|e| e.complete(op.pos.clone()))?;
|
||||||
|
if first_iter {
|
||||||
|
result = v;
|
||||||
|
first_iter = false;
|
||||||
|
} else {
|
||||||
|
result = r.call(vec![result, v]).map_err(|e| e.complete(op.pos.clone()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
TokenType::PipeDoubleBackslash => {
|
||||||
|
let mut result = Value::Nil;
|
||||||
|
let mut first_iter = true;
|
||||||
|
let lst = l.iter().map_err(|e| RuntimeError::new(e, op.pos.clone()))?.collect::<Vec<Result<Value, RuntimeError>>>();
|
||||||
|
for v in lst.into_iter().rev() {
|
||||||
|
let v = v.map_err(|e| e.complete(op.pos.clone()))?;
|
||||||
|
if first_iter {
|
||||||
|
result = v;
|
||||||
|
first_iter = false;
|
||||||
|
} else {
|
||||||
|
result = r.call(vec![v, result]).map_err(|e| e.complete(op.pos.clone()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ impl fmt::Debug for Stmt {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Binary { lhs: Box<Expr>, rhs: Box<Expr>, op: Token },
|
Binary { lhs: Box<Expr>, rhs: Box<Expr>, op: Token },
|
||||||
|
Ternary { arg1: Box<Expr>, arg2: Box<Expr>, arg3: Box<Expr>, op: Token },
|
||||||
Unary { arg: Box<Expr>, op: Token },
|
Unary { arg: Box<Expr>, op: Token },
|
||||||
Ident { value: Token },
|
Ident { value: Token },
|
||||||
Literal { value: Token },
|
Literal { value: Token },
|
||||||
|
@ -50,6 +51,7 @@ impl fmt::Debug for Expr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Binary { lhs: left, rhs: right, op} => write!(f, "({:?} {:?} {:?})", op, left, right),
|
Self::Binary { lhs: left, rhs: right, op} => write!(f, "({:?} {:?} {:?})", op, left, right),
|
||||||
|
Self::Ternary { arg1, arg2, arg3, op} => write!(f, "({:?} {:?} {:?} {:?})", op, arg1, arg2, arg3),
|
||||||
Self::Unary { arg, op } => write!(f, "({:?} {:?})", op, arg),
|
Self::Unary { arg, op } => write!(f, "({:?} {:?})", op, arg),
|
||||||
Self::Ident { value } => write!(f, "(ident {:?})", value),
|
Self::Ident { value } => write!(f, "(ident {:?})", value),
|
||||||
Self::Literal { value } => write!(f, "(lit {:?})", value),
|
Self::Literal { value } => write!(f, "(lit {:?})", value),
|
||||||
|
|
|
@ -191,12 +191,20 @@ impl Lexer {
|
||||||
Some('&') => self.add_token(TokenType::DoubleAmper, "&&"),
|
Some('&') => self.add_token(TokenType::DoubleAmper, "&&"),
|
||||||
_ => self.add_token(TokenType::Amper, "&"),
|
_ => self.add_token(TokenType::Amper, "&"),
|
||||||
},
|
},
|
||||||
'|' => match self.expect(&['|', ':', '?', '>', '&']) {
|
'|' => match self.expect(&['|', ':', '?', '>', '&', '/', '\\']) {
|
||||||
Some('|') => self.add_token(TokenType::DoublePipe, "||"),
|
Some('|') => self.add_token(TokenType::DoublePipe, "||"),
|
||||||
Some(':') => self.add_token(TokenType::PipeColon, "|:"),
|
Some(':') => self.add_token(TokenType::PipeColon, "|:"),
|
||||||
Some('?') => self.add_token(TokenType::PipeQuestion, "|?"),
|
Some('?') => self.add_token(TokenType::PipeQuestion, "|?"),
|
||||||
Some('>') => self.add_token(TokenType::PipePoint, "|>"),
|
Some('>') => self.add_token(TokenType::PipePoint, "|>"),
|
||||||
Some('&') => self.add_token(TokenType::PipeAmper, "|&"),
|
Some('&') => self.add_token(TokenType::PipeAmper, "|&"),
|
||||||
|
Some('/') => match self.expect(&['/']) {
|
||||||
|
Some(_) => self.add_token(TokenType::PipeDoubleSlash, "|//"),
|
||||||
|
None => self.add_token(TokenType::PipeSlash, "|/")
|
||||||
|
},
|
||||||
|
Some('\\') => match self.expect(&['\\']) {
|
||||||
|
Some(_) => self.add_token(TokenType::PipeDoubleBackslash, "|\\\\"),
|
||||||
|
None => self.add_token(TokenType::PipeBackslash, "|\\")
|
||||||
|
},
|
||||||
_ => self.add_token(TokenType::Pipe, "|"),
|
_ => self.add_token(TokenType::Pipe, "|"),
|
||||||
},
|
},
|
||||||
',' => self.add_token(TokenType::Comma, ","),
|
',' => self.add_token(TokenType::Comma, ","),
|
||||||
|
@ -208,12 +216,30 @@ impl Lexer {
|
||||||
']' => self.add_token(TokenType::RBrack, "]"),
|
']' => self.add_token(TokenType::RBrack, "]"),
|
||||||
'{' => self.add_token(TokenType::LBrace, "{"),
|
'{' => self.add_token(TokenType::LBrace, "{"),
|
||||||
'}' => self.add_token(TokenType::RBrace, "}"),
|
'}' => self.add_token(TokenType::RBrace, "}"),
|
||||||
'#' => {
|
'#' => match self.expect(&['{']) {
|
||||||
while !self.at_end() && self.peek() != '\n' {
|
Some(_) => {
|
||||||
self.advance(false);
|
while !self.at_end() {
|
||||||
}
|
if self.peek() == '}' {
|
||||||
self.advance(true);
|
self.advance(false);
|
||||||
},
|
if self.at_end() { break }
|
||||||
|
if self.peek() == '#' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.advance(false);
|
||||||
|
}
|
||||||
|
if self.at_end() {
|
||||||
|
return Err(self.mk_error("Unexpected EOF in block comment"))
|
||||||
|
}
|
||||||
|
self.advance(true);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
while !self.at_end() && self.peek() != '\n' {
|
||||||
|
self.advance(false);
|
||||||
|
}
|
||||||
|
self.advance(true);
|
||||||
|
},
|
||||||
|
}
|
||||||
'"' => self.string()?,
|
'"' => self.string()?,
|
||||||
'\'' => self.char()?,
|
'\'' => self.char()?,
|
||||||
' ' | '\t' | '\r' | '\n' => (),
|
' ' | '\t' | '\r' | '\n' => (),
|
||||||
|
|
|
@ -272,11 +272,30 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pipeline(&mut self) -> Result<Expr, ParserError> {
|
fn pipeline(&mut self) -> Result<Expr, ParserError> {
|
||||||
self.expr(OpType::Pipeline, Self::boolean)
|
let mut expr = self.logical_or()?;
|
||||||
|
while !self.at_end() && self.peek().ty.get_op_type() == Some(OpType::Pipeline) {
|
||||||
|
let op = self.next();
|
||||||
|
let right = self.logical_or()?;
|
||||||
|
if op.ty == TokenType::PipeSlash || op.ty == TokenType::PipeBackslash {
|
||||||
|
let next = self.next();
|
||||||
|
if next.ty != TokenType::Comma {
|
||||||
|
return Err(self.mk_error("Expected comma after first argument"))
|
||||||
|
}
|
||||||
|
let right2 = self.logical_or()?;
|
||||||
|
expr = Expr::Ternary { arg1: Box::new(expr), arg2: Box::new(right), arg3: Box::new(right2), op }
|
||||||
|
} else {
|
||||||
|
expr = Expr::Binary { lhs: Box::new(expr), rhs: Box::new(right), op };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn boolean(&mut self) -> Result<Expr, ParserError> {
|
fn logical_or(&mut self) -> Result<Expr, ParserError> {
|
||||||
self.expr(OpType::Boolean, Self::comparison)
|
self.expr(OpType::LogicalOr, Self::logical_and)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn logical_and(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
self.expr(OpType::LogicalAnd, Self::comparison)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> Result<Expr, ParserError> {
|
fn comparison(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
@ -339,7 +358,7 @@ impl Parser {
|
||||||
let index = self.assignment()?;
|
let index = self.assignment()?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
if self.next().ty != TokenType::RBrack {
|
if self.next().ty != TokenType::RBrack {
|
||||||
return Err(ParserError { message: "Expected RBrack after collection index".into(), pos: lbrack.pos });
|
return Err(self.mk_error("Expected RBrack after collection index"))
|
||||||
}
|
}
|
||||||
Ok(Expr::Index { lhs: Box::new(expr), index: Box::new(index), pos: lbrack.pos })
|
Ok(Expr::Index { lhs: Box::new(expr), index: Box::new(index), pos: lbrack.pos })
|
||||||
}
|
}
|
||||||
|
@ -349,7 +368,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let next = self.next();
|
let next = self.next();
|
||||||
if next.ty != TokenType::Colon {
|
if next.ty != TokenType::Colon {
|
||||||
return Err(ParserError { message: "Expected colon in key-value pair".into(), pos: next.pos })
|
return Err(self.mk_error("Expected colon in key-value pair"))
|
||||||
}
|
}
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let value = self.assignment()?;
|
let value = self.assignment()?;
|
||||||
|
@ -384,7 +403,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let next = self.next();
|
let next = self.next();
|
||||||
if let TokenType::LParen = next.ty {} else {
|
if let TokenType::LParen = next.ty {} else {
|
||||||
return Err(ParserError { message: "Expected left parenthesis to start arguments list".into(), pos: next.pos })
|
return Err(self.mk_error("Expected left parenthesis to start arguments list"))
|
||||||
}
|
}
|
||||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
|
|
|
@ -34,6 +34,8 @@ pub fn load(env: &mut Environment) {
|
||||||
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_time, arg_count: 0, name }));
|
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_time, arg_count: 0, name }));
|
||||||
name = Rc::from("list");
|
name = Rc::from("list");
|
||||||
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_list, arg_count: 1, name }));
|
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_list, arg_count: 1, name }));
|
||||||
|
name = Rc::from("take");
|
||||||
|
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_take, arg_count: 2, name }));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_str(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
fn fn_str(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
@ -160,3 +162,27 @@ fn fn_list(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
for v in a { res.push(v?); }
|
for v in a { res.push(v?); }
|
||||||
Ok(Value::from(res))
|
Ok(Value::from(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_inner(_: Vec<Value>, data: Rc<RefCell<Vec<Value>>>, iter_data: Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError> {
|
||||||
|
// 0: current index
|
||||||
|
// 1: target index
|
||||||
|
let mut d = data.borrow_mut();
|
||||||
|
if d[0] >= d[1] {
|
||||||
|
Ok(Value::Nil)
|
||||||
|
} else {
|
||||||
|
d[0] = (&d[0] + &Value::Int(1))?;
|
||||||
|
match iter_data.borrow_mut()[0].next() {
|
||||||
|
None => Ok(Value::Nil),
|
||||||
|
Some(x) => x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fn_take(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
return Ok(Value::Func(Func::BuiltinClosure {
|
||||||
|
arg_count: 0,
|
||||||
|
data: Rc::new(RefCell::new(vec![Value::Int(0), args[0].clone()])),
|
||||||
|
iter_data: Rc::new(RefCell::new(vec![args[1].iter()?])),
|
||||||
|
func: take_inner
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
@ -22,12 +22,14 @@ pub enum TokenType {
|
||||||
Ident(Rc<str>),
|
Ident(Rc<str>),
|
||||||
|
|
||||||
Plus, Minus, Star, Slash, Percent, DoubleSlash, Caret,
|
Plus, Minus, Star, Slash, Percent, DoubleSlash, Caret,
|
||||||
Bang, Amper, Pipe, DoubleAmper, DoublePipe,
|
Bang, DoubleAmper, DoublePipe,
|
||||||
|
Tilde, Amper, Pipe,
|
||||||
|
|
||||||
Equal, PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, DoubleSlashEqual, CaretEqual,
|
Equal, PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, DoubleSlashEqual, CaretEqual,
|
||||||
DoubleEqual, BangEqual, Greater, GreaterEqual, Less, LessEqual, Spaceship,
|
DoubleEqual, BangEqual, Greater, GreaterEqual, Less, LessEqual, Spaceship,
|
||||||
|
|
||||||
PipeColon, PipePoint, PipeQuestion, PipeAmper,
|
PipeColon, PipePoint, PipeQuestion, PipeAmper,
|
||||||
|
PipeSlash, PipeBackslash, PipeDoubleSlash, PipeDoubleBackslash,
|
||||||
|
|
||||||
Comma, Semicolon, Colon,
|
Comma, Semicolon, Colon,
|
||||||
|
|
||||||
|
@ -48,8 +50,8 @@ impl TokenType {
|
||||||
|
|
||||||
Self::Caret => Some(OpType::Exponential),
|
Self::Caret => Some(OpType::Exponential),
|
||||||
|
|
||||||
Self::PipeColon | Self::PipeAmper | Self::PipePoint
|
Self::PipeColon | Self::PipeAmper | Self::PipePoint | Self::PipeQuestion
|
||||||
| Self::PipeQuestion => Some(OpType::Pipeline),
|
| Self::PipeSlash | Self::PipeDoubleSlash | Self::PipeBackslash | Self::PipeDoubleBackslash => Some(OpType::Pipeline),
|
||||||
|
|
||||||
Self::Greater | Self::GreaterEqual | Self::Less | Self::LessEqual
|
Self::Greater | Self::GreaterEqual | Self::Less | Self::LessEqual
|
||||||
| Self::DoubleEqual | Self::BangEqual | Self::Spaceship => Some(OpType::Comparison),
|
| Self::DoubleEqual | Self::BangEqual | Self::Spaceship => Some(OpType::Comparison),
|
||||||
|
@ -58,7 +60,8 @@ impl TokenType {
|
||||||
| Self::StarEqual | Self::SlashEqual | Self::DoubleSlashEqual
|
| Self::StarEqual | Self::SlashEqual | Self::DoubleSlashEqual
|
||||||
| Self::CaretEqual | Self::PercentEqual => Some(OpType::Assignment),
|
| Self::CaretEqual | Self::PercentEqual => Some(OpType::Assignment),
|
||||||
|
|
||||||
Self::DoubleAmper | Self::DoublePipe => Some(OpType::Boolean),
|
Self::DoubleAmper => Some(OpType::LogicalAnd),
|
||||||
|
Self::DoublePipe => Some(OpType::LogicalOr),
|
||||||
|
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,7 @@ impl TokenType {
|
||||||
|
|
||||||
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
|
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
|
||||||
pub enum OpType {
|
pub enum OpType {
|
||||||
Assignment, Comparison, Pipeline, Additive, Multiplicative, Exponential, Boolean
|
Assignment, Comparison, Pipeline, Additive, Multiplicative, Exponential, LogicalAnd, LogicalOr
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpType {
|
impl OpType {
|
||||||
|
|
|
@ -25,6 +25,10 @@ pub enum Func {
|
||||||
data: Rc<RefCell<Vec<Value>>>,
|
data: Rc<RefCell<Vec<Value>>>,
|
||||||
iter_data: Rc<RefCell<Vec<CIterator>>>,
|
iter_data: Rc<RefCell<Vec<CIterator>>>,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
|
},
|
||||||
|
Partial {
|
||||||
|
inner: Box<Func>,
|
||||||
|
filled_args: Vec<Value>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +50,11 @@ impl fmt::Debug for Func {
|
||||||
.field("arg_count", arg_count)
|
.field("arg_count", arg_count)
|
||||||
.field("data", data)
|
.field("data", data)
|
||||||
.finish_non_exhaustive(),
|
.finish_non_exhaustive(),
|
||||||
|
Self::Partial { inner, filled_args }
|
||||||
|
=> f.debug_struct("Func::Partial")
|
||||||
|
.field("inner", inner)
|
||||||
|
.field("filled_args", filled_args)
|
||||||
|
.finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +66,20 @@ impl Func {
|
||||||
Self::Builtin { arg_count, .. } => *arg_count,
|
Self::Builtin { arg_count, .. } => *arg_count,
|
||||||
Self::BuiltinClosure { arg_count, .. } => *arg_count,
|
Self::BuiltinClosure { arg_count, .. } => *arg_count,
|
||||||
Self::Func { args, .. } => args.len(),
|
Self::Func { args, .. } => args.len(),
|
||||||
|
Self::Partial { inner, filled_args } => inner.arg_count() - filled_args.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, arg_values: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self::Builtin { name, .. } => Some(name.as_ref()),
|
||||||
|
Self::BuiltinClosure { .. } => None,
|
||||||
|
Self::Func { name, .. } => name.as_ref().map(|s| s.as_ref()),
|
||||||
|
Self::Partial { inner, .. } => inner.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, mut arg_values: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
match arg_values.len().cmp(&self.arg_count()) {
|
match arg_values.len().cmp(&self.arg_count()) {
|
||||||
Ordering::Equal => match self {
|
Ordering::Equal => match self {
|
||||||
Self::Builtin { func, .. }
|
Self::Builtin { func, .. }
|
||||||
|
@ -81,11 +100,16 @@ impl Func {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Self::Partial { inner, filled_args } => {
|
||||||
|
let mut filled_args = filled_args.clone();
|
||||||
|
filled_args.append(&mut arg_values);
|
||||||
|
inner.call(filled_args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ordering::Less => Err(RuntimeError::new_incomplete(
|
Ordering::Less => {
|
||||||
format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len())
|
Ok(Value::Func(Func::Partial { inner: Box::new(self.clone()), filled_args: arg_values }))
|
||||||
)),
|
},
|
||||||
Ordering::Greater => Err(RuntimeError::new_incomplete(
|
Ordering::Greater => Err(RuntimeError::new_incomplete(
|
||||||
format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len())
|
format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len())
|
||||||
))
|
))
|
||||||
|
@ -108,6 +132,10 @@ impl Hash for Func {
|
||||||
Self::BuiltinClosure { arg_count, data, .. } => {
|
Self::BuiltinClosure { arg_count, data, .. } => {
|
||||||
arg_count.hash(state);
|
arg_count.hash(state);
|
||||||
data.borrow().hash(state);
|
data.borrow().hash(state);
|
||||||
|
},
|
||||||
|
Self::Partial { inner, filled_args } => {
|
||||||
|
filled_args.hash(state);
|
||||||
|
inner.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,6 +249,10 @@ impl Value {
|
||||||
Self::Type(_) => todo!(),
|
Self::Type(_) => todo!(),
|
||||||
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
||||||
Self::Func(Func::BuiltinClosure { func, .. }) => Rc::from(format!("<builtin anonymous fn at {:?}>", *func as *const ())),
|
Self::Func(Func::BuiltinClosure { func, .. }) => Rc::from(format!("<builtin anonymous fn at {:?}>", *func as *const ())),
|
||||||
|
Self::Func(f @ Func::Partial { .. }) => match f.name() {
|
||||||
|
Some(name) => Rc::from(format!("<partial of fn {}>", name)),
|
||||||
|
None => Rc::from("<partial of anonymous fn>"),
|
||||||
|
}
|
||||||
Self::Func(Func::Func { name, .. }) => match name {
|
Self::Func(Func::Func { name, .. }) => match name {
|
||||||
Some(name) => Rc::from(format!("<fn {}>", name)),
|
Some(name) => Rc::from(format!("<fn {}>", name)),
|
||||||
None => Rc::from("<anonymous fn>"),
|
None => Rc::from("<anonymous fn>"),
|
||||||
|
|
Loading…
Reference in a new issue