add field specifiers
[ccc.git] / ast.c
diff --git a/ast.c b/ast.c
index 23619ec..97bd1ad 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -10,9 +10,9 @@ static const char *ast_type_str[] = {
        [an_assign] = "assign", [an_bool] = "bool", [an_binop] = "binop",
        [an_char] = "char", [an_cons] = "cons", [an_funcall] = "funcall",
        [an_fundecl] = "fundecl", [an_ident] = "ident", [an_if] = "if",
-       [an_int] = "int", [an_list] = "list", [an_return] = "return",
-       [an_stmt_expr] = "stmt_expr", [an_unop] = "unop",
-       [an_vardecl] = "vardecl", [an_while] = "while",
+       [an_int] = "int", [an_nil] = "nil", [an_list] = "list",
+       [an_return] = "return", [an_stmt_expr] = "stmt_expr",
+       [an_unop] = "unop", [an_vardecl] = "vardecl", [an_while] = "while",
 };
 #endif
 static const char *binop_str[] = {
@@ -21,6 +21,8 @@ static const char *binop_str[] = {
        [plus] = "+", [minus] = "-", [times] = "*", [divide] = "/",
        [modulo] = "%", [power] = "^",
 };
+static const char *fieldspec_str[] = {
+       [fst] = "fst", [snd] = "snd", [hd] = "hd", [tl] = "tl"};
 static const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
 
 #ifdef DEBUG
@@ -41,11 +43,7 @@ struct ast *ast_assign(struct ast *ident, struct ast *expr)
 {
        struct ast *res = ast_alloc();
        res->type = an_assign;
-
-       must_be(ident, an_ident, "ident of an assign");
-       res->data.an_assign.ident = ident->data.an_ident;
-       free(ident);
-
+       res->data.an_assign.ident = ident;
        res->data.an_assign.expr = expr;
        return res;
 }
@@ -119,7 +117,8 @@ struct ast *ast_funcall(struct ast *ident, struct ast *args)
 
        //ident
        must_be(ident, an_ident, "ident of a funcall");
-       res->data.an_funcall.ident = ident->data.an_ident;
+       res->data.an_funcall.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
 
        //args
@@ -137,18 +136,19 @@ struct ast *ast_fundecl(struct ast *ident, struct ast *args, struct ast *body)
 
        //ident
        must_be(ident, an_ident, "ident of a fundecl");
-       res->data.an_fundecl.ident = ident->data.an_ident;
+       res->data.an_fundecl.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
 
        //args
        must_be(args, an_list, "args of a fundecl");
        res->data.an_fundecl.nargs = args->data.an_list.n;
-       res->data.an_fundecl.args = (char **)safe_malloc(
-               args->data.an_list.n*sizeof(char *));
+       res->data.an_fundecl.args = (char **)args->data.an_list.ptr;
        for (int i = 0; i<args->data.an_list.n; i++) {
                struct ast *e = args->data.an_list.ptr[i];
                must_be(e, an_ident, "arg of a fundecl")
-               res->data.an_fundecl.args[i] = e->data.an_ident;
+               res->data.an_fundecl.args[i] = e->data.an_ident.ident;
+               free(e->data.an_ident.fields);
                free(e);
        }
        free(args);
@@ -168,12 +168,12 @@ struct ast *ast_if(struct ast *pred, struct ast *then, struct ast *els)
        res->type = an_if;
        res->data.an_if.pred = pred;
 
-       must_be(body, an_list, "body of a then");
+       must_be(then, an_list, "body of a then");
        res->data.an_if.nthen = then->data.an_list.n;
        res->data.an_if.then = then->data.an_list.ptr;
        free(then);
 
-       must_be(body, an_list, "body of a els");
+       must_be(els, an_list, "body of a els");
        res->data.an_if.nels = els->data.an_list.n;
        res->data.an_if.els = els->data.an_list.ptr;
        free(els);
@@ -189,11 +189,44 @@ struct ast *ast_int(int integer)
        return res;
 }
 
