Skip to content

Commit

Permalink
Let in expressions (#1130)
Browse files Browse the repository at this point in the history
Enhancements:
- Allow variables to be defined within expressions with `let` `in` (see #1126)
  • Loading branch information
degory authored Mar 19, 2024
1 parent 73d7dc8 commit fd6e084
Show file tree
Hide file tree
Showing 62 changed files with 581 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]
},
"ghul.compiler": {
"version": "0.8.23",
"version": "0.8.24",
"commands": [
"ghul-compiler"
]
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.8.24-alpha.12</Version>
<Version>0.8.25-alpha.2</Version>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>
<ItemGroup>
Expand Down
23 changes: 23 additions & 0 deletions integration-tests/execution/let-in-1/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run test",
"command": "dotnet ghul-test \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "Capture test expectation",
"command": "../../../tasks/capture.sh \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
Empty file.
6 changes: 6 additions & 0 deletions integration-tests/execution/let-in-1/ghul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compiler": "../../../bin/Release/net8.0/ghul",
"source": [
"."
]
}
1 change: 1 addition & 0 deletions integration-tests/execution/let-in-1/ghulflags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--dotnet
Empty file.
13 changes: 13 additions & 0 deletions integration-tests/execution/let-in-1/run.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
simple_expression_body(5) = 10
simple_expression_body((5, 6)) = 11
fib(0) = 0
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(5) = 5
if_expression_condition_1(5) = 5 * 2 more than 10
if_expression_condition_2(5, 6) = 5 * 2 and 6 * 2 more than 10
generator_1().take(5).to_list() = 0, 1, 2, 3, 4
generator_fibonacci().take(5).to_list() = 0, 1, 1, 2, 3
generator_factorial().take(5).to_list() = 1, 2, 6, 24, 120
115 changes: 115 additions & 0 deletions integration-tests/execution/let-in-1/test.ghul
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use IO.Std.write_line;

entry() is
write_line("simple_expression_body(5) = " + simple_expression_body_1(5)); // 10
write_line("simple_expression_body((5, 6)) = " + simple_expression_body_2((5, 6))); // 11
recursive_anonymous_function();

write_line("if_expression_condition_1(5) = " + if_expression_condition_1(5)); // 5 * 2 less than 10
write_line("if_expression_condition_2(5, 6) = " + if_expression_condition_2(5, 6)); // 5 * 2 less than 10

write_line("generator_1().take(5).to_list() = " + generator_incremental() | .take(5)); // [0, 1, 2, 3, 4]
write_line("generator_fibonacci().take(5).to_list() = " + generator_fibonacci() | .take(5)); // [0, 1, 1, 2, 3]
write_line("generator_factorial().take(5).to_list() = " + generator_factorial() | .take(5)); // [1, 1, 2, 6, 24]
si

simple_expression_body_1(i: int) -> int =>
let times_2 = i * 2
in times_2;

simple_expression_body_2(i: (int, int)) -> int =>
let (a, b) = i
in a + b;

recursive_anonymous_function() is
let fib = (n: int) -> int rec =>
let fib = rec in
if n < 2 then
n
else
fib(n - 1) + fib(n - 2);
fi;

for (i, f) in (0..6) | .map(i => fib(i)) .index() do
write_line("fib(" + i + ") = " + f);
od
si

generator_incremental() -> Collections.Iterable[int] =>
generate(0,
(i: int) =>
let next = i + 1 in (next, i));

generator_fibonacci() -> Collections.Iterable[int] =>
generate((0, 1),
(state: (int, int)) =>
let
(a, b) = state,
next = (b, a + b)
in (next, a));

generator_factorial() -> Collections.Iterable[int] =>
generate((1, 1),
(state: (int, int)) =>
let
(i, f) = state,
next = (i + 1, f * (i + 1))
in (next, f));

if_expression_condition_1(i: int) -> string =>
if
let x = i * 2 in x < 10
then
"{i} * 2 less than 10"
else
"{i} * 2 more than 10"
fi;

if_expression_condition_2(i: int, j: int) -> string =>
if
let x = i * 2 in x < 10
then
"{i} * 2 less than 10"
elif
let y = j * 2 in y < 10
then
"{j} * 2 less than 10"
else
"{i} * 2 and {j} * 2 more than 10"
fi;


class GENERATOR[T, S]: Collections.Iterator[T], Collections.Iterable[T] is
current: T;
iterator: Collections.Iterator[T] => self;

_initial: S;
_state: S;
_generator: S -> (S, T); // given the current state, return the next state and the current value

init(initial: S, generator: S -> (S, T)) is
_initial = initial;
_generator = generator;
reset();
si

init() is
reset();
si

move_next() -> bool is
(_state, current) = _generator(_state);
return true;
si

reset() is
_state = _initial;
si

dispose() is
si
si

