| author | |
| committer | |
| log | 266f616b552eb86530ed664e44aea026cb5820db |
| tree | ac537bd975a86f79730ca87c12b09cf957b062dc |
| parent | bf7dedc48580545fcbcbb877d6f84087b96b4c62 |
6 files changed, 219 insertions(+), 79 deletions(-)
cli/src/main.rs+52-3| ... | @@ -20,8 +20,16 @@ struct Cli { | ... | @@ -20,8 +20,16 @@ struct Cli { |
| 20 | enum Commands { | 20 | enum Commands { |
| 21 | /// Compiles a file into javascript | 21 | /// Compiles a file into javascript |
| 22 | Compile { | 22 | Compile { |
| 23 | /// lists test values | ||
| 24 | file: PathBuf, | 23 | file: PathBuf, |
| 24 | // Whether to output to stdout instead of a file | ||
| 25 | #[arg(long, default_value_t = false)] | ||
| 26 | stdout: bool, | ||
| 27 | }, | ||
| 28 | Run { | ||
| 29 | file: PathBuf, | ||
| 30 | /// What javascript runtime to use | ||
| 31 | #[arg(short, long, default_value = "deno")] | ||
| 32 | runtime: String, | ||
| 25 | }, | 33 | }, |
| 26 | } | 34 | } |
| 27 | 35 | ||
| ... | @@ -29,10 +37,51 @@ fn main() -> Result<()> { | ... | @@ -29,10 +37,51 @@ fn main() -> Result<()> { |
| 29 | let cli = Cli::parse(); | 37 | let cli = Cli::parse(); |
| 30 | 38 | ||
| 31 | match cli.command { | 39 | match cli.command { |
| 32 | Commands::Compile { file } => { | 40 | Commands::Compile { file, stdout } => { |
| 41 | let contents = std::fs::read_to_string(file.clone()).unwrap(); | ||
| 42 | let result = transpile(contents.clone())?; | ||
| 43 | |||
| 44 | if stdout { | ||
| 45 | println!("{}", result); | ||
| 46 | } else { | ||
| 47 | std::fs::write(file.with_extension("js"), result).unwrap(); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | Commands::Run { file, runtime } => { | ||
| 33 | let contents = std::fs::read_to_string(file.clone()).unwrap(); | 51 | let contents = std::fs::read_to_string(file.clone()).unwrap(); |
| 34 | let result = transpile(contents.clone())?; | 52 | let result = transpile(contents.clone())?; |
| 35 | std::fs::write(file.with_extension("js"), result).unwrap(); | 53 | let mut temp_file = std::env::temp_dir(); |
| 54 | temp_file.push("temp.js"); | ||
| 55 | std::fs::write(temp_file.clone(), result).unwrap(); | ||
| 56 | match runtime.as_str() { | ||
| 57 | "deno" => { | ||
| 58 | let output = std::process::Command::new("deno") | ||
| 59 | .arg("run") | ||
| 60 | .arg("-A") | ||
| 61 | .arg(temp_file) | ||
| 62 | .output() | ||
| 63 | .expect("Failed to execute process"); | ||
| 64 | println!("{}", String::from_utf8_lossy(&output.stdout)); | ||
| 65 | } | ||
| 66 | "node" => { | ||
| 67 | let output = std::process::Command::new("node") | ||
| 68 | .arg(temp_file) | ||
| 69 | .output() | ||
| 70 | .expect("Failed to execute process"); | ||
| 71 | println!("{}", String::from_utf8_lossy(&output.stdout)); | ||
| 72 | } | ||
| 73 | "bun" => { | ||
| 74 | let output = std::process::Command::new("bun") | ||
| 75 | .arg("run") | ||
| 76 | .arg(temp_file) | ||
| 77 | .output() | ||
| 78 | .expect("Failed to execute process"); | ||
| 79 | println!("{}", String::from_utf8_lossy(&output.stdout)); | ||
| 80 | } | ||
| 81 | _ => { | ||
| 82 | println!("Unknown runtime: {}", runtime); | ||
| 83 | } | ||
| 84 | } | ||
| 36 | } | 85 | } |
| 37 | } | 86 | } |
| 38 | 87 |
compiler/src/ast/mod.rs+121-45| ... | @@ -6,42 +6,50 @@ mod types; | ... | @@ -6,42 +6,50 @@ mod types; |
| 6 | use super::tokenizer::Token; | 6 | use super::tokenizer::Token; |
| 7 | 7 | ||
| 8 | use error::AstError; | 8 | use error::AstError; |
| 9 | use types::{ParserContext, Argument}; | 9 | use types::{Argument, ParserContext}; |
| 10 | 10 | ||
| 11 | pub use types::{Ast, Type}; | 11 | pub use types::{Ast, Type}; |
| 12 | 12 | ||
| 13 | fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { | 13 | fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> { |
| 14 | |||
| 15 | let left = match tokens.next() { | 14 | let left = match tokens.next() { |
| 16 | Some(token) => match token { | 15 | Some(token) => match token { |
| 17 | Token::Number(number) => Ast::Number(number.clone()), | 16 | Token::Number(number) => Ast::Number(number.clone()), |
| 18 | Token::Identifier(name) => { | 17 | Token::Identifier(name) => match tokens.peek() { |
| 19 | match tokens.peek() { | 18 | Some(Token::OpenParanthesis) => { |
| 20 | Some(Token::OpenParanthesis) => { | 19 | tokens.next(); |
| 21 | tokens.next(); | ||
| 22 | 20 | ||
| 23 | let mut arguments = Vec::new(); | 21 | let mut arguments = Vec::new(); |
| 22 | |||
| 23 | loop { | ||
| 24 | match tokens.peek() { | ||
| 25 | Some(Token::ClosedParanthesis) => { | ||
| 26 | tokens.next(); | ||
| 27 | break; | ||
| 28 | } | ||
| 29 | _ => (), | ||
| 30 | } | ||
| 31 | arguments.push(parse_expression(tokens)?); | ||
| 24 | 32 | ||
| 25 | loop { | 33 | match tokens.peek() { |
| 26 | match tokens.peek() { | 34 | Some(Token::Comma) => { |
| 27 | Some(Token::ClosedParanthesis) => break, | 35 | tokens.next(); |
| 28 | _ => () | ||
| 29 | } | 36 | } |
| 30 | arguments.push(parse_expression(tokens)?); | 37 | Some(Token::ClosedParanthesis) => (), |
| 31 | 38 | _ => { | |
| 32 | match tokens.peek() { | 39 | return Err(AstError::new( |
| 33 | Some(Token::Comma) => { | 40 | "Expected ) or , but found something else instead.", |
| 34 | tokens.next(); | 41 | ) |
| 35 | } | 42 | .into()) |
| 36 | Some(Token::ClosedParanthesis) => (), | ||
| 37 | _ => return Err(AstError::new("Expected ) or , but found something else instead.").into()), | ||
| 38 | } | 43 | } |
| 39 | } | 44 | } |
| 45 | } | ||
| 40 | 46 | ||
| 41 | Ast::FunctionCall { name: name.clone(), arguments } | 47 | Ast::FunctionCall { |
| 48 | name: name.clone(), | ||
| 49 | arguments, | ||
| 42 | } | 50 | } |
| 43 | _ => Ast::Identifier(name.clone()) | ||
| 44 | } | 51 | } |
| 52 | _ => Ast::Identifier(name.clone()), | ||
| 45 | }, | 53 | }, |
| 46 | _ => return Err(AstError::new("Expected expression, but did not get it").into()), | 54 | _ => return Err(AstError::new("Expected expression, but did not get it").into()), |
| 47 | }, | 55 | }, |
| ... | @@ -90,7 +98,9 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -90,7 +98,9 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 90 | 98 | ||
| 91 | let inner = parse_statement(tokens)?; | 99 | let inner = parse_statement(tokens)?; |
| 92 | 100 | ||
| 93 | return Ok(Ast::Public { value: Box::new(inner) }) | 101 | return Ok(Ast::Public { |
| 102 | value: Box::new(inner), | ||
| 103 | }); | ||
| 94 | } | 104 | } |
| 95 | Token::Let => { | 105 | Token::Let => { |
| 96 | let name = match tokens.next() { | 106 | let name = match tokens.next() { |
| ... | @@ -151,14 +161,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -151,14 +161,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 151 | 161 | ||
| 152 | match tokens.next() { | 162 | match tokens.next() { |
| 153 | Some(Token::Semicolon) => (), | 163 | Some(Token::Semicolon) => (), |
| 154 | _ => { | 164 | _ => return Err(AstError::new("Expected semicolon after return statement").into()), |
| 155 | return Err( | ||
| 156 | AstError::new("Expected semicolon after return statement").into(), | ||
| 157 | ) | ||
| 158 | } | ||
| 159 | }; | 165 | }; |
| 160 | 166 | ||
| 161 | Ok(Ast::Return { return_value: Box::new(expression) }) | 167 | Ok(Ast::Return { |
| 168 | return_value: Box::new(expression), | ||
| 169 | }) | ||
| 162 | } | 170 | } |
| 163 | Token::Function => { | 171 | Token::Function => { |
| 164 | let name = match tokens.next() { | 172 | let name = match tokens.next() { |
| ... | @@ -168,7 +176,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -168,7 +176,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 168 | 176 | ||
| 169 | match tokens.next() { | 177 | match tokens.next() { |
| 170 | Some(Token::OpenParanthesis) => (), | 178 | Some(Token::OpenParanthesis) => (), |
| 171 | _ => return Err(AstError::new("Expected open paranthesis after identifier in function").into()), | 179 | _ => { |
| 180 | return Err(AstError::new( | ||
| 181 | "Expected open paranthesis after identifier in function", | ||
| 182 | ) | ||
| 183 | .into()) | ||
| 184 | } | ||
| 172 | }; | 185 | }; |
| 173 | 186 | ||
| 174 | let mut arguments = Vec::new(); | 187 | let mut arguments = Vec::new(); |
| ... | @@ -178,13 +191,18 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -178,13 +191,18 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 178 | Some(Token::ClosedParanthesis) => { | 191 | Some(Token::ClosedParanthesis) => { |
| 179 | tokens.next(); | 192 | tokens.next(); |
| 180 | break; | 193 | break; |
| 181 | }, | 194 | } |
| 182 | _ => () | 195 | _ => (), |
| 183 | } | 196 | } |
| 184 | 197 | ||
| 185 | let argument_name = match tokens.next() { | 198 | let argument_name = match tokens.next() { |
| 186 | Some(Token::Identifier(name)) => name, | 199 | Some(Token::Identifier(name)) => name, |
| 187 | _ => return Err(AstError::new("Expected identifier for argument name in function").into()), | 200 | _ => { |
| 201 | return Err(AstError::new( | ||
| 202 | "Expected identifier for argument name in function", | ||
| 203 | ) | ||
| 204 | .into()) | ||
| 205 | } | ||
| 188 | }; | 206 | }; |
| 189 | 207 | ||
| 190 | let return_type = match tokens.next() { | 208 | let return_type = match tokens.next() { |
| ... | @@ -195,21 +213,34 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -195,21 +213,34 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 195 | match tokens.peek() { | 213 | match tokens.peek() { |
| 196 | Some(Token::Comma) => { | 214 | Some(Token::Comma) => { |
| 197 | tokens.next(); | 215 | tokens.next(); |
| 198 | }, | 216 | } |
| 199 | _ => () | 217 | _ => (), |
| 200 | } | 218 | } |
| 201 | 219 | ||
| 202 | arguments.push(Argument { name: argument_name.clone(), return_type}) | 220 | arguments.push(Argument { |
| 221 | name: argument_name.clone(), | ||
| 222 | return_type, | ||
| 223 | }) | ||
| 203 | } | 224 | } |
| 204 | 225 | ||
| 205 | let return_type = match tokens.next() { | 226 | let return_type = match tokens.next() { |
| 206 | Some(Token::RightArrow) => parse_type(tokens)?, | 227 | Some(Token::RightArrow) => parse_type(tokens)?, |
| 207 | _ => return Err(AstError::new("Expected right arrow after argument list in function").into()), | 228 | _ => { |
| 229 | return Err(AstError::new( | ||
| 230 | "Expected right arrow after argument list in function", | ||
| 231 | ) | ||
| 232 | .into()) | ||
| 233 | } | ||
| 208 | }; | 234 | }; |
| 209 | 235 | ||
| 210 | match tokens.next() { | 236 | match tokens.next() { |
| 211 | Some(Token::OpenBracket) => (), | 237 | Some(Token::OpenBracket) => (), |
| 212 | _ => return Err(AstError::new("Expected open bracket after type in function declaration").into()), | 238 | _ => { |
| 239 | return Err(AstError::new( | ||
| 240 | "Expected open bracket after type in function declaration", | ||
| 241 | ) | ||
| 242 | .into()) | ||
| 243 | } | ||
| 213 | }; | 244 | }; |
| 214 | 245 | ||
| 215 | let mut value = Vec::new(); | 246 | let mut value = Vec::new(); |
| ... | @@ -219,15 +250,62 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -219,15 +250,62 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 219 | Some(Token::ClosedBracket) => { | 250 | Some(Token::ClosedBracket) => { |
| 220 | tokens.next(); | 251 | tokens.next(); |
| 221 | break; | 252 | break; |
| 222 | }, | 253 | } |
| 223 | _ => () | 254 | _ => (), |
| 224 | } | 255 | } |
| 225 | 256 | ||
| 226 | value.push(parse_statement(tokens)?); | 257 | value.push(parse_statement(tokens)?); |
| 227 | } | 258 | } |
| 228 | 259 | ||
| 229 | return Ok(Ast::Function { name, arguments, return_type, value }) | 260 | return Ok(Ast::Function { |
| 261 | name, | ||
| 262 | arguments, | ||
| 263 | return_type, | ||
| 264 | value, | ||
| 265 | }); | ||
| 230 | } | 266 | } |
| 267 | Token::Identifier(name) => match tokens.peek() { | ||
| 268 | Some(Token::OpenParanthesis) => { | ||
| 269 | tokens.next(); | ||
| 270 | |||
| 271 | let mut arguments = Vec::new(); | ||
| 272 | |||
| 273 | loop { | ||
| 274 | match tokens.peek() { | ||
| 275 | Some(Token::ClosedParanthesis) => { | ||
| 276 | tokens.next(); | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | _ => (), | ||
| 280 | } | ||
| 281 | arguments.push(parse_expression(tokens)?); | ||
| 282 | |||
| 283 | match tokens.peek() { | ||
| 284 | Some(Token::Comma) => { | ||
| 285 | tokens.next(); | ||
| 286 | } | ||
| 287 | Some(Token::ClosedParanthesis) => (), | ||
| 288 | _ => { | ||
| 289 | return Err(AstError::new( | ||
| 290 | "Expected ) or , but found something else instead.", | ||
| 291 | ) | ||
| 292 | .into()) | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | match tokens.next() { | ||
| 298 | Some(Token::Semicolon) => (), | ||
| 299 | _ => return Err(AstError::new("Expected semicolon after function call").into()), | ||
| 300 | }; | ||
| 301 | |||
| 302 | Ok(Ast::FunctionCall { | ||
| 303 | name: name.clone(), | ||
| 304 | arguments, | ||
| 305 | }) | ||
| 306 | } | ||
| 307 | _ => Err(AstError::new("Unexpected identifier").into()), | ||
| 308 | }, | ||
| 231 | Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), | 309 | Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), |
| 232 | Token::DocComment(comment) => { | 310 | Token::DocComment(comment) => { |
| 233 | let mut concatted_comments = comment.clone(); | 311 | let mut concatted_comments = comment.clone(); |
| ... | @@ -236,15 +314,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { | ... | @@ -236,15 +314,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> { |
| 236 | Some(Token::DocComment(comment)) => { | 314 | Some(Token::DocComment(comment)) => { |
| 237 | concatted_comments.push_str(format!("\n{}", comment).as_str()); | 315 | concatted_comments.push_str(format!("\n{}", comment).as_str()); |
| 238 | tokens.next(); | 316 | tokens.next(); |
| 239 | }, | 317 | } |
| 240 | _ => break, | 318 | _ => break, |
| 241 | } | 319 | } |
| 242 | } | 320 | } |
| 243 | Ok(Ast::DocComment(concatted_comments)) | 321 | Ok(Ast::DocComment(concatted_comments)) |
| 244 | }, | 322 | } |
| 245 | _ => { | 323 | _ => return Err(AstError::new("Unexpected token").into()), |
| 246 | return Err(AstError::new("Unexpected token").into()) | ||
| 247 | }, | ||
| 248 | } | 324 | } |
| 249 | } | 325 | } |
| 250 | 326 |
compiler/src/ast/types.rs+7-8| ... | @@ -1,10 +1,10 @@ | ... | @@ -1,10 +1,10 @@ |
| 1 | use crate::util::Operator; | ||
| 2 | use crate::tokenizer::Token; | 1 | use crate::tokenizer::Token; |
| 2 | use crate::util::Operator; | ||
| 3 | 3 | ||
| 4 | #[derive(Debug)] | 4 | #[derive(Debug)] |
| 5 | pub struct ParserContext { | 5 | pub struct ParserContext { |
| 6 | pub tokens: Vec<Token>, | 6 | pub tokens: Vec<Token>, |
| 7 | pub cursor: usize | 7 | pub cursor: usize, |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | impl ParserContext { | 10 | impl ParserContext { |
| ... | @@ -35,7 +35,6 @@ impl ParserContext { | ... | @@ -35,7 +35,6 @@ impl ParserContext { |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | |||
| 39 | #[derive(Debug)] | 38 | #[derive(Debug)] |
| 40 | pub enum Type { | 39 | pub enum Type { |
| 41 | Int, | 40 | Int, |
| ... | @@ -46,13 +45,13 @@ pub enum Type { | ... | @@ -46,13 +45,13 @@ pub enum Type { |
| 46 | #[derive(Debug)] | 45 | #[derive(Debug)] |
| 47 | pub struct Argument { | 46 | pub struct Argument { |
| 48 | pub name: String, | 47 | pub name: String, |
| 49 | pub return_type: Type | 48 | pub return_type: Type, |
| 50 | } | 49 | } |
| 51 | 50 | ||
| 52 | #[derive(Debug)] | 51 | #[derive(Debug)] |
| 53 | pub enum Ast { | 52 | pub enum Ast { |
| 54 | Public { | 53 | Public { |
| 55 | value: Box<Ast> | 54 | value: Box<Ast>, |
| 56 | }, | 55 | }, |
| 57 | ConstantDeclaration { | 56 | ConstantDeclaration { |
| 58 | name: String, | 57 | name: String, |
| ... | @@ -70,13 +69,13 @@ pub enum Ast { | ... | @@ -70,13 +69,13 @@ pub enum Ast { |
| 70 | right: Box<Ast>, | 69 | right: Box<Ast>, |
| 71 | }, | 70 | }, |
| 72 | Return { | 71 | Return { |
| 73 | return_value: Box<Ast> | 72 | return_value: Box<Ast>, |
| 74 | }, | 73 | }, |
| 75 | Function { | 74 | Function { |
| 76 | name: String, | 75 | name: String, |
| 77 | arguments: Vec<Argument>, | 76 | arguments: Vec<Argument>, |
| 78 | return_type: Type, | 77 | return_type: Type, |
| 79 | value: Vec<Ast> | 78 | value: Vec<Ast>, |
| 80 | }, | 79 | }, |
| 81 | FunctionCall { | 80 | FunctionCall { |
| 82 | name: String, | 81 | name: String, |
| ... | @@ -85,5 +84,5 @@ pub enum Ast { | ... | @@ -85,5 +84,5 @@ pub enum Ast { |
| 85 | Number(String), | 84 | Number(String), |
| 86 | Identifier(String), | 85 | Identifier(String), |
| 87 | Comment(String), | 86 | Comment(String), |
| 88 | DocComment(String) | 87 | DocComment(String), |
| 89 | } | 88 | } |
compiler/src/tokenizer.rs+14-18| ... | @@ -94,23 +94,19 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { | ... | @@ -94,23 +94,19 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { |
| 94 | '=' => tokens.push(Token::Equals), | 94 | '=' => tokens.push(Token::Equals), |
| 95 | ';' => tokens.push(Token::Semicolon), | 95 | ';' => tokens.push(Token::Semicolon), |
| 96 | '+' => tokens.push(Token::Operator(Operator::Add)), | 96 | '+' => tokens.push(Token::Operator(Operator::Add)), |
| 97 | '-' => { | 97 | '-' => match chars.peek() { |
| 98 | match chars.peek() { | 98 | Some((_, '>')) => { |
| 99 | Some((_, '>')) => { | 99 | chars.next(); |
| 100 | chars.next(); | 100 | tokens.push(Token::RightArrow); |
| 101 | tokens.push(Token::RightArrow); | ||
| 102 | } | ||
| 103 | _ => tokens.push(Token::Operator(Operator::Substract)) | ||
| 104 | } | 101 | } |
| 102 | _ => tokens.push(Token::Operator(Operator::Substract)), | ||
| 105 | }, | 103 | }, |
| 106 | '*' => { | 104 | '*' => match chars.peek() { |
| 107 | match chars.peek() { | 105 | Some((_, '*')) => { |
| 108 | Some((_, '*')) => { | 106 | chars.next(); |
| 109 | chars.next(); | 107 | tokens.push(Token::Operator(Operator::Power)); |
| 110 | tokens.push(Token::Operator(Operator::Power)); | ||
| 111 | } | ||
| 112 | _ => tokens.push(Token::Operator(Operator::Multiply)) | ||
| 113 | } | 108 | } |
| 109 | _ => tokens.push(Token::Operator(Operator::Multiply)), | ||
| 114 | }, | 110 | }, |
| 115 | '/' => { | 111 | '/' => { |
| 116 | match chars.peek() { | 112 | match chars.peek() { |
| ... | @@ -121,7 +117,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { | ... | @@ -121,7 +117,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { |
| 121 | Some((_, '/')) => { | 117 | Some((_, '/')) => { |
| 122 | chars.next(); // Consume the third slash | 118 | chars.next(); // Consume the third slash |
| 123 | true | 119 | true |
| 124 | }, | 120 | } |
| 125 | _ => false, | 121 | _ => false, |
| 126 | }; | 122 | }; |
| 127 | 123 | ||
| ... | @@ -136,7 +132,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { | ... | @@ -136,7 +132,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { |
| 136 | '\n' => break, | 132 | '\n' => break, |
| 137 | _ => { | 133 | _ => { |
| 138 | comment.push(c.clone()); | 134 | comment.push(c.clone()); |
| 139 | }, | 135 | } |
| 140 | } | 136 | } |
| 141 | } | 137 | } |
| 142 | 138 | ||
| ... | @@ -148,9 +144,9 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { | ... | @@ -148,9 +144,9 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> { |
| 148 | tokens.push(Token::Comment(comment)); | 144 | tokens.push(Token::Comment(comment)); |
| 149 | } | 145 | } |
| 150 | } | 146 | } |
| 151 | _ => tokens.push(Token::Operator(Operator::Divide)) | 147 | _ => tokens.push(Token::Operator(Operator::Divide)), |
| 152 | } | 148 | } |
| 153 | }, | 149 | } |
| 154 | ',' => tokens.push(Token::Comma), | 150 | ',' => tokens.push(Token::Comma), |
| 155 | '(' => tokens.push(Token::OpenParanthesis), | 151 | '(' => tokens.push(Token::OpenParanthesis), |
| 156 | ')' => tokens.push(Token::ClosedParanthesis), | 152 | ')' => tokens.push(Token::ClosedParanthesis), |
compiler/src/walker.rs+23-5| ... | @@ -19,16 +19,29 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -19,16 +19,29 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 19 | transpile_helper(right)? | 19 | transpile_helper(right)? |
| 20 | ), | 20 | ), |
| 21 | Ast::Public { value } => format!("export {}", transpile_helper(value)?), | 21 | Ast::Public { value } => format!("export {}", transpile_helper(value)?), |
| 22 | Ast::VariableDeclaration { name, return_type, value } => match return_type { | 22 | Ast::VariableDeclaration { |
| 23 | name, | ||
| 24 | return_type, | ||
| 25 | value, | ||
| 26 | } => match return_type { | ||
| 23 | Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(value)?), | 27 | Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(value)?), |
| 24 | _ => format!("let {} = {};\n", name, transpile_helper(value)?), | 28 | _ => format!("let {} = {};\n", name, transpile_helper(value)?), |
| 25 | }, | 29 | }, |
| 26 | Ast::ConstantDeclaration { name, return_type, value } => match return_type { | 30 | Ast::ConstantDeclaration { |
| 31 | name, | ||
| 32 | return_type, | ||
| 33 | value, | ||
| 34 | } => match return_type { | ||
| 27 | Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(value)?), | 35 | Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(value)?), |
| 28 | _ => format!("const {} = {};\n", name, transpile_helper(value)?), | 36 | _ => format!("const {} = {};\n", name, transpile_helper(value)?), |
| 29 | }, | 37 | }, |
| 30 | Ast::Return { return_value } => format!("return {};\n", transpile_helper(return_value)?), | 38 | Ast::Return { return_value } => format!("return {};\n", transpile_helper(return_value)?), |
| 31 | Ast::Function { name, arguments, return_type: _, value } => { | 39 | Ast::Function { |
| 40 | name, | ||
| 41 | arguments, | ||
| 42 | return_type: _, | ||
| 43 | value, | ||
| 44 | } => { | ||
| 32 | let mut result = format!("function {}(", name); | 45 | let mut result = format!("function {}(", name); |
| 33 | 46 | ||
| 34 | for (i, argument) in arguments.iter().enumerate() { | 47 | for (i, argument) in arguments.iter().enumerate() { |
| ... | @@ -48,9 +61,12 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -48,9 +61,12 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 48 | result += "}\n"; | 61 | result += "}\n"; |
| 49 | 62 | ||
| 50 | result | 63 | result |
| 51 | }, | 64 | } |
| 52 | Ast::FunctionCall { name, arguments } => { | 65 | Ast::FunctionCall { name, arguments } => { |
| 53 | let mut result = format!("{}(", name); | 66 | let mut result = match name.as_str() { |
| 67 | "print" => String::from("console.log("), | ||
| 68 | _ => format!("{}(", name), | ||
| 69 | }; | ||
| 54 | 70 | ||
| 55 | for (i, argument) in arguments.iter().enumerate() { | 71 | for (i, argument) in arguments.iter().enumerate() { |
| 56 | if i == 0 { | 72 | if i == 0 { |
| ... | @@ -60,6 +76,8 @@ fn transpile_helper(tree: &Ast) -> Result<String> { | ... | @@ -60,6 +76,8 @@ fn transpile_helper(tree: &Ast) -> Result<String> { |
| 60 | } | 76 | } |
| 61 | } | 77 | } |
| 62 | 78 | ||
| 79 | result += ")"; | ||
| 80 | |||
| 63 | result | 81 | result |
| 64 | } | 82 | } |
| 65 | }) | 83 | }) |
examples/basics/functions.blight+2| ... | @@ -3,3 +3,5 @@ fn bingus(x: int, y: int) -> int { | ... | @@ -3,3 +3,5 @@ fn bingus(x: int, y: int) -> int { |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | let result: int = bingus(10, 25); | 5 | let result: int = bingus(10, 25); |
| 6 | |||
| 7 | print(result); // built-in function |