From: Michael D. Lowis Date: Sat, 12 Dec 2015 05:05:27 +0000 (-0500) Subject: Implemented function syntax for functions with no arguments X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=a1ac6e0c934ea07d111ba95b5250edc84c877dcb;p=proto%2Fsclpl.git Implemented function syntax for functions with no arguments --- diff --git a/source/ast.c b/source/ast.c index 3f92fff..2497c91 100644 --- a/source/ast.c +++ b/source/ast.c @@ -238,9 +238,23 @@ AST* block_get(AST* block, size_t index) return (AST*)vec_at(&(block->value.exprs), index); } +AST* Func(AST* args, AST* body) +{ + AST* node = ast(AST_FUNC); + node->value.func.args = args; + node->value.func.body = body; + return node; +} +AST* func_args(AST* func) +{ + return func->value.func.args; +} - +AST* func_body(AST* func) +{ + return func->value.func.body; +} //AST* Ann(char* name, AST* value) //{ @@ -261,25 +275,6 @@ AST* block_get(AST* block, size_t index) // return NULL; //} // -//AST* Func(AST* args, AST* body) -//{ -// (void)args; -// (void)body; -// return NULL; -//} -// -//AST* func_args(AST* func) -//{ -// (void)func; -// return NULL; -//} -// -//AST* func_body(AST* func) -//{ -// (void)func; -// return NULL; -//} -// //AST* Block(void) //{ // return NULL; diff --git a/source/grammar.c b/source/grammar.c index 38d35a6..f70a25c 100644 --- a/source/grammar.c +++ b/source/grammar.c @@ -10,6 +10,7 @@ static AST* require(Parser* p); static AST* definition(Parser* p); static AST* expression(Parser* p); static AST* if_stmnt(Parser* p); +static AST* function(Parser* p); static AST* literal(Parser* p); static AST* expr_block(Parser* p); static AST* token_to_tree(Tok* tok); @@ -20,9 +21,9 @@ AST* toplevel(Parser* p) if (!match(p, T_END_FILE)) { if (accept_str(p, T_ID, "require")) ret = require(p); - else if (accept_str(p, T_ID, "def")) + else if (accept_str(p, T_ID, "def")) { ret = definition(p); - else + } else ret = expression(p); } //printf("%p\n", ret); @@ -35,13 +36,14 @@ AST* toplevel(Parser* p) static AST* definition(Parser* p) { - Tok* id = expect(p, T_ID);//expect_lit(p, T_ID); + Tok* id = expect(p, T_ID); AST* expr; - //if (peek(p)->type == T_LPAR) - // expr = function(p); - //else + if (peek(p)->type == T_LPAR) { + expr = function(p); + } else { expr = expression(p); - expect(p, T_END); + expect(p, T_END); + } return Def(id, expr); } @@ -62,8 +64,8 @@ static AST* expression(Parser* p) return expr; } else if (accept_str(p, T_ID, "if")) { return if_stmnt(p); - //} else if (accept_str(p, T_ID, "fn")) { - // return fn_stmnt(p); + } else if (accept_str(p, T_ID, "fn")) { + return function(p); } else if (match(p, T_ID)) { return Ident(expect(p,T_ID)); //if (peek(p)->type == T_LPAR) { @@ -87,6 +89,20 @@ static AST* if_stmnt(Parser* p) return ifexpr; } +static AST* function(Parser* p) +{ + expect(p, T_LPAR); + //while(peek(p)->type != T_RPAR) { + // expect(p, T_ID); + // if(peek(p)->type != T_RPAR) + // expect(p, T_COMMA); + //} + expect(p, T_RPAR); + AST* body = expr_block(p); + expect(p, T_END); + return Func(NULL,body); +} + static AST* literal(Parser* p) { AST* ret = NULL; @@ -216,24 +232,5 @@ static AST* arglist(Parser* p) } -static AST* fn_stmnt(Parser* p) -{ - ////size_t mark1 = mark(p); - //expect(p, T_LPAR); - ////size_t mark2 = mark(p); - //while(peek(p)->type != T_RPAR) { - // expect(p, T_ID); - // if(peek(p)->type != T_RPAR) - // expect(p, T_COMMA); - //} - //expect(p, T_RPAR); - ////reduce(p, mark2); - //while(peek(p)->type != T_END) { - // expression(p); - //} - //expect(p, T_END); - ////reduce(p, mark1); - return NULL; -} #endif diff --git a/source/main.c b/source/main.c index 39c20ba..b9bf557 100644 --- a/source/main.c +++ b/source/main.c @@ -1,23 +1,8 @@ #include char* ARGV0; -bool verbose = false; -char* artifact = "bin"; - -/* Command Line Options - *****************************************************************************/ -const char Usage[] = - "Usage: sclpl [OPTION]... MODE [FILE]...\n" - "\n-A Emit the given type of artifact" - "\n-h Print help information" - "\n-v Enable verbose status messages" - "\n" -; - -void usage(void) { - fprintf(stderr, "%s", Usage); - exit(1); -} +bool Verbose = false; +char* Artifact = "bin"; /* Driver Modes *****************************************************************************/ @@ -53,6 +38,17 @@ static int emit_program(void) { return 0; } +/* Main Routine and Usage + *****************************************************************************/ +void usage(void) { + fprintf(stderr, "%s\n", + "Usage: sclpl [OPTION]... MODE [FILE]...\n" + "\n-A Emit the given type of artifact" + "\n-h Print help information" + "\n-v Enable verbose status messages"); + exit(1); +} + /* TODO: * Formalize grammar for parser @@ -62,25 +58,26 @@ static int emit_program(void) { */ int user_main(int argc, char **argv) { + /* Option parsing */ OPTBEGIN { - case 'A': artifact = EOPTARG(usage()); break; - case 'v': verbose = true; break; + case 'A': Artifact = EOPTARG(usage()); break; + case 'v': Verbose = true; break; default: usage(); } OPTEND; /* Execute the main compiler process */ - if (0 == strcmp("bin", artifact)) { + if (0 == strcmp("bin", Artifact)) { return emit_program(); - } else if (0 == strcmp("lib", artifact)) { + } else if (0 == strcmp("lib", Artifact)) { return emit_staticlib(); - } else if (0 == strcmp("src", artifact)) { + } else if (0 == strcmp("src", Artifact)) { return emit_csource(); - } else if (0 == strcmp("ast", artifact)) { + } else if (0 == strcmp("ast", Artifact)) { return emit_tree(); - } else if (0 == strcmp("tok", artifact)) { + } else if (0 == strcmp("tok", Artifact)) { return emit_tokens(); } else { - fprintf(stderr, "Unknonwn artifact type: '%s'\n\n", artifact); + fprintf(stderr, "Unknonwn artifact type: '%s'\n\n", Artifact); usage(); } return 1; diff --git a/source/pprint.c b/source/pprint.c index 53fcad2..52721e3 100644 --- a/source/pprint.c +++ b/source/pprint.c @@ -153,6 +153,12 @@ void pprint_tree(FILE* file, AST* tree, int depth) break; case AST_FUNC: + printf("(fn ()"); + for (size_t i = 0; i < block_size(func_body(tree)); i++) { + printf(" "); + pprint_tree(file, block_get(func_body(tree), i), depth); + } + printf(")"); break; default: diff --git a/source/sclpl.h b/source/sclpl.h index 296c30c..14a5700 100644 --- a/source/sclpl.h +++ b/source/sclpl.h @@ -171,7 +171,10 @@ void block_append(AST* block, AST* expr); size_t block_size(AST* block); AST* block_get(AST* block, size_t index); - +/* Function */ +AST* Func(AST* args, AST* body); +AST* func_args(AST* func); +AST* func_body(AST* func); ///* Annotation */ //AST* Ann(char* name, AST* value); @@ -179,10 +182,6 @@ AST* block_get(AST* block, size_t index); //AST* ann_value(AST* def); // // -///* Function */ -//AST* Func(AST* args, AST* body); -//AST* func_args(AST* func); -//AST* func_body(AST* func); // // /* Lexer and Parser Types diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index eb01dcf..545e4c6 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -69,8 +69,7 @@ describe "sclpl grammar" do ["if", "T_INT:123", ["block", "T_INT:321"], ["block", "T_INT:456"]]]) 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'] ]) @@ -129,21 +128,21 @@ describe "sclpl grammar" do # ['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 -# it "should parse a value definition" do -# expect(ast('def foo 123;')).to eq([ ['T_ID:def', 'T_ID:foo', 'T_INT:123'] ]) -# end -# -# it "should parse a function definition" do -# expect(ast('def foo() 123;')).to eq([ -# ['T_ID:def', 'T_ID:foo', ['T_ID:fn', [], 'T_INT:123']] ]) -# end -# -# it "should parse a function definition with multiple expressions in the body" do -# expect(ast('def foo() 123 321;')).to eq([ -# ['T_ID:def', 'T_ID:foo', ['T_ID:fn', [], 'T_INT:123', 'T_INT:321']] ]) -# end + + context "definitions" do + it "should parse a value definition" do + expect(ast('def foo 123;')).to eq([ ['def', 'foo', 'T_INT:123'] ]) + end + + it "should parse a function definition" do + expect(ast('def foo() 123;')).to eq([ + ['def', 'foo', ['fn', [], 'T_INT:123']] ]) + 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']] ]) + end # # it "should parse a function definition with one argument" do # expect(ast('def foo(a) 123;')).to eq([ @@ -159,7 +158,7 @@ describe "sclpl grammar" do # expect(ast('def foo(a,b,c) 123;')).to eq([ # ['T_ID:def', 'T_ID:foo', ['T_ID:fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'], 'T_INT:123']] ]) # end -# end + end # # context "annotations" do # it "should parse a type annotation for a simple type" do @@ -181,21 +180,21 @@ describe "sclpl grammar" do # end # end # -# context "expressions" do -# context "parenthese grouping" do -# it "should parse a parenthesized expression" do -# expect(ast('(123)')).to eq([['T_INT:123']]) -# end -# -# it "should parse a nested parenthesized expression" do -# expect(ast('((123))')).to eq([[['T_INT:123']]]) -# end -# end -# -# context "function literals" do -# it "should parse a function with no params" do -# expect(ast('fn() 123;')).to eq([["T_ID:fn", [], "T_INT:123"]]) -# end + context "expressions" do + context "parenthese grouping" do + it "should parse a parenthesized expression" do + expect(ast('(123)')).to eq(['T_INT:123']) + end + + it "should parse a nested parenthesized expression" do + expect(ast('((123))')).to eq(['T_INT:123']) + end + end + + context "function literals" do + it "should parse a function with no params" do + expect(ast('fn() 123;')).to eq([["fn", [], "T_INT:123"]]) + end # # it "should parse a function with one param" do # expect(ast('fn(a) 123;')).to eq([["T_ID:fn", ["T_ID:a"], "T_INT:123"]]) @@ -204,7 +203,7 @@ describe "sclpl grammar" do # it "should parse a function with two params" do # expect(ast('fn(a,b) 123;')).to eq([["T_ID:fn", ["T_ID:a", "T_ID:b"], "T_INT:123"]]) # end -# end + end # # context "function application" do # it "should parse an application with no params " do @@ -219,15 +218,15 @@ describe "sclpl grammar" do # expect(ast('foo(a,b)')).to eq([["T_ID:foo", "T_ID:a", "T_ID:b"]]) # end # end -# end -# -# context "corner cases" do -# it "an unexpected terminator should error" do -# expect{ast(';')}.to raise_error /Error/ -# end -# -# it "an invalid literal should error" do -# expect{ast('\'')}.to raise_error /Error/ -# end -# end + end + + context "corner cases" do + it "an unexpected terminator should error" do + expect{ast(';')}.to raise_error /Error/ + end + + it "an invalid literal should error" do + expect{ast('\'')}.to raise_error /Error/ + end + end end