Skip to content

Commit e60ade5

Browse files
authored
Merge pull request #55 from leonidas1712/type-check
feat: type checking for functions
2 parents 50d9b30 + 7a063b7 commit e60ade5

17 files changed

+567
-128
lines changed

compiler/oxidate/src/tests.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ mod tests {
1313
fn exp_compile_str(inp: &str) -> Vec<ByteCode> {
1414
let parser = Parser::new_from_string(inp);
1515
let parsed = parser.parse().expect("Should parse");
16+
dbg!(inp);
1617
dbg!("parsed:", &parsed);
1718
let comp = Compiler::new(parsed);
1819
comp.compile().expect("Should compile")
1920
}
2021

2122
fn test_comp(inp: &str, exp: Vec<ByteCode>) {
2223
let res = exp_compile_str(inp);
23-
dbg!(&res);
24+
// dbg!(&res[28]);
2425
assert_eq!(res, exp);
2526
}
2627

example/concurrency-01.rst

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Expected: prints in order
2+
13
fn loop_and_print(x: int) {
24
let count = 0;
35

@@ -12,6 +14,8 @@ fn loop_and_print(x: int) {
1214
}
1315
}
1416

17+
print("Spawning 3 threads");
18+
1519
let thread_id_1 = spawn loop_and_print(1);
1620
let thread_id_2 = spawn loop_and_print(2);
1721
let thread_id_3 = spawn loop_and_print(3);
@@ -20,4 +24,4 @@ join thread_id_3;
2024
join thread_id_2;
2125
join thread_id_1;
2226

23-
println(true);
27+
println("Done");

example/concurrency-03.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// Expected: inconsistent count on each run due to race on count
2-
// When running with a small quantum e.g 1
1+
// Expected: count != 3000 on each run, though we want 3000
32

43
let count = 0;
54

example/concurrency-04.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Expected: count = 3000 on each run
22

33
let count = 0;
4-
let sem = sem_create();
4+
let sem : sem = sem_create();
55

66
fn increment(times: int) {
77
let i = 0;

example/garbage-collection-02.rst

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// Compile untyped: hof type annotation not added yet
2-
fn higher_order(x) {
3-
fn g(y) {
1+
fn higher_order(x: int) -> fn(int) -> int {
2+
fn g(y:int) -> int {
43
x + y
54
}
65

example/higher-order-fn-01.rst

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
// Compile untyped: hof type annotation not added yet
2-
3-
fn f(x) {
1+
fn f(x: int) -> fn(int) -> int {
42
let z = 3;
5-
fn g(y) {
3+
fn g(y: int) -> int {
64
return x + y + z;
75
}
86

97
g
108
}
119

12-
let hof = f(2);
10+
// try uncommenting this line to get type error when compiling
11+
// let hof : fn(int) -> bool = f(2);
12+
13+
let hof : fn(int) -> int = f(2);
1314

15+
// Expected: 9
1416
hof(4)

example/loop-04.rst

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// Doesn't do anything in particular, I asked ChatGPT to generate this and verified
2-
// by converting to Rust
3-
41
let count = 0;
52
let x = 0;
63

example/simple-spawn.rst

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
fn func() {
2-
let j = 500;
3-
loop j < 600 {
4-
println(j);
2+
let j = 0;
3+
loop j < 100 {
4+
println("in func");
55
j = j + 1;
66
}
7+
8+
println("func is done");
79
}
810

911

1012

1113
let tid = spawn func();
1214

1315
let i = 0;
14-
loop i < 100 {
15-
println(i);
16+
loop i < 200 {
17+
println("in main");
1618
i = i + 1;
1719
}
1820

1921
// Uncomment to ensure func finishes before main
2022
//join tid;
23+
24+
println("main is done");

src/parser/src/fn_decl.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<'inp> Parser<'inp> {
6262
param_ty.replace(ty);
6363

6464
// to go past last token of type_ann, so peek is at comma or close paren
65-
self.advance();
65+
// self.advance();
6666
}
6767

6868
// Comma or CloseParen
@@ -98,7 +98,7 @@ impl<'inp> Parser<'inp> {
9898
if self.consume_opt_token_type(Token::FnDeclReturn) {
9999
// peek is now at type_ann first token
100100
let ret_ty_ann = self.parse_type_annotation()?;
101-
self.advance(); // go past last token of ty_ann
101+
// self.advance(); // go past last token of ty_ann
102102

103103
ret_ty = ret_ty_ann;
104104
}
@@ -426,4 +426,21 @@ mod tests {
426426
"fn fac (n:int) -> int { if (n==0) { return 1; };return (n*fac((n-1))); };",
427427
);
428428
}
429+
430+
#[test]
431+
fn test_parse_fn_decl_hof_ret() {
432+
let t = r"
433+
fn adder(x : int) -> fn(int) -> bool {
434+
fn f(y:int) -> bool {
435+
x+y > 0
436+
}
437+
438+
adder
439+
}
440+
";
441+
test_parse(
442+
t,
443+
"fn adder (x:int) -> fn(int) -> bool { fn f (y:int) -> bool { ((x+y)>0) };adder };",
444+
);
445+
}
429446
}

src/parser/src/let_stmt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'inp> Parser<'inp> {
2525
type_ann.replace(ty);
2626

2727
// call advance so peek is at equals
28-
self.advance();
28+
// self.advance();
2929
}
3030

3131
self.consume_token_type(Token::Eq, "Expected '='")?;

src/parser/src/lib.rs

+2-67
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod ident;
1010
pub mod if_else;
1111
pub mod let_stmt;
1212
pub mod parse_loop;
13+
pub mod parse_type_ann;
1314
pub mod seq;
1415
pub mod structs;
1516

@@ -135,7 +136,7 @@ impl<'inp> Parser<'inp> {
135136
fn expect_token_for_type_ann(token: Option<&Result<Token, ()>>) -> Result<(), ParseError> {
136137
if let Some(Ok(tok)) = token {
137138
match tok {
138-
Token::Ident(_) | Token::OpenParen => Ok(()),
139+
Token::Ident(_) | Token::OpenParen | Token::Fn => Ok(()),
139140
_ => {
140141
let e = format!(
141142
"Expected identifier or '(' for type annotation, got '{}'",
@@ -150,39 +151,6 @@ impl<'inp> Parser<'inp> {
150151
))
151152
}
152153
}
153-
154-
/// Parse and return type annotation. Expect lexer.peek() to be at Colon before call
155-
// Should only consume tokens belonging to the annotation, starting peek at first token and ending
156-
// peek at the last token of the annotation
157-
fn parse_type_annotation(&mut self) -> Result<Type, ParseError> {
158-
// self.consume_token_type(Token::Colon, "Expected a colon")?;
159-
// expect_token_body!(self.lexer.peek(), Ident, "identifier")?;
160-
Parser::expect_token_for_type_ann(self.lexer.peek())?;
161-
162-
// if ident, get the string and try to convert type. else, handle specially
163-
let peek = self
164-
.lexer
165-
.peek()
166-
.unwrap()
167-
.to_owned()
168-
.expect("Lexer should not fail"); // would have erred earlier
169-
170-
let type_ann = match peek {
171-
Token::Ident(id) => Type::from_string(&id),
172-
Token::OpenParen => {
173-
self.advance();
174-
if let Some(Ok(Token::CloseParen)) = self.lexer.peek() {
175-
Ok(Type::Unit)
176-
} else {
177-
Err(ParseError::new("Expected '()' for unit type annotation"))
178-
}
179-
}
180-
_ => unreachable!(),
181-
}?;
182-
183-
Ok(type_ann)
184-
}
185-
186154
/* Precedence */
187155

188156
// Return (left bp, right bp)
@@ -384,39 +352,6 @@ mod tests {
384352
);
385353
}
386354

387-
#[test]
388-
fn test_parse_type_annotations() {
389-
test_parse("let x : int = 2;", "let x : int = 2;");
390-
test_parse("let x : bool = true;", "let x : bool = true;");
391-
test_parse("let x : float = true;", "let x : float = true;");
392-
test_parse("let x : () = true;", "let x : () = true;");
393-
}
394-
395-
#[test]
396-
fn test_parse_type_annotations_errs() {
397-
// test_parse("let x : int = 2;", "");
398-
test_parse_err(
399-
"let x : let ",
400-
"Expected identifier or '(' for type annotation, got 'let'",
401-
true,
402-
);
403-
test_parse_err(
404-
"let x : 2 ",
405-
"Expected identifier or '(' for type annotation, got '2'",
406-
true,
407-
);
408-
test_parse_err(
409-
"let x : ",
410-
"Expected identifier or '(' for type annotation, got end of input",
411-
true,
412-
);
413-
test_parse_err(
414-
"let x : (2 ",
415-
"Expected '()' for unit type annotation",
416-
true,
417-
);
418-
}
419-
420355
#[test]
421356
fn test_parse_concurrency() {
422357
let t = r"

0 commit comments

Comments
 (0)