static AST* identifier(Parser* p);
static AST* expr_list(Parser* p, int firstc, int endc);
+#define TRACE
+#ifdef TRACE
+static int Indent = 0;
+#define parse_enter() \
+ (printf("%*c-> %s\n", ++Indent * 2, ' ', __func__))
+#define parse_exit() \
+ (printf("%*c<- %s\n", --Indent * 2, ' ', __func__))
+#else
+#define parse_enter()
+#define parse_exit()
+#endif
+
/* Parsing Routines
*****************************************************************************/
static Tok* peek(Parser* p) {
/* Grammar Definition
*****************************************************************************/
void toplevel(Parser* p) {
+ parse_enter();
if (matches(p, T_REQUIRES))
require_list(p);
if (matches(p, T_PROVIDES))
provide_list(p);
definition_list(p);
+ parse_exit();
}
static void require_list(Parser* p) {
+ parse_enter();
accept(p, T_REQUIRES);
expect(p, '(');
while (!matches(p, ')')) {
pkg_add_require(&(p->pkg), tok->text);
}
expect(p, ')');
+ parse_exit();
}
static void provide_list(Parser* p) {
+ parse_enter();
accept(p, T_PROVIDES);
expect(p, '(');
while (!matches(p, ')')) {
pkg_add_provide(&(p->pkg), tok->text);
}
expect(p, ')');
+ parse_exit();
}
static void definition_list(Parser* p) {
+ parse_enter();
while (!matches(p, T_END_FILE)) {
AST* def = NULL;
if (matches(p, T_LET) || matches(p, T_VAR)) {
puts("");
pkg_add_definition(&(p->pkg), def);
}
+ parse_exit();
}
static AST* definition(Parser* p) {
+ parse_enter();
bool is_const = matches(p, T_LET);
if (!accept(p, T_LET) && !accept(p, T_VAR))
error(p, "constant or variable definition expected");
AST* type = type_expression(p);
expect(p, '=');
AST* val = expression(p);
+ parse_exit();
return Var(str, val, type, SF_CONSTANT);
}
static AST* type_definition(Parser* p) {
+ parse_enter();
expect(p, T_TYPE);
char* str = strdup(expect_val(p, T_ID)->text);
expect(p, '=');
AST* type = type_expression(p);
+ parse_exit();
return Var(str, NULL, type, SF_TYPEDEF);
}
static AST* func_definition(Parser* p) {
+ parse_enter();
expect(p, T_FUN);
char* name = strdup(expect_val(p, T_ID)->text);
expect(p, '(');
AST* type = type_expression(p);
AST* body = expression_block(p);
AST* func = Func(arglist, body, type);
+ parse_exit();
return Var(name, func, type, SF_CONSTANT);
}
+static AST* member_access(Parser* p);
+static AST* parenthesized(Parser* p);
+static AST* literal(Parser* p);
+
static AST* expression(Parser* p) {
+ parse_enter();
+ AST* exp;
+ if (matches(p, '{')) {
+ exp = expression_block(p);
+ } else if (matches(p, T_IF)) {
+ exp = if_expression(p);
+ } else {
+ exp = member_access(p);
+ /* check for function call syntax */
+ if (matches(p, '('))
+ exp = Apply(exp, expr_list(p, '(', ')'));
+ }
+ parse_exit();
+ return exp;
+}
+
+static AST* member_access(Parser* p) {
+ parse_enter();
+ AST* exp = parenthesized(p);
+ if (accept(p, '.')) {
+ AST* field = identifier(p);
+ // TODO: convert access to an apply or dedicated AST type
+ }
+ parse_exit();
+ return exp;
+}
+
+static AST* parenthesized(Parser* p) {
+ parse_enter();
AST* exp;
if (matches(p, '(')) {
expect(p, '(');
exp = expression(p);
expect(p, ')');
- } else if (matches(p, '[')) {
+ } else {
+ exp = literal(p);
+ }
+ parse_exit();
+ return exp;
+}
+
+static AST* literal(Parser* p) {
+ parse_enter();
+ AST* exp;
+ if (matches(p, '[')) {
exp = expr_list(p, '[', ']');
- } else if (matches(p, '{')) {
- exp = expression_block(p);
- } else if (matches(p, T_IF)) {
- exp = if_expression(p);
} else if (matches(p, T_ID)) {
exp = identifier(p);
+ // TODO: Struct init here?
} else {
exp = constant(p);
}
-
- /* check for member reference or UFCS call */
- AST *member = NULL, *args = NULL;
- if (accept(p, '.'))
- member = identifier(p);
- if (matches(p, '('))
- args = expr_list(p, '(', ')');
-
- if (member && !args)
- exp = exp; // ??? AST for struct reference
- else if (member && args)
- exp = Apply(member, args);
- else if (!member && args)
- exp = args;
-
+ parse_exit();
return exp;
}
static AST* constant(Parser* p) {
+ parse_enter();
AST* tree = NULL;
Tok* tok = peek(p);
switch (tok->type) {
default: error(p, "expected an expression");
}
accept(p, tok->type);
+ parse_exit();
return tree;
}