bool Verbose = false;
char* Artifact = "bin";
+AST* normalize(AST* tree);
+
bool isatomic(AST* tree)
{
switch (tree->type) {
}
}
-//AST* normalize_fnapp_args(AST* tree)
-//{
-//}
+AST* normalize_def(AST* tree)
+{
+ Tok name = { .value.text = def_name(tree) };
+ return Def(&name, normalize(def_value(tree)));
+}
AST* normalize_fnapp(AST* tree)
{
return normalized;
}
+AST* normalize_if(AST* tree)
+{
+ AST* cond = normalize(ifexpr_cond(tree));
+ AST* thenbr = normalize(ifexpr_then(tree));
+ AST* elsebr = normalize(ifexpr_else(tree));
+ if (!isatomic(cond)) {
+ AST* temp = TempVar();
+ AST* body = IfExpr(); //(temp, thenbr, elsebr);
+ ifexpr_set_cond(body, temp);
+ ifexpr_set_then(body, thenbr);
+ ifexpr_set_else(body, elsebr);
+ tree = Let(temp, cond, body);
+ } else {
+ tree = IfExpr(); //(cond, thenbr, elsebr);
+ ifexpr_set_cond(tree, cond);
+ ifexpr_set_then(tree, thenbr);
+ ifexpr_set_else(tree, elsebr);
+ }
+ return tree;
+}
+
+AST* normalize_func(AST* tree)
+{
+ func_set_body(tree, normalize(func_body(tree)));
+ return tree;
+}
+
+AST* normalize_let(AST* tree)
+{
+ AST* var = let_var(tree);
+ AST* val = normalize(let_val(tree));
+ AST* body = normalize(let_body(tree));
+ /* Find the inner most let block */
+ if (!isatomic(val)) {
+ AST* let = val;
+ while (let->type == AST_LET && let_body(let)->type == AST_LET)
+ let = let_body(let);
+ let_set_body(let, Let(var, let_body(let), body));
+ tree = let;
+ } else {
+ tree = Let(var, val, body);
+ }
+ return tree;
+}
+
AST* normalize(AST* tree)
{
- if (tree->type == AST_FNAPP)
- return normalize_fnapp(tree);
- else
+ if (NULL == tree)
return tree;
+ switch (tree->type)
+ {
+ case AST_DEF: tree = normalize_def(tree); break;
+ case AST_FNAPP: tree = normalize_fnapp(tree); break;
+ case AST_IF: tree = normalize_if(tree); break;
+ case AST_FUNC: tree = normalize_func(tree); break;
+ case AST_LET: tree = normalize_let(tree); break;
+ default: break;
+ }
+ return tree;
}
/* Driver Modes
end
end
+ context "definitions" do
+ it "should leave atomic defintions alone" do
+ expect(anf('def foo 123;')).to eq([["def", "foo", "T_INT:123"]])
+ end
+
+ it "should leave normalize complex defintions" do
+ expect(anf('def foo bar();')).to eq([["def", "foo", ["T_ID:bar"]]])
+ end
+ end
+
context "function applications" do
it "should leave an application with no args alone" do
expect(anf('foo()')).to eq([['T_ID:foo']])
['T_ID:foo', '$:0', '$:1', 'T_ID:a']]]])
end
end
+
+ context "if expressions" do
+ it "should leave atomic expressions alone" do
+ expect(anf('if 1 2 3;')).to eq([
+ ["if", "T_INT:1",
+ ["let", ["$:0", "T_INT:2"],
+ ["let", ["$:1", "T_INT:3"],
+ "$:1"]]]])
+ end
+
+ it "should normalize the conditional expression" do
+ expect(anf('if foo() 2 else 3;')).to eq([
+ ["let", ["$:2", ["T_ID:foo"]],
+ ["if", "$:2",
+ ["let", ["$:0", "T_INT:2"], "$:0"],
+ ["let", ["$:1", "T_INT:3"], "$:1"]]]])
+ end
+
+ it "should normalize the first branch expression" do
+ expect(anf('if 1 foo() else 3;')).to eq([
+ ["if", "T_INT:1",
+ ["let", ["$:0", ["T_ID:foo"]], "$:0"],
+ ["let", ["$:1", "T_INT:3"], "$:1"]]])
+ end
+
+ it "should normalize the first branch expression" do
+ expect(anf('if 1 2 else foo();')).to eq([
+ ["if", "T_INT:1",
+ ["let", ["$:0", "T_INT:2"], "$:0"],
+ ["let", ["$:1", ["T_ID:foo"]], "$:1"]]])
+ end
+ end
+
+ context "function literals" do
+ it "should normalize a literal with a complex expression" do
+ expect(anf('fn() foo(bar());')).to eq([
+ ["fn", [],
+ ["let", ["$:1", ["T_ID:bar"]],
+ ["let", ["$:0", ["T_ID:foo", "$:1"]],
+ "$:0"]]]
+ ])
+ end
+ end
end
context "if statements" do
it "should parse an if statement with no else clause" do
expect(ast('if 123 321 end')).to eq([
- ["if", "T_INT:123", ["block", "T_INT:321"]]])
+ ["if", "T_INT:123", ["let", ["$:0", "T_INT:321"], "$:0"]]])
end
it "should parse an if statement with an optional then keyword" do
expect(ast('if 123 then 321 end')).to eq([
- ["if", "T_INT:123", ["block", "T_INT:321"]]])
+ ["if", "T_INT:123", ["let", ["$:0", "T_INT:321"], "$:0"]]])
end
it "should parse an if statement with an else clause " do
expect(ast('if 123 321 else 456 end')).to eq([
- ["if", "T_INT:123", ["block", "T_INT:321"], ["block", "T_INT:456"]]])
+ ["if", "T_INT:123",
+ ["let", ["$:0", "T_INT:321"], "$:0"],
+ ["let", ["$:1", "T_INT:456"], "$:1"]]])
end
- end
-# context "type definitions" do
-# it "should parse a simple type definition" do
-# expect(ast('type foo is int;')).to eq([ ['T_ID:type', 'T_ID:foo', 'T_ID:is', 'T_ID:int'] ])
-# end
-#
-# it "should parse a function type definition with no args" do
-# expect(ast('type foo is int();')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:int', []]] ])
-# end
-#
-# it "should parse a function type definition with one arg" do
-# expect(ast('type foo is int(int);')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:int', ['T_ID:int']]] ])
-# end
-#
-# it "should parse a function type definition with two args" do
-# expect(ast('type foo is int(int,int);')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:int', ['T_ID:int', 'T_ID:int']]] ])
-# end
-#
-# it "should parse a function type definition with three args" do
-# expect(ast('type foo is int(int,int,int);')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:int', ['T_ID:int', 'T_ID:int', 'T_ID:int']]] ])
-# end
-#
-# it "should parse a tuple type definition with one field" do
-# expect(ast('type foo is {int};')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:tuple', 'T_ID:int']] ])
-# end
-#
-# it "should parse a tuple type definition with two fields" do
-# expect(ast('type foo is {int,int};')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:tuple', 'T_ID:int', 'T_ID:int']] ])
-# end
-#
-# it "should parse a tuple type definition with three fields" do
-# expect(ast('type foo is {int,int,int};')).to eq([
-# ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:tuple', 'T_ID:int', 'T_ID:int', 'T_ID:int']] ])
-# end
-#
-# it "should parse a record type definition with one field" do
-# pending "Type annotations have not been implemented yet"
-# expect(ast('type foo is { int a };')).to eq([
-# ['T_ID:type', 'T_ID:foo', ['T_ID:record', ['T_ID:int', 'T_ID:a']]] ])
-# end
-#
-# it "should parse a record type definition with two fields" do
-# pending "Type annotations have not been implemented yet"
-# expect(ast('type foo is { int a, int b };')).to eq([
-# ['T_ID:type', 'T_ID:foo', ['T_ID:record', ['T_ID:int', 'T_ID:a'], ['T_ID:int', 'T_ID:b']]] ])
-# end
-#
-# it "should parse a record type definition with three fields" do
-# pending "Type annotations have not been implemented yet"
-# expect(ast('type foo is { int a, int b };')).to eq([
-# ['T_ID:type', 'T_ID:foo', ['T_ID:record', ['T_ID:int', 'T_ID:a'], ['T_ID:int', 'T_ID:b'], ['T_ID:int', 'T_ID:c']]] ])
-# end
-# end
+ it "should parse an if statement with a then clause with multiple expressions" do
+ expect(ast('if 1 2 3 else 4 end')).to eq([
+ ["if", "T_INT:1",
+ ["let", ["$:0", "T_INT:2"],
+ ["let", ["$:1", "T_INT:3"], "$:1"]],
+ ["let", ["$:2", "T_INT:4"], "$:2"]]])
+ end
+
+ it "should parse an if statement with an else clause with multiple expressions" do
+ expect(ast('if 1 2 else 3 4 end')).to eq([
+ ["if", "T_INT:1",
+ ["let", ["$:0", "T_INT:2"], "$:0"],
+ ["let", ["$:1", "T_INT:3"],
+ ["let", ["$:2", "T_INT:4"], "$:2"]],
+ ]])
+ end
+ end
context "definitions" do
it "should parse a value definition" do
it "should parse a function definition" do
expect(ast('def foo() 123;')).to eq([
- ['def', 'foo', ['fn', [], 'T_INT:123']] ])
+ ['def', 'foo', ['fn', [],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]] ])
end
it "should parse a function definition with multiple expressions in the body" do
expect(ast('def foo() 123 321;')).to eq([
- ['def', 'foo', ['fn', [], 'T_INT:123', 'T_INT:321']] ])
+ ['def', 'foo', ['fn', [],
+ ["let", ["$:0", "T_INT:123"],
+ ["let", ["$:1", "T_INT:321"], "$:1"]]]]])
+ end
+
+ it "should parse a function definition with one definition and expression" do
+ expect(ast('def foo() def bar 123; add(bar,321);')).to eq([
+ ['def', 'foo', ['fn', [],
+ ["let", ["T_ID:bar", "T_INT:123"],
+ ["let", ["$:0", ["T_ID:add", "T_ID:bar", "T_INT:321"]], "$:0"]]]]])
end
it "should parse a function definition with one argument" do
expect(ast('def foo(a) 123;')).to eq([
- ['def', 'foo', ['fn', ['T_ID:a'], 'T_INT:123']] ])
+ ['def', 'foo', ['fn', ['T_ID:a'],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]]])
end
it "should parse a function definition with two arguments" do
expect(ast('def foo(a,b) 123;')).to eq([
- ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b'], 'T_INT:123']] ])
+ ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b'],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]]])
end
it "should parse a function definition with three arguments" do
expect(ast('def foo(a,b,c) 123;')).to eq([
- ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'], 'T_INT:123']] ])
+ ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]]])
end
end
-# context "annotations" do
-# it "should parse a type annotation for a simple type" do
-# expect(ast('ann foo int;')).to eq([ ['T_ID:ann', 'T_ID:foo', 'T_ID:int'] ])
-# end
-#
-# it "should parse a type annotation for a function type" do
-# expect(ast('ann foo int();')).to eq([ ['T_ID:ann', 'T_ID:foo', ['T_ID:int', []]] ])
-# end
-#
-# it "should parse a type annotation for a tuple type" do
-# expect(ast('ann foo {int, int};')).to eq([ ['T_ID:ann', 'T_ID:foo', ['T_ID:tuple', 'T_ID:int', 'T_ID:int']] ])
-# end
-#
-# it "should parse a type annotation with a generic type" do
-# pending "Type annotations have not been implemented yet"
-# expect(ast('ann foo Pair[int,int];')).to eq([
-# ['T_ID:ann', 'T_ID:foo', ['T_ID:Pair', 'T_ID:int', 'T_ID:int']] ])
-# end
-# end
-#
context "expressions" do
context "parenthese grouping" do
it "should parse a parenthesized expression" do
context "function literals" do
it "should parse a function with no params" do
- expect(ast('fn() 123;')).to eq([["fn", [], "T_INT:123"]])
+ expect(ast('fn() 123;')).to eq([
+ ["fn", [],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]])
end
it "should parse a function with one param" do
- expect(ast('fn(a) 123;')).to eq([["fn", ["T_ID:a"], "T_INT:123"]])
+ expect(ast('fn(a) 123;')).to eq([
+ ["fn", ["T_ID:a"],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]])
end
it "should parse a function with two params" do
- expect(ast('fn(a,b) 123;')).to eq([["fn", ["T_ID:a", "T_ID:b"], "T_INT:123"]])
+ expect(ast('fn(a,b) 123;')).to eq([
+ ["fn", ["T_ID:a", "T_ID:b"],
+ ["let", ["$:0", "T_INT:123"], "$:0"]]])
end
end