#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
+#include "util.h"
#include "ast.h"
+#include "type.h"
+#include "list.h"
+#include "parse.h"
-struct ast *ast_alloc()
+const char *binop_str[] = {
+ [binor] = "||", [binand] = "&&", [eq] = "==", [neq] = "!=",
+ [leq] = "<=", [le] = "<", [geq] = ">=", [ge] = ">", [cons] = ":",
+ [plus] = "+", [minus] = "-", [times] = "*", [divide] = "/",
+ [modulo] = "%", [power] = "^",
+};
+const char *fieldspec_str[] = {
+ [fst] = "fst", [snd] = "snd", [hd] = "hd", [tl] = "tl"};
+const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
+
+struct ast *ast(struct list *decls)
+{
+ struct ast *res = safe_malloc(sizeof(struct ast));
+ res->decls = (struct decl **)list_to_array(decls, &res->ndecls, true);
+ return res;
+}
+
+struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr)
+{
+ struct vardecl *res = safe_malloc(sizeof(struct vardecl));
+ res->type = type;
+ res->ident = ident;
+ res->expr = expr;
+ return res;
+}
+struct fundecl *fundecl(char *ident, struct list *args, struct list *atypes,
+ struct type *rtype, struct list *body)
+{
+ struct fundecl *res = safe_malloc(sizeof(struct fundecl));
+ res->ident = ident;
+ res->args = (char **)list_to_array(args, &res->nargs, true);
+ res->atypes = (struct type **)list_to_array(atypes, &res->natypes, true);
+ res->rtype = rtype;
+ res->body = (struct stmt **)list_to_array(body, &res->nbody, true);
+ return res;
+}
+
+struct decl *decl_fun(struct fundecl *fundecl)
+{
+ struct decl *res = safe_malloc(sizeof(struct decl));
+ res->type = dfundecl;
+ res->data.dfun = fundecl;
+ return res;
+}
+
+struct decl *decl_var(struct vardecl *vardecl)
+{
+ struct decl *res = safe_malloc(sizeof(struct decl));
+ res->type = dvardecl;
+ res->data.dvar = vardecl;
+ return res;
+}
+
+struct stmt *stmt_assign(char *ident, struct list *fields, struct expr *expr)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = sassign;
+ res->data.sassign.ident = ident;
+ res->data.sassign.fields = (char **)
+ list_to_array(fields, &res->data.sassign.nfields, true);
+ res->data.sassign.expr = expr;
+ return res;
+}
+
+struct stmt *stmt_if(struct expr *pred, struct list *then, struct list *els)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = sif;
+ res->data.sif.pred = pred;
+ res->data.sif.then = (struct stmt **)
+ list_to_array(then, &res->data.sif.nthen, true);
+ res->data.sif.els = (struct stmt **)
+ list_to_array(els, &res->data.sif.nels, true);
+ return res;
+}
+
+struct stmt *stmt_return(struct expr *rtrn)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = sreturn;
+ res->data.sreturn = rtrn;
+ return res;
+}
+
+struct stmt *stmt_expr(struct expr *expr)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = sexpr;
+ res->data.sexpr = expr;
+ return res;
+}
+
+struct stmt *stmt_vardecl(struct vardecl *vardecl)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = svardecl;
+ res->data.svardecl = vardecl;
+ return res;
+}
+
+struct stmt *stmt_while(struct expr *pred, struct list *body)
+{
+ struct stmt *res = safe_malloc(sizeof(struct stmt));
+ res->type = swhile;
+ res->data.swhile.pred = pred;
+ res->data.swhile.body = (struct stmt **)
+ list_to_array(body, &res->data.swhile.nbody, true);
+ return res;
+}
+
+struct expr *expr_binop(struct expr *l, enum binop op, struct expr *r)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = ebinop;
+ res->data.ebinop.l = l;
+ res->data.ebinop.op = op;
+ res->data.ebinop.r = r;
+ return res;
+}
+
+struct expr *expr_bool(bool b)
{
- struct ast *res = malloc(sizeof(struct ast));
- if (res == NULL) {
- perror("malloc");
- exit(1);
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = ebool;
+ res->data.ebool = b;
+ return res;
+}
+
+struct expr *expr_char(char *c)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = echar;
+ res->data.echar = unescape_char(c)[0];
+ return res;
+}
+
+static void set_fields(enum fieldspec **farray, int *n, struct list *fields)
+{
+ void **els = list_to_array(fields, n, true);
+ *farray = (enum fieldspec *)safe_malloc(*n*sizeof(enum fieldspec));
+ for (int i = 0; i<*n; i++) {
+ char *t = els[i];
+ if (strcmp(t, "fst") == 0)
+ (*farray)[i] = fst;
+ else if (strcmp(t, "snd") == 0)
+ (*farray)[i] = snd;
+ else if (strcmp(t, "hd") == 0)
+ (*farray)[i] = hd;
+ else if (strcmp(t, "tl") == 0)
+ (*farray)[i] = tl;
+ free(t);
}
+ free(els);
+}
+
+
+struct expr *expr_funcall(char *ident, struct list *args, struct list *fields)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = efuncall;
+ res->data.efuncall.ident = ident;
+ res->data.efuncall.args = (struct expr **)
+ list_to_array(args, &res->data.efuncall.nargs, true);
+ set_fields(&res->data.efuncall.fields,
+ &res->data.efuncall.nfields, fields);
return res;
}
-struct ast *ast_cons(struct ast *el, struct ast *tail)
+struct expr *expr_int(int integer)
{
- struct ast *res = ast_alloc();
- res->type = an_cons;
- res->data.an_cons.el = el;
- res->data.an_cons.tail = tail;
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = eint;
+ res->data.eint = integer;
return res;
}
-struct ast *ast_binop(struct ast *l, enum binop op, struct ast *r)
+struct expr *expr_ident(char *ident, struct list *fields)
{
- struct ast *res = ast_alloc();
- res->type = an_binop;
- res->data.an_binop.l = l;
- res->data.an_binop.op = op;
- res->data.an_binop.r = r;
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = eident;
+ res->data.eident.ident = ident;
+ set_fields(&res->data.eident.fields, &res->data.eident.nfields, fields);
return res;
}
-struct ast *ast_int(int integer)
+struct expr *expr_nil()
{
- struct ast *res = ast_alloc();
- res->type = an_int;
- res->data.an_int = integer;
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = enil;
return res;
}
-static const char *binop_str[] = {
- [plus] = "+",
- [minus] = "+",
- [times] = "+",
- [divide] = "+",
-};
+struct expr *expr_tuple(struct expr *left, struct expr *right)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = etuple;
+ res->data.etuple.left = left;
+ res->data.etuple.right = right;
+ return res;
+}
-void ast_print(struct ast * ast, FILE *out)
+struct expr *expr_string(char *str)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = estring;
+ res->data.estring.nchars = 0;
+ res->data.estring.chars = safe_malloc(strlen(str)+1);
+ char *p = res->data.estring.chars;
+ while(*str != '\0') {
+ str = unescape_char(str);
+ *p++ = *str++;
+ res->data.estring.nchars++;
+ }
+ *p = '\0';
+ return res;
+}
+
+struct expr *expr_unop(enum unop op, struct expr *l)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = eunop;
+ res->data.eunop.op = op;
+ res->data.eunop.l = l;
+ return res;
+}
+
+void ast_print(struct ast *ast, FILE *out)
{
if (ast == NULL)
return;
- switch(ast->type) {
- case an_binop:
- fprintf(out, "(");
- ast_print(ast->data.an_binop.l, out);
- fprintf(out, "%s", binop_str[ast->data.an_binop.op]);
- ast_print(ast->data.an_binop.r, out);
- fprintf(out, ")");
- break;
- case an_cons:
- ast_print(ast->data.an_cons.el, out);
- fprintf(out, ";\n");
- ast_print(ast->data.an_cons.tail, out);
- break;
- case an_int:
- fprintf(out, "%d", ast->data.an_int);
+ for (int i = 0; i<ast->ndecls; i++)
+ decl_print(ast->decls[i], out);
+}
+
+void vardecl_print(struct vardecl *decl, int indent, FILE *out)
+{
+ pindent(indent, out);
+ if (decl->type == NULL)
+ safe_fprintf(out, "var");
+ else
+ type_print(decl->type, out);
+ safe_fprintf(out, " %s = ", decl->ident);
+ expr_print(decl->expr, out);
+ safe_fprintf(out, ";\n");
+}
+
+void fundecl_print(struct fundecl *decl, FILE *out)
+{
+ safe_fprintf(out, "%s (", decl->ident);
+ for (int i = 0; i<decl->nargs; i++) {
+ safe_fprintf(out, "%s", decl->args[i]);
+ if (i < decl->nargs - 1)
+ safe_fprintf(out, ", ");
+ }
+ safe_fprintf(out, ")");
+ if (decl->rtype != NULL) {
+ safe_fprintf(out, " :: ");
+ for (int i = 0; i<decl->natypes; i++) {
+ type_print(decl->atypes[i], out);
+ safe_fprintf(out, " ");
+ }
+ safe_fprintf(out, "-> ");
+ type_print(decl->rtype, out);
+ }
+ safe_fprintf(out, " {\n");
+ for (int i = 0; i<decl->nbody; i++)
+ stmt_print(decl->body[i], 1, out);
+ safe_fprintf(out, "}\n");
+}
+
+void decl_print(struct decl *decl, FILE *out)
+{
+ if (decl == NULL)
+ return;
+ switch(decl->type) {
+ case dfundecl:
+ fundecl_print(decl->data.dfun, out);
+ break;
+ case dvardecl:
+ vardecl_print(decl->data.dvar, 0, out);
+ break;
+ case dcomp:
+ fprintf(out, "//<<<comp\n");
+ for (int i = 0; i<decl->data.dcomp.ndecls; i++)
+ fundecl_print(decl->data.dcomp.decls[i], out);
+ fprintf(out, "//>>>comp\n");
break;
default:
- fprintf(stderr, "Unsupported AST node\n");
- exit(1);
+ die("Unsupported decl node\n");
+ }
+}
+
+void stmt_print(struct stmt *stmt, int indent, FILE *out)
+{
+ if (stmt == NULL)
+ return;
+ switch(stmt->type) {
+ case sassign:
+ pindent(indent, out);
+ fprintf(out, "%s", stmt->data.sassign.ident);
+ for (int i = 0; i<stmt->data.sassign.nfields; i++)
+ fprintf(out, ".%s", stmt->data.sassign.fields[i]);
+ safe_fprintf(out, " = ");
+ expr_print(stmt->data.sassign.expr, out);
+ safe_fprintf(out, ";\n");
+ break;
+ case sif:
+ pindent(indent, out);
+ safe_fprintf(out, "if (");
+ expr_print(stmt->data.sif.pred, out);
+ safe_fprintf(out, ") {\n");
+ for (int i = 0; i<stmt->data.sif.nthen; i++)
+ stmt_print(stmt->data.sif.then[i], indent+1, out);
+ pindent(indent, out);
+ safe_fprintf(out, "} else {\n");
+ for (int i = 0; i<stmt->data.sif.nels; i++)
+ stmt_print(stmt->data.sif.els[i], indent+1, out);
+ pindent(indent, out);
+ safe_fprintf(out, "}\n");
+ break;
+ case sreturn:
+ pindent(indent, out);
+ safe_fprintf(out, "return ");
+ expr_print(stmt->data.sreturn, out);
+ safe_fprintf(out, ";\n");
+ break;
+ case sexpr:
+ pindent(indent, out);
+ expr_print(stmt->data.sexpr, out);
+ safe_fprintf(out, ";\n");
+ break;
+ case svardecl:
+ vardecl_print(stmt->data.svardecl, indent, out);
+ break;
+ case swhile:
+ pindent(indent, out);
+ safe_fprintf(out, "while (");
+ expr_print(stmt->data.swhile.pred, out);
+ safe_fprintf(out, ") {\n");
+ for (int i = 0; i<stmt->data.swhile.nbody; i++)
+ stmt_print(stmt->data.swhile.body[i], indent+1, out);
+ pindent(indent, out);
+ safe_fprintf(out, "}\n");
+ break;
+ default:
+ die("Unsupported stmt node\n");
+ }
+}
+
+void expr_print(struct expr *expr, FILE *out)
+{
+ if (expr == NULL)
+ return;
+ char buf[] = "\\xff";
+ switch(expr->type) {
+ case ebinop:
+ safe_fprintf(out, "(");
+ expr_print(expr->data.ebinop.l, out);
+ safe_fprintf(out, "%s", binop_str[expr->data.ebinop.op]);
+ expr_print(expr->data.ebinop.r, out);
+ safe_fprintf(out, ")");
+ break;
+ case ebool:
+ safe_fprintf(out, "%s", expr->data.ebool ? "true" : "false");
+ break;
+ case echar:
+ safe_fprintf(out, "'%s'",
+ escape_char(expr->data.echar, buf, false));
+ break;
+ case efuncall:
+ safe_fprintf(out, "%s(", expr->data.efuncall.ident);
+ for(int i = 0; i<expr->data.efuncall.nargs; i++) {
+ expr_print(expr->data.efuncall.args[i], out);
+ if (i+1 < expr->data.efuncall.nargs)
+ safe_fprintf(out, ", ");
+ }
+ safe_fprintf(out, ")");
+ for (int i = 0; i<expr->data.efuncall.nfields; i++)
+ fprintf(out, ".%s",
+ fieldspec_str[expr->data.efuncall.fields[i]]);
+ break;
+ case eint:
+ safe_fprintf(out, "%d", expr->data.eint);
+ break;
+ case eident:
+ fprintf(out, "%s", expr->data.eident.ident);
+ for (int i = 0; i<expr->data.eident.nfields; i++)
+ fprintf(out, ".%s",
+ fieldspec_str[expr->data.eident.fields[i]]);
+ break;
+ case enil:
+ safe_fprintf(out, "[]");
+ break;
+ case etuple:
+ safe_fprintf(out, "(");
+ expr_print(expr->data.etuple.left, out);
+ safe_fprintf(out, ", ");
+ expr_print(expr->data.etuple.right, out);
+ safe_fprintf(out, ")");
+ break;
+ case estring:
+ safe_fprintf(out, "\"");
+ for (int i = 0; i<expr->data.estring.nchars; i++)
+ safe_fprintf(out, "%s", escape_char(
+ expr->data.estring.chars[i], buf, true));
+ safe_fprintf(out, "\"");
+ break;
+ case eunop:
+ safe_fprintf(out, "(%s", unop_str[expr->data.eunop.op]);
+ expr_print(expr->data.eunop.l, out);
+ safe_fprintf(out, ")");
+ break;
+ default:
+ die("Unsupported expr node\n");
}
}
{
if (ast == NULL)
return;
- switch(ast->type) {
- case an_binop:
- ast_free(ast->data.an_binop.l);
- ast_free(ast->data.an_binop.r);
+ for (int i = 0; i<ast->ndecls; i++)
+ decl_free(ast->decls[i]);
+ free(ast->decls);
+ free(ast);
+}
+
+void vardecl_free(struct vardecl *decl)
+{
+ type_free(decl->type);
+ free(decl->ident);
+ expr_free(decl->expr);
+ free(decl);
+}
+
+void fundecl_free(struct fundecl *decl)
+{
+ free(decl->ident);
+ for (int i = 0; i<decl->nargs; i++)
+ free(decl->args[i]);
+ free(decl->args);
+ for (int i = 0; i<decl->natypes; i++)
+ type_free(decl->atypes[i]);
+ free(decl->atypes);
+ type_free(decl->rtype);
+ for (int i = 0; i<decl->nbody; i++)
+ stmt_free(decl->body[i]);
+ free(decl->body);
+ free(decl);
+}
+
+void decl_free(struct decl *decl)
+{
+ if (decl == NULL)
+ return;
+ switch(decl->type) {
+ case dcomp:
+ for (int i = 0; i<decl->data.dcomp.ndecls; i++)
+ fundecl_free(decl->data.dcomp.decls[i]);
+ free(decl->data.dcomp.decls);
break;
- case an_cons:
- ast_free(ast->data.an_cons.el);
- ast_free(ast->data.an_cons.tail);
+ case dfundecl:
+ fundecl_free(decl->data.dfun);
break;
- case an_int:
+ case dvardecl:
+ vardecl_free(decl->data.dvar);
break;
default:
- fprintf(stderr, "Unsupported AST node\n");
- exit(1);
+ die("Unsupported decl node\n");
}
- free(ast);
+ free(decl);
+}
+
+void stmt_free(struct stmt *stmt)
+{
+ if (stmt == NULL)
+ return;
+ switch(stmt->type) {
+ case sassign:
+ free(stmt->data.sassign.ident);
+ for (int i = 0; i<stmt->data.sassign.nfields; i++)
+ free(stmt->data.sassign.fields[i]);
+ free(stmt->data.sassign.fields);
+ expr_free(stmt->data.sassign.expr);
+ break;
+ case sif:
+ expr_free(stmt->data.sif.pred);
+ for (int i = 0; i<stmt->data.sif.nthen; i++)
+ stmt_free(stmt->data.sif.then[i]);
+ free(stmt->data.sif.then);
+ for (int i = 0; i<stmt->data.sif.nels; i++)
+ stmt_free(stmt->data.sif.els[i]);
+ free(stmt->data.sif.els);
+ break;
+ case sreturn:
+ expr_free(stmt->data.sreturn);
+ break;
+ case sexpr:
+ expr_free(stmt->data.sexpr);
+ break;
+ case swhile:
+ expr_free(stmt->data.swhile.pred);
+ for (int i = 0; i<stmt->data.swhile.nbody; i++)
+ stmt_free(stmt->data.swhile.body[i]);
+ free(stmt->data.swhile.body);
+ break;
+ case svardecl:
+ vardecl_free(stmt->data.svardecl);
+ break;
+ default:
+ die("Unsupported stmt node\n");
+ }
+ free(stmt);
+}
+
+void expr_free(struct expr *expr)
+{
+ if (expr == NULL)
+ return;
+ switch(expr->type) {
+ case ebinop:
+ expr_free(expr->data.ebinop.l);
+ expr_free(expr->data.ebinop.r);
+ break;
+ case ebool:
+ break;
+ case echar:
+ break;
+ case efuncall:
+ free(expr->data.efuncall.ident);
+ for (int i = 0; i<expr->data.efuncall.nargs; i++)
+ expr_free(expr->data.efuncall.args[i]);
+ free(expr->data.efuncall.fields);
+ free(expr->data.efuncall.args);
+ break;
+ case eint:
+ break;
+ case eident:
+ free(expr->data.eident.ident);
+ free(expr->data.eident.fields);
+ break;
+ case enil:
+ break;
+ case etuple:
+ expr_free(expr->data.etuple.left);
+ expr_free(expr->data.etuple.right);
+ break;
+ case estring:
+ free(expr->data.estring.chars);
+ break;
+ case eunop:
+ expr_free(expr->data.eunop.l);
+ break;
+ default:
+ die("Unsupported expr node\n");
+ }
+ free(expr);
}