-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
make most function args evaluate lazily and support first-class funct…
…ions (29)
- Loading branch information
1 parent
edd3c07
commit 04ac575
Showing
31 changed files
with
413 additions
and
258 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,136 @@ | ||
use crate::{expr, Error, Result, Rule, Value}; | ||
use pest::iterators::Pair; | ||
|
||
#[derive(Clone)] | ||
#[derive(Clone, Debug)] | ||
pub enum Arg<'a> { | ||
Eager(Value), | ||
Lazy(Pair<'a, Rule>), | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct ArgParser<'a> { | ||
pair: Pair<'a, Rule>, | ||
pub data: &'a Value, | ||
context: Option<Value>, | ||
pub function: String, | ||
args: Vec<Arg<'a>>, | ||
} | ||
|
||
impl<'a> ArgParser<'a> { | ||
pub fn new(pair: Pair<'a, Rule>, data: &'a Value, context: Option<Value>) -> Result<Self> { | ||
let function = match pair.as_rule() { | ||
Rule::ident => pair.as_str().to_string(), | ||
Rule::function => ident_from_fn(pair.clone().into_inner().next().unwrap(), data)?, | ||
_ => unreachable!(), | ||
}; | ||
|
||
Ok(Self { | ||
pair: pair, | ||
data: data, | ||
context: context, | ||
function: function, | ||
}) | ||
impl<'a> Arg<'a> { | ||
pub fn to_pair(&self) -> Result<Pair<'a, Rule>> { | ||
match self { | ||
Arg::Lazy(pair) => Ok(pair.clone()), | ||
Arg::Eager(_) => Err(Error::eval( | ||
"can't convert evaluated argument to lazy argument".to_string(), | ||
)), | ||
} | ||
} | ||
|
||
fn eager_args(&self, skip: usize) -> Result<Vec<Value>> { | ||
let mut args = self | ||
.pair | ||
.clone() | ||
.into_inner() | ||
.skip(skip) | ||
.map(|arg| expr::eval(arg, self.data, None)) | ||
.collect::<Result<Vec<Value>>>()?; | ||
|
||
if let Some(ctx) = self.context.clone() { | ||
args.push(ctx); | ||
pub fn to_value(&self, data: &Value) -> Result<Value> { | ||
match self { | ||
Arg::Eager(val) => Ok(val.clone()), | ||
Arg::Lazy(pair) => expr::eval(pair.clone(), data, None), | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
fn lazy_arg(&self) -> Result<Pair<Rule>> { | ||
match self.pair.clone().into_inner().skip(1).next() { | ||
None => Err(Error::eval("expected fn as argument, got none".to_string())), | ||
Some(pair) => Ok(pair), | ||
pub fn to_ident(&self) -> Result<Value> { | ||
match self { | ||
Arg::Eager(Value::Ident(val)) => Ok(Value::Ident(val.clone())), | ||
Arg::Eager(val) => Err(Error::eval(format!("expected ident, got {:?}", val))), | ||
Arg::Lazy(pair) => match pair.as_rule() { | ||
Rule::ident => Ok(Value::Ident(pair.as_str().to_string())), | ||
_ => Err(Error::eval(format!("pair isn't an ident: {:?}", pair))), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
pub fn one_arg(&self) -> Result<Value> { | ||
let args = self.eager_args(1)?; | ||
if args.len() == 1 { | ||
Ok(args[0].clone()) | ||
} else { | ||
Err(Error::arity(self.function.clone(), 1, args.len())) | ||
impl<'a> ArgParser<'a> { | ||
pub fn from_pair( | ||
pair: Pair<'a, Rule>, | ||
data: &'a Value, | ||
context: Option<Value>, | ||
) -> Result<Self> { | ||
let mut components_itr = pair.into_inner(); | ||
let function_pair = components_itr.next().unwrap().into_inner().next().unwrap(); | ||
|
||
let function = match function_pair.as_rule() { | ||
Rule::ident => function_pair.as_str().to_string(), | ||
Rule::function => match super::fn_ident_eval(function_pair, data, context.clone())? { | ||
Value::Ident(s) => s, | ||
value => { | ||
return Err(Error::eval(format!( | ||
"higher-order function must return an identifier (got {:?}", | ||
value | ||
))) | ||
} | ||
}, | ||
_ => { | ||
return Err(Error::unimplemented(format!( | ||
"fn_ident rule {:?}", | ||
function_pair | ||
))) | ||
} | ||
}; | ||
|
||
let mut args: Vec<Arg<'a>> = components_itr | ||
.next() | ||
.unwrap() | ||
.into_inner() | ||
.map(|arg| Arg::Lazy(arg)) | ||
.collect(); | ||
|
||
if let Some(ctx) = context.clone() { | ||
args.push(Arg::Eager(ctx)); | ||
} | ||
|
||
Ok(Self { | ||
data: data, | ||
function: function, | ||
args: args, | ||
}) | ||
} | ||
|
||
pub fn two_args(&self) -> Result<(Value, Value)> { | ||
let args = self.eager_args(1)?; | ||
if args.len() == 2 { | ||
Ok((args[0].clone(), args[1].clone())) | ||
} else { | ||
Err(Error::arity(self.function.clone(), 2, args.len())) | ||
} | ||
pub fn from_ident( | ||
pair: &Pair<'a, Rule>, | ||
data: &'a Value, | ||
context: Option<Value>, | ||
) -> Result<Self> { | ||
let args = match context { | ||
Some(ctx) => vec![Arg::Eager(ctx)], | ||
None => vec![Arg::Eager(data.clone())], | ||
}; | ||
|
||
Ok(Self { | ||
data: data, | ||
function: pair.as_str().to_string(), | ||
args: args, | ||
}) | ||
} | ||
|
||
pub fn three_args(&self) -> Result<(Value, Value, Value)> { | ||
let args = self.eager_args(1)?; | ||
if args.len() == 3 { | ||
Ok((args[0].clone(), args[1].clone(), args[2].clone())) | ||
pub fn one_arg(&self) -> Result<Arg> { | ||
if self.args.len() == 1 { | ||
Ok(self.args[0].clone()) | ||
} else { | ||
Err(Error::arity(self.function.clone(), 3, args.len())) | ||
Err(Error::arity(self.function.to_string(), 1, self.args.len())) | ||
} | ||
} | ||
|
||
pub fn one_func_one_arg(&self) -> Result<(Pair<Rule>, Value)> { | ||
let func = self.lazy_arg()?; | ||
let args = self.eager_args(2)?; | ||
|
||
if args.len() == 1 { | ||
Ok((func, args[0].clone())) | ||
pub fn two_args(&self) -> Result<(Arg, Arg)> { | ||
if self.args.len() == 2 { | ||
Ok((self.args[0].clone(), self.args[1].clone())) | ||
} else { | ||
Err(Error::arity(self.function.clone(), 1, args.len())) | ||
Err(Error::arity(self.function.to_string(), 2, self.args.len())) | ||
} | ||
} | ||
|
||
pub fn one_func_two_args(&self) -> Result<(Pair<Rule>, Value, Value)> { | ||
let func = self.lazy_arg()?; | ||
let args = self.eager_args(2)?; | ||
|
||
if args.len() == 2 { | ||
Ok((func, args[0].clone(), args[1].clone())) | ||
pub fn three_args(&self) -> Result<(Arg, Arg, Arg)> { | ||
if self.args.len() == 3 { | ||
Ok(( | ||
self.args[0].clone(), | ||
self.args[1].clone(), | ||
self.args[2].clone(), | ||
)) | ||
} else { | ||
Err(Error::arity(self.function.clone(), 2, args.len())) | ||
Err(Error::arity(self.function.to_string(), 3, self.args.len())) | ||
} | ||
} | ||
} | ||
|
||
fn ident_from_fn<'a>(pair: Pair<'a, Rule>, data: &'a Value) -> Result<String> { | ||
dbg!(pair.as_str()); | ||
match pair.as_rule() { | ||
Rule::ident => Ok(pair.as_str().to_string()), | ||
Rule::function => match super::eval(pair, data, None)? { | ||
Value::Ident(s) => Ok(s), | ||
_ => unreachable!(), | ||
}, | ||
rule => Err(Error::unimplemented(format!("fn rule {:?}", rule))), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.