Browse Source

Add optional types for declares

github-actions
Garrit Franke 3 years ago
parent
commit
64b43c7c0c
  1. 2
      examples/ackermann.sb
  2. 2
      examples/fib.sb
  3. 2
      examples/greeter.sb
  4. 8
      examples/playground.sb
  5. 10
      lib/stdio.sb
  6. 38
      playground.js
  7. 4
      src/lexer/mod.rs
  8. 1
      src/main.rs
  9. 48
      src/parser/rules.rs
  10. 58
      src/parser/tests.rs

2
examples/ackermann.sb

@ -4,7 +4,7 @@ fn main() {
println(ackermann(m, n)) println(ackermann(m, n))
} }
fn ackermann(m int, n int) { fn ackermann(m: int, n: int) {
if m == 0 { if m == 0 {
return n + 1 return n + 1
} else if n == 0 { } else if n == 0 {

2
examples/fib.sb

@ -3,7 +3,7 @@ fn main() {
println(fib(num)) println(fib(num))
} }
fn fib(n int) { fn fib(n: int) {
if 1 >= n { if 1 >= n {
return n return n
} }

2
examples/greeter.sb

@ -2,6 +2,6 @@ fn main() {
println(greet("World")) println(greet("World"))
} }
fn greet(name string) { fn greet(name: string) {
return "Hello " + name return "Hello " + name
} }

8
examples/playground.sb

@ -1,3 +1,5 @@
fn main() { fn main(n: int) {
let arr = [1, 4, 2, 5, 3] if n {
} return n
}
}

10
lib/stdio.sb

@ -1,16 +1,16 @@
// Raw wrapper around _printf builtin function. // Raw wrapper around _printf builtin function.
// Writes the given content to stdout // Writes the given content to stdout
fn print(msg string) { fn print(arg: string) {
_printf(msg) _printf(arg)
} }
// Like print(), but with an extra newline ('\n') character // Like print(), but with an extra newline ('\n') character
fn println(msg string) { fn println(msg: string) {
print(msg + "\n") print(msg + "\n")
} }
// Prints the size of an array // Prints the size of an array
fn len(arr int[]) { fn len(arr: int[]) {
let c = 0 let c = 0
while arr[c] { while arr[c] {
c = c + 1 c = c + 1
@ -21,7 +21,7 @@ fn len(arr int[]) {
// Reverses an array // Reverses an array
// TODO: fix me! // TODO: fix me!
fn rev(arr int[]) { fn rev(arr: int[]) {
let l = len(arr) let l = len(arr)
let new_arr = [] let new_arr = []

38
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();

4
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 { pub fn is_whitespace(c: char) -> bool {
match c { match c {
' ' | '\n' | '\r' | '\t' => true, ' ' | '\n' | '\r' | '\t' => true,
'\u{00A0}' => {
dbg!("Non-standard unicode character found: '\u{00A0}'");
true
}
_ => false, _ => false,
} }
} }

1
src/main.rs

@ -67,7 +67,6 @@ fn main() -> Result<(), String> {
let tokens = lexer::tokenize(&contents); let tokens = lexer::tokenize(&contents);
let program = parser::parse(tokens, Some(contents))?; let program = parser::parse(tokens, Some(contents))?;
dbg!(&program);
let output = generator::js::JsGenerator::generate(program); let output = generator::js::JsGenerator::generate(program);
let mut file = std::fs::File::create(out_file).expect("create failed"); let mut file = std::fs::File::create(out_file).expect("create failed");

48
src/parser/rules.rs

@ -80,10 +80,12 @@ impl Parser {
TokenKind::Comma => { TokenKind::Comma => {
continue; continue;
} }
TokenKind::Identifier(name) => args.push(Variable { TokenKind::Identifier(name) => {
name: name, args.push(Variable {
ty: Some(self.parse_type()?), name: name,
}), ty: Some(self.parse_type()?),
});
}
_ => return Err(self.make_error(TokenKind::Identifier("Argument".into()), next)), _ => return Err(self.make_error(TokenKind::Identifier("Argument".into()), next)),
} }
} }
@ -92,13 +94,14 @@ impl Parser {
} }
fn parse_type(&mut self) -> Result<Type, String> { fn parse_type(&mut self) -> Result<Type, String> {
let next = self.next()?; self.match_token(TokenKind::Colon)?;
let next = self.peek()?;
let typ = match next.kind { let typ = match next.kind {
TokenKind::Identifier(t) => Type::try_from(t), TokenKind::Identifier(_) => Type::try_from(self.next()?.raw),
_ => Err("Expected type".into()), _ => Err("Expected type".into()),
}?; }?;
if let Ok(_) = self.peek_token(TokenKind::SquareBraceOpen) { if let Ok(_) = self.peek_token(TokenKind::SquareBraceOpen) {
self.drop(1); self.match_token(TokenKind::SquareBraceOpen)?;
self.match_token(TokenKind::SquareBraceClose)?; self.match_token(TokenKind::SquareBraceClose)?;
Ok(Type::Array(Box::new(typ))) Ok(Type::Array(Box::new(typ)))
} else { } else {
@ -242,16 +245,20 @@ impl Parser {
fn parse_array(&mut self) -> Result<Expression, String> { fn parse_array(&mut self) -> Result<Expression, String> {
let mut elements = Vec::new(); let mut elements = Vec::new();
loop { loop {
let next = self.next()?; let next = self.peek()?;
match next.kind { match next.kind {
TokenKind::SquareBraceClose => {}
TokenKind::Literal(Value::Int) => { TokenKind::Literal(Value::Int) => {
let value = next.raw.parse::<u32>().map_err(|e| e.to_string())?; let value = self.next()?.raw.parse::<u32>().map_err(|e| e.to_string())?;
elements.push(Expression::Int(value)); elements.push(Expression::Int(value));
} }
TokenKind::Literal(Value::Str) => { 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() { if self.peek_token(TokenKind::SquareBraceClose).is_ok() {
break; break;
@ -347,17 +354,14 @@ impl Parser {
fn parse_declare(&mut self) -> Result<Statement, String> { fn parse_declare(&mut self) -> Result<Statement, String> {
self.match_keyword(Keyword::Let)?; self.match_keyword(Keyword::Let)?;
match (self.next()?.kind, self.peek()?.kind) { let name = self.match_identifier()?;
(TokenKind::Identifier(name), TokenKind::SemiColon) => { let ty = match self.peek()?.kind {
Ok(Statement::Declare(Variable { name, ty: None }, None)) TokenKind::Colon => Some(self.parse_type()?),
} _ => None,
(TokenKind::Identifier(name), TokenKind::Assign) => { };
self.drop(1); self.match_token(TokenKind::Assign)?;
let exp = self.parse_expression().ok(); let expr = self.parse_expression()?;
Ok(Statement::Declare(Variable { name, ty: None }, exp)) Ok(Statement::Declare(Variable { name, ty }, Some(expr)))
}
other => Err(format!("Expected identifier, found {:?}", other)),
}
} }
fn parse_assignent(&mut self, name: Option<Expression>) -> Result<Statement, String> { fn parse_assignent(&mut self, name: Option<Expression>) -> Result<Statement, String> {

58
src/parser/tests.rs

@ -120,7 +120,7 @@ fn test_parse_variable_declaration_added() {
#[test] #[test]
fn test_parse_function_with_args() { fn test_parse_function_with_args() {
let raw = " let raw = "
fn main(foo int) { fn main(foo: int) {
return foo return foo
} }
"; ";
@ -132,7 +132,7 @@ fn test_parse_function_with_args() {
#[test] #[test]
fn test_parse_function_call() { fn test_parse_function_call() {
let raw = " let raw = "
fn main(foo int) { fn main(foo: int) {
foo() foo()
} }
@ -184,7 +184,7 @@ fn test_parse_nexted_function_call() {
fib(fib(2), 2) fib(fib(2), 2)
} }
fn fib(n int) { fn fib(n: int) {
return 2 return 2
} }
"; ";
@ -244,7 +244,7 @@ fn test_parse_compound_ops_with_strings() {
#[test] #[test]
fn test_parse_compound_ops_with_identifier() { fn test_parse_compound_ops_with_identifier() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
return 2 * n return 2 * n
} }
"; ";
@ -256,7 +256,7 @@ fn test_parse_compound_ops_with_identifier() {
#[test] #[test]
fn test_parse_compound_ops_with_identifier_first() { fn test_parse_compound_ops_with_identifier_first() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
return n * 2 return n * 2
} }
"; ";
@ -268,7 +268,7 @@ fn test_parse_compound_ops_with_identifier_first() {
#[test] #[test]
fn test_parse_compound_ops_return() { fn test_parse_compound_ops_return() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
return 2 * n return 2 * n
} }
"; ";
@ -280,7 +280,7 @@ fn test_parse_compound_ops_return() {
#[test] #[test]
fn test_parse_basic_conditional() { fn test_parse_basic_conditional() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n { if n {
return n return n
} }
@ -294,7 +294,7 @@ fn test_parse_basic_conditional() {
#[test] #[test]
fn test_parse_basic_conditional_with_multiple_statements() { fn test_parse_basic_conditional_with_multiple_statements() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n { if n {
let x = 2 * n let x = 2 * n
return x return x
@ -309,7 +309,7 @@ fn test_parse_basic_conditional_with_multiple_statements() {
#[test] #[test]
fn test_parse_conditional_else_if_branch() { fn test_parse_conditional_else_if_branch() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n > 10 { if n > 10 {
let x = 2 * n let x = 2 * n
return x return x
@ -326,7 +326,7 @@ fn test_parse_conditional_else_if_branch() {
#[test] #[test]
fn test_parse_conditional_multiple_else_if_branch_branches() { fn test_parse_conditional_multiple_else_if_branch_branches() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n > 10 { if n > 10 {
let x = 2 * n let x = 2 * n
return x return x
@ -345,7 +345,7 @@ fn test_parse_conditional_multiple_else_if_branch_branches() {
#[test] #[test]
fn test_parse_conditional_else_branch() { fn test_parse_conditional_else_branch() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n > 10 { if n > 10 {
let x = 2 * n let x = 2 * n
return x return x
@ -362,7 +362,7 @@ fn test_parse_conditional_else_branch() {
#[test] #[test]
fn test_parse_conditional_elseif_else_branch() { fn test_parse_conditional_elseif_else_branch() {
let raw = " let raw = "
fn main(n int) { fn main(n: int) {
if n > 10 { if n > 10 {
let x = 2 * n let x = 2 * n
return x return x
@ -383,7 +383,7 @@ fn test_parse_conditional_elseif_else_branch() {
#[test] #[test]
fn test_int_array() { fn test_int_array() {
let raw = " let raw = "
fn main(n int) { fn main() {
let arr = [1, 2, 3] let arr = [1, 2, 3]
return arr return arr
} }
@ -396,7 +396,7 @@ fn test_int_array() {
#[test] #[test]
fn test_string_array() { fn test_string_array() {
let raw = " let raw = "
fn main(n int) { fn main(n:int) {
return [\"Foo\", \"Bar\", \"Baz\"] return [\"Foo\", \"Bar\", \"Baz\"]
} }
"; ";
@ -533,7 +533,7 @@ fn test_uninitialized_variables() {
#[test] #[test]
fn test_function_call_math() { fn test_function_call_math() {
let raw = " let raw = "
fn main(m int) { fn main(m: int) {
main(m - 1) main(m - 1)
} }
"; ";
@ -545,7 +545,7 @@ fn test_function_call_math() {
#[test] #[test]
fn test_function_multiple_args() { fn test_function_multiple_args() {
let raw = " let raw = "
fn main(m int, n int) { fn main(m: int, n: int) {
main(m, n) main(m, n)
} }
"; ";
@ -565,3 +565,29 @@ fn test_array_position_assignment() {
let tree = parse(tokens, Some(raw.to_string())); let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok()) 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())
}

Loading…
Cancel
Save