diff --git a/compiler/src/ast/mod.rs b/compiler/src/ast/mod.rs index af0367c7ddb2497d40cd6145f9bbbf25c3a8298d..48830442209d3f3dbf9638ee55774e0afc624012 100644 --- a/compiler/src/ast/mod.rs +++ b/compiler/src/ast/mod.rs @@ -8,12 +8,21 @@ use super::tokenizer::Token; use error::AstError; use types::{Argument, ParserContext}; -pub use types::{Ast, Type}; +pub use types::{Ast, Block, Type}; fn parse_expression(tokens: &mut ParserContext) -> Result { let left = match tokens.next() { Some(token) => match token { Token::Number(number) => Ast::Number(number.clone()), + Token::String(string) => Ast::String(string.clone()), + Token::True => Ast::Bool(true), + Token::False => Ast::Bool(false), + Token::OpenBracket => { + // FRICK we consumed the open bracket + // we need to put the cursor back + tokens.cursor -= 1; + Ast::Block(parse_block(tokens)?) + } Token::Identifier(name) => match tokens.peek() { Some(Token::OpenParanthesis) => { tokens.next(); @@ -74,12 +83,60 @@ fn parse_expression(tokens: &mut ParserContext) -> Result { Ok(left) } +fn parse_block(tokens: &mut ParserContext) -> Result { + match tokens.next() { + Some(Token::OpenBracket) => (), + _ => return Err(AstError::new("Expected { when parsing block").into()), + } + + let mut value = Vec::new(); + let mut implicit_return = false; + + loop { + match tokens.peek() { + Some(Token::ClosedBracket) => { + tokens.next(); + break; + } + _ => (), + } + + let current_cursor = tokens.cursor; + let result = parse_statement(tokens); + + match result { + Ok(ast) => value.push(ast), + Err(_) => { + tokens.cursor = current_cursor; + value.push(parse_expression(tokens)?); + implicit_return = true; + match tokens.peek() { + Some(Token::ClosedBracket) => (), + _ => { + return Err(AstError::new( + "Expected closed bracket after expression in function body", + ) + .into()); + } + } + } + } + } + + Ok(Block { + value, + implicit_return, + }) +} + fn parse_type(tokens: &mut ParserContext) -> Result { match tokens.next() { Some(Token::Identifier(typ)) => match typ.as_str() { "int" => Ok(Type::Int), "float" => Ok(Type::Float), "bigint" => Ok(Type::Bigint), + "bool" => Ok(Type::Bool), + "string" => Ok(Type::String), _ => return Err(AstError::new("Expected type").into()), }, _ => return Err(AstError::new("Expected type").into()), @@ -233,7 +290,7 @@ fn parse_statement(tokens: &mut ParserContext) -> Result { } }; - match tokens.next() { + match tokens.peek() { Some(Token::OpenBracket) => (), _ => { return Err(AstError::new( @@ -243,25 +300,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result { } }; - let mut value = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedBracket) => { - tokens.next(); - break; - } - _ => (), - } - - value.push(parse_statement(tokens)?); - } + let block = parse_block(tokens)?; return Ok(Ast::Function { name, arguments, return_type, - value, + block }); } Token::Identifier(name) => match tokens.peek() { diff --git a/compiler/src/ast/types.rs b/compiler/src/ast/types.rs index 9017263626910df62029a21156356946f50e2430..5316d03afc134b346d0906a1770f4db116a271cf 100644 --- a/compiler/src/ast/types.rs +++ b/compiler/src/ast/types.rs @@ -1,3 +1,5 @@ +// TODO(lino-levan): Split up AST into expressions, statements, etc. + use crate::tokenizer::Token; use crate::util::Operator; @@ -40,6 +42,14 @@ pub enum Type { Int, Float, Bigint, + Bool, + String, +} + +#[derive(Debug)] +pub struct Block { + pub value: Vec, + pub implicit_return: bool, } #[derive(Debug)] @@ -75,13 +85,16 @@ pub enum Ast { name: String, arguments: Vec, return_type: Type, - value: Vec, + block: Block }, FunctionCall { name: String, arguments: Vec, }, + Block(Block), Number(String), + Bool(bool), + String(String), Identifier(String), Comment(String), DocComment(String), diff --git a/compiler/src/tokenizer.rs b/compiler/src/tokenizer.rs index cca3003f9559005512d084e033206d71367c83c6..804d8212147f9fd3782ca0310a339c9f4d0bcb2b 100644 --- a/compiler/src/tokenizer.rs +++ b/compiler/src/tokenizer.rs @@ -15,12 +15,17 @@ pub enum Token { // Literals Identifier(String), Number(String), + String(String), // Comments Comment(String), DocComment(String), // Keywords + True, + False, Let, Var, + If, + Else, Return, Pub, Function, @@ -65,12 +70,31 @@ pub fn tokenize(content: String) -> Result> { match current_token.as_str() { "var" => tokens.push(Token::Var), "let" => tokens.push(Token::Let), + "if" => tokens.push(Token::If), + "else" => tokens.push(Token::Else), "pub" => tokens.push(Token::Pub), "fn" => tokens.push(Token::Function), "return" => tokens.push(Token::Return), + "true" => tokens.push(Token::True), + "false" => tokens.push(Token::False), _ => tokens.push(Token::Identifier(current_token)), } } + '"' => { + let mut current_token = String::new(); + loop { + let c = chars.next(); + if c.is_none() { + break; + } + let (_, c) = c.unwrap(); + match c { + '"' => break, + _ => current_token.push(c), + } + } + tokens.push(Token::String(current_token)); + } '0'..='9' => { let mut current_token = String::new(); current_token.push(c); diff --git a/compiler/src/walker.rs b/compiler/src/walker.rs index 7f43bce3ba9aeb7236b07d80d60bd9c5c38da2fe..2167cf457aaac4c98fb56065325fb9a701c494db 100644 --- a/compiler/src/walker.rs +++ b/compiler/src/walker.rs @@ -6,6 +6,8 @@ fn transpile_helper(tree: &Ast) -> Result { Ok(match tree { Ast::Number(number) => format!("{}", number), Ast::Identifier(name) => format!("{}", name), + Ast::Bool(value) => format!("{}", value), + Ast::String(value) => format!("\"{}\"", value), Ast::Comment(comment) => format!("// {}\n", comment), Ast::DocComment(comment) => format!("/** {} */\n", comment), Ast::Operation { @@ -40,7 +42,7 @@ fn transpile_helper(tree: &Ast) -> Result { name, arguments, return_type: _, - value, + block } => { let mut result = format!("function {}(", name); @@ -54,7 +56,11 @@ fn transpile_helper(tree: &Ast) -> Result { result += ") {\n"; - for statement in value { + for (i, statement) in block.value.iter().enumerate() { + if block.implicit_return && i == block.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } result += transpile_helper(statement)?.as_str(); } @@ -78,6 +84,20 @@ fn transpile_helper(tree: &Ast) -> Result { result += ")"; + result + } + Ast::Block(block) => { + let mut result = String::from("(()=>{"); + for (i, statement) in block.value.iter().enumerate() { + if block.implicit_return && i == block.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } + result += transpile_helper(statement)?.as_str(); + } + + result += "})()\n"; + result } }) diff --git a/examples/basics/control.blight b/examples/basics/control.blight index 8b137891791fe96927ad78e64b0aad7bded08bdc..34a7e402a84c33e5fbadc95d34ad11b7bb2376a1 100644 --- a/examples/basics/control.blight +++ b/examples/basics/control.blight @@ -1 +1,5 @@ +let x: bool = true; +if x { + print("x is true!"); +} diff --git a/examples/basics/expressions.blight b/examples/basics/expressions.blight new file mode 100644 index 0000000000000000000000000000000000000000..553407cb046bdb2f0bcbe3bfc9a7db0b83366594 --- /dev/null +++ b/examples/basics/expressions.blight @@ -0,0 +1,10 @@ +// everything is an expression in blight +// everything. +// hehe + +let x: int = 5 + { + let y: int = 5; + y +}; + +print(x); // 10 diff --git a/examples/basics/functions.blight b/examples/basics/functions.blight index f209f19cc05683a8698d1b0ada617c9135918c42..dc14aaef31aa61086b22d34a0946cf4c253e4e23 100644 --- a/examples/basics/functions.blight +++ b/examples/basics/functions.blight @@ -1,5 +1,5 @@ fn bingus(x: int, y: int) -> int { - return x * y; + x * y } let result: int = bingus(10, 25);