diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2021-11-17 16:13:54 +0200 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2021-11-17 16:13:54 +0200 |
| commit | a4f91d8e4509ccacb2ad09d9ec47f77a5c01470e (patch) | |
| tree | bc2923c73d29a3cae907a7c2082a2e0f75b0f03b /src | |
| parent | 847bf5cbcf61e0594b0fff0a3e895ddcc59e8d89 (diff) | |
Work on runtime
Diffstat (limited to 'src')
| -rw-r--r-- | src/grammar.pest | 2 | ||||
| -rw-r--r-- | src/main.rs | 194 |
2 files changed, 164 insertions, 32 deletions
diff --git a/src/grammar.pest b/src/grammar.pest index bfb783b..9ef2b1b 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -4,7 +4,7 @@ program = { SOI ~ statement+ ~ EOI } statement = { (definition | expression) ~ NEWLINE* } definition = { symbol+ ~ "=" ~ expression } expression = { expression_node+ } -expression_node = { integer_literal | builtin | symbol | ("(" ~ expression ~ ")") } +expression_node = { integer_literal | builtin | symbol } builtin = { "+" | "-" | "/" | "*" } integer_literal = @{ "-"? ~ ASCII_DIGIT+ } symbol = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | ".")* }
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs index db4ce92..bf84c36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ mod ast { #[pest_ast(rule(Rule::program))] pub struct Program { pub statements: Vec<Statement>, - eoi: EOI, + pub eoi: EOI, } #[derive(Debug, FromPest)] @@ -40,13 +40,13 @@ mod ast { pub expression: Expression, } - #[derive(Debug, FromPest)] + #[derive(Debug, FromPest, Clone)] #[pest_ast(rule(Rule::expression))] pub struct Expression { pub nodes: Vec<ExpressionNode>, } - #[derive(Debug, FromPest)] + #[derive(Debug, FromPest, Clone)] #[pest_ast(rule(Rule::expression_node))] pub enum ExpressionNode { Symbol(Symbol), @@ -64,78 +64,209 @@ mod ast { MultiplyOp, } - #[derive(Debug, FromPest)] + #[derive(Debug, FromPest, Copy, Clone)] #[pest_ast(rule(Rule::integer_literal))] pub struct IntegerLiteral { #[pest_ast(outer(with(span_into_str), with(str::parse::<i64>), with(Result::unwrap)))] pub value: i64, } - #[derive(Debug, FromPest)] + #[derive(Debug, FromPest, Clone)] #[pest_ast(rule(Rule::symbol))] pub struct Symbol { #[pest_ast(outer(with(span_into_str), with(String::from)))] pub value: String, } - #[derive(Debug, FromPest)] + #[derive(Debug, FromPest, Copy, Clone)] #[pest_ast(rule(Rule::EOI))] - struct EOI; + pub struct EOI; +} + +mod ir { + use super::ast; + + pub fn left_associate_exprs(program: &ast::Program) -> ast::Program { + fn associate(expr: &ast::Expression) -> ast::Expression { + match expr.nodes.len() { + 1 | 2 => expr.clone(), + 3.. => { + let inner_node = ast::ExpressionNode::Expression(ast::Expression { + nodes: expr.nodes[0..2].to_vec(), + }); + let rest = expr.nodes[2..].to_vec(); + let mut new_nodes = vec![inner_node]; + new_nodes.extend(rest); + let outer_node = ast::Expression { nodes: new_nodes }; + associate(&outer_node) + } + _ => unreachable!(), + } + } + + let statements = program + .statements + .iter() + .map(|s| match s { + ast::Statement::Expression(expr) => ast::Statement::Expression(associate(expr)), + ast::Statement::Definition(def) => ast::Statement::Definition(ast::Definition { + symbols: def.symbols.clone(), + expression: associate(&def.expression), + }), + }) + .collect(); + + ast::Program { + statements, + eoi: program.eoi.clone(), + } + } } mod runtime { use super::ast; use std::collections::HashMap; + #[derive(Debug, Clone)] pub enum RuntimeExpression { Integer(i64), - BuiltinFunction(ast::Builtin, Box<RuntimeExpression>), + Function { + unbound: Vec<String>, + bound: HashMap<String, Box<RuntimeExpression>>, + body: Box<RuntimeExpression>, + }, } pub fn evaluate(ast: &ast::Program) { - let mut _symbol_table: HashMap<String, RuntimeExpression> = HashMap::new(); + let mut symbol_table: HashMap<String, RuntimeExpression> = HashMap::new(); + symbol_table.insert( + String::from("my-func"), + RuntimeExpression::Function { + unbound: vec![String::from("a"), String::from("b")], + bound: HashMap::new(), + body: Box::new(RuntimeExpression::Integer(10)), + }, + ); - fn evaluate_nonary(node: &ast::ExpressionNode) -> Box<RuntimeExpression> { + fn apply_function(function: &RuntimeExpression) -> Box<RuntimeExpression> { + match function { + RuntimeExpression::Function { + bound, + unbound, + body, + } => todo!("function application"), + _ => unreachable!("trying to apply something else than a function"), + } + } + + fn evaluate_nonary( + table: &HashMap<String, RuntimeExpression>, + node: &ast::ExpressionNode, + ) -> Box<RuntimeExpression> { match node { ast::ExpressionNode::IntegerLiteral(literal) => { Box::new(RuntimeExpression::Integer(literal.value)) } - _ => todo!("_ case of evaluate_nonary"), + ast::ExpressionNode::Symbol(symbol) => { + let rt_expr = table + .get(&symbol.value) + .expect(&format!("no such symbol: {}", symbol.value)); + return Box::new(rt_expr.clone()); + } + _ => { + println!("_ case of evaluate_nonary for {:#?}", node); + panic!() + } } } fn evaluate_unary( + table: &HashMap<String, RuntimeExpression>, node: &ast::ExpressionNode, arg: &ast::ExpressionNode, ) -> Box<RuntimeExpression> { - let evaluated_arg = evaluate_expression_node(arg); + let evaluated_arg = evaluate_expression_node(table, arg); match node { - ast::ExpressionNode::Builtin(builtin) => { - Box::new(RuntimeExpression::BuiltinFunction(*builtin, evaluated_arg)) - } - _ => todo!("_ case of evaluate_unary"), - } - } + ast::ExpressionNode::Symbol(symbol) => { + let rt_expr = table.get(&symbol.value).expect(&format!("no such symbol")); - fn evaluate_expression_node(node: &ast::ExpressionNode) -> Box<RuntimeExpression> { - match node { - ast::ExpressionNode::Expression(expr) => evaluate_expression(expr), - _ => todo!("_ case of evaluate_expression_node"), + match rt_expr { + RuntimeExpression::Integer(_) => { + panic!("trying to apply to integer like a function") + } + RuntimeExpression::Function { + unbound, + bound, + body, + } => { + let unbounds_left = unbound.len(); + if unbounds_left == 0 { + unreachable!("function is somehow called with arguments while it has no unbound parameters") + } + + let mut new_bound: HashMap<String, Box<RuntimeExpression>> = + HashMap::new(); + for (key, value) in bound { + new_bound.insert(String::from(key), Box::new(*value.clone())); + } + + let next_to_bind = &unbound[0]; + new_bound.insert(String::from(next_to_bind), evaluated_arg); + + let new_unbound = unbound[1..].to_vec(); + let new_body = Box::new(*body.clone()); + + let new_unbound_length = new_unbound.len(); + + let new_func = RuntimeExpression::Function { + unbound: new_unbound, + bound: new_bound, + body: new_body, + }; + + if new_unbound_length == 0 { + return apply_function(&new_func); + } else { + return Box::new(new_func); + } + } + } + } + _ => { + println!("_ case of evaluate_unary for {:#?}, {:#?}", node, arg); + panic!() + } } } - fn evaluate_expression(expression: &ast::Expression) -> Box<RuntimeExpression> { + fn evaluate_expression( + table: &HashMap<String, RuntimeExpression>, + expression: &ast::Expression, + ) -> Box<RuntimeExpression> { let nodes = &expression.nodes; return match nodes.len() { - 1 => evaluate_nonary(&nodes[0]), - 2 => evaluate_unary(&nodes[0], &nodes[1]), - _ => todo!("_ case of evaluate_expression"), + 1 => evaluate_nonary(table, &nodes[0]), + 2 => evaluate_unary(table, &nodes[0], &nodes[1]), + _ => unreachable!("expression has more than 2 nodes"), }; } + fn evaluate_expression_node( + table: &HashMap<String, RuntimeExpression>, + node: &ast::ExpressionNode, + ) -> Box<RuntimeExpression> { + match node { + ast::ExpressionNode::Expression(expr) => evaluate_expression(table, expr), + ast::ExpressionNode::IntegerLiteral(_) => evaluate_nonary(&table, node), + _ => todo!("_ case of evaluate_expression_node"), + } + } + for statement in &ast.statements { let runtime_expr = match statement { - ast::Statement::Expression(expression) => evaluate_expression(&expression), + ast::Statement::Expression(expression) => { + evaluate_expression(&symbol_table, &expression) + } ast::Statement::Definition(_) => { panic!("unsupported statement type: definition") } @@ -143,9 +274,7 @@ mod runtime { match *runtime_expr { RuntimeExpression::Integer(value) => println!("{}", value), - RuntimeExpression::BuiltinFunction(builtin, _arg) => match builtin { - _ => todo!("_ case of runtime_expr eval handling"), - }, + other => println!("{:#?}", other), } } } @@ -165,7 +294,10 @@ fn main() { let syntax_tree: Program = Program::from_pest(&mut parse_tree).expect("infallible"); println!("syntax tree = {:#?}", syntax_tree); - runtime::evaluate(&syntax_tree); + let ir_tree = ir::left_associate_exprs(&syntax_tree); + println!("ir tree = {:#?}", ir_tree); + + runtime::evaluate(&ir_tree); // let tokens = program. |
