authorgravatar for 11367844+lino-levan@users.noreply.github.comLino Le Van <11367844+lino-levan@users.noreply.github.com> 2024-01-10 08:31:10-08:00
committergravatar for 11367844+lino-levan@users.noreply.github.comLino Le Van <11367844+lino-levan@users.noreply.github.com> 2024-01-10 08:31:10-08:00
log266f616b552eb86530ed664e44aea026cb5820db
treeac537bd975a86f79730ca87c12b09cf957b062dc
parentbf7dedc48580545fcbcbb877d6f84087b96b4c62

feat: add function calling and print built-in


6 files changed, 219 insertions(+), 79 deletions(-)

cli/src/main.rs+52-3
......@@ -20,8 +20,16 @@ struct Cli {
2020enum Commands {
2121 /// Compiles a file into javascript
2222 Compile {
23 /// lists test values
2423 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,
2533 },
2634}
2735
......@@ -29,10 +37,51 @@ fn main() -> Result<()> {
2937 let cli = Cli::parse();
3038
3139 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 } => {
3351 let contents = std::fs::read_to_string(file.clone()).unwrap();
3452 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 }
3685 }
3786 }
3887
compiler/src/ast/mod.rs+121-45
......@@ -6,42 +6,50 @@ mod types;
66use super::tokenizer::Token;
77
88use error::AstError;
9use types::{ParserContext, Argument};
9use types::{Argument, ParserContext};
1010
1111pub use types::{Ast, Type};
1212
1313fn parse_expression(tokens: &mut ParserContext) -> Result<Ast> {
14
1514 let left = match tokens.next() {
1615 Some(token) => match token {
1716 Token::Number(number) => Ast::Number(number.clone()),
18 Token::Identifier(name) => {
19 match tokens.peek() {
20 Some(Token::OpenParanthesis) => {
21 tokens.next();
17 Token::Identifier(name) => match tokens.peek() {
18 Some(Token::OpenParanthesis) => {
19 tokens.next();
2220
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)?);
2432
25 loop {
26 match tokens.peek() {
27 Some(Token::ClosedParanthesis) => break,
28 _ => ()
33 match tokens.peek() {
34 Some(Token::Comma) => {
35 tokens.next();
2936 }
30 arguments.push(parse_expression(tokens)?);
31
32 match tokens.peek() {
33 Some(Token::Comma) => {
34 tokens.next();
35 }
36 Some(Token::ClosedParanthesis) => (),
37 _ => return Err(AstError::new("Expected ) or , but found something else instead.").into()),
37 Some(Token::ClosedParanthesis) => (),
38 _ => {
39 return Err(AstError::new(
40 "Expected ) or , but found something else instead.",
41 )
42 .into())
3843 }
3944 }
45 }
4046
41 Ast::FunctionCall { name: name.clone(), arguments }
47 Ast::FunctionCall {
48 name: name.clone(),
49 arguments,
4250 }
43 _ => Ast::Identifier(name.clone())
4451 }
52 _ => Ast::Identifier(name.clone()),
4553 },
4654 _ => return Err(AstError::new("Expected expression, but did not get it").into()),
4755 },
......@@ -90,7 +98,9 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
9098
9199 let inner = parse_statement(tokens)?;
92100
93 return Ok(Ast::Public { value: Box::new(inner) })
101 return Ok(Ast::Public {
102 value: Box::new(inner),
103 });
94104 }
95105 Token::Let => {
96106 let name = match tokens.next() {
......@@ -151,14 +161,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
151161
152162 match tokens.next() {
153163 Some(Token::Semicolon) => (),
154 _ => {
155 return Err(
156 AstError::new("Expected semicolon after return statement").into(),
157 )
158 }
164 _ => return Err(AstError::new("Expected semicolon after return statement").into()),
159165 };
160166
161 Ok(Ast::Return { return_value: Box::new(expression) })
167 Ok(Ast::Return {
168 return_value: Box::new(expression),
169 })
162170 }
163171 Token::Function => {
164172 let name = match tokens.next() {
......@@ -168,7 +176,12 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
168176
169177 match tokens.next() {
170178 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 }
172185 };
173186
174187 let mut arguments = Vec::new();
......@@ -178,13 +191,18 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
178191 Some(Token::ClosedParanthesis) => {
179192 tokens.next();
180193 break;
181 },
182 _ => ()
194 }
195 _ => (),
183196 }
184197
185198 let argument_name = match tokens.next() {
186199 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 }
188206 };
189207
190208 let return_type = match tokens.next() {
......@@ -195,21 +213,34 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
195213 match tokens.peek() {
196214 Some(Token::Comma) => {
197215 tokens.next();
198 },
199 _ => ()
216 }
217 _ => (),
200218 }
201219
202 arguments.push(Argument { name: argument_name.clone(), return_type})
220 arguments.push(Argument {
221 name: argument_name.clone(),
222 return_type,
223 })
203224 }
204225
205226 let return_type = match tokens.next() {
206227 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 }
208234 };
209235
210236 match tokens.next() {
211237 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 }
213244 };
214245
215246 let mut value = Vec::new();
......@@ -219,15 +250,62 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
219250 Some(Token::ClosedBracket) => {
220251 tokens.next();
221252 break;
222 },
223 _ => ()
253 }
254 _ => (),
224255 }
225256
226257 value.push(parse_statement(tokens)?);
227258 }
228259
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 });
230266 }
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 },
231309 Token::Comment(comment) => Ok(Ast::Comment(comment.clone())),
232310 Token::DocComment(comment) => {
233311 let mut concatted_comments = comment.clone();
......@@ -236,15 +314,13 @@ fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
236314 Some(Token::DocComment(comment)) => {
237315 concatted_comments.push_str(format!("\n{}", comment).as_str());
238316 tokens.next();
239 },
317 }
240318 _ => break,
241319 }
242320 }
243321 Ok(Ast::DocComment(concatted_comments))
244 },
245 _ => {
246 return Err(AstError::new("Unexpected token").into())
247 },
322 }
323 _ => return Err(AstError::new("Unexpected token").into()),
248324 }
249325}
250326
compiler/src/ast/types.rs+7-8
......@@ -1,10 +1,10 @@
1use crate::util::Operator;
21use crate::tokenizer::Token;
2use crate::util::Operator;
33
44#[derive(Debug)]
55pub struct ParserContext {
66 pub tokens: Vec<Token>,
7 pub cursor: usize
7 pub cursor: usize,
88}
99
1010impl ParserContext {
......@@ -35,7 +35,6 @@ impl ParserContext {
3535 }
3636}
3737
38
3938#[derive(Debug)]
4039pub enum Type {
4140 Int,
......@@ -46,13 +45,13 @@ pub enum Type {
4645#[derive(Debug)]
4746pub struct Argument {
4847 pub name: String,
49 pub return_type: Type
48 pub return_type: Type,
5049}
5150
5251#[derive(Debug)]
5352pub enum Ast {
5453 Public {
55 value: Box<Ast>
54 value: Box<Ast>,
5655 },
5756 ConstantDeclaration {
5857 name: String,
......@@ -70,13 +69,13 @@ pub enum Ast {
7069 right: Box<Ast>,
7170 },
7271 Return {
73 return_value: Box<Ast>
72 return_value: Box<Ast>,
7473 },
7574 Function {
7675 name: String,
7776 arguments: Vec<Argument>,
7877 return_type: Type,
79 value: Vec<Ast>
78 value: Vec<Ast>,
8079 },
8180 FunctionCall {
8281 name: String,
......@@ -85,5 +84,5 @@ pub enum Ast {
8584 Number(String),
8685 Identifier(String),
8786 Comment(String),
88 DocComment(String)
87 DocComment(String),
8988}
compiler/src/tokenizer.rs+14-18
......@@ -94,23 +94,19 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> {
9494 '=' => tokens.push(Token::Equals),
9595 ';' => tokens.push(Token::Semicolon),
9696 '+' => tokens.push(Token::Operator(Operator::Add)),
97 '-' => {
98 match chars.peek() {
99 Some((_, '>')) => {
100 chars.next();
101 tokens.push(Token::RightArrow);
102 }
103 _ => tokens.push(Token::Operator(Operator::Substract))
97 '-' => match chars.peek() {
98 Some((_, '>')) => {
99 chars.next();
100 tokens.push(Token::RightArrow);
104101 }
102 _ => tokens.push(Token::Operator(Operator::Substract)),
105103 },
106 '*' => {
107 match chars.peek() {
108 Some((_, '*')) => {
109 chars.next();
110 tokens.push(Token::Operator(Operator::Power));
111 }
112 _ => tokens.push(Token::Operator(Operator::Multiply))
104 '*' => match chars.peek() {
105 Some((_, '*')) => {
106 chars.next();
107 tokens.push(Token::Operator(Operator::Power));
113108 }
109 _ => tokens.push(Token::Operator(Operator::Multiply)),
114110 },
115111 '/' => {
116112 match chars.peek() {
......@@ -121,7 +117,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> {
121117 Some((_, '/')) => {
122118 chars.next(); // Consume the third slash
123119 true
124 },
120 }
125121 _ => false,
126122 };
127123
......@@ -136,7 +132,7 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> {
136132 '\n' => break,
137133 _ => {
138134 comment.push(c.clone());
139 },
135 }
140136 }
141137 }
142138
......@@ -148,9 +144,9 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> {
148144 tokens.push(Token::Comment(comment));
149145 }
150146 }
151 _ => tokens.push(Token::Operator(Operator::Divide))
147 _ => tokens.push(Token::Operator(Operator::Divide)),
152148 }
153 },
149 }
154150 ',' => tokens.push(Token::Comma),
155151 '(' => tokens.push(Token::OpenParanthesis),
156152 ')' => tokens.push(Token::ClosedParanthesis),
compiler/src/walker.rs+23-5
......@@ -19,16 +19,29 @@ fn transpile_helper(tree: &Ast) -> Result<String> {
1919 transpile_helper(right)?
2020 ),
2121 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 {
2327 Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(value)?),
2428 _ => format!("let {} = {};\n", name, transpile_helper(value)?),
2529 },
26 Ast::ConstantDeclaration { name, return_type, value } => match return_type {
30 Ast::ConstantDeclaration {
31 name,
32 return_type,
33 value,
34 } => match return_type {
2735 Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(value)?),
2836 _ => format!("const {} = {};\n", name, transpile_helper(value)?),
2937 },
3038 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 } => {
3245 let mut result = format!("function {}(", name);
3346
3447 for (i, argument) in arguments.iter().enumerate() {
......@@ -48,9 +61,12 @@ fn transpile_helper(tree: &Ast) -> Result<String> {
4861 result += "}\n";
4962
5063 result
51 },
64 }
5265 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 };
5470
5571 for (i, argument) in arguments.iter().enumerate() {
5672 if i == 0 {
......@@ -60,6 +76,8 @@ fn transpile_helper(tree: &Ast) -> Result<String> {
6076 }
6177 }
6278
79 result += ")";
80
6381 result
6482 }
6583 })
examples/basics/functions.blight+2
......@@ -3,3 +3,5 @@ fn bingus(x: int, y: int) -> int {
33}
44
55let result: int = bingus(10, 25);
6
7print(result); // built-in function