aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2021-11-17 16:13:54 +0200
committerJan Tuomi <jans.tuomi@gmail.com>2021-11-17 16:13:54 +0200
commita4f91d8e4509ccacb2ad09d9ec47f77a5c01470e (patch)
treebc2923c73d29a3cae907a7c2082a2e0f75b0f03b
parent847bf5cbcf61e0594b0fff0a3e895ddcc59e8d89 (diff)
Work on runtime
-rw-r--r--samples/sample1.code3
-rw-r--r--src/grammar.pest2
-rw-r--r--src/main.rs194
3 files changed, 165 insertions, 34 deletions
diff --git a/samples/sample1.code b/samples/sample1.code
index f24fa12..f033721 100644
--- a/samples/sample1.code
+++ b/samples/sample1.code
@@ -1,2 +1 @@
-/* Sample code */
-+ 123 456 \ No newline at end of file
+my-func 1 2 \ No newline at end of file
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.