diff --git a/compiler/src/ast/mod.rs b/compiler/src/ast/mod.rs index ec3cecc66fb024813ef8b54b6b5eb14140f744d6..7207f0bf0ffd68f9f55f01a3ef7ff00125893ae8 100644 --- a/compiler/src/ast/mod.rs +++ b/compiler/src/ast/mod.rs @@ -1,374 +1,19 @@ use miette::Result; mod error; +mod parse_block; +mod parse_expression; +mod parse_statement; +mod parse_type; mod types; -use super::tokenizer::Token; +pub use super::tokenizer::Token; -use error::AstError; -use types::{Argument, ParserContext}; +use parse_statement::parse_statement; +use types::ParserContext; 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(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - - Ast::FunctionCall { - name: name.clone(), - arguments, - } - } - _ => Ast::Identifier(name.clone()), - }, - _ => return Err(AstError::new("Expected expression, but did not get it").into()), - }, - None => return Err(AstError::new("Expected expression, but got nothing instead").into()), - }; - - match tokens.peek() { - Some(token) => match token { - Token::Operator(operator) => { - tokens.next(); - return Ok(Ast::Operation { - operator: operator.clone(), - left: Box::new(left), - right: Box::new(parse_expression(tokens)?), - }); - } - _ => (), - }, - _ => (), - } - - 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()), - } -} - -/// Precondition: There is at least one token in the iterator -fn parse_statement(tokens: &mut ParserContext) -> Result { - let token = tokens.next().unwrap(); - match token { - Token::Pub => { - match tokens.peek() { - Some(Token::Let) | Some(Token::Var) | Some(Token::Function) => (), - _ => return Err(AstError::new("Expected let, var, or fn after pub").into()), - } - - let inner = parse_statement(tokens)?; - - return Ok(Ast::Public { - value: Box::new(inner), - }); - } - Token::Let => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => return Err(AstError::new("Expected identifier after var").into()), - }; - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - let value = match tokens.next() { - Some(Token::Equals) => parse_expression(tokens)?, - _ => return Err(AstError::new("Expected equals after identifier").into()), - }; - match tokens.next() { - Some(Token::Semicolon) => (), - _ => { - return Err( - AstError::new("Expected semicolon after variable declaration").into(), - ) - } - }; - Ok(Ast::ConstantDeclaration { - name: name.clone(), - return_type, - value: Box::new(value), - }) - } - Token::Var => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => return Err(AstError::new("Expected identifier after var").into()), - }; - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - let value = match tokens.next() { - Some(Token::Equals) => parse_expression(tokens)?, - _ => return Err(AstError::new("Expected equals after identifier").into()), - }; - match tokens.next() { - Some(Token::Semicolon) => (), - _ => { - return Err( - AstError::new("Expected semicolon after variable declaration").into(), - ) - } - }; - Ok(Ast::VariableDeclaration { - name: name.clone(), - return_type, - value: Box::new(value), - }) - } - Token::Return => { - let expression = parse_expression(tokens)?; - - match tokens.next() { - Some(Token::Semicolon) => (), - _ => return Err(AstError::new("Expected semicolon after return statement").into()), - }; - - Ok(Ast::Return { - return_value: Box::new(expression), - }) - } - Token::Function => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name.clone(), - _ => return Err(AstError::new("Expected identifier after fn").into()), - }; - - match tokens.next() { - Some(Token::OpenParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected open paranthesis after identifier in function", - ) - .into()) - } - }; - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - - let argument_name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => { - return Err(AstError::new( - "Expected identifier for argument name in function", - ) - .into()) - } - }; - - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - _ => (), - } - - arguments.push(Argument { - name: argument_name.clone(), - return_type, - }) - } - - let return_type = match tokens.next() { - Some(Token::RightArrow) => parse_type(tokens)?, - _ => { - return Err(AstError::new( - "Expected right arrow after argument list in function", - ) - .into()) - } - }; - - match tokens.peek() { - Some(Token::OpenBracket) => (), - _ => { - return Err(AstError::new( - "Expected open bracket after type in function declaration", - ) - .into()) - } - }; - - let block = parse_block(tokens)?; - - return Ok(Ast::Function { - name, - arguments, - return_type, - block, - }); - } - Token::Identifier(name) => match tokens.peek() { - Some(Token::OpenParanthesis) => { - tokens.next(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - - match tokens.next() { - Some(Token::Semicolon) => (), - _ => return Err(AstError::new("Expected semicolon after function call").into()), - }; - - Ok(Ast::FunctionCall { - name: name.clone(), - arguments, - }) - } - _ => Err(AstError::new("Unexpected identifier").into()), - }, - Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), - Token::DocComment(comment) => { - let mut concatted_comments = comment.clone(); - loop { - match tokens.peek() { - Some(Token::DocComment(comment)) => { - concatted_comments.push_str(format!("\n{}", comment).as_str()); - tokens.next(); - } - _ => break, - } - } - Ok(Ast::DocComment(concatted_comments)) - } - _ => return Err(AstError::new("Unexpected token").into()), - } -} - pub fn parse(tokens: Vec) -> Result> { let mut ctx = ParserContext::new(tokens); let mut ast: Vec = Vec::new(); diff --git a/compiler/src/ast/parse_block.rs b/compiler/src/ast/parse_block.rs new file mode 100644 index 0000000000000000000000000000000000000000..eb74a773d89edefac89123e4815b58d34490bbdf --- /dev/null +++ b/compiler/src/ast/parse_block.rs @@ -0,0 +1,54 @@ +use miette::Result; + +use super::error::AstError; +use super::parse_expression::parse_expression; +use super::parse_statement::parse_statement; +use super::types::Block; +use super::types::ParserContext; +use super::Token; + +pub 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, + }) +} diff --git a/compiler/src/ast/parse_expression.rs b/compiler/src/ast/parse_expression.rs new file mode 100644 index 0000000000000000000000000000000000000000..2ce6a45866c7e308019b409fdf4f034d2f3dd424 --- /dev/null +++ b/compiler/src/ast/parse_expression.rs @@ -0,0 +1,116 @@ +use miette::Result; + +use super::error::AstError; +use super::parse_block::parse_block; +use super::types::{Ast, ParserContext}; +use super::Token; + +pub 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.back(); + Ast::Block(parse_block(tokens)?) + } + Token::If => { + let condition = parse_expression(tokens)?; + + let value = parse_block(tokens)?; + + let mut else_value = None; + + match tokens.peek() { + Some(Token::Else) => { + tokens.next(); + match tokens.peek() { + Option::Some(Token::If) => { + else_value = Some(Box::new(parse_expression(tokens)?)); + } + Option::Some(Token::OpenBracket) => { + else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); + } + _ => { + return Err(AstError::new( + "Expected if or open bracket after else in if statement", + ) + .into()) + } + } + } + _ => (), + } + + return Ok(Ast::If { + condition: Box::new(condition), + value, + else_value, + }); + } + Token::Identifier(name) => match tokens.peek() { + Some(Token::OpenParanthesis) => { + tokens.next(); + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + arguments.push(parse_expression(tokens)?); + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + Some(Token::ClosedParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected ) or , but found something else instead.", + ) + .into()) + } + } + } + + Ast::FunctionCall { + name: name.clone(), + arguments, + } + } + _ => Ast::Identifier(name.clone()), + }, + _ => { + println!("token: {:?}", token); + return Err(AstError::new("Expected expression, but did not get it").into()); + } + }, + None => return Err(AstError::new("Expected expression, but got nothing instead").into()), + }; + + match tokens.peek() { + Some(token) => match token { + Token::Operator(operator) => { + tokens.next(); + return Ok(Ast::Operation { + operator: operator.clone(), + left: Box::new(left), + right: Box::new(parse_expression(tokens)?), + }); + } + _ => (), + }, + _ => (), + } + + Ok(left) +} diff --git a/compiler/src/ast/parse_statement.rs b/compiler/src/ast/parse_statement.rs new file mode 100644 index 0000000000000000000000000000000000000000..6d034218d390d38b5ae957ee3dde9bdcf2976459 --- /dev/null +++ b/compiler/src/ast/parse_statement.rs @@ -0,0 +1,268 @@ +use miette::Result; + +use super::error::AstError; +use super::parse_block::parse_block; +use super::parse_expression::parse_expression; +use super::parse_type::parse_type; +use super::types::{Argument, Ast, ParserContext}; +use super::Token; + +/// Precondition: There is at least one token in the iterator +pub fn parse_statement(tokens: &mut ParserContext) -> Result { + let token = tokens.next().unwrap(); + match token { + Token::Pub => { + match tokens.peek() { + Some(Token::Let) | Some(Token::Var) | Some(Token::Function) => (), + _ => return Err(AstError::new("Expected let, var, or fn after pub").into()), + } + + let inner = parse_statement(tokens)?; + + return Ok(Ast::Public { + value: Box::new(inner), + }); + } + Token::Let => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => return Err(AstError::new("Expected identifier after var").into()), + }; + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + let value = match tokens.next() { + Some(Token::Equals) => parse_expression(tokens)?, + _ => return Err(AstError::new("Expected equals after identifier").into()), + }; + match tokens.next() { + Some(Token::Semicolon) => (), + _ => { + return Err( + AstError::new("Expected semicolon after variable declaration").into(), + ) + } + }; + Ok(Ast::ConstantDeclaration { + name: name.clone(), + return_type, + value: Box::new(value), + }) + } + Token::Var => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => return Err(AstError::new("Expected identifier after var").into()), + }; + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + let value = match tokens.next() { + Some(Token::Equals) => parse_expression(tokens)?, + _ => return Err(AstError::new("Expected equals after identifier").into()), + }; + match tokens.next() { + Some(Token::Semicolon) => (), + _ => { + return Err( + AstError::new("Expected semicolon after variable declaration").into(), + ) + } + }; + Ok(Ast::VariableDeclaration { + name: name.clone(), + return_type, + value: Box::new(value), + }) + } + Token::Return => { + let expression = parse_expression(tokens)?; + + match tokens.next() { + Some(Token::Semicolon) => (), + _ => return Err(AstError::new("Expected semicolon after return statement").into()), + }; + + Ok(Ast::Return { + return_value: Box::new(expression), + }) + } + Token::Function => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name.clone(), + _ => return Err(AstError::new("Expected identifier after fn").into()), + }; + + match tokens.next() { + Some(Token::OpenParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected open paranthesis after identifier in function", + ) + .into()) + } + }; + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + + let argument_name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => { + return Err(AstError::new( + "Expected identifier for argument name in function", + ) + .into()) + } + }; + + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + _ => (), + } + + arguments.push(Argument { + name: argument_name.clone(), + return_type, + }) + } + + let return_type = match tokens.next() { + Some(Token::RightArrow) => parse_type(tokens)?, + _ => { + return Err(AstError::new( + "Expected right arrow after argument list in function", + ) + .into()) + } + }; + + match tokens.peek() { + Some(Token::OpenBracket) => (), + _ => { + return Err(AstError::new( + "Expected open bracket after type in function declaration", + ) + .into()) + } + }; + + let block = parse_block(tokens)?; + + return Ok(Ast::Function { + name, + arguments, + return_type, + block, + }); + } + Token::If => { + let condition = parse_expression(tokens)?; + + let value = parse_block(tokens)?; + + let mut else_value = None; + + match tokens.peek() { + Some(Token::Else) => { + tokens.next(); + match tokens.peek() { + Option::Some(Token::If) => { + else_value = Some(Box::new(parse_expression(tokens)?)); + } + Option::Some(Token::OpenBracket) => { + else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); + } + _ => { + return Err(AstError::new( + "Expected if or open bracket after else in if statement", + ) + .into()) + } + } + } + _ => (), + } + + return Ok(Ast::If { + condition: Box::new(condition), + value, + else_value, + }); + } + Token::Identifier(name) => match tokens.peek() { + Some(Token::OpenParanthesis) => { + tokens.next(); + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + arguments.push(parse_expression(tokens)?); + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + Some(Token::ClosedParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected ) or , but found something else instead.", + ) + .into()) + } + } + } + + match tokens.next() { + Some(Token::Semicolon) => (), + _ => return Err(AstError::new("Expected semicolon after function call").into()), + }; + + Ok(Ast::FunctionCall { + name: name.clone(), + arguments, + }) + } + _ => Err(AstError::new("Unexpected identifier").into()), + }, + Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), + Token::DocComment(comment) => { + let mut concatted_comments = comment.clone(); + loop { + match tokens.peek() { + Some(Token::DocComment(comment)) => { + concatted_comments.push_str(format!("\n{}", comment).as_str()); + tokens.next(); + } + _ => break, + } + } + Ok(Ast::DocComment(concatted_comments)) + } + _ => return Err(AstError::new("Unexpected token").into()), + } +} diff --git a/compiler/src/ast/parse_type.rs b/compiler/src/ast/parse_type.rs new file mode 100644 index 0000000000000000000000000000000000000000..1d895c4cc5d7e1318610434de4c998dfb2cb6864 --- /dev/null +++ b/compiler/src/ast/parse_type.rs @@ -0,0 +1,19 @@ +use miette::Result; + +use super::error::AstError; +use super::types::{ParserContext, Type}; +use super::Token; + +pub 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()), + } +} diff --git a/compiler/src/ast/types.rs b/compiler/src/ast/types.rs index b888312fd3e3e2322fbdb788639e8e7d4c3cc8eb..9ae6193937927925b377858e1cba6b3c01067502 100644 --- a/compiler/src/ast/types.rs +++ b/compiler/src/ast/types.rs @@ -18,6 +18,10 @@ impl ParserContext { self.cursor == self.tokens.len() } + pub fn back(&mut self) { + self.cursor -= 1; + } + pub fn next(&mut self) -> Option { if self.cursor == self.tokens.len() { return None; @@ -91,6 +95,11 @@ pub enum Ast { name: String, arguments: Vec, }, + If { + condition: Box, + value: Block, + else_value: Option>, + }, Block(Block), Number(String), Bool(bool), diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index a3ca6bab3b85dd3d7428cf40a3877a1e9c5a3b07..d09edd2a279a2ed694d425f1b0f2f7acf6d3a8d9 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -7,12 +7,14 @@ pub mod walker; pub mod util; pub fn transpile(content: String) -> Result { - // // 1. Tokenize the input + // 1. Tokenize the input let tokens = tokenizer::tokenize(content)?; - // // 2. Parse the tokens into an AST + // 2. Parse the tokens into an AST let tree = ast::parse(tokens)?; - // // 3. Transpile the AST into javascript + // 3. Type check the AST + // type_check(tree.clone())?; + // 4. Transpile the AST into javascript let result = walker::transpile(tree)?; - // 4. Return the javascript + // 5. Return the javascript return Ok(result); } diff --git a/compiler/src/tokenizer.rs b/compiler/src/tokenizer.rs index 804d8212147f9fd3782ca0310a339c9f4d0bcb2b..9229028ec160ab61dca9b81734437d77308cb035 100644 --- a/compiler/src/tokenizer.rs +++ b/compiler/src/tokenizer.rs @@ -115,7 +115,13 @@ pub fn tokenize(content: String) -> Result> { tokens.push(Token::Number(current_token)); } ':' => tokens.push(Token::Colon), - '=' => tokens.push(Token::Equals), + '=' => match chars.peek() { + Some((_, '=')) => { + chars.next(); + tokens.push(Token::Operator(Operator::Equals)); + } + _ => tokens.push(Token::Equals), + }, ';' => tokens.push(Token::Semicolon), '+' => tokens.push(Token::Operator(Operator::Add)), '-' => match chars.peek() { diff --git a/compiler/src/util.rs b/compiler/src/util.rs index ff730d7a9ab1ac0d9bf45d80f7d64da0d177f1b6..130f73004cfe6e03e5dbd5c169378677d091dc54 100644 --- a/compiler/src/util.rs +++ b/compiler/src/util.rs @@ -5,6 +5,7 @@ pub enum Operator { Multiply, Divide, Power, + Equals, } impl Operator { @@ -15,6 +16,7 @@ impl Operator { Self::Divide => "/", Self::Multiply => "*", Self::Power => "**", + Self::Equals => "===", }) } } diff --git a/compiler/src/walker.rs b/compiler/src/walker.rs index 2b3328afe7d3b97c086aa4b710cbb16b2dda19d2..fb310f0a88210c1429169a2f1149e4f70c386ec0 100644 --- a/compiler/src/walker.rs +++ b/compiler/src/walker.rs @@ -68,6 +68,31 @@ fn transpile_helper(tree: &Ast) -> Result { result } + Ast::If { + condition, + value, + else_value, + } => { + let mut result = format!("if ({}) {{\n", transpile_helper(condition)?,); + + for (i, statement) in value.value.iter().enumerate() { + if value.implicit_return && i == value.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } + result += transpile_helper(statement)?.as_str(); + } + + result += "}"; + + if let Some(val) = else_value { + result += format!(" else {{\n{}}}", transpile_helper(val)?).as_str(); + } else { + result += "\n"; + } + + result + } Ast::FunctionCall { name, arguments } => { let mut result = match name.as_str() { "print" => String::from("console.log("), @@ -87,7 +112,7 @@ fn transpile_helper(tree: &Ast) -> Result { result } Ast::Block(block) => { - let mut result = String::from("(()=>{"); + let mut result = String::from("(()=>{\n"); 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(); diff --git a/examples/basics/control.blight b/examples/basics/control.blight index 34a7e402a84c33e5fbadc95d34ad11b7bb2376a1..a6d7f06cd84c9b6e611d6cf9e42e988093f765e3 100644 --- a/examples/basics/control.blight +++ b/examples/basics/control.blight @@ -3,3 +3,13 @@ let x: bool = true; if x { print("x is true!"); } + +let y: int = 3; + +if y == 1 { + print("y is 1!"); +} else if y == 2 { + print("y is 2!"); +} else { + print("y is not 1 or 2!"); +} diff --git a/examples/basics/fib.blight b/examples/basics/fib.blight new file mode 100644 index 0000000000000000000000000000000000000000..2ab4f7adcf7235373787e76b82fd178d15f3e2d6 --- /dev/null +++ b/examples/basics/fib.blight @@ -0,0 +1,11 @@ +pub fn fib(n: int) -> int { + if n == 0 { + return 0; + } + if n == 1 { + return 1; + } + fib(n - 1) + fib(n - 2) +} + +print(fib(10));