From: Michael D. Lowis Date: Wed, 31 Aug 2016 02:14:02 +0000 (-0400) Subject: Added basic recognition of types and type annotations X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=HEAD;p=proto%2Fsclpl.git Added basic recognition of types and type annotations --- diff --git a/.gitignore b/.gitignore index 4bf735a..c85b455 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ cscope.out .rsconscache sclpl source/lexer.c +project.vim diff --git a/Makefile b/Makefile index 7fb63fe..8136bc9 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ TESTBIN = testsclpl TESTOBJS = tests/atf.o \ tests/sclpl/main.o -.PHONY: all options tests specs -all: sclpl specs tests +.PHONY: all tests specs +all: sclpl tests specs lib${BIN}.a: ${OBJS} ${AR} ${ARFLAGS} $@ $^ @@ -41,11 +41,11 @@ lib${BIN}.a: ${OBJS} ${BIN}: lib${BIN}.a ${LD} ${LDFLAGS} -o $@ $^ -${TESTBIN}: ${TESTOBJS} - ${LD} ${LDFLAGS} -o $@ $^ +#${TESTBIN}: ${TESTOBJS} +# ${LD} ${LDFLAGS} -o $@ $^ -tests: $(TESTBIN) - ./$< +#tests: ${TESTBIN} +# ./$< specs: $(BIN) rspec --pattern 'spec/**{,/*/**}/*_spec.rb' --format documentation diff --git a/source/lexer.l b/source/lexer.l index 9f949a2..a076a4c 100644 --- a/source/lexer.l +++ b/source/lexer.l @@ -43,6 +43,7 @@ NOSPACE [^ \t\r\n] "," { return T_COMMA; } "'" { return T_SQUOTE; } ":" { return T_COLON; } +"&" { return T_AMP; } \\. { Value.character = yytext[1]; return T_CHAR; } \\space { Value.character = ' '; return T_CHAR; } diff --git a/source/parser.c b/source/parser.c index 1b0840b..3bd066c 100644 --- a/source/parser.c +++ b/source/parser.c @@ -21,6 +21,7 @@ static AST* literal(Parser* p); static AST* expr_block(Parser* p); static AST* token_to_tree(Tok* tok); static AST* func_app(Parser* p, AST* fn); +static void optional_type(Parser* p); // Parsing Routines static void parser_free(void* obj); @@ -56,6 +57,7 @@ static AST* definition(Parser* p) if (peek(p)->type == T_LPAR) { expr = function(p); } else { + optional_type(p); expr = expression(p); expect(p, T_END); } @@ -109,10 +111,12 @@ static AST* function(Parser* p) expect(p, T_LPAR); while(peek(p)->type != T_RPAR) { func_add_arg(func, Ident(expect(p,T_ID))); + optional_type(p); if(peek(p)->type != T_RPAR) expect(p, T_COMMA); } expect(p, T_RPAR); + optional_type(p); func_set_body(func, expr_block(p)); expect(p, T_END); return func; @@ -188,6 +192,21 @@ static AST* func_app(Parser* p, AST* fn) return app; } +static void optional_type(Parser* p) +{ + if (accept(p, T_COLON)) { + expect(p, T_ID); + /* array type */ + if (accept(p,T_LBRACK)) { + accept(p, T_INT); + expect(p, T_RBRACK); + /* reference type */ + } else if (accept(p, T_AMP)) { + + } + } +} + /* Parsing Routines *****************************************************************************/ Parser* parser_new(char* prompt, FILE* input) diff --git a/source/pprint.c b/source/pprint.c index 048e7df..f8bb651 100644 --- a/source/pprint.c +++ b/source/pprint.c @@ -28,6 +28,7 @@ static const char* token_type_to_string(TokType type) { case T_ID: return "T_ID"; case T_END: return "T_END"; case T_COLON: return "T_COLON"; + case T_AMP: return "T_AMP"; case T_SQUOTE: return "T_SQUOTE"; case T_DQUOTE: return "T_DQUOTE"; case T_END_FILE: return "T_END_FILE"; diff --git a/source/sclpl.h b/source/sclpl.h index 64fff92..9ba913c 100644 --- a/source/sclpl.h +++ b/source/sclpl.h @@ -51,7 +51,7 @@ void vec_set(vec_t* vec, size_t index, void* data); *****************************************************************************/ typedef enum { T_ID, T_CHAR, T_INT, T_FLOAT, T_BOOL, T_STRING, T_LBRACE, T_RBRACE, T_LBRACK, - T_RBRACK, T_LPAR, T_RPAR, T_COMMA, T_SQUOTE, T_DQUOTE, T_END, T_COLON, + T_RBRACK, T_LPAR, T_RPAR, T_COMMA, T_SQUOTE, T_DQUOTE, T_END, T_COLON, T_AMP, T_REQUIRE, T_DEF, T_IF, T_FN, T_THEN, T_ELSE, T_END_FILE } TokType; @@ -82,6 +82,7 @@ typedef struct AST { /* Definition Node */ struct { char* name; + struct AST* type; struct AST* value; } def; /* If Expression */ diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 0f7376c..59ad238 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -94,12 +94,31 @@ describe "sclpl grammar" do expect(ast('def foo 123;')).to eq([ ['def', 'foo', 'T_INT:123'] ]) end + it "should error on missing type for definiton" do + expect{ast('def foo : 123;')}.to raise_error /Error/ + end + + it "should parse a value definition with type annotation" do + expect(ast('def foo:int 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', [], ["let", ["$:0", "T_INT:123"], "$:0"]]] ]) end + it "should parse a function definition with return type annotation" do + expect(ast('def foo():int 123;')).to eq([ + ['def', 'foo', ['fn', [], + ["let", ["$:0", "T_INT:123"], "$:0"]]] ]) + end + + it "should error on a function definition with missing return type" do + pending("TODO: fix the error message here") + expect(ast('def foo() : 123;')).to raise_error /Error/ + 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', [], @@ -151,12 +170,24 @@ describe "sclpl grammar" do ["let", ["$:0", "T_INT:123"], "$:0"]]]) end + it "should parse a function with no params and a return type annotation" do + expect(ast('fn():int 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"], ["let", ["$:0", "T_INT:123"], "$:0"]]]) end + it "should parse a function with one param with type annotation" do + expect(ast('fn(a:int) 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"],