]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Half-implemented ANF transformation
authorMichael D. Lowis <mike@mdlowis.com>
Mon, 28 Dec 2015 01:29:57 +0000 (20:29 -0500)
committerMichael D. Lowis <mike@mdlowis.com>
Mon, 28 Dec 2015 01:29:57 +0000 (20:29 -0500)
Makefile
source/ast.c
source/main.c
source/parser.c
source/pprint.c
source/sclpl.h
spec/anf_spec.rb
spec/parser_spec.rb

index 654a84d013b0107b4324fe5d1671c533c66574ab..c6fe2cf8dd0a08d1fa9ad9c4efbc25f52226920c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,14 +16,13 @@ LDFLAGS  += ${LIBS}
 #------------------------------------------------------------------------------
 # Build Targets and Rules
 #------------------------------------------------------------------------------
-SRCS = source/main.c    \
-       source/lexer.c   \
-       source/parser.c  \
-       source/pprint.c  \
-       source/gc.c      \
-       source/vec.c     \
-       source/ast.c
-OBJS = ${SRCS:.c=.o}
+OBJS = source/main.o    \
+       source/lexer.o   \
+       source/parser.o  \
+       source/pprint.o  \
+       source/gc.o      \
+       source/vec.o     \
+       source/ast.o
 
 all: options sclpl test
 
index 460cfa23627600560bd59666acc7ae0d32613607..561bef3e2780a4c52c617b29d4babf8102992641 100644 (file)
@@ -34,10 +34,6 @@ static void ast_free(void* ptr)
             vec_deinit(&(ast->value.fnapp.args));
             break;
 
-        case AST_BLOCK:
-            vec_deinit(&(ast->value.exprs));
-            break;
-
         case AST_LET:
             break;
 
@@ -233,28 +229,6 @@ void ifexpr_set_else(AST* ifexpr, AST* belse)
     ifexpr->value.ifexpr.belse = (AST*)gc_addref(belse);
 }
 
