basic array functions
This commit is contained in:
@@ -18,6 +18,7 @@ pub enum RuntimeError {
|
||||
NotAVariable(String),
|
||||
ParseFail(String, Type),
|
||||
TypeError(Type, Type),
|
||||
EmptyArray,
|
||||
IO(io::Error),
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ impl Display for RuntimeError {
|
||||
match self {
|
||||
Self::ParseError(e) => write!(f, "Parser Error: {e}"),
|
||||
Self::NoOverloadForTypes(op, values)
|
||||
=> write!(f, "No overload of `{op}` exists for the operands `[{}]`",
|
||||
=> write!(f, "No overload of `{op}` exists for the operands `{}`",
|
||||
values.iter().map(|x| format!("{}({x})", x.get_type())).collect::<Vec<_>>().join(", ")),
|
||||
Self::ImmutableError(ident) => write!(f, "`{ident}` already exists and cannot be redefined"),
|
||||
Self::VariableUndefined(ident) => write!(f, "variable `{ident}` was not defined"),
|
||||
@@ -36,6 +37,7 @@ impl Display for RuntimeError {
|
||||
Self::ParseFail(s, t) => write!(f, "`\"{s}\"` couldn't be parsed into {}", t),
|
||||
Self::IO(e) => write!(f, "{e}"),
|
||||
Self::TypeError(left, right) => write!(f, "expected type `{left}` but got type `{right}`"),
|
||||
Self::EmptyArray => write!(f, "attempt to access element from an empty array"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,8 +114,28 @@ where
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 + y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
|
||||
(Value::String(x), Value::String(y)) => Ok(Value::String(format!("{x}{y}"))),
|
||||
(Value::Array(_, x), y) => Ok(Value::Array(Type::Any, [x, vec![y]].concat())),
|
||||
(x, Value::Array(_, y)) => Ok(Value::Array(Type::Any, [vec![x], y].concat())),
|
||||
(Value::Array(t, x), y) => {
|
||||
let ytype = y.get_type();
|
||||
|
||||
if t != ytype {
|
||||
return Err(RuntimeError::TypeError(t, ytype));
|
||||
}
|
||||
|
||||
// NOTE: use y's type instead of the arrays type.
|
||||
// an `empty` array has Any type, but any value will have a fixed type.
|
||||
// this converts the empty array into a typed array.
|
||||
Ok(Value::Array(ytype, [x, vec![y]].concat()))
|
||||
},
|
||||
(x, Value::Array(t, y)) => {
|
||||
let xtype = x.get_type();
|
||||
|
||||
if t != xtype {
|
||||
return Err(RuntimeError::TypeError(t, xtype));
|
||||
}
|
||||
|
||||
// NOTE: read above
|
||||
Ok(Value::Array(xtype, [vec![x], y].concat()))
|
||||
},
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("+".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Sub(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||
@@ -371,6 +393,22 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
ParseTree::Head(x) => match self.exec(x, locals)? {
|
||||
Value::Array(_, x) => Ok(x.first().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("head".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Tail(x) => match self.exec(x, locals)? {
|
||||
Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[1..].to_vec() } else { vec![] })),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("tail".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Init(x) => match self.exec(x, locals)? {
|
||||
Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[..x.len() - 1].to_vec() } else { vec![] })),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("init".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Fini(x) => match self.exec(x, locals)? {
|
||||
Value::Array(_, x) => Ok(x.last().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("fini".into(), vec![t]))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ pub struct Function {
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn lambda(t: FunctionType, arg_names: Vec<String>, body: Option<Box<ParseTree>>) -> Self {
|
||||
fn lambda(t: FunctionType, arg_names: Vec<String>, body: Option<Box<ParseTree>>) -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
t,
|
||||
@@ -122,7 +122,7 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn named(name: &str, t: FunctionType, arg_names: Option<Vec<String>>, body: Option<Box<ParseTree>>) -> Self {
|
||||
fn named(name: &str, t: FunctionType, arg_names: Option<Vec<String>>, body: Option<Box<ParseTree>>) -> Self {
|
||||
Self {
|
||||
name: Some(name.to_string()),
|
||||
t,
|
||||
|
||||
@@ -70,6 +70,10 @@ pub(crate) enum ParseTree {
|
||||
// Functional Operations
|
||||
Compose(Box<ParseTree>, Box<ParseTree>),
|
||||
Id(Box<ParseTree>),
|
||||
Head(Box<ParseTree>),
|
||||
Tail(Box<ParseTree>),
|
||||
Init(Box<ParseTree>),
|
||||
Fini(Box<ParseTree>),
|
||||
|
||||
// Branching
|
||||
If(Box<ParseTree>, Box<ParseTree>),
|
||||
@@ -262,6 +266,10 @@ impl ParseTree {
|
||||
let name = Self::get_identifier(tokens.next())?;
|
||||
Ok(ParseTree::NonCall(name))
|
||||
},
|
||||
Op::Head => one_arg!(Head, tokens, globals, locals),
|
||||
Op::Tail => one_arg!(Tail, tokens, globals, locals),
|
||||
Op::Init => one_arg!(Init, tokens, globals, locals),
|
||||
Op::Fini => one_arg!(Fini, tokens, globals, locals),
|
||||
op => Err(ParseError::UnwantedToken(Token::Operator(op))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,10 @@ pub(crate) enum Op {
|
||||
And,
|
||||
Or,
|
||||
NonCall,
|
||||
Head,
|
||||
Tail,
|
||||
Init,
|
||||
Fini,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -118,6 +122,10 @@ impl Token {
|
||||
"string" => Ok(Token::Operator(Op::StringCast)),
|
||||
"print" => Ok(Token::Operator(Op::Print)),
|
||||
"empty" => Ok(Token::Operator(Op::Empty)),
|
||||
"head" => Ok(Token::Operator(Op::Head)),
|
||||
"tail" => Ok(Token::Operator(Op::Tail)),
|
||||
"init" => Ok(Token::Operator(Op::Init)),
|
||||
"fini" => Ok(Token::Operator(Op::Fini)),
|
||||
|
||||
// Types
|
||||
"Any" => Ok(Token::Type(Type::Any)),
|
||||
@@ -412,7 +420,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn uwu() {
|
||||
let program = ":. apply : f x f x apply ; x ** x 2 10";
|
||||
let program = ":. map ?: f Any -> Any ?. x [Any] -> [Any] ?? bool x + f head x map 'f tail x empty map ;x ** x 2 [1 2 3 4 5]";
|
||||
|
||||
let tokens: Vec<Token> = Tokenizer::from_str(program).unwrap().collect::<Result<_, TokenizeError>>().unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user