diff --git a/examples/ackermann.sb b/examples/ackermann.sb index c07a96f..8d1437b 100644 --- a/examples/ackermann.sb +++ b/examples/ackermann.sb @@ -4,7 +4,7 @@ fn main() { println(ackermann(m, n)) } -fn ackermann(m int, n int) { +fn ackermann(m: int, n: int) { if m == 0 { return n + 1 } else if n == 0 { diff --git a/examples/fib.sb b/examples/fib.sb index 7f7011a..895c78c 100644 --- a/examples/fib.sb +++ b/examples/fib.sb @@ -3,7 +3,7 @@ fn main() { println(fib(num)) } -fn fib(n int) { +fn fib(n: int) { if 1 >= n { return n } diff --git a/examples/greeter.sb b/examples/greeter.sb index c2597b8..bd72412 100644 --- a/examples/greeter.sb +++ b/examples/greeter.sb @@ -2,6 +2,6 @@ fn main() { println(greet("World")) } -fn greet(name string) { +fn greet(name: string) { return "Hello " + name } diff --git a/examples/playground.sb b/examples/playground.sb index 31265c6..78cfac5 100644 --- a/examples/playground.sb +++ b/examples/playground.sb @@ -1,3 +1,5 @@ -fn main() { - let arr = [1, 4, 2, 5, 3] -} +fn main(n: int) { + if n { + return n + } +} \ No newline at end of file diff --git a/lib/stdio.sb b/lib/stdio.sb index 25fa46e..b86fec7 100644 --- a/lib/stdio.sb +++ b/lib/stdio.sb @@ -1,16 +1,16 @@ // Raw wrapper around _printf builtin function. // Writes the given content to stdout -fn print(msg string) { - _printf(msg) +fn print(arg: string) { + _printf(arg) } // Like print(), but with an extra newline ('\n') character -fn println(msg string) { +fn println(msg: string) { print(msg + "\n") } // Prints the size of an array -fn len(arr int[]) { +fn len(arr: int[]) { let c = 0 while arr[c] { c = c + 1 @@ -21,7 +21,7 @@ fn len(arr int[]) { // Reverses an array // TODO: fix me! -fn rev(arr int[]) { +fn rev(arr: int[]) { let l = len(arr) let new_arr = [] diff --git a/playground.js b/playground.js new file mode 100644 index 0000000..6bfc3a0 --- /dev/null +++ b/playground.js @@ -0,0 +1,38 @@ +/* START builtins */ + +function _printf(msg) { + process.stdout.write(msg); +} + +/* END builtins */ +function print(msg){ +_printf(msg); +} +function println(msg){ +print(msg + "\n"); +} +function len(arr){ +var c = 0; +while (arr[c]) { +c = c + 1; +} +; +return c; +} +function rev(arr){ +var l = len(arr); +var new_arr = []; +var i = 0; +var j = l; +while (i < l) { +new_arr[i] = arr[j]; +i = i - 1; +j = j - 1; +} +; +return new_arr; +} +function main(){ +var arr = [1, 4, 2, 5, 3]; +} +main(); \ No newline at end of file diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 3da70c3..5a65d5e 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -161,6 +161,10 @@ pub fn first_token(input: &str, pos: &mut Position) -> Token { pub fn is_whitespace(c: char) -> bool { match c { ' ' | '\n' | '\r' | '\t' => true, + '\u{00A0}' => { + dbg!("Non-standard unicode character found: '\u{00A0}'"); + true + } _ => false, } } diff --git a/src/main.rs b/src/main.rs index b44b359..03f0b03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,7 +67,6 @@ fn main() -> Result<(), String> { let tokens = lexer::tokenize(&contents); let program = parser::parse(tokens, Some(contents))?; - dbg!(&program); let output = generator::js::JsGenerator::generate(program); let mut file = std::fs::File::create(out_file).expect("create failed"); diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 4fce8ed..b9e04e2 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -80,10 +80,12 @@ impl Parser { TokenKind::Comma => { continue; } - TokenKind::Identifier(name) => args.push(Variable { - name: name, - ty: Some(self.parse_type()?), - }), + TokenKind::Identifier(name) => { + args.push(Variable { + name: name, + ty: Some(self.parse_type()?), + }); + } _ => return Err(self.make_error(TokenKind::Identifier("Argument".into()), next)), } } @@ -92,13 +94,14 @@ impl Parser { } fn parse_type(&mut self) -> Result { - let next = self.next()?; + self.match_token(TokenKind::Colon)?; + let next = self.peek()?; let typ = match next.kind { - TokenKind::Identifier(t) => Type::try_from(t), + TokenKind::Identifier(_) => Type::try_from(self.next()?.raw), _ => Err("Expected type".into()), }?; if let Ok(_) = self.peek_token(TokenKind::SquareBraceOpen) { - self.drop(1); + self.match_token(TokenKind::SquareBraceOpen)?; self.match_token(TokenKind::SquareBraceClose)?; Ok(Type::Array(Box::new(typ))) } else { @@ -242,16 +245,20 @@ impl Parser { fn parse_array(&mut self) -> Result { let mut elements = Vec::new(); loop { - let next = self.next()?; + let next = self.peek()?; match next.kind { + TokenKind::SquareBraceClose => {} TokenKind::Literal(Value::Int) => { - let value = next.raw.parse::().map_err(|e| e.to_string())?; + let value = self.next()?.raw.parse::().map_err(|e| e.to_string())?; elements.push(Expression::Int(value)); } TokenKind::Literal(Value::Str) => { - elements.push(Expression::Str(next.raw)); + elements.push(Expression::Str(self.next()?.raw)); + } + _ => { + let n = self.next()?; + return Err(self.make_error(TokenKind::Identifier("Argument".into()), n)); } - _ => return Err(self.make_error(TokenKind::Identifier("Argument".into()), next)), }; if self.peek_token(TokenKind::SquareBraceClose).is_ok() { break; @@ -347,17 +354,14 @@ impl Parser { fn parse_declare(&mut self) -> Result { self.match_keyword(Keyword::Let)?; - match (self.next()?.kind, self.peek()?.kind) { - (TokenKind::Identifier(name), TokenKind::SemiColon) => { - Ok(Statement::Declare(Variable { name, ty: None }, None)) - } - (TokenKind::Identifier(name), TokenKind::Assign) => { - self.drop(1); - let exp = self.parse_expression().ok(); - Ok(Statement::Declare(Variable { name, ty: None }, exp)) - } - other => Err(format!("Expected identifier, found {:?}", other)), - } + let name = self.match_identifier()?; + let ty = match self.peek()?.kind { + TokenKind::Colon => Some(self.parse_type()?), + _ => None, + }; + self.match_token(TokenKind::Assign)?; + let expr = self.parse_expression()?; + Ok(Statement::Declare(Variable { name, ty }, Some(expr))) } fn parse_assignent(&mut self, name: Option) -> Result { diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 74c0c53..baf3258 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -120,7 +120,7 @@ fn test_parse_variable_declaration_added() { #[test] fn test_parse_function_with_args() { let raw = " - fn main(foo int) { + fn main(foo: int) { return foo } "; @@ -132,7 +132,7 @@ fn test_parse_function_with_args() { #[test] fn test_parse_function_call() { let raw = " - fn main(foo int) { + fn main(foo: int) { foo() } @@ -184,7 +184,7 @@ fn test_parse_nexted_function_call() { fib(fib(2), 2) } - fn fib(n int) { + fn fib(n: int) { return 2 } "; @@ -244,7 +244,7 @@ fn test_parse_compound_ops_with_strings() { #[test] fn test_parse_compound_ops_with_identifier() { let raw = " - fn main(n int) { + fn main(n: int) { return 2 * n } "; @@ -256,7 +256,7 @@ fn test_parse_compound_ops_with_identifier() { #[test] fn test_parse_compound_ops_with_identifier_first() { let raw = " - fn main(n int) { + fn main(n: int) { return n * 2 } "; @@ -268,7 +268,7 @@ fn test_parse_compound_ops_with_identifier_first() { #[test] fn test_parse_compound_ops_return() { let raw = " - fn main(n int) { + fn main(n: int) { return 2 * n } "; @@ -280,7 +280,7 @@ fn test_parse_compound_ops_return() { #[test] fn test_parse_basic_conditional() { let raw = " - fn main(n int) { + fn main(n: int) { if n { return n } @@ -294,7 +294,7 @@ fn test_parse_basic_conditional() { #[test] fn test_parse_basic_conditional_with_multiple_statements() { let raw = " - fn main(n int) { + fn main(n: int) { if n { let x = 2 * n return x @@ -309,7 +309,7 @@ fn test_parse_basic_conditional_with_multiple_statements() { #[test] fn test_parse_conditional_else_if_branch() { let raw = " - fn main(n int) { + fn main(n: int) { if n > 10 { let x = 2 * n return x @@ -326,7 +326,7 @@ fn test_parse_conditional_else_if_branch() { #[test] fn test_parse_conditional_multiple_else_if_branch_branches() { let raw = " - fn main(n int) { + fn main(n: int) { if n > 10 { let x = 2 * n return x @@ -345,7 +345,7 @@ fn test_parse_conditional_multiple_else_if_branch_branches() { #[test] fn test_parse_conditional_else_branch() { let raw = " - fn main(n int) { + fn main(n: int) { if n > 10 { let x = 2 * n return x @@ -362,7 +362,7 @@ fn test_parse_conditional_else_branch() { #[test] fn test_parse_conditional_elseif_else_branch() { let raw = " - fn main(n int) { + fn main(n: int) { if n > 10 { let x = 2 * n return x @@ -383,7 +383,7 @@ fn test_parse_conditional_elseif_else_branch() { #[test] fn test_int_array() { let raw = " - fn main(n int) { + fn main() { let arr = [1, 2, 3] return arr } @@ -396,7 +396,7 @@ fn test_int_array() { #[test] fn test_string_array() { let raw = " - fn main(n int) { + fn main(n:int) { return [\"Foo\", \"Bar\", \"Baz\"] } "; @@ -533,7 +533,7 @@ fn test_uninitialized_variables() { #[test] fn test_function_call_math() { let raw = " - fn main(m int) { + fn main(m: int) { main(m - 1) } "; @@ -545,7 +545,7 @@ fn test_function_call_math() { #[test] fn test_function_multiple_args() { let raw = " - fn main(m int, n int) { + fn main(m: int, n: int) { main(m, n) } "; @@ -565,3 +565,29 @@ fn test_array_position_assignment() { let tree = parse(tokens, Some(raw.to_string())); assert!(tree.is_ok()) } + +#[test] +fn test_typed_declare() { + let raw = " + fn main() { + let x = 5 + let y: int = 1 + let z: bool = false + } + "; + let tokens = tokenize(raw); + let tree = parse(tokens, Some(raw.to_string())); + assert!(tree.is_ok()) +} + +#[test] +fn test_no_function_args_without_type() { + let raw = " + fn main(x) { + return n + } + "; + let tokens = tokenize(raw); + let tree = parse(tokens, Some(raw.to_string())); + assert!(tree.is_err()) +}