-struct ast *ast_ident(char *ident)
+struct ast *ast_identc(char *ident)
+{
+       struct ast *res = ast_alloc();
+       res->type = an_ident;
+       res->data.an_ident.ident = safe_strdup(ident);
+       res->data.an_ident.nfields = 0;
+       res->data.an_ident.fields = NULL;
+       return res;
+}
+
+struct ast *ast_ident(struct ast *ident, struct ast *fields)
 {
        struct ast *res = ast_alloc();
        res->type = an_ident;
-       res->data.an_ident = safe_strdup(ident);
+       must_be(fields, an_ident, "ident of an ident");
+       res->data.an_ident.ident = ident->data.an_ident.ident;
+       free(ident);
+
+       must_be(fields, an_list, "fields of an ident");
+       res->data.an_ident.nfields = fields->data.an_list.n;
+       res->data.an_ident.fields = (enum fieldspec *)safe_malloc(
+               fields->data.an_list.n*sizeof(enum fieldspec));
+       for (int i = 0; i<fields->data.an_list.n; i++) {
+               struct ast *t = fields->data.an_list.ptr[i];
+               must_be(t, an_ident, "field of an ident");
+               if (strcmp(t->data.an_ident.ident, "fst") == 0)
+                       res->data.an_ident.fields[i] = fst;
+               else if (strcmp(t->data.an_ident.ident, "snd") == 0)
+                       res->data.an_ident.fields[i] = snd;
+               else if (strcmp(t->data.an_ident.ident, "hd") == 0)
+                       res->data.an_ident.fields[i] = hd;
+               else if (strcmp(t->data.an_ident.ident, "tl") == 0)
+                       res->data.an_ident.fields[i] = tl;
+               free(t->data.an_ident.ident);
+               free(t);
+       }
+       free(fields->data.an_list.ptr);
+       free(fields);
        return res;
 }
 
@@ -258,7 +291,8 @@ struct ast *ast_vardecl(struct ast *ident, struct ast *l)
        res->type = an_vardecl;
        must_be(ident, an_ident, "ident of a vardecl");
 
-       res->data.an_vardecl.ident = ident->data.an_ident;
+       res->data.an_vardecl.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
        res->data.an_vardecl.l = l;
        return res;
@@ -311,7 +345,8 @@ void ast_print(struct ast *ast, int indent, FILE *out)
        switch(ast->type) {
        case an_assign:
                pindent(indent, out);
-               safe_fprintf(out, "%s = ", ast->data.an_assign.ident);
+               ast_print(ast->data.an_assign.ident, indent, out);
+               safe_fprintf(out, " = ");
                ast_print(ast->data.an_assign.expr, indent, out);
                safe_fprintf(out, ";\n");
                break;
@@ -375,7 +410,10 @@ void ast_print(struct ast *ast, int indent, FILE *out)
                safe_fprintf(out, "%d", ast->data.an_int);
                break;
        case an_ident:
-               safe_fprintf(out, "%s", ast->data.an_ident);
+               fprintf(out, "%s", ast->data.an_ident.ident);
+               for (int i = 0; i<ast->data.an_ident.nfields; i++)
+                       fprintf(out, ".%s",
+                               fieldspec_str[ast->data.an_ident.fields[i]]);
                break;
        case an_cons:
                ast_print(ast->data.an_cons.el, indent, out);
@@ -435,7 +473,7 @@ void ast_free(struct ast *ast)
 #endif
        switch(ast->type) {
        case an_assign:
-               free(ast->data.an_assign.ident);
+               ast_free(ast->data.an_assign.ident);
                ast_free(ast->data.an_assign.expr);
                break;
        case an_binop:
@@ -453,7 +491,7 @@ void ast_free(struct ast *ast)
        case an_funcall:
                free(ast->data.an_funcall.ident);
                for (int i = 0; i<ast->data.an_fundecl.nargs; i++)
-                       free(ast->data.an_fundecl.args[i]);
+                       ast_free(ast->data.an_funcall.args[i]);
                free(ast->data.an_funcall.args);
                break;
        case an_fundecl:
@@ -477,7 +515,8 @@ void ast_free(struct ast *ast)
        case an_int:
                break;
        case an_ident:
-               free(ast->data.an_ident);
+               free(ast->data.an_ident.ident);
+               free(ast->data.an_ident.fields);
                break;
        case an_list:
                for (int i = 0; i<ast->data.an_list.n; i++)