authorgravatar for 11367844+lino-levan@users.noreply.github.comLino Le Van <11367844+lino-levan@users.noreply.github.com> 2024-01-03 18:10:07+01:00
committergravatar for 11367844+lino-levan@users.noreply.github.comLino Le Van <11367844+lino-levan@users.noreply.github.com> 2024-01-03 18:10:07+01:00
log6c14072860c381a177f886b7c3f00001fafd9abc
treece847a8d38b134e2a3e349ddc141dc98eb7c2618
parentde824b0e32bfb81f03869727ac3ff2006a3492e9

feat: add operators


9 files changed, 177 insertions(+), 135 deletions(-)

examples/easy.blight deleted-7
......@@ -1,7 +0,0 @@
1var x: int = 0;
2var y: float = 0;
3var z: bigint = 0;
4
5let a: int = 0;
6let b: float = 0;
7let c: bigint = 0;
examples/operations.blight created+1
......@@ -0,0 +1 @@
1let a: int = 10 - 2 / 4 * 15;
examples/variables.blight created+7
......@@ -0,0 +1,7 @@
1var x: int = 0;
2var y: float = 0;
3var z: bigint = 0;
4
5let a: int = 0;
6let b: float = 0;
7let c: bigint = 0;
src/main.rs+2-2
......@@ -1,7 +1,7 @@
11use std::path::PathBuf;
22
3use miette::{Result, NamedSource};
43use clap::{Parser, Subcommand};
4use miette::Result;
55
66mod transpile;
77
......@@ -21,7 +21,7 @@ enum Commands {
2121 /// Compiles a file into javascript
2222 Compile {
2323 /// lists test values
24 file: PathBuf
24 file: PathBuf,
2525 },
2626}
2727
src/transpile/ast.rs+71-50
......@@ -1,19 +1,21 @@
1use miette::{Result, Diagnostic};
1use miette::{Diagnostic, Result};
22use thiserror::Error;
33
44use super::tokenizer::Token;
5use super::util::PeekableIterator;
5use super::util::{Operator, PeekableIterator};
66
77#[derive(Error, Diagnostic, Debug)]
88#[error("AstError")]
99struct AstError {
1010 #[help]
11 error: String
11 error: String,
1212}
1313
1414impl AstError {
1515 fn new(error: &'static str) -> AstError {
16 AstError { error: String::from(error) }
16 AstError {
17 error: String::from(error),
18 }
1719 }
1820}
1921
......@@ -21,7 +23,7 @@ impl AstError {
2123pub enum Type {
2224 Int,
2325 Float,
24 Bigint
26 Bigint,
2527}
2628
2729#[derive(Debug)]
......@@ -29,107 +31,126 @@ pub enum Ast {
2931 ConstantDeclaration {
3032 name: String,
3133 typ: Type,
32 value: Box<Ast>
34 value: Box<Ast>,
3335 },
3436 VariableDeclaration {
3537 name: String,
3638 typ: Type,
37 value: Box<Ast>
39 value: Box<Ast>,
40 },
41 Operation {
42 operator: Operator,
43 left: Box<Ast>,
44 right: Box<Ast>,
3845 },
3946 Number(String),
4047}
4148
42fn parse_expression(tokens: &mut dyn PeekableIterator<Item=&Token>) -> Result<Ast> {
43 match tokens.next() {
49fn parse_expression(tokens: &mut dyn PeekableIterator<Item = &Token>) -> Result<Ast> {
50 let left = match tokens.next() {
4451 Some(token) => match token {
45 Token::Number(number) => Token::Number(number.clone()),
46 _ => return Err(AstError::new("Expected expression, but did not get it").into())
52 Token::Number(number) => Ast::Number(number.clone()),
53 _ => return Err(AstError::new("Expected expression, but did not get it").into()),
4754 },
48 None => return Err(AstError::new("Expected expression, but got nothing instead").into())
49
55 None => return Err(AstError::new("Expected expression, but got nothing instead").into()),
5056 };
57
58 match tokens.peek() {
59 Some(token) => match token {
60 Token::Operator(operator) => {
61 tokens.next();
62 return Ok(Ast::Operation {
63 operator: operator.clone(),
64 left: Box::new(left),
65 right: Box::new(parse_expression(tokens)?),
66 });
67 }
68 _ => (),
69 },
70 _ => (),
71 }
72
5173 Ok(Ast::Number(String::from("10")))
5274}
5375
5476/// Precondition: There is at least one token in the iterator
55fn parse_statement(tokens: &mut dyn PeekableIterator<Item=&Token>) -> Result<Ast> {
77fn parse_statement(tokens: &mut dyn PeekableIterator<Item = &Token>) -> Result<Ast> {
5678 match tokens.next().unwrap() {
5779 Token::Let => {
5880 let name = match tokens.next() {
5981 Some(Token::Identifier(name)) => name,
60 _ => return Err(AstError::new("Expected identifier after var").into())
82 _ => return Err(AstError::new("Expected identifier after var").into()),
6183 };
6284 let typ = match tokens.next() {
63 Some(Token::Colon) => {
64 match tokens.next() {
65 Some(Token::Identifier(typ)) => {
66 match typ.as_str() {
67 "int" => Type::Int,
68 "float" => Type::Float,
69 "bigint" => Type::Bigint,
70 _ => return Err(AstError::new("Expected type after colon").into())
71 }
72 },
73 _ => return Err(AstError::new("Expected type after colon").into())
74 }
85 Some(Token::Colon) => match tokens.next() {
86 Some(Token::Identifier(typ)) => match typ.as_str() {
87 "int" => Type::Int,
88 "float" => Type::Float,
89 "bigint" => Type::Bigint,
90 _ => return Err(AstError::new("Expected type after colon").into()),
91 },
92 _ => return Err(AstError::new("Expected type after colon").into()),
7593 },
76 _ => return Err(AstError::new("Expected colon after identifier").into())
94 _ => return Err(AstError::new("Expected colon after identifier").into()),
7795 };
7896 let value = match tokens.next() {
7997 Some(Token::Equals) => parse_expression(tokens)?,
80 _ => return Err(AstError::new("Expected equals after identifier").into())
98 _ => return Err(AstError::new("Expected equals after identifier").into()),
8199 };
82100 match tokens.next() {
83101 Some(Token::Semicolon) => (),
84 _ => return Err(AstError::new("Expected semicolon after variable declaration").into())
102 _ => {
103 return Err(
104 AstError::new("Expected semicolon after variable declaration").into(),
105 )
106 }
85107 };
86108 Ok(Ast::ConstantDeclaration {
87109 name: name.clone(),
88110 typ,
89111 value: Box::new(value),
90112 })
91 },
113 }
92114 Token::Var => {
93115 let name = match tokens.next() {
94116 Some(Token::Identifier(name)) => name,
95 _ => return Err(AstError::new("Expected identifier after var").into())
117 _ => return Err(AstError::new("Expected identifier after var").into()),
96118 };
97119 let typ = match tokens.next() {
98 Some(Token::Colon) => {
99 match tokens.next() {
100 Some(Token::Identifier(typ)) => {
101 match typ.as_str() {
102 "int" => Type::Int,
103 "float" => Type::Float,
104 "bigint" => Type::Bigint,
105 _ => return Err(AstError::new("Expected type after colon").into())
106 }
107 },
108 _ => return Err(AstError::new("Expected type after colon").into())
109 }
120 Some(Token::Colon) => match tokens.next() {
121 Some(Token::Identifier(typ)) => match typ.as_str() {
122 "int" => Type::Int,
123 "float" => Type::Float,
124 "bigint" => Type::Bigint,
125 _ => return Err(AstError::new("Expected type after colon").into()),
126 },
127 _ => return Err(AstError::new("Expected type after colon").into()),
110128 },
111 _ => return Err(AstError::new("Expected colon after identifier").into())
129 _ => return Err(AstError::new("Expected colon after identifier").into()),
112130 };
113131 let value = match tokens.next() {
114132 Some(Token::Equals) => parse_expression(tokens)?,
115 _ => return Err(AstError::new("Expected equals after identifier").into())
133 _ => return Err(AstError::new("Expected equals after identifier").into()),
116134 };
117135 match tokens.next() {
118136 Some(Token::Semicolon) => (),
119 _ => return Err(AstError::new("Expected semicolon after variable declaration").into())
137 _ => {
138 return Err(
139 AstError::new("Expected semicolon after variable declaration").into(),
140 )
141 }
120142 };
121143 Ok(Ast::VariableDeclaration {
122144 name: name.clone(),
123145 typ,
124146 value: Box::new(value),
125147 })
126 },
148 }
127149 Token::Number(number) => Ok(Ast::Number(number.clone())),
128 _ => return Err(AstError::new("Unexpected token").into())
150 _ => return Err(AstError::new("Unexpected token").into()),
129151 }
130152}
131153
132
133154pub fn parse(tokens: Vec<Token>) -> Result<Vec<Ast>> {
134155 let mut iter = tokens.iter().peekable();
135156 let mut ast: Vec<Ast> = Vec::new();
src/transpile/mod.rs+3-3
......@@ -1,12 +1,12 @@
1use miette::{Result};
1use miette::Result;
22
3mod tokenizer;
43mod ast;
4mod tokenizer;
55mod walker;
66
77mod util;
88
9pub fn transpile(content: String) -> Result<String> {
9pub fn transpile(content: String) -> Result<String> {
1010 // 1. Tokenize the input
1111 let tokens = tokenizer::tokenize(content)?;
1212 // 2. Parse the tokens into an AST
src/transpile/tokenizer.rs+56-61
......@@ -1,19 +1,13 @@
1use miette::{Result, Diagnostic};
1use miette::{Diagnostic, Result};
22use thiserror::Error;
33
4use super::util::Operator;
5
46#[derive(Error, Diagnostic, Debug)]
57#[error("UnknownCharacter")]
68struct UnknownCharacter {
79 #[help]
8 error: String
9}
10
11#[derive(Debug, Clone)]
12pub enum Operator {
13 Add,
14 Substract,
15 Multiply,
16 Divide,
10 error: String,
1711}
1812
1913#[derive(Debug, Clone)]
......@@ -28,7 +22,7 @@ pub enum Token {
2822 Equals,
2923 Semicolon,
3024 // Operators
31 Operator(Operator)
25 Operator(Operator),
3226}
3327
3428pub fn tokenize(content: String) -> Result<Vec<Token>> {
......@@ -37,64 +31,65 @@ pub fn tokenize(content: String) -> Result<Vec<Token>> {
3731
3832 loop {
3933 match chars.next() {
40 Some((i, c)) => {
41 match c {
42 'a'..='z' | 'A'..='Z' | '_' => {
43 let mut current_token = String::new();
44 current_token.push(c);
45 loop {
46 let c = chars.peek();
47 if c.is_none() {
48 break;
49 }
50 let (_, c) = c.unwrap();
51 match c {
52 'a'..='z' | 'A'..='Z' | '_' | '0'..='9' => {
53 current_token.push(*c);
54 chars.next();
55 },
56 _ => break,
34 Some((_, c)) => match c {
35 'a'..='z' | 'A'..='Z' | '_' => {
36 let mut current_token = String::new();
37 current_token.push(c);
38 loop {
39 let c = chars.peek();
40 if c.is_none() {
41 break;
42 }
43 let (_, c) = c.unwrap();
44 match c {
45 'a'..='z' | 'A'..='Z' | '_' | '0'..='9' => {
46 current_token.push(*c);
47 chars.next();
5748 }
49 _ => break,
5850 }
51 }
5952
60 match current_token.as_str() {
61 "var" => tokens.push(Token::Var),
62 "let" => tokens.push(Token::Let),
63 _ => tokens.push(Token::Identifier(current_token)),
53 match current_token.as_str() {
54 "var" => tokens.push(Token::Var),
55 "let" => tokens.push(Token::Let),
56 _ => tokens.push(Token::Identifier(current_token)),
57 }
58 }
59 '0'..='9' => {
60 let mut current_token = String::new();
61 current_token.push(c);
62 loop {
63 let c = chars.peek();
64 if c.is_none() {
65 break;
6466 }
65 },
66 '0'..='9' => {
67 let mut current_token = String::new();
68 current_token.push(c);
69 loop {
70 let c = chars.peek();
71 if c.is_none() {
72 break;
73 }
74 let (_, c) = c.unwrap();
75 match c {
76 '0'..='9' => {
77 current_token.push(*c);
78 chars.next();
79 },
80 _ => break,
67 let (_, c) = c.unwrap();
68 match c {
69 '0'..='9' => {
70 current_token.push(*c);
71 chars.next();
8172 }
73 _ => break,
8274 }
83 tokens.push(Token::Number(current_token));
84 },
85 ':' => tokens.push(Token::Colon),
86 '=' => tokens.push(Token::Equals),
87 ';' => tokens.push(Token::Semicolon),
88 '+' => tokens.push(Token::Operator(Operator::Add)),
89 '-' => tokens.push(Token::Operator(Operator::Substract)),
90 '*' => tokens.push(Token::Operator(Operator::Multiply)),
91 '/' => tokens.push(Token::Operator(Operator::Divide)),
92 s if s.is_whitespace() => (),
93 _ => {
94 return Err(UnknownCharacter { error: format!("Unsupported character: {}", c)}.into())
9575 }
76 tokens.push(Token::Number(current_token));
77 }
78 ':' => tokens.push(Token::Colon),
79 '=' => tokens.push(Token::Equals),
80 ';' => tokens.push(Token::Semicolon),
81 '+' => tokens.push(Token::Operator(Operator::Add)),
82 '-' => tokens.push(Token::Operator(Operator::Substract)),
83 '*' => tokens.push(Token::Operator(Operator::Multiply)),
84 '/' => tokens.push(Token::Operator(Operator::Divide)),
85 s if s.is_whitespace() => (),
86 _ => {
87 return Err(UnknownCharacter {
88 error: format!("Unsupported character: {}", c),
89 }
90 .into())
9691 }
97 }
92 },
9893 None => break,
9994 }
10095 }
src/transpile/util.rs+20-1
......@@ -1,6 +1,6 @@
11// Rust why do you not have a peekable iterator in the standard library?
22// Stolen from https://users.rust-lang.org/t/peekable-argument-there-has-to-be-a-simpler-way/6959
3pub trait PeekableIterator : std::iter::Iterator {
3pub trait PeekableIterator: std::iter::Iterator {
44 fn peek(&mut self) -> Option<&Self::Item>;
55}
66
......@@ -9,3 +9,22 @@ impl<I: std::iter::Iterator> PeekableIterator for std::iter::Peekable<I> {
99 std::iter::Peekable::peek(self)
1010 }
1111}
12
13#[derive(Debug, Clone)]
14pub enum Operator {
15 Add,
16 Substract,
17 Multiply,
18 Divide,
19}
20
21impl Operator {
22 pub fn to_string(self) -> String {
23 String::from(match self {
24 Self::Add => "+",
25 Self::Substract => "-",
26 Self::Divide => "/",
27 Self::Multiply => "*",
28 })
29 }
30}
src/transpile/walker.rs+17-11
......@@ -3,18 +3,24 @@ use super::ast::{Ast, Type};
33fn transpile_helper(tree: Ast) -> String {
44 match tree {
55 Ast::Number(number) => format!("{}", number),
6 Ast::VariableDeclaration { name, typ, value } => {
7 match typ {
8 Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(*value)),
9 _ => format!("let {} = {};\n", name, transpile_helper(*value))
10 }
6 Ast::Operation {
7 operator,
8 left,
9 right,
10 } => format!(
11 "{} {} {}",
12 transpile_helper(*left),
13 operator.to_string(),
14 transpile_helper(*right)
15 ),
16 Ast::VariableDeclaration { name, typ, value } => match typ {
17 Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(*value)),
18 _ => format!("let {} = {};\n", name, transpile_helper(*value)),
19 },
20 Ast::ConstantDeclaration { name, typ, value } => match typ {
21 Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(*value)),
22 _ => format!("const {} = {};\n", name, transpile_helper(*value)),
1123 },
12 Ast::ConstantDeclaration { name, typ, value } => {
13 match typ {
14 Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(*value)),
15 _ => format!("const {} = {};\n", name, transpile_helper(*value))
16 }
17 }
1824 }
1925}
2026