// generator constructor helper so we don't have to specify types
generate[T, S](initial: S, generator: S -> (S, T)) -> GENERATOR[T, S] =>
new GENERATOR[T, S](initial, generator);
Empty file.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 11,37..11,39: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found []
test.ghul: 11,37..11,39: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found []
test.ghul: 11,37..11,39: error: syntax error: expected ; but found []
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 15,37..15,39: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found []
test.ghul: 15,37..15,39: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found []
test.ghul: 15,37..15,39: error: syntax error: expected ; but found []
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-call-1/err.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
test.ghul: 7,13..7,17: error: symbol not found: blah
test.ghul: 8,9..8,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 8,9..8,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 8,9..8,11: error: in secondary expression: expected ) but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-enum-6/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 8,1..8,2: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 8,1..8,2: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-for-10/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 2,14..2,16: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found do
test.ghul: 2,14..2,16: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found do
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-for-3/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 4,1..4,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 4,1..4,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-for-4/err.expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 3,1..3,3: error: in for statement: expected do but found si
test.ghul: 3,1..3,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 3,1..3,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-if-1/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 8,9..8,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 8,9..8,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
23 changes: 23 additions & 0 deletions integration-tests/parse/incomplete-let-in-1/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run test",
"command": "dotnet ghul-test \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "Capture test expectation",
"command": "../../../tasks/capture.sh \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
2 changes: 2 additions & 0 deletions integration-tests/parse/incomplete-let-in-1/err.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test.ghul: 10,5..10,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 10,5..10,7: error: syntax error: expected ; but found si
1 change: 1 addition & 0 deletions integration-tests/parse/incomplete-let-in-1/fail.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

6 changes: 6 additions & 0 deletions integration-tests/parse/incomplete-let-in-1/ghul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compiler": "dotnet ../../../publish/ghul.dll",
"source": [
"."
]
}
1 change: 1 addition & 0 deletions integration-tests/parse/incomplete-let-in-1/ghulflags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--type-check
Empty file.
17 changes: 17 additions & 0 deletions integration-tests/parse/incomplete-let-in-1/test.ghul
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Test.ParseLetIn is
use Collections;

class TestA is
test_simple() -> int =>
let
x = new D()
in

si

class D is
value: int => 1234;
init() is
si
si
si
Empty file.
23 changes: 23 additions & 0 deletions integration-tests/parse/incomplete-let-in-2/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run test",
"command": "dotnet ghul-test \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "Capture test expectation",
"command": "../../../tasks/capture.sh \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
3 changes: 3 additions & 0 deletions integration-tests/parse/incomplete-let-in-2/err.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test.ghul: 8,5..8,7: error: in variable: expected ( or identifier but found si
test.ghul: 8,5..8,7: error: syntax error: expected ; but found si
test.ghul: 8,5..8,7: error: syntax error: expected in but found si
1 change: 1 addition & 0 deletions integration-tests/parse/incomplete-let-in-2/fail.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

6 changes: 6 additions & 0 deletions integration-tests/parse/incomplete-let-in-2/ghul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compiler": "dotnet ../../../publish/ghul.dll",
"source": [
"."
]
}
1 change: 1 addition & 0 deletions integration-tests/parse/incomplete-let-in-2/ghulflags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--type-check
Empty file.
15 changes: 15 additions & 0 deletions integration-tests/parse/incomplete-let-in-2/test.ghul
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Test.ParseLetIn is
use Collections;

class TestA is
test_simple() -> int =>
let

si

class D is
value: int => 1234;
init() is
si
si
si
Empty file.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 5,5..5,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 5,5..5,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 5,5..5,7: error: syntax error: expected ; but found si
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 6,5..6,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 6,5..6,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 6,5..6,7: error: syntax error: expected ; but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-property-3/err.expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 5,5..5,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 5,5..5,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 5,5..5,7: error: syntax error: expected ; but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-property-4/err.expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test.ghul: 6,5..6,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 6,5..6,7: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 6,5..6,7: error: syntax error: expected ; but found si
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 7,19..7,33: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found } interpolate
test.ghul: 7,19..7,33: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found } interpolate
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 7,1..7,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 7,1..7,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 7,1..7,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 7,1..7,3: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-variable-5/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 7,9..7,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 7,9..7,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
2 changes: 1 addition & 1 deletion integration-tests/parse/incomplete-variable-6/err.expected
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.ghul: 7,9..7,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, new, null, rec, self, string literal, super, true, typeof or { but found si
test.ghul: 7,9..7,11: error: in primary expression: expected (, [, cast, char literal, false, float literal, identifier, if, int literal, isa, let, new, null, rec, self, string literal, super, true, typeof or { but found si
23 changes: 23 additions & 0 deletions integration-tests/semantic/variable-let-in-1/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run test",
"command": "dotnet ghul-test \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "Capture test expectation",
"command": "../../../tasks/capture.sh \"${workspaceFolder}\"",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
1 change: 1 addition & 0 deletions integration-tests/semantic/variable-let-in-1/err.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test.ghul: 99,13..99,39: error: let in expression result is not used
1 change: 1 addition & 0 deletions integration-tests/semantic/variable-let-in-1/fail.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

6 changes: 6 additions & 0 deletions integration-tests/semantic/variable-let-in-1/ghul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compiler": "dotnet ../../../publish/ghul.dll",
"source": [
"."
]
}
1 change: 1 addition & 0 deletions integration-tests/semantic/variable-let-in-1/ghulflags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--type-check
Empty file.
Loading

0 comments on commit fd6e084

Please sign in to comment.