basic array functions
This commit is contained in:
@@ -18,6 +18,7 @@ pub enum RuntimeError {
|
|||||||
NotAVariable(String),
|
NotAVariable(String),
|
||||||
ParseFail(String, Type),
|
ParseFail(String, Type),
|
||||||
TypeError(Type, Type),
|
TypeError(Type, Type),
|
||||||
|
EmptyArray,
|
||||||
IO(io::Error),
|
IO(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ impl Display for RuntimeError {
|
|||||||
match self {
|
match self {
|
||||||
Self::ParseError(e) => write!(f, "Parser Error: {e}"),
|
Self::ParseError(e) => write!(f, "Parser Error: {e}"),
|
||||||
Self::NoOverloadForTypes(op, values)
|
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(", ")),
|
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::ImmutableError(ident) => write!(f, "`{ident}` already exists and cannot be redefined"),
|
||||||
Self::VariableUndefined(ident) => write!(f, "variable `{ident}` was not defined"),
|
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::ParseFail(s, t) => write!(f, "`\"{s}\"` couldn't be parsed into {}", t),
|
||||||
Self::IO(e) => write!(f, "{e}"),
|
Self::IO(e) => write!(f, "{e}"),
|
||||||
Self::TypeError(left, right) => write!(f, "expected type `{left}` but got type `{right}`"),
|
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::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 + y)),
|
||||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + 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::String(x), Value::String(y)) => Ok(Value::String(format!("{x}{y}"))),
|
||||||
(Value::Array(_, x), y) => Ok(Value::Array(Type::Any, [x, vec![y]].concat())),
|
(Value::Array(t, x), y) => {
|
||||||
(x, Value::Array(_, y)) => Ok(Value::Array(Type::Any, [vec![x], y].concat())),
|
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]))
|
(x, y) => Err(RuntimeError::NoOverloadForTypes("+".into(), vec![x, y]))
|
||||||
},
|
},
|
||||||
ParseTree::Sub(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
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 {
|
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 {
|
Self {
|
||||||
name: None,
|
name: None,
|
||||||
t,
|
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 {
|
Self {
|
||||||
name: Some(name.to_string()),
|
name: Some(name.to_string()),
|
||||||
t,
|
t,
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ pub(crate) enum ParseTree {
|
|||||||
// Functional Operations
|
// Functional Operations
|
||||||
Compose(Box<ParseTree>, Box<ParseTree>),
|
Compose(Box<ParseTree>, Box<ParseTree>),
|
||||||
Id(Box<ParseTree>),
|
Id(Box<ParseTree>),
|
||||||
|
Head(Box<ParseTree>),
|
||||||
|
Tail(Box<ParseTree>),
|
||||||
|
Init(Box<ParseTree>),
|
||||||
|
Fini(Box<ParseTree>),
|
||||||
|
|
||||||
// Branching
|
// Branching
|
||||||
If(Box<ParseTree>, Box<ParseTree>),
|
If(Box<ParseTree>, Box<ParseTree>),
|
||||||
@@ -262,6 +266,10 @@ impl ParseTree {
|
|||||||
let name = Self::get_identifier(tokens.next())?;
|
let name = Self::get_identifier(tokens.next())?;
|
||||||
Ok(ParseTree::NonCall(name))
|
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))),
|
op => Err(ParseError::UnwantedToken(Token::Operator(op))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ pub(crate) enum Op {
|
|||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
NonCall,
|
NonCall,
|
||||||
|
Head,
|
||||||
|
Tail,
|
||||||
|
Init,
|
||||||
|
Fini,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -118,6 +122,10 @@ impl Token {
|
|||||||
"string" => Ok(Token::Operator(Op::StringCast)),
|
"string" => Ok(Token::Operator(Op::StringCast)),
|
||||||
"print" => Ok(Token::Operator(Op::Print)),
|
"print" => Ok(Token::Operator(Op::Print)),
|
||||||
"empty" => Ok(Token::Operator(Op::Empty)),
|
"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
|
// Types
|
||||||
"Any" => Ok(Token::Type(Type::Any)),
|
"Any" => Ok(Token::Type(Type::Any)),
|
||||||
@@ -412,7 +420,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn uwu() {
|
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();
|
let tokens: Vec<Token> = Tokenizer::from_str(program).unwrap().collect::<Result<_, TokenizeError>>().unwrap();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user