From 5a3bc07079b1e9d1692b15c59369f5e3871705d7 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 18 Nov 2021 10:19:06 +0200 Subject: WIP Rewrite to point-free style --- samples/sample1.code | 9 +- src/grammar.pest | 15 +- src/main.rs | 443 ++++++++++++++++++++------------------------------- 3 files changed, 184 insertions(+), 283 deletions(-) diff --git a/samples/sample1.code b/samples/sample1.code index f033721..337bd6d 100644 --- a/samples/sample1.code +++ b/samples/sample1.code @@ -1 +1,8 @@ -my-func 1 2 \ No newline at end of file +foo = "foo"; +bar = "bar"; +int.double = int.multiply 2; +list.multiply-all = reduce int.multiply 1; + +ifelse (string.eq? foo bar) + (int.double 1) # if foo = bar, calc 1 * 2 + (int.double 2) # else, calc 2 * 2 diff --git a/src/grammar.pest b/src/grammar.pest index 9ef2b1b..822e256 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -1,10 +1,9 @@ -WHITESPACE = _{ " " | "\t" } -COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" ~ NEWLINE* } +COMMENT = _{ "#" ~ (!("#" | NEWLINE) ~ ANY)* ~ NEWLINE* } +WHITESPACE = _{ " " | "\t" | NEWLINE } program = { SOI ~ statement+ ~ EOI } -statement = { (definition | expression) ~ NEWLINE* } -definition = { symbol+ ~ "=" ~ expression } -expression = { expression_node+ } -expression_node = { integer_literal | builtin | symbol } -builtin = { "+" | "-" | "/" | "*" } +statement = { (definition | expression)} +definition = { symbol ~ "=" ~ expression ~ ";"+ } +expression = { (symbol | integer_literal | string_literal | ("(" ~ expression ~ ")"))+ } integer_literal = @{ "-"? ~ ASCII_DIGIT+ } -symbol = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | ".")* } \ No newline at end of file +string_literal = { QUOTATION_MARK ~ (!QUOTATION_MARK ~ ANY)* ~ QUOTATION_MARK } +symbol = @{ (ASCII_ALPHA | "_.") ~ (ASCII_ALPHANUMERIC | "-" | "." | "?" | "!")* } diff --git a/src/main.rs b/src/main.rs index bf84c36..41b4422 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,277 +11,172 @@ mod parser { pub struct Parser; } -mod ast { - use super::parser::Rule; - use pest::Span; - - fn span_into_str(span: Span) -> &str { - span.as_str() - } - - #[derive(Debug, FromPest)] - #[pest_ast(rule(Rule::program))] - pub struct Program { - pub statements: Vec, - pub eoi: EOI, - } - - #[derive(Debug, FromPest)] - #[pest_ast(rule(Rule::statement))] - pub enum Statement { - Definition(Definition), - Expression(Expression), - } - - #[derive(Debug, FromPest)] - #[pest_ast(rule(Rule::definition))] - pub struct Definition { - pub symbols: Vec, - pub expression: Expression, - } - - #[derive(Debug, FromPest, Clone)] - #[pest_ast(rule(Rule::expression))] - pub struct Expression { - pub nodes: Vec, - } - - #[derive(Debug, FromPest, Clone)] - #[pest_ast(rule(Rule::expression_node))] - pub enum ExpressionNode { - Symbol(Symbol), - Builtin(Builtin), - IntegerLiteral(IntegerLiteral), - Expression(Expression), - } - - #[derive(Debug, FromPest, Copy, Clone)] - #[pest_ast(rule(Rule::builtin))] - pub enum Builtin { - SumOp, - SubtractOp, - DivideOp, - MultiplyOp, - } - - #[derive(Debug, FromPest, Copy, Clone)] - #[pest_ast(rule(Rule::integer_literal))] - pub struct IntegerLiteral { - #[pest_ast(outer(with(span_into_str), with(str::parse::), with(Result::unwrap)))] - pub value: i64, - } - - #[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, Copy, Clone)] - #[pest_ast(rule(Rule::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), - Function { - unbound: Vec, - bound: HashMap>, - body: Box, - }, - } - - pub fn evaluate(ast: &ast::Program) { - let mut symbol_table: HashMap = 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 apply_function(function: &RuntimeExpression) -> Box { - match function { - RuntimeExpression::Function { - bound, - unbound, - body, - } => todo!("function application"), - _ => unreachable!("trying to apply something else than a function"), - } - } - - fn evaluate_nonary( - table: &HashMap, - node: &ast::ExpressionNode, - ) -> Box { - match node { - ast::ExpressionNode::IntegerLiteral(literal) => { - Box::new(RuntimeExpression::Integer(literal.value)) - } - 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, - node: &ast::ExpressionNode, - arg: &ast::ExpressionNode, - ) -> Box { - let evaluated_arg = evaluate_expression_node(table, arg); - match node { - ast::ExpressionNode::Symbol(symbol) => { - let rt_expr = table.get(&symbol.value).expect(&format!("no such symbol")); - - 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> = - 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( - table: &HashMap, - expression: &ast::Expression, - ) -> Box { - let nodes = &expression.nodes; - return match nodes.len() { - 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, - node: &ast::ExpressionNode, - ) -> Box { - 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(&symbol_table, &expression) - } - ast::Statement::Definition(_) => { - panic!("unsupported statement type: definition") - } - }; - - match *runtime_expr { - RuntimeExpression::Integer(value) => println!("{}", value), - other => println!("{:#?}", other), - } - } - } -} +// mod ast { +// use super::parser::Rule; +// use pest::Span; + +// fn span_into_str(span: Span) -> &str { +// span.as_str() +// } + +// #[derive(Debug, FromPest)] +// #[pest_ast(rule(Rule::program))] +// pub struct Program { +// pub statements: Vec, +// pub eoi: EOI, +// } + +// #[derive(Debug, FromPest)] +// #[pest_ast(rule(Rule::statement))] +// pub enum Statement { +// Definition(Definition), +// Expression(Expression), +// } + +// #[derive(Debug, FromPest)] +// #[pest_ast(rule(Rule::definition))] +// pub struct Definition { +// pub symbols: Vec, +// pub expression: Expression, +// } + +// #[derive(Debug, FromPest, Clone)] +// #[pest_ast(rule(Rule::expression))] +// pub enum Expression { +// IntegerLiteral(IntegerLiteral), +// Symbol(Symbol), +// SubExpressions(Vec), +// } + +// #[derive(Debug, FromPest, Copy, Clone)] +// #[pest_ast(rule(Rule::integer_literal))] +// pub struct IntegerLiteral { +// #[pest_ast(outer(with(span_into_str), with(str::parse::), with(Result::unwrap)))] +// pub value: i64, +// } + +// #[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, Copy, Clone)] +// #[pest_ast(rule(Rule::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::SubNodes(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; +// use std::rc::Rc; + +// #[derive(Debug)] +// pub enum BuiltinFn { +// Const(i64), +// } + +// #[derive(Debug)] +// pub enum Function { +// Builtin(BuiltinFn), +// } + +// pub fn evaluate(ast: &ast::Program) { +// let mut symbol_table: HashMap> = HashMap::new(); + +// // symbol_table.insert(String::from("const")); + +// // fn apply_function(function: &Function, arg: &Function) -> Function { +// // match function { +// // Function::Builtin(builtin_fn) => match builtin_fn { +// // BuiltinFn::Const(value) => Function::Builtin(BuiltinFn::Const(*value)), +// // }, +// // } +// // } + +// fn evaluate_nonary( +// table: &HashMap>, +// lhs: &ast::ExpressionNode, +// ) -> Rc { +// match lhs { +// ast::ExpressionNode::IntegerLiteral(literal) => { +// Rc::new(Function::Builtin(BuiltinFn::Const(literal.value))) +// } +// ast::ExpressionNode::Symbol(symbol) => match symbol.value.as_str() { +// "math-zero" => Rc::new(Function::Builtin(BuiltinFn::Const(0))), +// sym => (*table.get(sym).expect("symbol not found")).clone(), +// }, +// _ => todo!("_ case in evaluate_nonary"), +// } +// } + +// fn evaluate_unary( +// table: &HashMap>, +// lhs: &ast::ExpressionNode, +// rhs: &ast::ExpressionNode, +// ) -> Rc { +// let rhs_evaled = evaluate_nonary(&table, rhs); +// todo!("evaluate_unary") +// } + +// for statement in &ast.statements { +// let res: Rc = match statement { +// ast::Statement::Expression(expression) => match expression.nodes.len() { +// 1 => evaluate_nonary(&symbol_table, &expression.nodes[0]), +// 2 => evaluate_unary(&symbol_table, &expression.nodes[0], &expression.nodes[1]), +// _ => unreachable!("expr arity > 2"), +// }, +// ast::Statement::Definition(_) => { +// panic!("unsupported statement type: definition") +// } +// }; + +// println!("Result: {:#?}", res) +// } +// } +// } fn main() { - use ast::Program; + // use ast::Program; use from_pest::FromPest; use pest::Parser; use std::fs; @@ -291,13 +186,13 @@ fn main() { parser::Parser::parse(parser::Rule::program, &unparsed_file).expect("unsuccessful parse"); println!("parse tree = {:#?}", parse_tree); - let syntax_tree: Program = Program::from_pest(&mut parse_tree).expect("infallible"); - println!("syntax tree = {:#?}", syntax_tree); + // let syntax_tree: Program = Program::from_pest(&mut parse_tree).expect("infallible"); + // println!("syntax tree = {:#?}", syntax_tree); - let ir_tree = ir::left_associate_exprs(&syntax_tree); - println!("ir tree = {:#?}", ir_tree); + // let ir_tree = ir::left_associate_exprs(&syntax_tree); + // println!("ir tree = {:#?}", ir_tree); - runtime::evaluate(&ir_tree); + // runtime::evaluate(&ir_tree); // let tokens = program. -- cgit v1.3