]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Added type definitions and annotations to the grammar
authorMichael D. Lowis <mike@mdlowis.com>
Wed, 29 Oct 2014 17:38:13 +0000 (13:38 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Wed, 29 Oct 2014 17:38:13 +0000 (13:38 -0400)
source/sclpl/grammar.c
source/sclpl/grammar.h
source/sclpl/scanner.c
spec/lexer_spec.rb
spec/parser_spec.rb

index 9436e0ff985465c8b3c2a0b1895612686160c5bf..4beecf7d48a8b938a431c93c6f95b8362ccae023 100644 (file)
 #include "lexer.h"
 #include "exn.h"
 
-tree_t* grammar_toplevel(parser_t* p_parser)
+tree_t* grammar_toplevel(parser_t* p)
 {
     tree_t* p_tree = NULL;
     try {
-        if (parser_accept_str(p_parser, T_ID, "require"))
-            grammar_require(p_parser);
-        else if (parser_accept_str(p_parser, T_ID, "def"))
-            grammar_definition(p_parser);
+        if (parser_accept_str(p, T_ID, "require"))
+            grammar_require(p);
+        else if (parser_accept_str(p, T_ID, "type"))
+            grammar_type_definition(p);
+        else if (parser_accept_str(p, T_ID, "ann"))
+            grammar_type_annotation(p);
+        else if (parser_accept_str(p, T_ID, "def"))
+            grammar_definition(p);
         else
-            grammar_expression(p_parser);
-        p_tree = parser_get_tree(p_parser);
+            grammar_expression(p);
+        p_tree = parser_get_tree(p);
     } catch(ParseException) {
         fprintf(stderr, "Invalid Syntax\n");
     }
     return p_tree;
 }
 
-void grammar_require(parser_t* p_parser)
+void grammar_require(parser_t* p)
 {
-    size_t mark = parser_mark(p_parser);
-    parser_expect(p_parser, T_STRING);
-    parser_expect(p_parser, T_END);
-    parser_reduce(p_parser, mark);
+    size_t mark = parser_mark(p);
+    parser_expect(p, T_STRING);
+    parser_expect(p, T_END);
+    parser_reduce(p, mark);
 }
 
-void grammar_definition(parser_t* p_parser)
+void grammar_type_annotation(parser_t* p)
 {
-    size_t mark = parser_mark(p_parser);
-    parser_expect(p_parser,T_ID);
-    if (parser_peek(p_parser)->type == T_LPAR) {
-        parser_insert(p_parser, T_ID, lexer_dup("fn"));
-        grammar_fn_stmnt(p_parser);
+    size_t mark = parser_mark(p);
+    parser_expect(p, T_ID);
+    grammar_type(p);
+    parser_expect(p, T_END);
+    parser_reduce(p, mark);
+}
+
+void grammar_type_definition(parser_t* p)
+{
+    size_t mark = parser_mark(p);
+    parser_expect(p, T_ID);
+    parser_expect_str(p, T_ID, "is");
+    grammar_type(p);
+    parser_expect(p, T_END);
+    parser_reduce(p, mark);
+}
+
+void grammar_type(parser_t* p) {
+    if (parser_accept(p, T_LBRACE)) {
+        grammar_tuple(p);
     } else {
-        grammar_expression(p_parser);
-        parser_expect(p_parser,T_END);
+        parser_expect(p, T_ID);
+        if (parser_accept(p, T_LPAR)) {
+            grammar_function(p);
+        }
     }
-    parser_reduce(p_parser, mark);
 }
 
-void grammar_expression(parser_t* p_parser)
+void grammar_tuple(parser_t* p) {
+    size_t mark = parser_mark(p);
+    parser_insert(p, T_ID, lexer_dup("tuple"));
+    do {
+        grammar_type(p);
+    } while (parser_accept(p, T_COMMA));
+    parser_expect(p, T_RBRACE);
+    parser_reduce(p, mark);
+}
+
+void grammar_function(parser_t* p) {
+    size_t mark1 = parser_mark(p) - 1;
+    size_t mark2 = parser_mark(p);
+    while (!parser_accept(p, T_RPAR)) {
+        grammar_type(p);
+        if (T_RPAR != parser_peek(p)->type)
+            parser_expect(p, T_COMMA);
+    }
+    parser_reduce(p, mark2);
+    parser_reduce(p, mark1);
+}
+
+void grammar_definition(parser_t* p)
+{
+    size_t mark = parser_mark(p);
+    parser_expect(p,T_ID);
+    if (parser_peek(p)->type == T_LPAR) {
+        parser_insert(p, T_ID, lexer_dup("fn"));
+        grammar_fn_stmnt(p);
+    } else {
+        grammar_expression(p);
+        parser_expect(p,T_END);
+    }
+    parser_reduce(p, mark);
+}
+
+void grammar_expression(parser_t* p)
 {
-    if (parser_accept(p_parser, T_LPAR)) {
-        size_t mark = parser_mark(p_parser);
-        grammar_expression(p_parser);
-        parser_expect(p_parser, T_RPAR);
-        parser_reduce(p_parser, mark);
-    } else if (parser_accept_str(p_parser, T_ID, "if")) {
-        grammar_if_stmnt(p_parser);
-    } else if (parser_accept_str(p_parser, T_ID, "fn")) {
-        grammar_fn_stmnt(p_parser);
-    } else if (parser_peek(p_parser)->type == T_ID) {
-        parser_expect(p_parser, T_ID);
-        if (parser_peek(p_parser)->type == T_LPAR) {
-            grammar_arglist(p_parser);
+    if (parser_accept(p, T_LPAR)) {
+        size_t mark = parser_mark(p);
+        grammar_expression(p);
+        parser_expect(p, T_RPAR);
+        parser_reduce(p, mark);
+    } else if (parser_accept_str(p, T_ID, "if")) {
+        grammar_if_stmnt(p);
+    } else if (parser_accept_str(p, T_ID, "fn")) {
+        grammar_fn_stmnt(p);
+    } else if (parser_peek(p)->type == T_ID) {
+        parser_expect(p, T_ID);
+        if (parser_peek(p)->type == T_LPAR) {
+            grammar_arglist(p);
         }
     } else {
-        grammar_literal(p_parser);
+        grammar_literal(p);
     }
 }
 
-void grammar_literal(parser_t* p_parser)
+void grammar_literal(parser_t* p)
 {
-    switch (parser_peek(p_parser)->type) {
+    switch (parser_peek(p)->type) {
         case T_BOOL:
         case T_CHAR:
         case T_STRING:
         case T_INT:
         case T_FLOAT:
-            parser_accept(p_parser, parser_peek(p_parser)->type);
+            parser_accept(p, parser_peek(p)->type);
             break;
 
         default:
-            parser_error(p_parser, "Not a valid expression");
+            parser_error(p, "Not a valid expression");
     }
 }
 
-void grammar_arglist(parser_t* p_parser)
+void grammar_arglist(parser_t* p)
 {
-    size_t mark = parser_mark(p_parser);
-    parser_expect(p_parser, T_LPAR);
-    while(parser_peek(p_parser)->type != T_RPAR) {
-        grammar_expression(p_parser);
-        if(parser_peek(p_parser)->type != T_RPAR)
-            parser_expect(p_parser, T_COMMA);
+    size_t mark = parser_mark(p);
+    parser_expect(p, T_LPAR);
+    while(parser_peek(p)->type != T_RPAR) {
+        grammar_expression(p);
+        if(parser_peek(p)->type != T_RPAR)
+            parser_expect(p, T_COMMA);
     }
-    parser_expect(p_parser, T_RPAR);
-    parser_reduce(p_parser, mark);
+    parser_expect(p, T_RPAR);
+    parser_reduce(p, mark);
 }
 
-void grammar_if_stmnt(parser_t* p_parser)
+void grammar_if_stmnt(parser_t* p)
 {
-    size_t mark = parser_mark(p_parser);
-    grammar_expression(p_parser);
-    grammar_expression(p_parser);
-    if (parser_accept_str(p_parser, T_ID, "else")) {
-        grammar_expression(p_parser);
+    size_t mark = parser_mark(p);
+    grammar_expression(p);
+    grammar_expression(p);
+    if (parser_accept_str(p, T_ID, "else")) {
+        grammar_expression(p);
     }
-    parser_expect(p_parser,T_END);
-    parser_reduce(p_parser, mark);
+    parser_expect(p,T_END);
+    parser_reduce(p, mark);
 }
 
-void grammar_fn_stmnt(parser_t* p_parser)
+void grammar_fn_stmnt(parser_t* p)
 {
-    size_t mark1 = parser_mark(p_parser);
-    parser_expect(p_parser, T_LPAR);
-    size_t mark2 = parser_mark(p_parser);
-    while(parser_peek(p_parser)->type != T_RPAR) {
-        parser_expect(p_parser, T_ID);
-        if(parser_peek(p_parser)->type != T_RPAR)
-            parser_expect(p_parser, T_COMMA);
+    size_t mark1 = parser_mark(p);
+    parser_expect(p, T_LPAR);
+    size_t mark2 = parser_mark(p);
+    while(parser_peek(p)->type != T_RPAR) {
+        parser_expect(p, T_ID);
+        if(parser_peek(p)->type != T_RPAR)
+            parser_expect(p, T_COMMA);
     }
-    parser_expect(p_parser, T_RPAR);
-    parser_reduce(p_parser, mark2);
-    while(parser_peek(p_parser)->type != T_END) {
-        grammar_expression(p_parser);
+    parser_expect(p, T_RPAR);
+    parser_reduce(p, mark2);
+    while(parser_peek(p)->type != T_END) {
+        grammar_expression(p);
     }
-    parser_expect(p_parser, T_END);
-    parser_reduce(p_parser, mark1);
+    parser_expect(p, T_END);
+    parser_reduce(p, mark1);
 }
+
index 08f4954e97e37e8be57cb4aa3c8bbd8d78990a73..942c3f02db52b6e44883a823c16149fe9c47313b 100644 (file)
@@ -7,20 +7,18 @@
 
 #include "parser.h"
 
-tree_t* grammar_toplevel(parser_t* p_parser);
-
-void grammar_require(parser_t* p_parser);
-
-void grammar_definition(parser_t* p_parser);
-
-void grammar_expression(parser_t* p_parser);
-
-void grammar_literal(parser_t* p_parser);
-
-void grammar_arglist(parser_t* p_parser);
-
-void grammar_if_stmnt(parser_t* p_parser);
-
-void grammar_fn_stmnt(parser_t* p_parser);
+tree_t* grammar_toplevel(parser_t* p);
+void grammar_require(parser_t* p);
+void grammar_type_annotation(parser_t* p);
+void grammar_type_definition(parser_t* p);
+void grammar_type(parser_t* p);
+void grammar_tuple(parser_t* p);
+void grammar_function(parser_t* p);
+void grammar_definition(parser_t* p);
+void grammar_expression(parser_t* p);
+void grammar_literal(parser_t* p);
+void grammar_arglist(parser_t* p);
+void grammar_if_stmnt(parser_t* p);
+void grammar_fn_stmnt(parser_t* p);
 
 #endif /* GRAMMAR_H */
index e6360879c77ac5aa9b5cf3fa412b455d5d5c05bb..9db651b6eeabda608d41a70701967e3e6762bb5e 100644 (file)
@@ -33,7 +33,7 @@ char* scanner_read(scanner_t* p_scanner) {
             p_tok = scanner_read_string(p_scanner);
         } else {
             size_t start = p_scanner->index;
-            while(!scanner_oneof(p_scanner," \t\r\n()[];,'\"") &&
+            while(!scanner_oneof(p_scanner," \t\r\n()[]{};,'\"") &&
                   (scanner_current(p_scanner) != '\0')) {
                 p_scanner->index++;
             }
index a8bf968bb7ff5e11474034877e38b7efd0b26f25..c167cdb3a6286d83a61b580cf6abd985d023d5c1 100644 (file)
@@ -43,6 +43,42 @@ describe "lexer" do
         ["T_LBRACK", "T_RBRACK", "T_LPAR", "T_RPAR", "T_LBRACE", "T_RBRACE",
          "T_SQUOTE", "T_COMMA", "T_END"])
     end
+
+    it "should recognize [ after an identifier" do
+      expect(lexer('foo[')).to eq(['T_ID:foo', 'T_LBRACK'])
+    end
+
+    it "should recognize ] after an identifier" do
+      expect(lexer('foo]')).to eq(['T_ID:foo', 'T_RBRACK'])
+    end
+
+    it "should recognize ( after an identifier" do
+      expect(lexer('foo(')).to eq(['T_ID:foo', 'T_LPAR'])
+    end
+
+    it "should recognize ) after an identifier" do
+      expect(lexer('foo)')).to eq(['T_ID:foo', 'T_RPAR'])
+    end
+
+    it "should recognize { after an identifier" do
+      expect(lexer('foo{')).to eq(['T_ID:foo', 'T_LBRACE'])
+    end
+
+    it "should recognize } after an identifier" do
+      expect(lexer('foo}')).to eq(['T_ID:foo', 'T_RBRACE'])
+    end
+
+    it "should recognize } after an identifier" do
+      expect(lexer('foo\'')).to eq(['T_ID:foo', 'T_SQUOTE'])
+    end
+
+    it "should recognize } after an identifier" do
+      expect(lexer('foo,')).to eq(['T_ID:foo', 'T_COMMA'])
+    end
+
+    it "should recognize } after an identifier" do
+      expect(lexer('foo;')).to eq(['T_ID:foo', 'T_END'])
+    end
   end
 
   context "characters" do
index 23f96229c0345fe02c42d8a550404c15b5a9158b..89b254222e72362e8dd6a0933de2a6788c58d170 100644 (file)
@@ -29,50 +29,42 @@ describe "sclpl grammar" do
 
   context "type definitions" do
     it "should parse a simple type definition" do
-      pending "Type annotations have not been implemented yet"
-      expect(ast('type foo is int;')).to eq([ ['T_ID:type', 'T_ID:foo', 'T_ID:int'] ])
+      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
-      pending "Type annotations have not been implemented yet"
-      expect(ast('type foo is (-> int ());')).to eq([
-          ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:->', 'T_ID:int', []]] ])
+      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
-      pending "Type annotations have not been implemented yet"
-      expect(ast('type foo is (-> int (int));')).to eq([
-          ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:->', 'T_ID:int', ['T_ID:int']]] ])
+      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
-      pending "Type annotations have not been implemented yet"
-      expect(ast('type foo is (-> int (int, int));')).to eq([
-          ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:->', 'T_ID:int', ['T_ID:int', 'T_ID:int']]] ])
+      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
-      pending "Type annotations have not been implemented yet"
-      expect(ast('type foo is (-> int (int, int, int));')).to eq([
-          ['T_ID:type', 'T_ID:foo', 'T_ID:is', ['T_ID:->', 'T_ID:int', ['T_ID:int', 'T_ID:int', 'T_ID:int']]] ])
+      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
-      pending "Type annotations have not been implemented yet"
       expect(ast('type foo is {int};')).to eq([
-          ['T_ID:type', 'T_ID:foo', ['T_ID:tuple', 'T_ID:int']] ])
+          ['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
-      pending "Type annotations have not been implemented yet"
       expect(ast('type foo is {int,int};')).to eq([
-          ['T_ID:type', 'T_ID:foo', ['T_ID:tuple', 'T_ID:int', 'T_ID:int']] ])
+          ['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
-      pending "Type annotations have not been implemented yet"
       expect(ast('type foo is {int,int,int};')).to eq([
-          ['T_ID:type', 'T_ID:foo', ['T_ID:tuple', 'T_ID:int', 'T_ID:int', 'T_ID:int']] ])
+          ['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
@@ -92,7 +84,6 @@ describe "sclpl grammar" do
       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
 
   context "definitions" do
@@ -127,11 +118,18 @@ describe "sclpl grammar" do
   end
 
   context "annotations" do
-    it "should parse a type annotation" do
-      pending "Type annotations have not been implemented yet"
+    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([