Browse Source

Add optional types for declares

github-actions
Garrit Franke 2 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))
}
fn ackermann(m int, n int) {
fn ackermann(m: int, n: int) {
if m == 0 {
return n + 1
} else if n == 0 {

2
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
}

2
examples/greeter.sb

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

8
examples/playground.sb

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

10
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 = []

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

1
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");

48
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<Type, String> {
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<Expression, String> {
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::<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));
}
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<Statement, String> {
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<Expression>) -> Result<Statement, String> {

58
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())
}

Loading…
Cancel
Save