Skip to content
This repository has been archived by the owner on Apr 28, 2022. It is now read-only.

Commit

Permalink
Toma zambones ❤️
Browse files Browse the repository at this point in the history
  • Loading branch information
Henriquelay committed Mar 23, 2022
1 parent 21ae1ec commit 0602ebd
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 32 deletions.
34 changes: 26 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ macro_rules! for_every_number_Value {
match $expr {
(Literal::Num(n), Literal::Num(o)) => match (n, o) {
(Number::Integer(x), Number::Integer(y)) => $clj(x, y),
(Number::UInteger(x), Number::UInteger(y)) => $clj(x, y),
// (Number::UInteger(x), Number::UInteger(y)) => $clj(x, y),
(Number::Float(x), Number::Float(y)) => $clj(x, y),
_ => unimplemented!(),
},
Expand All @@ -36,7 +36,7 @@ macro_rules! for_every_number_Value_wrapped {
match $expr {
(Literal::Num(n), Literal::Num(o)) => match (n, o) {
(Number::Integer(x), Number::Integer(y)) => Number::Integer($clj(x, y)),
(Number::UInteger(x), Number::UInteger(y)) => Number::UInteger($clj(x, y)),
// (Number::UInteger(x), Number::UInteger(y)) => Number::UInteger($clj(x, y)),
(Number::Float(x), Number::Float(y)) => Number::Float($clj(x, y)),
_ => unimplemented!(),
},
Expand All @@ -48,7 +48,6 @@ macro_rules! for_every_number_Value_wrapped {
/// Evaluates return value
fn eval_expr<'a>(
expr: &'a Expr,
// TODO replace both symbol list with actual symbol tables, not lists
vars: &mut Vec<HashMap<String, Vec<Literal>>>,
funcs: &HashMap<String, &Function>,
) -> Result<Literal, String> {
Expand Down Expand Up @@ -76,14 +75,14 @@ fn eval_expr<'a>(
},
Expr::And(a, b) => match (eval_expr(a, vars, funcs)?, eval_expr(b, vars, funcs)?) {
(Literal::Num(x), Literal::Num(y)) => Ok(Literal::Bool(
x > Number::UInteger(1) && y > Number::UInteger(1),
x > Number::Integer(1) && y > Number::Integer(1),
)),
(Literal::Bool(x), Literal::Bool(y)) => Ok(Literal::Bool(x && y)),
_ => Err("Cannot apply AND".to_string()),
},
Expr::Or(a, b) => match (eval_expr(a, vars, funcs)?, eval_expr(b, vars, funcs)?) {
(Literal::Num(x), Literal::Num(y)) => Ok(Literal::Bool(
x > Number::UInteger(1) || y > Number::UInteger(1),
x > Number::Integer(1) || y > Number::Integer(1),
)),
(Literal::Bool(x), Literal::Bool(y)) => Ok(Literal::Bool(x || y)),
_ => Err("Cannot apply OR".to_string()),
Expand All @@ -108,7 +107,7 @@ fn eval_expr<'a>(
let right = eval_expr(b, vars, funcs)?;
for_every_number_Value_wrapped!((left, right), |x, y| x / y)
})),
Expr::Var(name) => {
Expr::Var { name, index } => {
// Searches the variable on variables symbol table that matches name with invoked variable
let mut retval = None;
for scope_vars in vars.iter().rev() {
Expand All @@ -123,8 +122,28 @@ fn eval_expr<'a>(
retval = Some(Err(format!("Cannot find variable `{}`", name)));
}
}

// If index is some, return value at index, if value is array
if let &Expr::Literal(Literal::Num(Number::Integer(index_number))) = index.as_ref() {
if index_number > 0 {
if let Literal::Array(array) = retval.unwrap().unwrap() {
retval = Some(Ok(array[index_number as usize].clone()))
} else {
retval = Some(Err("Cannot index non-array".to_string()))
}
}
} else {
retval = Some(Err("Cannot index with valu less than zero".to_string()));
}
retval.unwrap()
}
Expr::Array(array) => {
let mut retval = Vec::new();
for expr in array {
retval.push(eval_expr(expr, vars, funcs)?);
}
Ok(Literal::Array(retval))
}
Expr::Call(name, call_args) => {
// Retrieve the callee signature
if let Some(function) = funcs.get(name) {
Expand Down Expand Up @@ -170,7 +189,6 @@ fn eval_expr<'a>(
/// Evaluates return value for block
fn eval<'a>(
blk: &'a Block,
// TODO replace both symbol list with actual symbol tables, not lists
vars: &mut Vec<HashMap<String, Vec<Literal>>>,
funcs: &HashMap<String, &Function>,
is_loop: bool,
Expand Down Expand Up @@ -247,7 +265,7 @@ pub fn eval_source(src: String) -> Result<Literal, Vec<String>> {
let mut funcs: HashMap<String, &Function> = HashMap::new();
for item in ast.iter() {
match item {
Item::Function(f) => funcs.insert(f.name.clone(), &f),
Item::Function(f) => funcs.insert(f.name.clone(), &Box::new(f)),
};
}
// Searching for function called `main`
Expand Down
18 changes: 14 additions & 4 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub enum Literal {
Str(String),
/// Function variables
Fn(Function),
/// Array of literals
Array(Vec<Literal>),
/// Break special value
Break,
}
Expand Down Expand Up @@ -46,10 +48,18 @@ pub enum Expr {
/// Expr1 || Expr2. >0 is truthy
Or(Box<Expr>, Box<Expr>),

/// Declare an array of expressions
Array(Vec<Expr>),

/// Function call expression. `()` operator placed after a symbol, as in `foo()`
Call(String, Vec<Expr>),
/// Variable invocation
Var(String),
/// Variable invocation. Index is for array variable
Var {
/// Name of the variable
name: String,
/// Index offset from start of the array. If `[]` is not used, this is defaulted to `0`.
index: Box<Expr>,
},
}

/// Types for ZECA's expressions. Uses mostly native Rust types
Expand All @@ -58,7 +68,7 @@ pub enum Number {
/// Fake numbers. -1, 0, 1
Integer(isize),
/// Unsigned integer numbers. 0, 1, 2
UInteger(usize),
// UInteger(usize),
/// Real numbers
Float(f64),
}
Expand All @@ -70,7 +80,7 @@ impl std::ops::Neg for Number {
match self {
Self::Integer(x) => Self::Integer(-x),
// Notice the casting
Self::UInteger(x) => Self::Integer(-(x as isize)),
// Self::UInteger(x) => Self::Integer(-(x as isize)),
Self::Float(x) => Self::Float(-x),
}
}
Expand Down
55 changes: 44 additions & 11 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,17 @@ pub fn identifier_parser(
pub fn integer_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Copy + Clone {
// Parse for base 10
text::int(10)
.map(|s: String| Expr::Literal(Literal::Num(Number::Integer(s.parse().unwrap()))))
.map(|s: String| {
Expr::Literal(Literal::Num(Number::Integer(s.parse().unwrap())))
// Expr::Literal(Literal::Num({
// let int = s.parse::<usize>();
// if let Ok(int) = int {
// Number::UInteger(int)
// } else {
// Number::Integer(s.parse::<isize>().expect("Error parsing integer literal"))
// }
// }))
})
.padded()
}

Expand Down Expand Up @@ -83,6 +93,18 @@ pub fn string_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Copy +
// }
// Non-terminal (Composite types) {

/// Parses an variable assignment
pub fn assignment_parser() -> impl Parser<char, Statement, Error = Simple<char>> + Clone {
identifier_parser()
.then_ignore(just('='))
.then(expr_parser())
.then_ignore(just(";"))
.map(|(lvalue, rvalue)| Statement::Assign {
lvalue,
rvalue: Box::new(rvalue),
})
}

/// Statement-block-item parser. It parses all three, and are nested together because of the recursive nature of them (statement may be a block, a block is made of statements and items, with are made of functions which includes blocks etc.)
/// The parsers need to be individually extracted because of their interdependance, where a parse some of the other parser depends on can go out of scope, getting the value dropped. So, this functions returns all of them in a tuple
/// This is not less performant, because the other parsers would need to be evaluated anyway, since they are interdependant
Expand All @@ -104,7 +126,7 @@ pub fn string_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Copy +
/// - No support for nested functions
///
/// A Loop is a controle structure to repeat determined Statements, or, more precisely, a Block.
/// TODO does it had break implementation? Document it here.
/// A `break` statement may be placed to stop looping.
pub fn statement_block_item_loop_parser() -> (
impl Parser<char, Statement, Error = Simple<char>> + Clone,
impl Parser<char, Block, Error = Simple<char>> + Clone,
Expand All @@ -114,15 +136,8 @@ pub fn statement_block_item_loop_parser() -> (
let identifier = identifier_parser();
let comment = comment_parser();
let expr = expr_parser();
let assign = assignment_parser();

let assign = identifier
.then_ignore(just('='))
.then(expr.clone())
.then_ignore(just(";"))
.map(|(lvalue, rvalue)| Statement::Assign {
lvalue,
rvalue: Box::new(rvalue),
});
let r#let = text::keyword("let")
.ignored()
.then(assign.clone())
Expand Down Expand Up @@ -215,6 +230,7 @@ pub fn expr_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
let string = string_parser();
let number = number_parser();
let boolean = boolean_parser();

recursive(|expr| {
let call = identifier
.then(
Expand All @@ -225,14 +241,30 @@ pub fn expr_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
.delimited_by(just('('), just(')')),
)
.map(|(f, args)| Expr::Call(f, args));
let array_index = expr
.clone()
.padded()
.separated_by(just(','))
.delimited_by(just('['), just(']'))
.map(Expr::Array);

let atom = expr
.clone()
.delimited_by(just('('), just(')'))
.or(string)
.or(boolean)
.or(number)
.or(call)
.or(identifier.map(Expr::Var));
.or(array_index)
.or(identifier
.then(expr.delimited_by(just('['), just(']')).or_not())
.map(|(name, index)| Expr::Var {
name,
index: Box::new(
// index.unwrap_or(Expr::Literal(Literal::Num(Number::UInteger(0)))),
index.unwrap_or(Expr::Literal(Literal::Num(Number::Integer(0)))),
),
}));

let op = |c| just(c).padded();

Expand Down Expand Up @@ -289,6 +321,7 @@ pub fn expr_parser() -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
bool_algebra.padded()
})
}

// }

/// Parses the whole program for correct tokens and tokens order
Expand Down
32 changes: 32 additions & 0 deletions src/unittest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,33 @@ pub fn string() {
);
}

#[test]
pub fn assign() {
test_util::tests(
|s| {
crate::parser::assignment_parser()
.then_ignore(end())
.parse_recovery_verbose(s)
},
vec![
r#"x = 10;"#,
r#"x = -10;"#,
r#"complicated_name = 0.1;"#,
r#"a = true;"#,
r#"a = "strings";"#,
r#"a = [];"#,
r#"a = [1];"#,
r#"a = [1, 2, 3];"#,
r#"a = another_variable;"#,
],
vec![
r#"let a = "#,
r#"name with space = "#,
r#"array[index] = "#, // TODO not yet implemented
],
);
}

#[test]
pub fn expr() {
test_util::tests(
Expand Down Expand Up @@ -260,6 +287,11 @@ pub fn expr() {
"5 || -3",
// Str
r#""str são literals e portanto ainda estão dentro de expr.""#,
// Array
r#"array[2]"#,
r#"array[2 + 3]"#,
r#"array[array_index]"#,
r#"array[array_index + array_indexes[2]] + array[array_index + array_indexes[3]]"#,
],
vec![
"1+",
Expand Down
4 changes: 4 additions & 0 deletions tests/examples/good/array.zeca
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() {
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr[3] + arr[7];
}
Loading

0 comments on commit 0602ebd

Please sign in to comment.