diff --git a/src/ast.rs b/src/ast.rs index cebeb59..5e3a328 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,8 +6,8 @@ use std::collections::HashMap; #[derive(Debug, Clone)] pub struct Function { pub name: String, - pub statements: Vec, - pub n_args: u64, + pub statement: Statement, + pub args: Vec, assembly: Option, } @@ -19,6 +19,27 @@ pub enum Statement { Scope(Vec), } +#[derive(Debug, Clone)] +pub enum Expression { + Literal(Literal), + Variable(String), + Unary(Unary, Box), + Grouping(Box), + Binary(BinOp, Box, Box), +} + +#[derive(Debug, Clone)] +pub enum Unary { + PointerTo, + ValueFrom, +} + +#[derive(Debug, Clone)] +pub enum BinOp { + Plus, + Minus, +} + #[derive(Debug, Clone)] pub enum ValueNode { Literal(Literal), @@ -48,11 +69,11 @@ pub trait Node { } impl Function { - pub fn new(name: String, n_args: u64, statements: Vec) -> Function { + pub fn new(name: String, args: Vec, statement: Statement) -> Function { Function { name, - statements, - n_args, + statement, + args, assembly: None, } } @@ -78,8 +99,8 @@ fn get_default_functions() -> HashMap { "out".to_string(), Function { name: "out".to_string(), - statements: vec![], - n_args: 1, + statement: Statement::FunctionCall("".to_string(), vec![]), + args: vec!["value".to_string()], assembly: Some( " out: @@ -118,8 +139,8 @@ F-OUT JMP 0xFF" "exit".to_string(), Function { name: "exit".to_string(), - statements: vec![], - n_args: 0, + statement: Statement::FunctionCall("".to_string(), vec![]), + args: vec![], assembly: Some( " exit: @@ -136,9 +157,25 @@ impl Node for Function { fn to_assembly(&self, state: &mut AssemblerState) -> String { match &self.assembly { Some(v) => v.to_string(), - None => format!( - "{}: -{} + None => { + let name = &self.name; + + let mut pop_argument_assembly = "ROM-OUT FLAGS-IN 0x80".to_string(); + + for argument in &self.args { + state.variables.push(argument.to_string()); + pop_argument_assembly += " +SE-OUT A-IN 0xFF +ROM-OUT B-IN 0x01 +ALU-OUT SE-IN 0xFF +" + } + + let statement_assembly = self.statement.to_assembly(state); + format!( + "{name}: +{statement_assembly} +{pop_argument_assembly} ; ; Pop the return address of the stack ; @@ -154,15 +191,8 @@ ROM-OUT FLAGS-IN 0x00 ; Add mode F-OUT JMP 0xFF ", - self.name, - { - self.statements - .iter() - .map(|x| x.to_assembly(state)) - .collect::>() - .join("\n") - } - ), + ) + } } } } @@ -171,15 +201,7 @@ impl Node for Statement { fn to_assembly(&self, state: &mut AssemblerState) -> String { match self { Statement::Scope(statements) => { - let init_assembly = " -ROM-OUT FLAGS-IN 0x00 -SE-OUT A-IN 0xFF -ROM-OUT B-IN 0x01 -ALU-OUT SE-IN 0xFF -" - .to_string(); - - state.variables.push("start scope".to_string()); + let dropped_length = state.variables.len(); let statement_assembly = statements .iter() @@ -187,33 +209,20 @@ ALU-OUT SE-IN 0xFF .collect::>() .join("\n"); - let mut stop_assembly = "".to_string(); - - while state.variables.contains(&"start scope".to_string()) { - stop_assembly += &format!( - " -ROM-OUT FLAGS-IN 0x80 -SE-OUT A-IN 0xFF -ROM-OUT B-IN 0x01 -ALU-OUT SE-IN 0xFF -ROM-OUT FLAGS-IN 0x00" - ); + while state.variables.len() > dropped_length { state.variables.pop(); } + dbg!(&state.variables); - format!( - "{init_assembly} -{statement_assembly} -{stop_assembly}" - ) + statement_assembly } Statement::FunctionCall(name, arguments) => { if !state.functions.contains_key(name) { todo!() } - state.variables.push(name.to_owned()); + dbg!(&state.variables); let argument_assembly: String = arguments .into_iter() .map(|x| x.to_assembly(state)) @@ -226,7 +235,7 @@ ROM-OUT FLAGS-IN 0x00" .map(char::from) .collect(); - for _ in 0..state.functions.get(name).unwrap().n_args { + for _ in &state.functions.get(name).unwrap().args { state.variables.pop(); } @@ -316,6 +325,7 @@ impl Node for ValueNode { - state.variables.iter().position(|x| x == name).unwrap() - 1; + dbg!(&state.variables); state.variables.push(name.to_owned()); format!( diff --git a/src/main.rs b/src/main.rs index a50ee9e..05e071e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,28 @@ +use crate::tokeniser::Token; + mod ast; mod parse; mod tokeniser; fn main() { - let filename = "test.plonkus"; + // let filename: &str = &std::env::args().collect::>()[1]; - let contents = std::fs::read_to_string(filename).expect(&format!("No file named {}", filename)); + // let contents = std::fs::read_to_string(filename).expect(&format!("No file named {}", filename)); - let tokens = tokeniser::tokenise(contents); + // let tokens = tokeniser::tokenise(contents); - let functions = dbg!(parse::ast(tokens)); + // let functions = dbg!(parse::ast(tokens)); - let assembly = ast::to_assembly(functions); + // let assembly = ast::to_assembly(functions); - println!("{}", assembly); + // println!("{}", assembly); + + let mut i: usize = 0; + let tokens: Vec = vec![ + Token::OpenParanthesis, + Token::Star, + Token::Number("2".to_string()), + Token::CloseParanthesis, + ]; + dbg!(parse::parse_expression(&tokens, &mut i)); } diff --git a/src/parse.rs b/src/parse.rs index 1486f65..0576345 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -66,77 +66,143 @@ fn parse_math(tokens: &Vec) -> ValueNode { }; } -fn parse_statements(tokens: &Vec, starting_i: usize) -> (Vec, usize) { - let mut i = starting_i; +fn parse_basic(tokens: &Vec, i: &mut usize) -> Expression { + let literal = match &tokens[*i] { + Token::Identifier(identifier) => Expression::Variable(identifier.to_owned()), + Token::Number(number) => Expression::Literal(Literal::Int(number.parse::().unwrap())), + _ => todo!(), + }; + *i += 1; + literal +} + +fn parse_grouping(tokens: &Vec, i: &mut usize) -> Expression { + match &tokens[*i] { + Token::OpenParanthesis => { + *i += 1; + } + _ => todo!(), + }; + + let inner_expression = parse_expression(tokens, i); + + match &tokens[*i] { + Token::CloseParanthesis => {} + _ => todo!(), + }; + + inner_expression +} + +// TODO: replace parse_math with this recursive function +pub fn parse_expression(tokens: &Vec, i: &mut usize) -> Expression { + #[derive(Debug)] + enum OpExpr { + Expression(Expression), + BinOp(BinOp), + Unary(Unary), + } + + let mut in_expressions_and_operators: Vec = Vec::new(); + + loop { + in_expressions_and_operators.push(match &tokens[*i] { + Token::OpenParanthesis => OpExpr::Expression(parse_grouping(tokens, i)), + Token::Plus => { + *i += 1; + OpExpr::BinOp(BinOp::Plus) + } + Token::Minus => { + *i += 1; + OpExpr::BinOp(BinOp::Minus) + } + Token::Ampersand => { + *i += 1; + OpExpr::Unary(Unary::ValueFrom) + } + Token::Star => { + *i += 1; + OpExpr::Unary(Unary::PointerTo) + } + Token::Number(_) => OpExpr::Expression(parse_basic(tokens, i)), + _other => break, + }); + } + dbg!(in_expressions_and_operators); + Expression::Variable("a".to_string()) +} + +fn parse_statements(tokens: &Vec, i: &mut usize) -> Vec { + dbg!(&i); let mut statements = Vec::new(); - while i < tokens.len() { - statements.push(match &tokens[i] { + while *i < tokens.len() { + statements.push(match &tokens[*i] { Token::OpenSquiglyBracket => { - let (statements, added_to_i) = parse_statements(tokens, i + 1); - i = added_to_i + 1; + *i += 1; + let statements = parse_statements(tokens, i); Statement::Scope(statements) } Token::Keyword(Keyword::Let) => { - i += 1; - let name = match tokens[i].clone() { + *i += 1; + let name = match tokens[*i].clone() { Token::Identifier(identifier) => identifier, _ => todo!(), }; - i += 1; - match tokens[i].clone() { + *i += 1; + match tokens[*i].clone() { Token::Equals => {} _ => todo!(), }; - i += 1; + *i += 1; let mut declaration_tokens: Vec = Vec::new(); - while tokens[i] != Token::Semi { - declaration_tokens.push(tokens[i].clone()); - i += 1; + while tokens[*i] != Token::Semi { + declaration_tokens.push(tokens[*i].clone()); + *i += 1; } Statement::VariableDeclaration(name, parse_math(&declaration_tokens)) } Token::Keyword(Keyword::Assign) => { - i += 1; - let name = match tokens[i].clone() { + *i += 1; + let name = match tokens[*i].clone() { Token::Identifier(identifier) => identifier, _ => todo!(), }; - i += 1; - match tokens[i].clone() { + *i += 1; + match tokens[*i].clone() { Token::Equals => {} _ => todo!(), }; - i += 1; + *i += 1; let mut declaration_tokens: Vec = Vec::new(); - while tokens[i] != Token::Semi { - declaration_tokens.push(tokens[i].clone()); - i += 1; + while tokens[*i] != Token::Semi { + declaration_tokens.push(tokens[*i].clone()); + *i += 1; } Statement::VariableAssignment(name, parse_math(&declaration_tokens)) } Token::Identifier(identifier) => { - i += 1; + *i += 1; let mut declaration_tokens: Vec> = Vec::new(); - i += 1; - while tokens[i] != Token::CloseParanthesis { + *i += 1; + while tokens[*i] != Token::CloseParanthesis { let mut argument_tokens: Vec = Vec::new(); - while tokens[i] != Token::Comma { - argument_tokens.push(tokens[i].clone()); - i += 1; + while tokens[*i] != Token::Comma { + argument_tokens.push(tokens[*i].clone()); + *i += 1; } declaration_tokens.push(argument_tokens); - i += 1; + *i += 1; } - i += 1; + *i += 1; let mut arguments: Vec = Vec::new(); @@ -150,19 +216,35 @@ fn parse_statements(tokens: &Vec, starting_i: usize) -> (Vec, Statement::FunctionCall(identifier.to_owned(), arguments) } Token::CloseSquiglyBracket => { - return (statements, i); + *i += 1; + return statements; } Token::Semi => { - i += 1; + *i += 1; continue; } _other => { dbg!(_other); + dbg!(i); todo!() } }); } - (statements, i) + *i += 1; + statements +} + +pub fn parse_arguments(tokens: &Vec, i: &mut usize) -> Vec { + let mut argument_variables = Vec::new(); + while tokens[*i] != Token::OpenSquiglyBracket { + match &tokens[*i] { + Token::Identifier(identifier) => argument_variables.push(identifier.to_owned()), + Token::OpenSquiglyBracket => {} + _other => todo!(), + } + *i += 1; + } + argument_variables } pub fn ast(tokens: Vec) -> Vec { @@ -172,18 +254,23 @@ pub fn ast(tokens: Vec) -> Vec { while i < tokens.len() { match &tokens[i] { Token::Keyword(Keyword::Function) => { - let (statements, added_to_i) = parse_statements(&tokens, i + 4); - let statements = vec![Statement::Scope(statements)]; - let function_name = match &tokens[i + 1] { - Token::Identifier(identifier) => identifier.to_owned(), + i += 1; + + let name = match &tokens[i] { + Token::Identifier(identifier) => identifier, _ => todo!(), - }; - let n_args = match &tokens[i + 2] { - Token::Number(num) => num.parse::().unwrap(), - _ => todo!(), - }; - i += added_to_i; - functions.push(Function::new(function_name, n_args, statements)); + } + .to_owned(); + i += 1; + + let arguments = parse_arguments(&tokens, &mut i); + + i += 1; + let statements = parse_statements(&tokens, &mut i); + + let statement = Statement::Scope(statements); + + functions.push(Function::new(name, arguments, statement)); } _other => { dbg!(&functions); diff --git a/src/tokeniser.rs b/src/tokeniser.rs index 202bef6..b582871 100644 --- a/src/tokeniser.rs +++ b/src/tokeniser.rs @@ -5,6 +5,8 @@ pub enum Token { Comma, Plus, Minus, + Ampersand, + Star, Number(String), Identifier(String), Keyword(Keyword), @@ -85,22 +87,24 @@ fn tokenise_current_character( } { - use std::option::Option::Some as s; + use Option::Some as s; use Token as T; use TokenFinishedUnfinished::Unfinished as uf; - match current_character { - ';' => uf(s(T::Semi)), - '(' => uf(s(T::OpenParanthesis)), - ')' => uf(s(T::CloseParanthesis)), - '{' => uf(s(T::OpenSquiglyBracket)), - '}' => uf(s(T::CloseSquiglyBracket)), - '=' => uf(s(T::Equals)), - ',' => uf(s(T::Comma)), - '+' => uf(s(T::Plus)), - '-' => uf(s(T::Minus)), - _ => uf(None), - } + uf(match current_character { + ';' => s(T::Semi), + '(' => s(T::OpenParanthesis), + ')' => s(T::CloseParanthesis), + '{' => s(T::OpenSquiglyBracket), + '}' => s(T::CloseSquiglyBracket), + '=' => s(T::Equals), + ',' => s(T::Comma), + '+' => s(T::Plus), + '-' => s(T::Minus), + '&' => s(T::Ampersand), + '*' => s(T::Star), + _ => None, + }) } } Some(v) => Finished(v),