authorchloe caruso <git@paperclover.net> 2024-01-20 09:38:23-08:00
committerchloe caruso <git@paperclover.net> 2024-01-20 09:38:23-08:00
log9593137d0c6b96fae79c7366d2c37b6ddcd36d08
tree519ae1b9858dfd847159429ba8b72eadf0089d96
parent091dd237e9ee9de0d9e8f3b7a95ccbcffb618b68

swag


25 files changed, 437 insertions(+), 104 deletions(-)

.gitignore+1
......@@ -1 +1,2 @@
11target
2*.js
Cargo.lock+12
......@@ -126,6 +126,17 @@ version = "1.0.0"
126126source = "registry+https://github.com/rust-lang/crates.io-index"
127127checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
128128
129[[package]]
130name = "checker"
131version = "0.1.0"
132dependencies = [
133 "ast",
134 "miette",
135 "num",
136 "thiserror",
137 "util",
138]
139
129140[[package]]
130141name = "clap"
131142version = "4.4.14"
......@@ -171,6 +182,7 @@ name = "cli"
171182version = "0.1.0"
172183dependencies = [
173184 "ast",
185 "checker",
174186 "clap",
175187 "js_ast",
176188 "js_printer",
crates/ast/src/error.rs+4
......@@ -14,4 +14,8 @@ impl AstError {
1414 error: String::from(error),
1515 }
1616 }
17
18 pub fn from_string(error: String) -> AstError {
19 AstError { error }
20 }
1721}
crates/ast/src/lib.rs+3-3
......@@ -13,9 +13,9 @@ use tokenizer::Token;
1313use parse_statement::parse_statement;
1414use types::ParserContext;
1515
16pub use types::{Ast, Block, Type};
16pub use types::{Ast, Block, Module, Type};
1717
18pub fn parse(tokens: Vec<Token>) -> Result<Vec<Ast>> {
18pub fn parse(tokens: Vec<Token>) -> Result<Module> {
1919 let mut ctx = ParserContext::new(tokens);
2020 let mut ast: Vec<Ast> = Vec::new();
2121
......@@ -23,5 +23,5 @@ pub fn parse(tokens: Vec<Token>) -> Result<Vec<Ast>> {
2323 ast.push(parse_statement(&mut ctx)?);
2424 }
2525
26 Ok(ast)
26 Ok(Module { value: ast })
2727}
crates/ast/src/parse_statement.rs+17-33
......@@ -2,6 +2,8 @@ use miette::Result;
22
33use tokenizer::Token;
44
5use crate::Type;
6
57use super::error::AstError;
68use super::parse_block::parse_block;
79use super::parse_expression::parse_expression;
......@@ -38,41 +40,22 @@ pub fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
3840
3941 return Ok(Ast::Public(Box::new(inner)));
4042 }
41 Token::Let => {
42 let name = match tokens.next() {
43 Some(Token::Identifier(name)) => name,
44 _ => return Err(AstError::new("Expected identifier after var").into()),
45 };
46 let return_type = match tokens.next() {
47 Some(Token::Colon) => parse_type(tokens)?,
48 _ => return Err(AstError::new("Expected colon after identifier").into()),
49 };
50 let value = match tokens.next() {
51 Some(Token::Equals) => parse_expression(tokens)?,
52 _ => return Err(AstError::new("Expected equals after identifier").into()),
53 };
54 match tokens.next() {
55 Some(Token::Semicolon) => (),
56 _ => {
57 return Err(
58 AstError::new("Expected semicolon after constant declaration").into(),
59 )
60 }
43 Token::Var | Token::Let => {
44 let is_constant = match token {
45 Token::Var => false,
46 Token::Let => true,
47 _ => unreachable!(),
6148 };
62 Ok(Ast::ConstantDeclaration {
63 name: name.clone(),
64 return_type,
65 value: Box::new(value),
66 })
67 }
68 Token::Var => {
6949 let name = match tokens.next() {
7050 Some(Token::Identifier(name)) => name,
7151 _ => return Err(AstError::new("Expected identifier after var").into()),
7252 };
73 let return_type = match tokens.next() {
74 Some(Token::Colon) => parse_type(tokens)?,
75 _ => return Err(AstError::new("Expected colon after identifier").into()),
53 let return_type = match tokens.peek() {
54 Some(Token::Colon) => {
55 tokens.next();
56 parse_type(tokens)?
57 }
58 _ => Type::Infer,
7659 };
7760 let value = match tokens.next() {
7861 Some(Token::Equals) => parse_expression(tokens)?,
......@@ -82,14 +65,15 @@ pub fn parse_statement(tokens: &mut ParserContext) -> Result<Ast> {
8265 Some(Token::Semicolon) => (),
8366 _ => {
8467 return Err(
85 AstError::new("Expected semicolon after variable declaration").into(),
68 AstError::new("Expected semicolon after constant declaration").into(),
8669 )
8770 }
8871 };
89 Ok(Ast::VariableDeclaration {
72 Ok(Ast::Declaration {
9073 name: name.clone(),
91 return_type,
74 decl_type: return_type,
9275 value: Box::new(value),
76 is_constant,
9377 })
9478 }
9579 Token::Return => {
crates/ast/src/parse_type.rs+11-4
......@@ -10,12 +10,19 @@ pub fn parse_type(tokens: &mut ParserContext) -> Result<Type> {
1010 Some(Token::Identifier(typ)) => match typ.as_str() {
1111 "int" => Ok(Type::Int),
1212 "float" => Ok(Type::Float),
13 "bigint" => Ok(Type::Bigint),
13 "bigint" => Ok(Type::BigInt),
1414 "bool" => Ok(Type::Bool),
1515 "string" => Ok(Type::String),
16 "any" => Ok(Type::Any),
17 _ => return Err(AstError::new("Expected type").into()),
16 _ => {
17 return Err(
18 AstError::from_string(format!(
19 "Invalid type '{}' (TODO: add custom type support)",
20 typ
21 )
22 ).into())
23 }
1824 },
19 _ => return Err(AstError::new("Expected type").into()),
25 Some(unexpected) => return Err(AstError::from_string(format!("Expected type, got {}", unexpected)).into()),
26 None => return Err(AstError::from_string("Expected type, got EOF".to_string()).into()),
2027 }
2128}
crates/ast/src/types.rs+54-10
......@@ -41,14 +41,62 @@ impl ParserContext {
4141 }
4242}
4343
44#[derive(Debug, Clone)]
44#[derive(Debug, Clone, PartialEq)]
4545pub enum Type {
46 /// Variables without an explicit type are assigned this until
47 /// the type inferencer figures out what this is. There is not a
48 /// keyword for this.
49 Infer,
50 /// The type assigned to numeric literals. This allows integer literals
51 /// to coerce to integer or float depending on the context, but prevents
52 /// implicit casting of runtime values.
53 NumberLiteral(f64),
54 /// Return value of `@raw`. All type checks are disabled.
55 Any,
56 /// noreturn is the type of 'return', aka a value that never exists
57 NoReturn,
58 /// 32 signed integer
4659 Int,
60 /// 64 signed JS float
4761 Float,
48 Bigint,
62 /// Boolean
4963 Bool,
64 /// JS BigInt
65 BigInt,
66 /// JS String
5067 String,
51 Any,
68 /// A union of multiple possible types. Might be removed
69 Union(Vec<Type>),
70}
71
72impl std::fmt::Display for Type {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 Type::Infer => write!(f, "infered type"),
76 Type::Any => write!(f, "opaque js value"),
77 Type::NumberLiteral(_) => write!(f, "numeric literal"),
78 Type::Int => write!(f, "int"),
79 Type::Float => write!(f, "float"),
80 Type::BigInt => write!(f, "bigint"),
81 Type::Bool => write!(f, "bool"),
82 Type::String => write!(f, "string"),
83 Type::NoReturn => write!(f, "noreturn"),
84 Type::Union(of) => {
85 for (i, t) in of.iter().enumerate() {
86 if i != 0 {
87 write!(f, " | ")?;
88 }
89 write!(f, "{}", t)?;
90 }
91 Ok(())
92 }
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
98pub struct Module {
99 pub value: Vec<Ast>,
52100}
53101
54102#[derive(Debug, Clone)]
......@@ -65,15 +113,11 @@ pub struct Argument {
65113
66114#[derive(Debug, Clone)]
67115pub enum Ast {
68 ConstantDeclaration {
69 name: String,
70 return_type: Type,
71 value: Box<Ast>,
72 },
73 VariableDeclaration {
116 Declaration {
74117 name: String,
75 return_type: Type,
118 decl_type: Type,
76119 value: Box<Ast>,
120 is_constant: bool,
77121 },
78122 Operation {
79123 operator: Operator,
crates/checker/Cargo.toml created+14
......@@ -0,0 +1,14 @@
1[package]
2name = "checker"
3version = "0.1.0"
4edition = "2021"
5
6[lib]
7
8[dependencies]
9miette.workspace = true
10thiserror.workspace = true
11num.workspace = true
12
13ast = { path = "../ast" }
14util = { path = "../util" }
crates/checker/src/lib.rs created+203
......@@ -0,0 +1,203 @@
1use ast::{Ast, Module, Type};
2use miette::Result;
3
4use miette::Diagnostic;
5use thiserror::Error;
6
7#[derive(Error, Diagnostic, Debug)]
8#[error("TypeError")]
9pub struct TypeError {
10 #[help]
11 error: String,
12}
13
14impl TypeError {
15 pub fn new(error: String) -> Self {
16 Self { error }
17 }
18}
19
20pub fn check_module(block: &Module) -> Result<()> {
21 for statement in &block.value {
22 check_expression(statement)?;
23 }
24
25 Ok(())
26}
27
28pub fn resolve_type(expr: &Ast) -> Result<Type> {
29 match expr {
30 Ast::Number(value) => Ok(Type::NumberLiteral(value.clone())),
31 Ast::Declaration {
32 name,
33 decl_type,
34 value,
35 is_constant,
36 } => Ok(Type::NoReturn),
37 Ast::Operation {
38 operator,
39 left,
40 right,
41 } => merge_types(resolve_type(left)?, resolve_type(right)?),
42 Ast::Function {
43 name,
44 arguments,
45 return_type,
46 block,
47 } => todo!(),
48 Ast::FunctionCall { name, arguments } => todo!(),
49 Ast::If {
50 condition,
51 value,
52 else_value,
53 } => todo!(),
54 Ast::Return(_) => Ok(Type::NoReturn),
55 Ast::Public(_) => todo!(), // TODO: remove Public
56 Ast::Block(_) => todo!(),
57 Ast::Bool(_) => Ok(Type::Bool),
58 Ast::String(_) => Ok(Type::String),
59 Ast::Identifier(_) => todo!(),
60 Ast::BuiltIn(_) => todo!(),
61
62 Ast::Comment(_) => unreachable!(),
63 Ast::DocComment(_) => unreachable!(),
64 }
65}
66
67pub fn merge_types(a: Type, b: Type) -> Result<Type> {
68 match a {
69 Type::Infer => return Ok(b),
70 Type::Any => return Ok(Type::Any),
71 _ => {}
72 }
73
74 match b {
75 Type::Infer => return Ok(a),
76 Type::Any => return Ok(Type::Any),
77 _ => {}
78 }
79
80 if a == b {
81 return Ok(a);
82 }
83
84 Err(TypeError::new(format!("Cannot merge {} and {}", a, b)).into())
85}
86
87pub fn coerce_type(target: Type, source: Type) -> Result<Type> {
88 match source {
89 Type::Any => return Ok(target),
90 _ => {}
91 }
92 match target {
93 Type::Infer => Ok(source),
94 Type::Any => Ok(Type::Any),
95
96 Type::NumberLiteral(_) => unreachable!(),
97
98 Type::Int => match source {
99 Type::Int => Ok(Type::Int),
100 Type::Float => Ok(Type::Int),
101 Type::NumberLiteral(value) => {
102 if value.fract() != 0.0 {
103 Err(
104 TypeError::new(format!("Numeric Literal '{}' is not an integer", value))
105 .into(),
106 )
107 } else if value > i32::MAX.into() || value < i32::MIN.into() {
108 Err(TypeError::new(format!(
109 "Numeric Literal '{}' is out of range for an integer ({}..{})",
110 value,
111 i32::MIN,
112 i32::MAX
113 ))
114 .into())
115 } else {
116 Ok(Type::Int)
117 }
118 }
119 t => Err(TypeError::new(format!("Cannot coerce {} to int", t)).into()),
120 },
121
122 Type::BigInt => match source {
123 Type::Int => Ok(Type::Int),
124 Type::Float => Ok(Type::Int),
125 Type::NumberLiteral(value) => {
126 if value.fract() != 0.0 {
127 Err(
128 TypeError::new(format!("Numeric Literal '{}' is not an integer", value))
129 .into(),
130 )
131 } else {
132 Ok(Type::BigInt)
133 }
134 }
135 t => Err(TypeError::new(format!("Cannot coerce {} to int", t)).into()),
136 },
137
138 Type::Float => match source {
139 Type::Int => Ok(Type::Float),
140 Type::Float => Ok(Type::Float),
141 Type::NumberLiteral(value) => {
142 if value.fract() == 0.0 && value <= f64::MAX.into() && value >= f64::MIN.into() {
143 Ok(Type::Float)
144 } else {
145 Err(TypeError::new(format!("Numeric Literal")).into())
146 }
147 }
148 _ => Err(TypeError::new(format!("Cannot coerce int to float")).into()),
149 },
150
151 other => {
152 if other == source {
153 Ok(other)
154 } else {
155 Err(TypeError::new(format!("Cannot coerce {} to {}", source, other)).into())
156 }
157 }
158 }
159}
160
161pub fn check_expression(expr: &Ast) -> Result<()> {
162 match expr {
163 Ast::Declaration {
164 name,
165 decl_type: return_type,
166 value,
167 is_constant,
168 } => {
169 check_expression(value)?;
170 coerce_type(return_type.clone(), resolve_type(value)?)?;
171 }
172 _ => {}
173 // Ast::Operation {
174 // operator,
175 // left,
176 // right,
177 // } => Ok(()),
178 // Ast::Function {
179 // name,
180 // arguments,
181 // return_type,
182 // block,
183 // } => Ok(()),
184 // Ast::FunctionCall { name, arguments } => Ok(()),
185 // Ast::If {
186 // condition,
187 // value,
188 // else_value,
189 // } => Ok(()),
190 // Ast::Return(_) => Ok(()),
191 // Ast::Public(_) => Ok(()),
192 // Ast::Block(_) => Ok(()),
193 // Ast::Number(_) => Ok(()),
194 // Ast::Bool(_) => Ok(()),
195 // Ast::String(_) => Ok(()),
196 // Ast::Identifier(_) => Ok(()),
197 // Ast::BuiltIn(_) => Ok(()),
198 // Ast::Comment(_) => Ok(()),
199 // Ast::DocComment(_) => Ok(()),
200 }
201
202 Ok(())
203}
crates/cli/Cargo.toml+1
......@@ -16,3 +16,4 @@ tokenizer = { path = "../tokenizer" }
1616ast = { path = "../ast" }
1717js_ast = { path = "../js_ast" }
1818js_printer = { path = "../js_printer" }
19checker = { path = "../checker" }
crates/cli/src/main.rs+38-5
......@@ -1,5 +1,6 @@
1use std::path::PathBuf;
1use std::{io::Write, path::PathBuf};
22
3use checker;
34use clap::{Parser, Subcommand};
45use miette::Result;
56
......@@ -29,6 +30,9 @@ enum Commands {
2930 /// What javascript runtime to compile to
3031 #[arg(short, long, default_value = "deno")]
3132 target: String,
33 /// Format the output javascript?
34 #[arg(long, default_value_t = true)]
35 format: bool,
3236 },
3337 Run {
3438 file: PathBuf,
......@@ -51,11 +55,11 @@ pub fn transpile(content: String) -> Result<String> {
5155 // 2. Parse the tokens into an AST
5256 let blight_ast = ast::parse(tokens)?;
5357 // 3. Type check the AST
54 // type_check(tree.clone())?;
58 checker::check_module(&blight_ast)?;
5559 // 4. Optimize the AST
5660 // optimize(tree.clone())?;
5761 // 5. Translate the AST into javascript
58 let js_ast = js_ast::translate(blight_ast)?;
62 let js_ast = js_ast::translate(&blight_ast)?;
5963 // 6. Print the JS AST
6064 let javascript = js_printer::print(js_ast);
6165 // 7. Return the javascript
......@@ -70,9 +74,38 @@ fn main() -> Result<()> {
7074 file,
7175 stdout,
7276 target: _,
77 format,
7378 } => {
74 let contents = std::fs::read_to_string(file.clone()).unwrap();
75 let result = transpile(contents.clone())?;
79 let contents = match std::fs::read_to_string(file.clone()) {
80 Ok(contents) => contents,
81 Err(e) => {
82 eprintln!("Failed to read {}: {}", file.display(), e);
83 std::process::exit(1);
84 }
85 };
86
87 let mut result = transpile(contents.clone())?;
88
89 if format {
90 let mut formatter = std::process::Command::new("deno")
91 .stdin(std::process::Stdio::piped())
92 .stdout(std::process::Stdio::piped())
93 .stderr(std::process::Stdio::inherit())
94 .arg("fmt")
95 .arg("-")
96 .spawn()
97 .expect("Failed to execute 'deno fmt' on output");
98 let mut stdin = formatter.stdin.take().expect("Failed to open stdin");
99 stdin
100 .write_all(result.as_bytes())
101 .expect("Failed to write to stdin");
102 stdin.flush().expect("Failed to flush stdin");
103 drop(stdin);
104 let out = formatter
105 .wait_with_output()
106 .expect("Failed to execute 'deno fmt' on output");
107 result = String::from_utf8(out.stdout).unwrap();
108 }
76109
77110 if stdout {
78111 println!("{}", result);
crates/js_ast/src/lib.rs+16-28
......@@ -2,7 +2,7 @@ use std::collections::HashMap;
22
33use miette::Result;
44
5use ast::Ast;
5use ast::{Ast, Module};
66
77mod types;
88pub use types::{JsExpression, JsStatement};
......@@ -55,9 +55,10 @@ impl TranslateContext {
5555 .last_mut()
5656 .unwrap()
5757 .statements
58 .push(JsStatement::VariableDeclaration {
58 .push(JsStatement::Declaration {
5959 name: format!("${}", self.internal_counter),
6060 value,
61 is_constant: false,
6162 });
6263 self.internal_counter += 1;
6364 JsExpression::Identifier(format!("${}", self.internal_counter - 1))
......@@ -169,28 +170,18 @@ fn get_expression_handle(ast: &Ast, ctx: &mut TranslateContext) -> JsExpression
169170
170171fn translate_statement(ast: &Ast, ctx: &mut TranslateContext) {
171172 match ast {
172 Ast::ConstantDeclaration {
173 Ast::Declaration {
173174 name,
174 return_type: _,
175 value,
176 } => {
177 let handle = get_expression_handle(value, ctx);
178 let rename = ctx.declare_variable(name.clone());
179 ctx.push(JsStatement::ConstantDeclaration {
180 name: rename,
181 value: handle,
182 });
183 }
184 Ast::VariableDeclaration {
185 name,
186 return_type: _,
175 decl_type: _,
187176 value,
177 is_constant,
188178 } => {
189179 let handle = get_expression_handle(value, ctx);
190180 let rename = ctx.declare_variable(name.clone());
191 ctx.push(JsStatement::VariableDeclaration {
181 ctx.push(JsStatement::Declaration {
192182 name: rename,
193183 value: handle,
184 is_constant: is_constant.clone(),
194185 });
195186 }
196187 Ast::Function {
......@@ -226,16 +217,13 @@ fn translate_statement(ast: &Ast, ctx: &mut TranslateContext) {
226217 translate_statement(value, ctx);
227218 // I'm sorry, I just don't know how to get the original name properly... my bad
228219 match ctx.peek() {
229 JsStatement::Function { name, .. }
230 | JsStatement::VariableDeclaration { name, .. }
231 | JsStatement::ConstantDeclaration { name, .. } => {
220 JsStatement::Function { name, .. } | JsStatement::Declaration { name, .. } => {
232221 let original_name = name.split("$").next().unwrap().to_string();
233 ctx.push(JsStatement::Export(Box::new(
234 JsStatement::ConstantDeclaration {
235 name: original_name,
236 value: JsExpression::Identifier(name.clone()),
237 },
238 )));
222 ctx.push(JsStatement::Export(Box::new(JsStatement::Declaration {
223 name: original_name,
224 value: JsExpression::Identifier(name.clone()),
225 is_constant: false,
226 })));
239227 }
240228 _ => {
241229 panic!("Cannot make non-function public");
......@@ -337,10 +325,10 @@ fn translate_statement(ast: &Ast, ctx: &mut TranslateContext) {
337325 }
338326}
339327
340pub fn translate(_ast: Vec<Ast>) -> Result<Vec<JsStatement>> {
328pub fn translate(module: &Module) -> Result<Vec<JsStatement>> {
341329 let mut ctx = TranslateContext::new();
342330
343 for ast in _ast {
331 for ast in module.value.iter() {
344332 translate_statement(&ast, &mut ctx);
345333 }
346334
crates/js_ast/src/types.rs+2-5
......@@ -33,13 +33,10 @@ pub enum JsStatement {
3333 Expression(JsExpression),
3434 Export(Box<JsStatement>),
3535 Return(JsExpression),
36 VariableDeclaration {
37 name: String,
38 value: JsExpression,
39 },
40 ConstantDeclaration {
36 Declaration {
4137 name: String,
4238 value: JsExpression,
39 is_constant: bool,
4340 },
4441 Function {
4542 name: String,
crates/js_printer/src/print_expression.rs+1-1
......@@ -230,7 +230,7 @@ mod tests {
230230 assert_eq!(
231231 print_expression(&JsExpression::Function {
232232 arguments: vec!["a".to_string(), "b".to_string()],
233 value: vec![JsStatement::VariableDeclaration {
233 value: vec![JsStatement::Declaration {
234234 name: "a".to_string(),
235235 value: JsExpression::Number(1.0)
236236 }],
crates/js_printer/src/print_statement.rs+15-6
......@@ -7,11 +7,20 @@ pub fn print_statement(statement: &JsStatement) -> String {
77 JsStatement::Expression(value) => format!("{};", print_expression(value)),
88 JsStatement::Export(value) => format!("export {}", print_statement(value)),
99 JsStatement::Return(value) => format!("return {};", print_expression(value)),
10 JsStatement::VariableDeclaration { name, value } => {
11 format!("let {}={};", name, print_expression(value))
12 }
13 JsStatement::ConstantDeclaration { name, value } => {
14 format!("const {}={};", name, print_expression(value))
10 JsStatement::Declaration {
11 name,
12 value,
13 is_constant,
14 } => {
15 format!(
16 "{} {}={};",
17 match is_constant {
18 true => "const",
19 false => "let",
20 },
21 name,
22 print_expression(value)
23 )
1524 }
1625 JsStatement::Function {
1726 name,
......@@ -66,7 +75,7 @@ mod tests {
6675 #[test]
6776 fn variable_declaration() {
6877 assert_eq!(
69 print_statement(&JsStatement::VariableDeclaration {
78 print_statement(&JsStatement::Declaration {
7079 name: "x".to_string(),
7180 value: JsExpression::Number(1.0),
7281 }),
crates/tokenizer/src/lib.rs+36
......@@ -43,6 +43,42 @@ pub enum Token {
4343 Operator(Operator),
4444}
4545
46impl std::fmt::Display for Token {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 let token = match self {
49 Token::Identifier(_) => "an identifier".to_string(),
50 Token::Number(n) => n.to_string(),
51 Token::String(s) => format!("\"{}\"", s),
52 Token::BuiltIn(_) => "a builtin identifier".to_string(),
53 Token::Comment(_) => "a comment".to_string(),
54 Token::DocComment(_) => "a documentation comment".to_string(),
55 Token::True => "true".to_string(),
56 Token::False => "false".to_string(),
57 Token::Let => "let".to_string(),
58 Token::Var => "var".to_string(),
59 Token::If => "if".to_string(),
60 Token::Else => "else".to_string(),
61 Token::Return => "return".to_string(),
62 Token::Pub => "pub".to_string(),
63 Token::Function => "fn".to_string(),
64 Token::RightArrow => "->".to_string(),
65 Token::Comma => ",".to_string(),
66 Token::OpenParanthesis => "(".to_string(),
67 Token::ClosedParanthesis => ")".to_string(),
68 Token::OpenBracket => "{".to_string(),
69 Token::ClosedBracket => "}".to_string(),
70 Token::Colon => ":".to_string(),
71 Token::Equals => "=".to_string(),
72 Token::Semicolon => ";".to_string(),
73 Token::Operator(o) => o.clone().to_string(),
74 };
75
76 write!(f, "{}", token)
77 }
78}
79
80
81
4682pub fn tokenize(content: String) -> Result<Vec<Token>> {
4783 let mut tokens: Vec<Token> = Vec::new();
4884 let mut chars = content.chars().enumerate().peekable();
examples/basics/control.blight+1-1
......@@ -1,4 +1,4 @@
1let print: any = @raw("console.log");
1let print = @raw("console.log");
22
33let x: bool = true;
44
examples/basics/expressions.blight+1-1
......@@ -7,5 +7,5 @@ let x: int = 5 + {
77 y
88};
99
10let print: any = @raw("console.log");
10let print = @raw("console.log");
1111print(x); // 10
examples/basics/fib.blight+1-1
......@@ -8,5 +8,5 @@ pub fn fib(n: int) -> int {
88 }
99}
1010
11let print: any = @raw("console.log");
11let print = @raw("console.log");
1212print(fib(10));
examples/basics/functions.blight+1-1
......@@ -4,5 +4,5 @@ fn bingus(x: int, y: int) -> int {
44
55let result: int = bingus(10, 25);
66
7let print: any = @raw("console.log");
7let print = @raw("console.log");
88print(result);
examples/basics/operations.blight+1-1
......@@ -1,4 +1,4 @@
11let a: int = 10 - 2 / 4 * 15;
22
3let print: any = @raw("console.log");
3let print = @raw("console.log");
44print(a);
examples/basics/shadowing.blight+1-1
......@@ -1,4 +1,4 @@
1let print: any = @raw("console.log");
1let print = @raw("console.log");
22
33let x: int = 0;
44let x: int = 1;
examples/basics/variables.blight+1-1
......@@ -6,5 +6,5 @@ let a: int = 0;
66let b: float = 0;
77let c: bigint = 0;
88
9let print: any = @raw("console.log");
9let print = @raw("console.log");
1010print(x);
examples/basics/weird.blight+1-1
......@@ -9,6 +9,6 @@ fn bingus(y: bool) -> int {
99 x
1010}
1111
12let print: any = @raw("console.log");
12let print = @raw("console.log");
1313print(bingus(true));
1414print(bingus(false));
examples/interop/deno.blight+1-1
......@@ -1,4 +1,4 @@
1let writeTextFile: any = @raw("Deno.writeTextFile");
1let writeTextFile = @raw("Deno.writeTextFile");
22
33fn x() -> string {
44 "hello"