tomo/ast.c

181 lines
7.7 KiB
C

// Some basic operations defined on AST nodes, mainly converting to
// strings for debugging.
#include <gc/cord.h>
#include <stdarg.h>
#include <printf.h>
#include "ast.h"
static const char *OP_NAMES[] = {
[BINOP_UNKNOWN]="unknown",
[UNOP_NOT]="not", [UNOP_NEGATIVE]="negative",
[UNOP_HEAP_ALLOCATE]="@", [UNOP_STACK_REFERENCE]="&",
[BINOP_POWER]="^", [BINOP_MULT]="*", [BINOP_DIVIDE]="/",
[BINOP_MOD]="mod", [BINOP_MOD1]="mod1", [BINOP_PLUS]="+", [BINOP_MINUS]="minus",
[BINOP_CONCAT]="++", [BINOP_LSHIFT]="<<", [BINOP_RSHIFT]=">>", [BINOP_MIN]="min",
[BINOP_MAX]="max", [BINOP_EQ]="==", [BINOP_NE]="!=", [BINOP_LT]="<",
[BINOP_LE]="<=", [BINOP_GT]=">", [BINOP_GE]=">=", [BINOP_AND]="and", [BINOP_OR]="or", [BINOP_XOR]="xor",
};
static CORD ast_to_cord(ast_t *ast);
static CORD ast_list_to_cord(ast_list_t *asts);
static CORD type_ast_to_cord(type_ast_t *t);
static CORD arg_list_to_cord(arg_list_t *args);
static CORD tags_to_cord(tag_t *tags);
#define TO_CORD(x) _Generic(x, \
ast_t*: ast_to_cord(x), \
ast_list_t*: ast_list_to_cord(x), \
type_ast_t*: type_ast_to_cord(x), \
arg_list_t*: arg_list_to_cord(x), \
tag_t*: tags_to_cord(x), \
const char *: x, \
int64_t: CORD_asprintf("%ld", x), \
unsigned short int: CORD_asprintf("%d", x), \
double: CORD_asprintf("%g", x), \
bool: CORD_asprintf("%s", x ? "yes" : "no"), \
unsigned char: CORD_asprintf("%s", x ? "yes" : "no"))
CORD ast_list_to_cord(ast_list_t *asts)
{
if (!asts)
return "\x1b[35mNULL\x1b[m";
CORD c = "[";
for (; asts; asts = asts->next) {
c = CORD_cat(c, ast_to_cord(asts->ast));
if (asts->next) c = CORD_cat(c, ", ");
}
c = CORD_cat(c, "]");
return c;
}
CORD arg_list_to_cord(arg_list_t *args) {
CORD c = "Args(";
for (; args; args = args->next) {
if (args->var.name)
c = CORD_cat(c, args->var.name);
if (args->type)
CORD_sprintf(&c, "%r:%s", c, type_ast_to_cord(args->type));
if (args->default_val)
CORD_sprintf(&c, "%r=%s", c, ast_to_cord(args->default_val));
if (args->next) c = CORD_cat(c, ", ");
}
c = CORD_cat(c, ")");
return c;
}
CORD tags_to_cord(tag_t *tags) {
CORD c = "Tags(";
for (; tags; tags = tags->next) {
if (tags->name)
c = CORD_cat(c, tags->name);
CORD_sprintf(&c, "%r:%s=%ld", c, type_ast_to_cord(tags->type), tags->value);
if (tags->next) c = CORD_cat(c, ", ");
}
c = CORD_cat(c, ")");
return c;
}
CORD ast_to_cord(ast_t *ast)
{
if (!ast) return "\x1b[35mNULL\x1b[m";
switch (ast->tag) {
#define T(type, ...) case type: { auto data = ast->__data.type; (void)data; return CORD_asprintf("\x1b[34;1m" #type "\x1b[m" __VA_ARGS__); }
T(Unknown, "Unknown")
T(Nil, "(%r)", type_ast_to_cord(data.type))
T(Bool, "(\x1b[35m%s\x1b[m)", data.b ? "yes" : "no")
T(Var, "(\x1b[36;1m%s\x1b[m)", data.var.name)
T(Int, "(\x1b[35m%ld\x1b[m, precision=\x1b[35m%ld\x1b[m)", data.i, data.precision)
T(Num, "(\x1b[35m%ld\x1b[m, precision=\x1b[35m%ld\x1b[m)", data.n, data.precision)
T(Char, "(\x1b[35m'%c'\x1b[m)", data.c)
T(StringLiteral, "\x1b[35m\"%s\"\x1b[m", data.str)
T(StringJoin, "(%r)", ast_list_to_cord(data.children))
T(Interp, "(%r)", ast_to_cord(data.value))
T(Declare, "(var=%s, value=%s)", ast_to_cord(data.var), ast_to_cord(data.value))
T(Assign, "(targets=%r, values=%r)", ast_list_to_cord(data.targets), ast_list_to_cord(data.values))
T(BinaryOp, "(%r, %s, %r)", ast_to_cord(data.lhs), OP_NAMES[data.op], ast_to_cord(data.rhs))
T(UpdateAssign, "(%r, %s, %r)", ast_to_cord(data.lhs), OP_NAMES[data.op], ast_to_cord(data.rhs))
T(UnaryOp, "(%s, %r)", OP_NAMES[data.op], ast_to_cord(data.value))
T(Min, "(%r, %r, key=%r)", ast_to_cord(data.lhs), ast_to_cord(data.rhs), ast_to_cord(data.key))
T(Max, "(%r, %r, key=%r)", ast_to_cord(data.lhs), ast_to_cord(data.rhs), ast_to_cord(data.key))
T(Array, "(%r, type=%r)", ast_list_to_cord(data.items), type_ast_to_cord(data.type))
T(Table, "(key_type=%r, value_type=%r, fallback=%r, default_value=%r, entries=%r)",
type_ast_to_cord(data.key_type), type_ast_to_cord(data.value_type),
ast_to_cord(data.fallback), ast_to_cord(data.default_value),
ast_list_to_cord(data.entries))
T(TableEntry, "(%r => %r)", ast_to_cord(data.key), ast_to_cord(data.value))
T(FunctionDef, "(name=%r, args=%r, ret=%r, body=%r)", ast_to_cord(data.name),
arg_list_to_cord(data.args), type_ast_to_cord(data.ret_type), ast_to_cord(data.body))
T(Lambda, "(args=%r, body=%r)", arg_list_to_cord(data.args), ast_to_cord(data.body))
T(FunctionCall, "(fn=%r, args=%r)", ast_to_cord(data.fn), ast_list_to_cord(data.args))
T(KeywordArg, "(%s=%r)", ast_to_cord(data.arg))
T(Block, "(%r)", ast_list_to_cord(data.statements))
T(For, "(index=%r, value=%r, iter=%r, body=%r)", ast_to_cord(data.index), ast_to_cord(data.value),
ast_to_cord(data.iter), ast_to_cord(data.body))
T(While, "(condition=%r, body=%r)", ast_to_cord(data.condition), ast_to_cord(data.body))
T(If, "(condition=%r, body=%r, else=%r)", ast_to_cord(data.condition), ast_to_cord(data.body), ast_to_cord(data.else_body))
T(Reduction, "(iter=%r, combination=%r, fallback=%r)", ast_to_cord(data.iter), ast_to_cord(data.combination), ast_to_cord(data.fallback))
T(Skip, "(%s)", data.target)
T(Stop, "(%s)", data.target)
T(Pass, "")
T(Return, "(%r)", ast_to_cord(data.value))
T(Extern, "(name=%s, type=%r)", data.name, type_ast_to_cord(data.type))
T(TypeDef, "(%s, type=%r, namespace=%r)", data.var.name, type_ast_to_cord(data.type), ast_to_cord(data.namespace))
T(Index, "(indexed=%r, index=%r)", ast_to_cord(data.indexed), ast_to_cord(data.index))
T(FieldAccess, "(fielded=%r, field=%s)", ast_to_cord(data.fielded), data.field)
T(DocTest, "(expr=%r, output=%s)", ast_to_cord(data.expr), data.output)
T(Use, "(%s)", data.path)
T(LinkerDirective, "(%s)", data.directive)
#undef T
}
return NULL;
}
CORD type_ast_to_cord(type_ast_t *t)
{
if (!t) return "\x1b[35mNULL\x1b[m";
switch (t->tag) {
#define T(type, ...) case type: { auto data = t->__data.type; (void)data; return CORD_asprintf("\x1b[32;1m" #type "\x1b[m" __VA_ARGS__); }
T(TypeUnknown, "")
T(TypeVar, "(\x1b[36;1m%s\x1b[m)", data.var.name)
T(TypePointer, "(%r, is_optional=%d, is_stack=%d, is_readonly=%d)",
type_ast_to_cord(data.pointed), data.is_optional,
data.is_stack, data.is_readonly)
T(TypeStruct, "(%r)", arg_list_to_cord(data.fields))
T(TypeTaggedUnion, "(%r)", tags_to_cord(data.tags))
T(TypeArray, "(%r)", type_ast_to_cord(data.item))
T(TypeTable, "(%r => %r)", type_ast_to_cord(data.key), type_ast_to_cord(data.value))
T(TypeFunction, "(args=%r, ret=%r)", arg_list_to_cord(data.args), type_ast_to_cord(data.ret))
#undef T
}
return NULL;
}
const char *ast_to_str(ast_t *ast) {
CORD c = ast_to_cord(ast);
return CORD_to_char_star(c);
}
const char *type_ast_to_str(type_ast_t *t) {
CORD c = type_ast_to_cord(t);
return CORD_to_char_star(c);
}
int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[])
{
ast_t *ast = *(ast_t**)(args[0]);
if (ast) {
if (info->alt)
return fprintf(stream, "%.*s", (int)(ast->end - ast->start), ast->start);
else
return fprintf(stream, "%s", ast_to_str(ast));
} else {
return fputs("(null)", stream);
}
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0