-AST* Block(void)
-{
-    AST* node = ast(AST_BLOCK);
-    vec_init(&(node->value.exprs));
-    return node;
-}
-
-void block_append(AST* block, AST* expr)
-{
-    vec_push_back(&(block->value.exprs), gc_addref(expr));
-}
-
-size_t block_size(AST* block)
-{
-    return vec_size(&(block->value.exprs));
-}
-
-AST* block_get(AST* block, size_t index)
-{
-    return (AST*)vec_at(&(block->value.exprs), index);
-}
-
 AST* Func(void)
 {
     AST* node = ast(AST_FUNC);
index e8a21a7cb9d45c0171e90624e7821f536ff8e645..19f45b9c4de4a7cb0d0238527639e63324d1212d 100644 (file)
@@ -4,6 +4,8 @@ char* ARGV0;
 bool Verbose   = false;
 char* Artifact = "bin";
 
+AST* normalize(AST* tree);
+
 bool isatomic(AST* tree)
 {
     switch (tree->type) {
@@ -21,9 +23,11 @@ bool isatomic(AST* tree)
     }
 }
 
-//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)
 {
@@ -57,12 +61,65 @@ 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
index fab0d62e7b7c49976d83f596410f40fc287dc074..8ba7a8b85d756e18ee131ac4485ef249d6609e5a 100644 (file)
@@ -141,10 +141,27 @@ static AST* literal(Parser* p)
 
 static AST* expr_block(Parser* p)
 {
-    AST* block = Block();
+    AST* block = NULL;
+    vec_t exprs;
+    vec_init(&exprs);
+    /* Build all expressions into let forms with no bodies */
     do {
-        block_append(block, expression(p));
+        if (accept_str(p, T_ID, "def")) {
+            AST* def = definition(p);
+            Tok name = { .value.text = def_name(def) };
+            vec_push_back(&exprs, Let(Ident(&name), def_value(def), NULL));
+        } else {
+            vec_push_back(&exprs, Let(TempVar(), expression(p), NULL));
+        }
     } while(!match(p, T_END) && !match_str(p, T_ID, "else"));
+    /* Now nest all of the let forms making sure that the last one returns
+     * it's definition as its body */
+    for (int i = vec_size(&exprs); i > 0; i--) {
+        AST* let = (AST*)vec_at(&exprs,i-1);
+        let_set_body(let, (block == NULL) ? let_var(let) : block);
+        block = let;
+    }
+    vec_deinit(&exprs);
     return block;
 }
 
index 0cc839d595263a813e9d17f94c4dca4370c62e7c..41bf2f346aca4386ffb1d323d226c95b87a6e450 100644 (file)
@@ -118,8 +118,9 @@ static void pprint_literal(FILE* file, AST* tree, int depth)
 
 void pprint_tree(FILE* file, AST* tree, int depth)
 {
-    if (tree == NULL)
+    if (tree == NULL) {
         return;
+    }
     print_indent(file, depth);
     switch (tree->type) {
         case AST_REQ:
@@ -142,15 +143,6 @@ void pprint_tree(FILE* file, AST* tree, int depth)
             printf(")");
             break;
 
-        case AST_BLOCK:
-            printf("(block ");
-            for (size_t i = 0; i < block_size(tree); i++) {
-                printf(" ");
-                pprint_tree(file, block_get(tree, i), depth);
-            }
-            printf(")");
-            break;
-
         case AST_FUNC:
             printf("(fn (");
             for (size_t i = 0; i < vec_size(func_args(tree)); i++) {
@@ -158,10 +150,7 @@ void pprint_tree(FILE* file, AST* tree, int depth)
                 pprint_literal(file, vec_at(func_args(tree), i), depth);
             }
             printf(")");
-            for (size_t i = 0; i < block_size(func_body(tree)); i++) {
-                printf(" ");
-                pprint_tree(file, block_get(func_body(tree), i), depth);
-            }
+            pprint_tree(file, func_body(tree), depth);
             printf(")");
             break;
 
index 92c5a44a9aeed5c8c4536ce7df7376468b908efe..9ddc8d81823f90c4682f66246b027626b0b5adfe 100644 (file)
@@ -74,7 +74,7 @@ typedef struct {
  *****************************************************************************/
 typedef enum ASTType {
     AST_STRING, AST_SYMBOL, AST_CHAR, AST_INT, AST_FLOAT, AST_BOOL, AST_IDENT,
-    AST_REQ, AST_DEF, AST_IF, AST_FUNC, AST_FNAPP, AST_BLOCK, AST_LET, AST_TEMP
+    AST_REQ, AST_DEF, AST_IF, AST_FUNC, AST_FNAPP, AST_LET, AST_TEMP
 } ASTType;
 
 typedef struct AST {
@@ -107,8 +107,6 @@ typedef struct AST {
             struct AST* value;
             struct AST* body;
         } let;
-        /* Code Block */
-        vec_t exprs;
         /* String, Symbol, Identifier */
         char* text;
         /* Character */
@@ -172,12 +170,6 @@ void ifexpr_set_then(AST* ifexpr, AST* bthen);
 AST* ifexpr_else(AST* ifexpr);
 void ifexpr_set_else(AST* ifexpr, AST* belse);
 
-/* Code Block */
-AST* Block(void);
-void block_append(AST* block, AST* expr);
-size_t block_size(AST* block);
-AST* block_get(AST* block, size_t index);
-
 /* Function */
 AST* Func(void);
 vec_t* func_args(AST* func);
index 30342ad153540cc43cb4b64268db2ea1914fe32b..a22ee6d056ee2db9b26cc20042e8eaf53a5d436d 100644 (file)
@@ -27,6 +27,16 @@ describe "sclpl a-normal form" do
     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']])
@@ -80,4 +90,47 @@ describe "sclpl a-normal form" do
               ['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
index 49ec1744c827805643cc7779ea824d9a2bc4e1c9..a6eeed7c5926d0cce5b191adbd898a1960c386de 100644 (file)
@@ -56,78 +56,38 @@ describe "sclpl grammar" do
   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
@@ -136,50 +96,43 @@ describe "sclpl grammar" 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
@@ -193,15 +146,21 @@ describe "sclpl grammar" 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