add function parameters and type declarations
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use super::{Value, Type, FunctionDeclaration};
|
||||
use super::{Value, Type, Function, FunctionType};
|
||||
use super::parser::{ParseTree, ParseError};
|
||||
|
||||
use std::collections::HashMap;
|
||||
@@ -17,13 +17,14 @@ pub enum RuntimeError {
|
||||
FunctionUndefined(String),
|
||||
NotAVariable(String),
|
||||
ParseFail(String, Type),
|
||||
TypeError(Type, Type),
|
||||
IO(io::Error),
|
||||
}
|
||||
|
||||
impl Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ParseError(e) => write!(f, "{e}"),
|
||||
Self::ParseError(e) => write!(f, "Parser Error: {e}"),
|
||||
Self::NoOverloadForTypes(op, values)
|
||||
=> write!(f, "No overload of `{op}` exists for the operands `[{}]`",
|
||||
values.iter().map(|x| format!("{}({x})", x.get_type())).collect::<Vec<_>>().join(", ")),
|
||||
@@ -34,6 +35,7 @@ impl Display for RuntimeError {
|
||||
Self::NotAVariable(ident) => write!(f, "`{ident}` is a function but was attempted to be used like a variable"),
|
||||
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}`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,12 +52,6 @@ enum Evaluation {
|
||||
Uncomputed(Box<ParseTree>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Function {
|
||||
decl: FunctionDeclaration,
|
||||
body: Option<Box<ParseTree>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Object {
|
||||
Variable(Evaluation),
|
||||
@@ -116,8 +112,8 @@ 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([x, vec![y]].concat())),
|
||||
(x, Value::Array(y)) => Ok(Value::Array([vec![x], y].concat())),
|
||||
(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())),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("+".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Sub(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||
@@ -235,19 +231,29 @@ where
|
||||
self.exec(scope, &mut Cow::Borrowed(&locals))
|
||||
}
|
||||
},
|
||||
ParseTree::FunctionDefinition(ident, args, body, scope) => {
|
||||
let existing = locals.get(&ident).or(self.globals.get(&ident)).cloned();
|
||||
ParseTree::FunctionDefinition(func, scope) => {
|
||||
let ident = func.name.clone().unwrap();
|
||||
|
||||
let existing = locals.get(&ident)
|
||||
.or(self.globals.get(&ident));
|
||||
|
||||
match existing {
|
||||
Some(_) => Err(RuntimeError::ImmutableError(ident.clone())),
|
||||
Some(Object::Function(f)) => {
|
||||
if f.body.is_some() || f.arg_names.is_some() {
|
||||
return Err(RuntimeError::ImmutableError(ident.clone()));
|
||||
}
|
||||
|
||||
let new_func = Function::named(func.name.unwrap().as_str(), func.t.clone(), func.arg_names.clone(), func.body.clone());
|
||||
|
||||
let locals = locals.to_mut();
|
||||
locals.insert(ident.clone(), Object::Function(new_func));
|
||||
|
||||
self.exec(scope, &mut Cow::Borrowed(&locals))
|
||||
}
|
||||
Some(Object::Variable(_)) => Err(RuntimeError::ImmutableError(ident.clone())),
|
||||
None => {
|
||||
let locals = locals.to_mut();
|
||||
|
||||
locals.insert(ident.clone(), Object::Function(Function {
|
||||
decl: FunctionDeclaration { _name: ident.clone(), args },
|
||||
body: Some(body)
|
||||
}));
|
||||
|
||||
locals.insert(ident.clone(), Object::Function(func));
|
||||
self.exec(scope, &mut Cow::Borrowed(&locals))
|
||||
}
|
||||
}
|
||||
@@ -262,8 +268,9 @@ where
|
||||
Value::Int(i) => i != 0,
|
||||
Value::Bool(b) => b,
|
||||
Value::String(s) => !s.is_empty(),
|
||||
Value::Array(vec) => !vec.is_empty(),
|
||||
Value::Array(_, vec) => !vec.is_empty(),
|
||||
Value::Nil => false,
|
||||
x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])),
|
||||
} {
|
||||
self.exec(body, locals)
|
||||
} else {
|
||||
@@ -274,8 +281,9 @@ where
|
||||
Value::Int(i) => i != 0,
|
||||
Value::Bool(b) => b,
|
||||
Value::String(s) => !s.is_empty(),
|
||||
Value::Array(vec) => !vec.is_empty(),
|
||||
Value::Array(_, vec) => !vec.is_empty(),
|
||||
Value::Nil => false,
|
||||
x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])),
|
||||
} {
|
||||
self.exec(istrue, locals)
|
||||
} else {
|
||||
@@ -284,17 +292,26 @@ where
|
||||
ParseTree::FunctionCall(ident, args) => {
|
||||
let obj = locals.get(&ident).or(self.globals.get(&ident)).cloned();
|
||||
|
||||
if let Some(Object::Function(f)) = obj {
|
||||
match obj {
|
||||
Some(Object::Function(f)) => {
|
||||
let locals = locals.to_mut();
|
||||
let body = f.body.ok_or(RuntimeError::FunctionUndefined(ident.clone()))?;
|
||||
|
||||
for (name, tree) in std::iter::zip(f.decl.args, args) {
|
||||
locals.insert(name.clone(), Object::Variable(Evaluation::Computed(self.exec(Box::new(tree), &mut Cow::Borrowed(locals))?)));
|
||||
for ((t, name), tree) in std::iter::zip(std::iter::zip(f.t.1, f.arg_names.unwrap()), args) {
|
||||
let v = self.exec(Box::new(tree), &mut Cow::Borrowed(locals))?;
|
||||
|
||||
if v.get_type() != t && t != Type::Any {
|
||||
return Err(RuntimeError::TypeError(t, v.get_type()));
|
||||
}
|
||||
|
||||
self.exec(body, &mut Cow::Borrowed(&locals))
|
||||
} else {
|
||||
Err(RuntimeError::FunctionUndeclared(ident.clone()))
|
||||
locals.insert(name.clone(), match v {
|
||||
Value::Function(func) => Object::Function(func),
|
||||
_ => Object::Variable(Evaluation::Computed(v))
|
||||
});
|
||||
}
|
||||
|
||||
self.exec(f.body.unwrap(), &mut Cow::Borrowed(&locals))
|
||||
}
|
||||
_ => Err(RuntimeError::FunctionUndefined(ident.clone()))
|
||||
}
|
||||
},
|
||||
ParseTree::Variable(ident) => {
|
||||
@@ -342,7 +359,7 @@ where
|
||||
Value::Float(x) => Ok(Value::Bool(x != 0.0)),
|
||||
Value::Bool(x) => Ok(Value::Bool(x)),
|
||||
Value::String(x) => Ok(Value::Bool(!x.is_empty())),
|
||||
Value::Array(vec) => Ok(Value::Bool(!vec.is_empty())),
|
||||
Value::Array(_, vec) => Ok(Value::Bool(!vec.is_empty())),
|
||||
x => Err(RuntimeError::NoOverloadForTypes("bool".into(), vec![x])),
|
||||
},
|
||||
ParseTree::StringCast(x) => Ok(Value::String(format!("{}", self.exec(x, locals)?))),
|
||||
@@ -352,6 +369,18 @@ where
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
}
|
||||
ParseTree::FunctionDeclaration(func, scope) => {
|
||||
let locals = locals.to_mut();
|
||||
let name = func.name.clone().unwrap();
|
||||
|
||||
if locals.contains_key(&name) {
|
||||
Err(RuntimeError::ImmutableError(name.clone()))
|
||||
} else {
|
||||
locals.insert(name, Object::Function(func));
|
||||
self.exec(scope, &mut Cow::Borrowed(&locals))
|
||||
}
|
||||
}
|
||||
ParseTree::LambdaDefinition(func) => Ok(Value::Function(func)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
src/lib.rs
67
src/lib.rs
@@ -3,11 +3,12 @@ mod parser;
|
||||
mod executor;
|
||||
|
||||
use executor::{Executor, RuntimeError};
|
||||
use parser::Parser;
|
||||
use parser::{ParseTree, Parser};
|
||||
use tokenizer::Tokenizer;
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::io::{Write, Read, BufRead};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Type {
|
||||
@@ -15,21 +16,21 @@ pub enum Type {
|
||||
Int,
|
||||
Bool,
|
||||
String,
|
||||
Array,
|
||||
_Function(Box<Type>, Vec<Type>),
|
||||
Array(Box<Type>),
|
||||
Function(FunctionType),
|
||||
Nil,
|
||||
Any,
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", match self {
|
||||
Self::Float => "Float".into(),
|
||||
Self::Int => "Int".into(),
|
||||
Self::Bool => "Bool".into(),
|
||||
Self::String => "String".into(),
|
||||
Self::Array => format!("Array"),
|
||||
Self::_Function(r, _) => format!("Function -> {}", *r),
|
||||
Self::Array(t) => format!("[{t}]"),
|
||||
Self::Function(r) => format!("{r}"),
|
||||
Self::Nil => "Nil".into(),
|
||||
Self::Any => "Any".into(),
|
||||
})
|
||||
@@ -43,7 +44,8 @@ pub enum Value {
|
||||
Int(i64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Array(Vec<Value>),
|
||||
Array(Type, Vec<Value>),
|
||||
Function(Function),
|
||||
Nil,
|
||||
}
|
||||
|
||||
@@ -54,8 +56,9 @@ impl Value {
|
||||
Self::Int(_) => Type::Int,
|
||||
Self::Bool(_) => Type::Bool,
|
||||
Self::String(_) => Type::String,
|
||||
Self::Array(_) => Type::Array,
|
||||
Self::Array(t, _) => Type::Array(Box::new(t.clone())),
|
||||
Self::Nil => Type::Nil,
|
||||
Self::Function(f) => Type::Function(f.t.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,16 +70,54 @@ impl Display for Value {
|
||||
Self::Int(x) => write!(f, "{x}"),
|
||||
Self::Bool(x) => write!(f, "{}", if *x { "true" } else { "false" }),
|
||||
Self::String(x) => write!(f, "\"{x}\""),
|
||||
Self::Array(v) => write!(f, "[{}]", v.iter().map(|x| format!("{x}")).collect::<Vec<_>>().join(" ")),
|
||||
Self::Array(_t, v) => write!(f, "[{}]", v.iter().map(|x| format!("{x}")).collect::<Vec<_>>().join(" ")),
|
||||
Self::Function(func) => {
|
||||
if let Some(name) = &func.name {
|
||||
write!(f, "Function({}, {}, {})", name, func.t.0, func.t.1.iter().map(|x| format!("{x}")).collect::<Vec<_>>().join(", "))
|
||||
} else {
|
||||
write!(f, "{}", func.t)
|
||||
}
|
||||
}
|
||||
Self::Nil => write!(f, "nil"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct FunctionDeclaration {
|
||||
_name: String,
|
||||
args: Vec<String>,
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct FunctionType(Box<Type>, Vec<Type>);
|
||||
|
||||
impl Display for FunctionType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Function({}, {})", self.0, self.1.iter().map(|x| format!("{x}")).collect::<Vec<_>>().join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Function {
|
||||
name: Option<String>,
|
||||
t: FunctionType,
|
||||
arg_names: Option<Vec<String>>,
|
||||
body: Option<Box<ParseTree>>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn lambda(t: FunctionType, arg_names: Vec<String>, body: Option<Box<ParseTree>>) -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
t,
|
||||
arg_names: Some(arg_names),
|
||||
body
|
||||
}
|
||||
}
|
||||
|
||||
pub fn named(name: &str, t: FunctionType, arg_names: Option<Vec<String>>, body: Option<Box<ParseTree>>) -> Self {
|
||||
Self {
|
||||
name: Some(name.to_string()),
|
||||
t,
|
||||
arg_names,
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Runtime<'a, R: BufRead> {
|
||||
|
||||
172
src/parser.rs
172
src/parser.rs
@@ -1,4 +1,4 @@
|
||||
use super::{Type, Value, FunctionDeclaration};
|
||||
use super::{Value, Type, Function, FunctionType};
|
||||
use super::tokenizer::{Token, TokenizeError, Op};
|
||||
|
||||
use std::error;
|
||||
@@ -15,7 +15,9 @@ pub enum ParseError {
|
||||
FunctionUndefined(String),
|
||||
VariableUndefined(String),
|
||||
UnmatchedArrayClose,
|
||||
UnwantedToken(Token),
|
||||
TokenizeError(TokenizeError),
|
||||
ImmutableError(String),
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
@@ -28,14 +30,16 @@ impl Display for ParseError {
|
||||
ParseError::VariableUndefined(name) => write!(f, "Undefined variable `{name}`"),
|
||||
ParseError::NoInput => write!(f, "No input given"),
|
||||
ParseError::UnmatchedArrayClose => write!(f, "there was an unmatched array closing operator `]`"),
|
||||
ParseError::TokenizeError(e) => write!(f, "{e}"),
|
||||
ParseError::TokenizeError(e) => write!(f, "Tokenizer Error: {e}"),
|
||||
ParseError::ImmutableError(i) => write!(f, "attempt to redeclare {i} met with force"),
|
||||
ParseError::UnwantedToken(_t) => write!(f, "unexpected token"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ParseError {}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum ParseTree {
|
||||
// Mathematical Operators
|
||||
Add(Box<ParseTree>, Box<ParseTree>),
|
||||
@@ -59,7 +63,9 @@ pub(crate) enum ParseTree {
|
||||
// Defining Objects
|
||||
Equ(String, Box<ParseTree>, Box<ParseTree>),
|
||||
LazyEqu(String, Box<ParseTree>, Box<ParseTree>),
|
||||
FunctionDefinition(String, Vec<String>, Box<ParseTree>, Box<ParseTree>),
|
||||
FunctionDefinition(Function, Box<ParseTree>),
|
||||
FunctionDeclaration(Function, Box<ParseTree>),
|
||||
LambdaDefinition(Function),
|
||||
|
||||
// Functional Operations
|
||||
Compose(Box<ParseTree>, Box<ParseTree>),
|
||||
@@ -111,8 +117,8 @@ macro_rules! three_arg {
|
||||
impl ParseTree {
|
||||
fn parse<I>(
|
||||
tokens: &mut I,
|
||||
globals: &HashMap<String, FunctionDeclaration>,
|
||||
locals: &mut Cow<HashMap<String, FunctionDeclaration>>) -> Result<Self, ParseError>
|
||||
globals: &HashMap<String, Function>,
|
||||
locals: &mut Cow<HashMap<String, Function>>) -> Result<Self, ParseError>
|
||||
where
|
||||
I: Iterator<Item = Result<Token, TokenizeError>>,
|
||||
{
|
||||
@@ -124,8 +130,8 @@ impl ParseTree {
|
||||
// If it is found to be a function, get its argument count.
|
||||
// During parsing, we only keep track of function definitions
|
||||
// so that we know how many arguments it takes
|
||||
if let Some(decl) = locals.clone().get(&ident).or(globals.clone().get(&ident)) {
|
||||
let args = decl.args.iter()
|
||||
if let Some(f) = locals.clone().get(&ident).or(globals.clone().get(&ident)) {
|
||||
let args = f.t.1.iter()
|
||||
.map(|_| ParseTree::parse(tokens, globals, locals)).collect::<Result<Vec<_>, ParseError>>()?;
|
||||
|
||||
Ok(ParseTree::FunctionCall(ident.clone(), args))
|
||||
@@ -162,7 +168,7 @@ impl ParseTree {
|
||||
Err(ParseError::InvalidIdentifier)
|
||||
}
|
||||
}
|
||||
Op::FunctionDeclare(nargs) => {
|
||||
Op::FunctionDefine(nargs) => {
|
||||
let token = tokens.next()
|
||||
.ok_or(ParseError::UnexpectedEndInput)?
|
||||
.map_err(|e| ParseError::TokenizeError(e))?;
|
||||
@@ -176,18 +182,42 @@ impl ParseTree {
|
||||
})
|
||||
.collect::<Result<Vec<_>, ParseError>>()?;
|
||||
|
||||
let f = if locals.contains_key(&ident) {
|
||||
let locals = locals.to_mut();
|
||||
let f = locals.get(&ident).unwrap();
|
||||
let f = f.clone();
|
||||
|
||||
// iterate over f's types and push them
|
||||
for (t, name) in std::iter::zip(f.t.1.clone(), args.clone()) {
|
||||
match t {
|
||||
Type::Function(finner) => {
|
||||
locals.insert(name.clone(), Function::named(&name, finner, None, None));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Function::named(
|
||||
&ident,
|
||||
f.t.clone(),
|
||||
Some(args),
|
||||
Some(Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&locals))?)))
|
||||
} else {
|
||||
let f = Function::named(
|
||||
&ident,
|
||||
FunctionType(Box::new(Type::Any), args.iter().map(|_| Type::Any).collect()),
|
||||
Some(args),
|
||||
Some(Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&locals))?)));
|
||||
|
||||
let locals = locals.to_mut();
|
||||
|
||||
locals.insert(ident.clone(), FunctionDeclaration {
|
||||
_name: ident.clone(),
|
||||
args: args.clone(),
|
||||
});
|
||||
locals.insert(ident.clone(), f.clone());
|
||||
|
||||
Ok(ParseTree::FunctionDefinition(
|
||||
ident,
|
||||
args,
|
||||
Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&*locals))?),
|
||||
Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&*locals))?)))
|
||||
f
|
||||
};
|
||||
|
||||
Ok(ParseTree::FunctionDefinition(f,
|
||||
Box::new(ParseTree::parse(tokens, globals, locals)?)))
|
||||
} else {
|
||||
Err(ParseError::InvalidIdentifier)
|
||||
}
|
||||
@@ -232,25 +262,119 @@ impl ParseTree {
|
||||
.collect::<Result<_, ParseError>>()?;
|
||||
|
||||
let tree = trees.into_iter().fold(
|
||||
ParseTree::Constant(Value::Array(vec![])),
|
||||
ParseTree::Constant(Value::Array(Type::Any, vec![])),
|
||||
|acc, x| ParseTree::Add(Box::new(acc), Box::new(x.clone())),
|
||||
);
|
||||
|
||||
Ok(tree)
|
||||
}
|
||||
Op::Empty => Ok(ParseTree::Constant(Value::Array(vec![]))),
|
||||
Op::Empty => Ok(ParseTree::Constant(Value::Array(Type::Any, vec![]))),
|
||||
Op::CloseArray => Err(ParseError::UnmatchedArrayClose),
|
||||
Op::NotEqualTo => two_arg!(NotEqualTo, tokens, globals, locals),
|
||||
Op::And => two_arg!(And, tokens, globals, locals),
|
||||
Op::Or => two_arg!(Or, tokens, globals, locals),
|
||||
Op::FunctionDeclare(arg_count) => {
|
||||
let name = match tokens.next()
|
||||
.ok_or(ParseError::UnexpectedEndInput)?
|
||||
.map_err(|e| ParseError::TokenizeError(e))?
|
||||
{
|
||||
Token::Identifier(x) => x,
|
||||
_ => return Err(ParseError::InvalidIdentifier),
|
||||
};
|
||||
|
||||
let args: Vec<Type> = (0..arg_count)
|
||||
.map(|_| Self::parse_type(tokens))
|
||||
.collect::<Result<_, ParseError>>()?;
|
||||
|
||||
let rett = Self::parse_type(tokens)?;
|
||||
|
||||
if locals.contains_key(&name) {
|
||||
println!("{name} already found: {locals:?}");
|
||||
return Err(ParseError::ImmutableError(name.clone()));
|
||||
}
|
||||
|
||||
let f = Function::named(
|
||||
&name,
|
||||
FunctionType(Box::new(rett), args),
|
||||
None,
|
||||
None);
|
||||
|
||||
let locals = locals.to_mut();
|
||||
|
||||
locals.insert(name, f.clone());
|
||||
|
||||
Ok(ParseTree::FunctionDeclaration(
|
||||
f,
|
||||
Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&*locals))?)))
|
||||
}
|
||||
Op::LambdaDefine(arg_count) => {
|
||||
let args: Vec<String> = tokens.take(arg_count)
|
||||
.map(|token| match token {
|
||||
Ok(Token::Identifier(ident)) => Ok(ident),
|
||||
Ok(_) => Err(ParseError::InvalidIdentifier),
|
||||
Err(e) => Err(ParseError::TokenizeError(e)),
|
||||
})
|
||||
.collect::<Result<Vec<_>, ParseError>>()?;
|
||||
|
||||
Ok(ParseTree::LambdaDefinition(
|
||||
Function::lambda(
|
||||
FunctionType(Box::new(Type::Any), args.clone().into_iter().map(|_| Type::Any).collect()),
|
||||
args,
|
||||
Some(Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&*locals))?)))))
|
||||
}
|
||||
Op::NonCall => {
|
||||
let ident = match tokens.next().ok_or(ParseError::UnexpectedEndInput)?
|
||||
.map_err(|e| ParseError::TokenizeError(e))?
|
||||
{
|
||||
Token::Identifier(x) => x,
|
||||
_ => return Err(ParseError::InvalidIdentifier),
|
||||
};
|
||||
|
||||
if let Some(f) = locals.clone().get(&ident).or(globals.clone().get(&ident)).cloned() {
|
||||
Ok(ParseTree::Constant(Value::Function(f)))
|
||||
} else {
|
||||
Err(ParseError::FunctionUndefined(ident.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t => Err(ParseError::UnwantedToken(t)),
|
||||
}
|
||||
},
|
||||
Some(Err(e)) => Err(ParseError::TokenizeError(e)),
|
||||
None => Err(ParseError::NoInput),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type<I>(tokens: &mut I) -> Result<Type, ParseError>
|
||||
where
|
||||
I: Iterator<Item = Result<Token, TokenizeError>>,
|
||||
{
|
||||
match tokens.next() {
|
||||
Some(Ok(Token::Type(t))) => Ok(t),
|
||||
Some(Ok(Token::Operator(Op::FunctionDefine(n)))) => {
|
||||
let args: Vec<Type> = (0..n)
|
||||
.map(|_| Self::parse_type(tokens))
|
||||
.collect::<Result<_, ParseError>>()?;
|
||||
|
||||
let rett = Self::parse_type(tokens)?;
|
||||
|
||||
Ok(Type::Function(FunctionType(Box::new(rett), args.clone())))
|
||||
},
|
||||
Some(Ok(Token::Operator(Op::OpenArray))) => {
|
||||
let t = Self::parse_type(tokens)?;
|
||||
let _ = match tokens.next() {
|
||||
Some(Ok(Token::Operator(Op::CloseArray))) => (),
|
||||
_ => return Err(ParseError::UnmatchedArrayClose),
|
||||
};
|
||||
|
||||
Ok(Type::Array(Box::new(t)))
|
||||
}
|
||||
Some(Ok(t)) => Err(ParseError::UnwantedToken(t.clone())),
|
||||
Some(Err(e)) => Err(ParseError::TokenizeError(e)),
|
||||
None => Err(ParseError::UnexpectedEndInput),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses input tokens and produces ParseTrees for an Executor
|
||||
@@ -260,8 +384,8 @@ pub(crate) struct Parser<I: Iterator<Item = Result<Token, TokenizeError>>> {
|
||||
// These are used to keep track of functions in the current context
|
||||
// by the parser. otherwise the parser would have no way to tell
|
||||
// if the program `* a b 12` is supposed to be ((* a b) (12)) or (* (a b) 12)
|
||||
globals: HashMap<String, FunctionDeclaration>,
|
||||
locals: HashMap<String, FunctionDeclaration>,
|
||||
globals: HashMap<String, Function>,
|
||||
locals: HashMap<String, Function>,
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = Result<Token, TokenizeError>>> Parser<I> {
|
||||
@@ -273,7 +397,7 @@ impl<I: Iterator<Item = Result<Token, TokenizeError>>> Parser<I> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn globals(self, globals: HashMap<String, FunctionDeclaration>) -> Self {
|
||||
pub fn globals(self, globals: HashMap<String, Function>) -> Self {
|
||||
Self {
|
||||
tokens: self.tokens,
|
||||
globals,
|
||||
@@ -281,7 +405,7 @@ impl<I: Iterator<Item = Result<Token, TokenizeError>>> Parser<I> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn locals(self, locals: HashMap<String, FunctionDeclaration>) -> Self {
|
||||
pub fn locals(self, locals: HashMap<String, Function>) -> Self {
|
||||
Self {
|
||||
tokens: self.tokens,
|
||||
globals: self.globals,
|
||||
|
||||
@@ -2,6 +2,8 @@ use std::iter::Peekable;
|
||||
use std::{error, io};
|
||||
use std::collections::{VecDeque, HashMap};
|
||||
|
||||
use crate::Type;
|
||||
|
||||
use super::Value;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io::{BufRead, Cursor};
|
||||
@@ -49,7 +51,9 @@ pub(crate) enum Op {
|
||||
Equ,
|
||||
Mod,
|
||||
LazyEqu,
|
||||
FunctionDefine(usize),
|
||||
FunctionDeclare(usize),
|
||||
LambdaDefine(usize),
|
||||
Compose,
|
||||
Id,
|
||||
If,
|
||||
@@ -71,6 +75,7 @@ pub(crate) enum Op {
|
||||
Empty,
|
||||
And,
|
||||
Or,
|
||||
NonCall,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -78,6 +83,7 @@ pub(crate) enum Token {
|
||||
Identifier(String),
|
||||
Operator(Op),
|
||||
Constant(Value),
|
||||
Type(Type),
|
||||
}
|
||||
|
||||
fn get_dot_count<I: Iterator<Item = char>>(s: &mut Peekable<I>) -> Option<usize> {
|
||||
@@ -111,6 +117,13 @@ impl Token {
|
||||
"print" => Ok(Token::Operator(Op::Print)),
|
||||
"empty" => Ok(Token::Operator(Op::Empty)),
|
||||
|
||||
// Types
|
||||
"Any" => Ok(Token::Type(Type::Any)),
|
||||
"Int" => Ok(Token::Type(Type::Int)),
|
||||
"Float" => Ok(Token::Type(Type::Float)),
|
||||
"Bool" => Ok(Token::Type(Type::Bool)),
|
||||
"String" => Ok(Token::Type(Type::String)),
|
||||
|
||||
// then identifiers and numbers
|
||||
_ => {
|
||||
if identifier.is_match(s) {
|
||||
@@ -156,7 +169,9 @@ impl<R: BufRead> Tokenizer<R> {
|
||||
("%", Op::Mod),
|
||||
("=", Op::Equ),
|
||||
(".", Op::LazyEqu),
|
||||
(":", Op::FunctionDeclare(1)),
|
||||
(":", Op::FunctionDefine(1)),
|
||||
("?:", Op::FunctionDeclare(1)),
|
||||
(";", Op::LambdaDefine(1)),
|
||||
("~", Op::Compose),
|
||||
(",", Op::Id),
|
||||
("?", Op::If),
|
||||
@@ -172,6 +187,7 @@ impl<R: BufRead> Tokenizer<R> {
|
||||
("!", Op::Not),
|
||||
("&&", Op::And),
|
||||
("||", Op::Or),
|
||||
("'", Op::NonCall),
|
||||
]);
|
||||
|
||||
let c = if let Some(c) = iter.next() {
|
||||
@@ -256,6 +272,26 @@ impl<R: BufRead> Tokenizer<R> {
|
||||
};
|
||||
Op::FunctionDeclare(n + count)
|
||||
}
|
||||
Op::FunctionDefine(n) => {
|
||||
let count = match get_dot_count(&mut iter) {
|
||||
Some(count) => count,
|
||||
None => {
|
||||
self.tokens.push_back(Err(TokenizeError::InvalidDynamicOperator(token)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
Op::FunctionDefine(n + count)
|
||||
}
|
||||
Op::LambdaDefine(n) => {
|
||||
let count = match get_dot_count(&mut iter) {
|
||||
Some(count) => count,
|
||||
None => {
|
||||
self.tokens.push_back(Err(TokenizeError::InvalidDynamicOperator(token)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
Op::LambdaDefine(n + count)
|
||||
}
|
||||
op => op.clone(),
|
||||
})));
|
||||
|
||||
@@ -327,3 +363,25 @@ impl<R: BufRead> std::iter::Iterator for Tokenizer<R> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::parser::{Parser, ParseTree, ParseError};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn uwu() {
|
||||
let program = "?:. apply : Any Any Any Any :. apply f x f x : id x x apply ; x id x 12";
|
||||
|
||||
let tokens: Vec<Token> = Tokenizer::from_str(program).unwrap().collect::<Result<_, TokenizeError>>().unwrap();
|
||||
|
||||
println!("{tokens:?}");
|
||||
|
||||
let trees: Result<Vec<ParseTree>, ParseError> = Parser::new(tokens.into_iter().map(|x| Ok(x))).collect();
|
||||
|
||||
println!("{trees:?}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user