From: Michael D. Lowis Date: Wed, 29 Oct 2014 17:38:13 +0000 (-0400) Subject: Added type definitions and annotations to the grammar X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=38d748e2b46d6556d3eada3e06270982aeba0075;p=proto%2Fsclpl.git Added type definitions and annotations to the grammar --- diff --git a/source/sclpl/grammar.c b/source/sclpl/grammar.c index 9436e0f..4beecf7 100644 --- a/source/sclpl/grammar.c +++ b/source/sclpl/grammar.c @@ -8,122 +8,179 @@ #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); } + diff --git a/source/sclpl/grammar.h b/source/sclpl/grammar.h index 08f4954..942c3f0 100644 --- a/source/sclpl/grammar.h +++ b/source/sclpl/grammar.h @@ -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 */ diff --git a/source/sclpl/scanner.c b/source/sclpl/scanner.c index e636087..9db651b 100644 --- a/source/sclpl/scanner.c +++ b/source/sclpl/scanner.c @@ -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++; } diff --git a/spec/lexer_spec.rb b/spec/lexer_spec.rb index a8bf968..c167cdb 100644 --- a/spec/lexer_spec.rb +++ b/spec/lexer_spec.rb @@ -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 diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 23f9622..89b2542 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -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([