diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-02-04 15:23:59 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-02-04 15:23:59 -0500 |
| commit | 98f0c51119f9d42d733f44cb516b1c2bcd9061af (patch) | |
| tree | 39ab4fa635f858b76b9a8bbf84701c2788d5f498 /ast.c | |
Initial commit
Diffstat (limited to 'ast.c')
| -rw-r--r-- | ast.c | 179 |
1 files changed, 179 insertions, 0 deletions
@@ -0,0 +1,179 @@ +// 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", + [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 && 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=%ld)", data.i, data.precision) + T(Num, "(\x1b[35m%ld\x1b[m, precision=%ld)", 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 |
