| author | |
| committer | |
| log | e909581f4c8edf90471d89f9cce5abd05a457a46 |
| tree | 91283acb578d6f39c8d44aa9ef40f98171667dc1 |
| parent | 266f616b552eb86530ed664e44aea026cb5820db |
7 files changed, 136 insertions(+), 20 deletions(-)
compiler/src/ast/mod.rs+61-16| ... | @@ -8,12 +8,21 @@ use super::tokenizer::Token; | ... | @@ -8,12 +8,21 @@ use super::tokenizer::Token; |
| 8 | use error::AstError; | 8 | use error::AstError; |
| 9 | use types::{Argument, ParserContext}; | 9 | use types::{Argument, ParserContext}; |
| 10 | 10 | ||
| 11 | pub use types::{Ast, Type}; | 11 | pub use types::{Ast, Block, Type}; |
| 12 | 12 | ||
| 13 | fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { | 13 | fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { |
| 14 | let left = match tokens.next() { | 14 | let left = match tokens.next() { |
| 15 | Some(token) => match token { | 15 | Some(token) => match token { |
| 16 | Token::Number(number) => Ast::Number(number.clone()), | 16 | Token::Number(number) => Ast::Number(number.clone()), |
| 17 | Token::String(string) => Ast::String(string.clone()), | ||
| 18 | Token::True => Ast::Bool(true), | ||
| 19 | Token::False => Ast::Bool(false), | ||
| 20 | Token::OpenBracket => { | ||
| 21 | // FRICK we consumed the open bracket | ||
| 22 | // we need to put the cursor back | ||
| 23 | tokens.cursor -= 1; | ||
| 24 | Ast::Block(parse_block(tokens)?) | ||
| 25 | } | ||
| 17 | Token::Identifier(name) => match tokens.peek() { | 26 | Token::Identifier(name) => match tokens.peek() { |
| 18 | Some(Token::OpenParanthesis) => { | 27 | Some(Token::OpenParanthesis) => { |
| 19 | tokens.next(); | 28 | tokens.next(); |
| ... | @@ -74,12 +83,60 @@ fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -74,12 +83,60 @@ fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { |
| 74 | Ok(left) | 83 | Ok(left) |
| 75 | } | 84 | } |
| 76 | 85 | ||
| 86 | fn parse_block(tokens: &mut ParserContext) -> Result<Block> { | ||
| 87 | match tokens.next() { | ||
| 88 | Some(Token::OpenBracket) => (), | ||
| 89 | _ => return Err(AstError::new("Expected { when parsing block").into()), | ||
| 90 | } | ||
| 91 | |||
| 92 | let mut value = Vec::new(); | ||
| 93 | let mut implicit_return = false; | ||
| 94 | |||
| 95 | loop { | ||
| 96 | match tokens.peek() { | ||
| 97 | Some(Token::ClosedBracket) => { | ||
| 98 | tokens.next(); | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | _ => (), | ||
| 102 | } | ||
| 103 | |||
| 104 | let current_cursor = tokens.cursor; | ||
| 105 | let result = parse_statement(tokens); | ||
| 106 | |||
| 107 | match result { | ||
| 108 | Ok(ast) => value.push(ast), | ||
| 109 | Err(_) => { | ||
| 110 | tokens.cursor = current_cursor; | ||
| 111 | value.push(parse_expression(tokens)?); | ||
| 112 | implicit_return = true; | ||
| 113 | match tokens.peek() { | ||
| 114 | Some(Token::ClosedBracket) => (), | ||
| 115 | _ => { | ||
| 116 | return Err(AstError::new( | ||
| 117 | "Expected closed bracket after expression in function body", | ||
| 118 | ) | ||
| 119 | .into()); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | Ok(Block { | ||
| 127 | value, | ||
| 128 | implicit_return, | ||
| 129 | }) | ||
| 130 | } | ||
| 131 | |||
| 77 | fn parse_type(tokens: &mut ParserContext) -> Result<Type> { | 132 | fn parse_type(tokens: &mut ParserContext) -> Result<Type> { |
| 78 | match tokens.next() { | 133 | match tokens.next() { |
| 79 | Some(Token::Identifier(typ)) => match typ.as_str() { | 134 | Some(Token::Identifier(typ)) => match typ.as_str() { |
| 80 | "int" => Ok(Type::Int), | 135 | "int" => Ok(Type::Int), |
| 81 | "float" => Ok(Type::Float), | 136 | "float" => Ok(Type::Float), |
| 82 | "bigint" => Ok(Type::Bigint), | 137 | "bigint" => Ok(Type::Bigint), |
| 138 | "bool" => Ok(Type::Bool), | ||
| 139 | "string" => Ok(Type::String), | ||
| 83 | _ => return Err(AstError::new("Expected type").into()), | 140 | _ => return Err(AstError::new("Expected type").into()), |
| 84 | }, | 141 | }, |
| 85 | _ => return Err(AstError::new("Expected type").into()), | 142 | _ => return Err(AstError::new("Expected type").into()), |
| ... | @@ -233,7 +290,7 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -233,7 +290,7 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 233 | } | 290 | } |
| 234 | }; | 291 | }; |
| 235 | 292 | ||
| 236 | match tokens.next() { | 293 | match tokens.peek() { |
| 237 | Some(Token::OpenBracket) => (), | 294 | Some(Token::OpenBracket) => (), |
| 238 | _ => { | 295 | _ => { |
| 239 | return Err(AstError::new( | 296 | return Err(AstError::new( |
| ... | @@ -243,25 +300,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -243,25 +300,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 243 | } | 300 | } |
| 244 | }; | 301 | }; |
| 245 | 302 | ||
| 246 | let mut value = Vec::new(); | 303 | let block = parse_block(tokens)?; |
| 247 | |||
| 248 | loop { | ||
| 249 | match tokens.peek() { | ||
| 250 | Some(Token::ClosedBracket) => { | ||
| 251 | tokens.next(); | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | _ => (), | ||
| 255 | } | ||
| 256 | |||
| 257 | value.push(parse_statement(tokens)?); | ||
| 258 | } | ||
| 259 | 304 | ||
| 260 | return Ok(Ast::Function { | 305 | return Ok(Ast::Function { |
| 261 | name, | 306 | name, |
| 262 | arguments, | 307 | arguments, |
| 263 | return_type, | 308 | return_type, |
| 264 | value, | 309 | block |
| 265 | }); | 310 | }); |
| 266 | } | 311 | } |
| 267 | Token::Identifier(name) => match tokens.peek() { | 312 | Token::Identifier(name) => match tokens.peek() { |
compiler/src/ast/types.rs+14-1| ... | @@ -1,3 +1,5 @@ | ... | @@ -1,3 +1,5 @@ |
| 1 | // TODO(lino-levan): Split up AST into expressions, statements, etc. | ||
| 2 | |||
| 1 | use crate::tokenizer::Token; | 3 | use crate::tokenizer::Token; |
| 2 | use crate::util::Operator; | 4 | use crate::util::Operator; |
| 3 | 5 | ||
| ... | @@ -40,6 +42,14 @@ pub enum Type { | ... | @@ -40,6 +42,14 @@ pub enum Type { |
| 40 | Int, | 42 | Int, |
| 41 | Float, | 43 | Float, |
| 42 | Bigint, | 44 | Bigint, |
| 45 | Bool, | ||
| 46 | String, | ||
| 47 | } | ||
| 48 | |||
| 49 | #[derive(Debug)] | ||
| 50 | pub struct Block { | ||
| 51 | pub value: Vec<Ast>, | ||
| 52 | pub implicit_return: bool, | ||
| 43 | } | 53 | } |
| 44 | 54 | ||
| 45 | #[derive(Debug)] | 55 | #[derive(Debug)] |
| ... | @@ -75,13 +85,16 @@ pub enum Ast { | ... | @@ -75,13 +85,16 @@ pub enum Ast { |
| 75 | name: String, | 85 | name: String, |
| 76 | arguments: Vec<Argument>, | 86 | arguments: Vec<Argument>, |
| 77 | return_type: Type, | 87 | return_type: Type, |
| 78 | value: Vec<Ast>, | 88 | block: Block |
| 79 | }, | 89 | }, |
| 80 | FunctionCall { | 90 | FunctionCall { |
| 81 | name: String, | 91 | name: String, |
| 82 | arguments: Vec<Ast>, | 92 | arguments: Vec<Ast>, |
| 83 | }, | 93 | }, |
| 94 | Block(Block), | ||
| 84 | Number(String), | 95 | Number(String), |
| 96 | Bool(bool), | ||
| 97 | String(String), | ||
| 85 | Identifier(String), | 98 | Identifier(String), |
| 86 | Comment(String), | 99 | Comment(String), |
| 87 | DocComment(String), | 100 | DocComment(String), |
compiler/src/tokenizer.rs+24| ... | @@ -15,12 +15,17 @@ pub enum Token { | ... | @@ -15,12 +15,17 @@ pub enum Token { |
| 15 | // Literals | 15 | // Literals |
| 16 | Identifier(String), | 16 | Identifier(String), |
| 17 | Number(String), | 17 | Number(String), |
| 18 | String(String), | ||
| 18 | // Comments | 19 | // Comments |
| 19 | Comment(String), | 20 | Comment(String), |
| 20 | DocComment(String), | 21 | DocComment(String), |
| 21 | // Keywords | 22 | // Keywords |
| 23 | True, | ||
| 24 | False, | ||
| 22 | Let, | 25 | Let, |
| 23 | Var, | 26 | Var, |
| 27 | If, | ||
| 28 | Else, | ||
| 24 | Return, | 29 | Return, |
| 25 | Pub, | 30 | Pub, |
| 26 | Function, | 31 | Function, |
| ... | @@ -65,12 +70,31 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { | ... | @@ -65,12 +70,31 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { |
| 65 | match current_token.as_str() { | 70 | match current_token.as_str() { |
| 66 | "var" => tokens.push(Token::Var), | 71 | "var" => tokens.push(Token::Var), |
| 67 | "let" => tokens.push(Token::Let), | 72 | "let" => tokens.push(Token::Let), |
| 73 | "if" => tokens.push(Token::If), | ||
| 74 | "else" => tokens.push(Token::Else), | ||
| 68 | "pub" => tokens.push(Token::Pub), | 75 | "pub" => tokens.push(Token::Pub), |
| 69 | "fn" => tokens.push(Token::Function), | 76 | "fn" => tokens.push(Token::Function), |
| 70 | "return" => tokens.push(Token::Return), | 77 | "return" => tokens.push(Token::Return), |
| 78 | "true" => tokens.push(Token::True), | ||
| 79 | "false" => tokens.push(Token::False), | ||
| 71 | _ => tokens.push(Token::Identifier(current_token)), | 80 | _ => tokens.push(Token::Identifier(current_token)), |
| 72 | } | 81 | } |
| 73 | } | 82 | } |
| 83 | '"' => { | ||
| 84 | let mut current_token = String::new(); | ||
| 85 | loop { | ||
| 86 | let c = chars.next(); | ||
| 87 | if c.is_none() { | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | let (_, c) = c.unwrap(); | ||
| 91 | match c { | ||
| 92 | '"' => break, | ||
| 93 | _ => current_token.push(c), | ||
| 94 | } | ||
| 95 | } | ||
| 96 | tokens.push(Token::String(current_token)); | ||
| 97 | } | ||
| 74 | '0'..='9' => { | 98 | '0'..='9' => { |
| 75 | let mut current_token = String::new(); | 99 | let mut current_token = String::new(); |
| 76 | current_token.push(c); | 100 | current_token.push(c); |
compiler/src/walker.rs+22-2| ... | @@ -6,6 +6,8 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -6,6 +6,8 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 6 | Ok(match tree { | 6 | Ok(match tree { |
| 7 | Ast::Number(number) => format!("{}", number), | 7 | Ast::Number(number) => format!("{}", number), |
| 8 | Ast::Identifier(name) => format!("{}", name), | 8 | Ast::Identifier(name) => format!("{}", name), |
| 9 | Ast::Bool(value) => format!("{}", value), | ||
| 10 | Ast::String(value) => format!("\"{}\"", value), | ||
| 9 | Ast::Comment(comment) => format!("// {}\n", comment), | 11 | Ast::Comment(comment) => format!("// {}\n", comment), |
| 10 | Ast::DocComment(comment) => format!("/** {} */\n", comment), | 12 | Ast::DocComment(comment) => format!("/** {} */\n", comment), |
| 11 | Ast::Operation { | 13 | Ast::Operation { |
| ... | @@ -40,7 +42,7 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -40,7 +42,7 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 40 | name, | 42 | name, |
| 41 | arguments, | 43 | arguments, |
| 42 | return_type: _, | 44 | return_type: _, |
| 43 | value, | 45 | block |
| 44 | } => { | 46 | } => { |
| 45 | let mut result = format!("function {}(", name); | 47 | let mut result = format!("function {}(", name); |
| 46 | 48 | ||
| ... | @@ -54,7 +56,11 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -54,7 +56,11 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 54 | 56 | ||
| 55 | result += ") {\n"; | 57 | result += ") {\n"; |
| 56 | 58 | ||
| 57 | for statement in value { | 59 | for (i, statement) in block.value.iter().enumerate() { |
| 60 | if block.implicit_return && i == block.value.len() - 1 { | ||
| 61 | result += format!("return {};\n", transpile_helper(statement)?).as_str(); | ||
| 62 | break; | ||
| 63 | } | ||
| 58 | result += transpile_helper(statement)?.as_str(); | 64 | result += transpile_helper(statement)?.as_str(); |
| 59 | } | 65 | } |
| 60 | 66 | ||
| ... | @@ -78,6 +84,20 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -78,6 +84,20 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 78 | 84 | ||
| 79 | result += ")"; | 85 | result += ")"; |
| 80 | 86 | ||
| 87 | result | ||
| 88 | } | ||
| 89 | Ast::Block(block) => { | ||
| 90 | let mut result = String::from("(()=>{"); | ||
| 91 | for (i, statement) in block.value.iter().enumerate() { | ||
| 92 | if block.implicit_return && i == block.value.len() - 1 { | ||
| 93 | result += format!("return {};\n", transpile_helper(statement)?).as_str(); | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | result += transpile_helper(statement)?.as_str(); | ||
| 97 | } | ||
| 98 | |||
| 99 | result += "})()\n"; | ||
| 100 | |||
| 81 | result | 101 | result |
| 82 | } | 102 | } |
| 83 | }) | 103 | }) |
examples/basics/control.blight+4| ... | @@ -1 +1,5 @@ | ... | @@ -1 +1,5 @@ |
| 1 | let x: bool = true; | ||
| 1 | 2 | ||
| 3 | if x { | ||
| 4 | print("x is true!"); | ||
| 5 | } |
examples/basics/expressions.blight created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | // everything is an expression in blight | ||
| 2 | // everything. | ||
| 3 | // hehe | ||
| 4 | |||
| 5 | let x: int = 5 + { | ||
| 6 | let y: int = 5; | ||
| 7 | y | ||
| 8 | }; | ||
| 9 | |||
| 10 | print(x); // 10 | ||
examples/basics/functions.blight+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | fn bingus(x: int, y: int) -> int { | 1 | fn bingus(x: int, y: int) -> int { |
| 2 | return x * y; | 2 | x * y |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | let result: int = bingus(10, 25); | 5 | let result: int = bingus(10, 25); |