/* Private Declarations
*****************************************************************************/
-// Sentinel EOF Token
-Tok tok_eof = { NULL, 0, 0, T_END_FILE, {0} };
-
// Grammar Routines
-static AST* require(Parser* p);
+static AST* const_definition(Parser* p);
+static AST* const_expression(Parser* p);
static AST* definition(Parser* p);
static AST* expression(Parser* p);
-static AST* if_stmnt(Parser* p);
static AST* function(Parser* p);
+static void type_annotation(Parser* p);
static AST* literal(Parser* p);
static AST* expr_block(Parser* p);
+static AST* if_stmnt(Parser* p);
static AST* token_to_tree(Tok* tok);
static AST* func_app(Parser* p, AST* fn);
-static void type_annotation(Parser* p);
// Parsing Routines
static void fetch(Parser* parser);
/* Grammar Definition
*****************************************************************************/
-AST* toplevel(Parser* p)
-{
+AST* toplevel(Parser* p) {
AST* ret = NULL;
if (!match(p, T_END_FILE)) {
if (accept(p, T_DEF))
- ret = definition(p);
+ ret = const_definition(p);
else
error(p, "only definitions are allowed at the toplevel");
}
return ret;
}
-static AST* definition(Parser* p)
-{
+static AST* const_definition(Parser* p) {
AST* expr;
Tok* id = expect(p, T_ID);
if (peek(p)->type == T_LPAR) {
expr = function(p);
} else {
type_annotation(p);
- expr = expression(p);
+ expr = const_expression(p);
expect(p, T_END);
}
return Def(id, expr);
}
-static AST* require(Parser* p)
-{
- AST* ast = Require(expect(p, T_STRING));
- expect(p, T_END);
- return ast;
+static AST* const_expression(Parser* p) {
+ AST* expr = NULL;
+ if (accept(p, T_LPAR)) {
+ expr = const_expression(p);
+ expect(p, T_RPAR);
+ } else if (accept(p, T_FN)) {
+ expr = function(p);
+ } else if (match(p, T_ID)) {
+ expr = Ident(expect(p,T_ID));
+ } else {
+ expr = literal(p);
+ }
+ return expr;
}
-static AST* expression(Parser* p)
-{
+static AST* definition(Parser* p) {
+ AST* expr;
+ Tok* id = expect(p, T_ID);
+ if (peek(p)->type == T_LPAR) {
+ expr = function(p);
+ } else {
+ type_annotation(p);
+ expr = expression(p);
+ expect(p, T_END);
+ }
+ return Def(id, expr);
+}
+
+static AST* expression(Parser* p) {
AST* expr = NULL;
if (accept(p, T_LPAR)) {
expr = expression(p);
return expr;
}
-static AST* if_stmnt(Parser* p)
-{
- AST* ifexpr = IfExpr();
- ifexpr_set_cond( ifexpr, expression(p) );
- accept(p, T_THEN);
- ifexpr_set_then( ifexpr, expr_block(p) );
- if (accept(p, T_ELSE))
- ifexpr_set_else( ifexpr, expr_block(p) );
- expect(p,T_END);
- return ifexpr;
-}
-
-static AST* function(Parser* p)
-{
+static AST* function(Parser* p) {
AST* func = Func();
expect(p, T_LPAR);
while(peek(p)->type != T_RPAR) {
return func;
}
-static AST* literal(Parser* p)
-{
+static void type_annotation(Parser* p) {
+ 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)) {
+ // TODO: implement reference types
+ }
+}
+
+static AST* literal(Parser* p) {
AST* ret = NULL;
Tok* tok = peek(p);
switch (tok->type) {
return ret;
}
-static AST* expr_block(Parser* p)
-{
+static AST* expr_block(Parser* p) {
AST* block = NULL;
vec_t exprs;
vec_init(&exprs);
}
}
-static AST* func_app(Parser* p, AST* fn)
-{
+static AST* if_stmnt(Parser* p) {
+ AST* ifexpr = IfExpr();
+ ifexpr_set_cond( ifexpr, expression(p) );
+ accept(p, T_THEN);
+ ifexpr_set_then( ifexpr, expr_block(p) );
+ if (accept(p, T_ELSE))
+ ifexpr_set_else( ifexpr, expr_block(p) );
+ expect(p,T_END);
+ return ifexpr;
+}
+
+static AST* func_app(Parser* p, AST* fn) {
AST* app = FnApp(fn);
expect(p,T_LPAR);
while (peek(p)->type != T_RPAR) {
return app;
}
-static void type_annotation(Parser* p)
-{
- 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)
gettoken(parser, &(parser->tok));
}
-static Tok* peek(Parser* parser)
+static Tok* peek(Parser* p)
{
- if (T_NONE == parser->tok.type)
- fetch(parser);
- return &(parser->tok);
+ if (T_NONE == p->tok.type)
+ gettoken(p, &(p->tok));
+ return &(p->tok);
}
static bool parser_eof(Parser* parser)
error(parser, "Unexpected token");
return tok;
}
-
require 'open3'
describe "sclpl grammar" do
- context "requires" do
- it "should parse a require statement" do
- expect(ast('require "foo";')).to eq([ ['require', '"foo"'] ])
- end
-
- it "should parse a require statement using end keyword" do
- expect(ast('require "foo" end')).to eq([ ['require', '"foo"'] ])
- end
-
- it "should error on missing semicolon" do
- expect{ast('require "foo"')}.to raise_error /Error/
- end
-
- it "should error on missing filename" do
- expect{ast('require ;')}.to raise_error /Error/
- end
-
- it "should error on invalid filename type" do
- expect{ast('require 123;')}.to raise_error /Error/
- end
-
- it "should error on too many parameters" do
- expect{ast('require foo bar;')}.to raise_error /Error/
- end
- end
-
- context "definitions" do
- 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 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() int 123 321;')).to eq([
- ['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() int def bar int 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 int) int 123;')).to eq([
- ['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 int, b int) int 123;')).to eq([
- ['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 int, b int, c int) int 123;')).to eq([
- ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'],
- ["let", ["$:0", "T_INT:123"], "$:0"]]]])
- end
- end
-
+# context "definitions" do
+# 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 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() int 123 321;')).to eq([
+# ['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() int def bar int 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 int) int 123;')).to eq([
+# ['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 int, b int) int 123;')).to eq([
+# ['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 int, b int, c int) int 123;')).to eq([
+# ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'],
+# ["let", ["$:0", "T_INT:123"], "$:0"]]]])
+# end
+# end
+#
# context "literals" do
# it "should parse a string" do
# expect(ast('"foo"')).to eq(['T_STRING:"foo"'])