Skip to content

Commit 4be3a36

Browse files
committed
Implement implicit returns in functions by excluding semicolon
1 parent 728c94c commit 4be3a36

14 files changed

Lines changed: 185 additions & 10 deletions

docs/EXTENDING_LOX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ These are the documented changes to the language/syntax from the original Lox la
66

77
- Support to escape characters in strings: `\n`, `\r`, `\t`, `\"`, `\\`
88
- Function body expressions: `fun sum(a, b) = a + b;`
9+
- Function implicit returns: `fun sum(a, b) { a + b }`
910
- Native Functions
1011
- [ ] `arrSort(array, fn)`
1112
- [ ] `arrMap(array, fn)`

examples/fib.lox

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
fun fib(n) {
22
if (n < 2) return n;
3-
return fib(n - 2) + fib(n - 1);
3+
4+
fib(n - 2) + fib(n - 1)
45
}
56

67
print "Fibonacci";

examples/zoo.lox

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ class Zoo {
1414
this.elephant = 1;
1515
this.fox = 1;
1616
}
17-
ant() { return this.aardvark; }
18-
banana() { return this.baboon; }
19-
tuna() { return this.cat; }
20-
hay() { return this.donkey; }
21-
grass() { return this.elephant; }
22-
mouse() { return this.fox; }
17+
ant() { this.aardvark }
18+
banana() { this.baboon }
19+
tuna() { this.cat }
20+
hay() { this.donkey }
21+
grass() { this.elephant }
22+
mouse() { this.fox }
2323
}
2424

2525
var zoo = Zoo();

src/compiler.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static void endScope();
4949
static void classDeclaration(Scanner *scanner);
5050
static void namedVariable(Scanner *scanner, Token name, bool canAssign);
5151
static void indexValue(Scanner *scanner, bool canAssign);
52+
static void error(const char *message);
5253

5354
Parser parser;
5455
Chunk *compilingChunk;
@@ -152,7 +153,19 @@ static void statement(Scanner *scanner) {
152153
block(scanner);
153154
endScope();
154155
} else {
155-
expressionStatement(scanner);
156+
expression(scanner);
157+
158+
if (match(scanner, TOKEN_SEMICOLON)) {
159+
emitByte(OP_POP);
160+
return;
161+
}
162+
163+
if (current->type != TYPE_SCRIPT && check(TOKEN_RIGHT_BRACE)) {
164+
emitByte(OP_RETURN);
165+
return;
166+
}
167+
168+
error("Expect ';' after expression.");
156169
}
157170
}
158171

tests/assignments/assignment_edge_case.lox.err

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,4 @@
6565
0028 14 OP_NIL
6666
0029 | OP_RETURN
6767
[line 6] Error at '=' (TOKEN_EQUAL): Invalid assignment target.
68-
[line 6] Error at 'c' (TOKEN_IDENTIFIER): Expect ';' after expression.
68+
[line 6] Error at '=' (TOKEN_EQUAL): Expect ';' after expression.

tests/errors/compiler_error_missing_semicolon.lox.err

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,4 @@
6464
0026 | OP_DEFINE_GLOBAL 12 'is_empty'
6565
0028 14 OP_NIL
6666
0029 | OP_RETURN
67-
[line 1] Error at end: Expect ';' after expression.
67+
[line 1] Error at '1' (TOKEN_NUMBER): Expect ';' after expression.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fun sum(a, b) { a + b }
2+
3+
print sum(1, 2);
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
== is ==
2+
0000 1 OP_GET_GLOBAL 0 'typeof'
3+
0002 | OP_GET_LOCAL 1
4+
0004 | OP_CALL 1
5+
0006 | OP_GET_LOCAL 2
6+
0008 | OP_EQUAL
7+
0009 | OP_RETURN
8+
== is_function ==
9+
0000 3 OP_GET_GLOBAL 0 'is'
10+
0002 | OP_GET_LOCAL 1
11+
0004 | OP_CONSTANT 1 'function'
12+
0006 | OP_CALL 2
13+
0008 | OP_RETURN
14+
== is_number ==
15+
0000 5 OP_GET_GLOBAL 0 'is'
16+
0002 | OP_GET_LOCAL 1
17+
0004 | OP_CONSTANT 1 'number'
18+
0006 | OP_CALL 2
19+
0008 | OP_RETURN
20+
== is_string ==
21+
0000 7 OP_GET_GLOBAL 0 'is'
22+
0002 | OP_GET_LOCAL 1
23+
0004 | OP_CONSTANT 1 'string'
24+
0006 | OP_CALL 2
25+
0008 | OP_RETURN
26+
== is_bool ==
27+
0000 9 OP_GET_GLOBAL 0 'is'
28+
0002 | OP_GET_LOCAL 1
29+
0004 | OP_CONSTANT 1 'bool'
30+
0006 | OP_CALL 2
31+
0008 | OP_RETURN
32+
== is_nil ==
33+
0000 11 OP_GET_GLOBAL 0 'is'
34+
0002 | OP_GET_LOCAL 1
35+
0004 | OP_CONSTANT 1 'nil'
36+
0006 | OP_CALL 2
37+
0008 | OP_RETURN
38+
== is_empty ==
39+
0000 13 OP_GET_GLOBAL 0 'is_string'
40+
0002 | OP_GET_LOCAL 1
41+
0004 | OP_CALL 1
42+
0006 | OP_JUMP_IF_FALSE 6 -> 19
43+
0009 | OP_POP
44+
0010 | OP_GET_GLOBAL 1 'len'
45+
0012 | OP_GET_LOCAL 1
46+
0014 | OP_CALL 1
47+
0016 | OP_CONSTANT 2 '0.000000'
48+
0018 | OP_EQUAL
49+
0019 | OP_RETURN
50+
== <script> ==
51+
0000 1 OP_CLOSURE 1 <fn is>
52+
0002 | OP_DEFINE_GLOBAL 0 'is'
53+
0004 3 OP_CLOSURE 3 <fn is_function>
54+
0006 | OP_DEFINE_GLOBAL 2 'is_function'
55+
0008 5 OP_CLOSURE 5 <fn is_number>
56+
0010 | OP_DEFINE_GLOBAL 4 'is_number'
57+
0012 7 OP_CLOSURE 7 <fn is_string>
58+
0014 | OP_DEFINE_GLOBAL 6 'is_string'
59+
0016 9 OP_CLOSURE 9 <fn is_bool>
60+
0018 | OP_DEFINE_GLOBAL 8 'is_bool'
61+
0020 11 OP_CLOSURE 11 <fn is_nil>
62+
0022 | OP_DEFINE_GLOBAL 10 'is_nil'
63+
0024 13 OP_CLOSURE 13 <fn is_empty>
64+
0026 | OP_DEFINE_GLOBAL 12 'is_empty'
65+
0028 14 OP_NIL
66+
0029 | OP_RETURN
67+
== sum ==
68+
0000 1 OP_GET_LOCAL 1
69+
0002 | OP_GET_LOCAL 2
70+
0004 | OP_ADD
71+
0005 | OP_RETURN
72+
== <script> ==
73+
0000 1 OP_CLOSURE 1 <fn sum>
74+
0002 | OP_DEFINE_GLOBAL 0 'sum'
75+
0004 3 OP_GET_GLOBAL 2 'sum'
76+
0006 | OP_CONSTANT 3 '1.000000'
77+
0008 | OP_CONSTANT 4 '2.000000'
78+
0010 | OP_CALL 2
79+
0012 | OP_PRINT
80+
0013 4 OP_NIL
81+
0014 | OP_RETURN
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.000000

0 commit comments

Comments
 (0)