diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | ast.c | 7 | ||||
| -rw-r--r-- | ast.h | 13 | ||||
| -rw-r--r-- | builtins/datatypes.h | 8 | ||||
| -rw-r--r-- | builtins/table.c | 1 | ||||
| -rw-r--r-- | compile.c | 75 | ||||
| -rw-r--r-- | environment.c | 52 | ||||
| -rw-r--r-- | environment.h | 31 | ||||
| -rw-r--r-- | nextlang.c | 20 | ||||
| -rw-r--r-- | parse.c | 12 | ||||
| -rw-r--r-- | types.c | 112 | ||||
| -rw-r--r-- | types.h | 15 |
12 files changed, 258 insertions, 90 deletions
@@ -29,7 +29,7 @@ BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/builtins.o builtins/float all: nextlang libnext.so -nextlang: nextlang.c parse.o files.o util.o ast.o compile.o types.o environment.o SipHash/halfsiphash.o $(BUILTIN_OBJS) +nextlang: nextlang.c SipHash/halfsiphash.o util.o files.o ast.o parse.o environment.o types.o typecheck.o compile.o $(BUILTIN_OBJS) libnext.so: util.o SipHash/halfsiphash.o $(CC) $^ $(CFLAGS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) $(LDLIBS) -Wl,-soname,libnext.so -shared -o $@ @@ -8,8 +8,6 @@ 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", @@ -95,7 +93,10 @@ CORD ast_to_cord(ast_t *ast) 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(Negative, "(%r)", ast_to_cord(data.value)) + T(Not, "(%r)", ast_to_cord(data.value)) + T(HeapAllocate, "(%r)", ast_to_cord(data.value)) + T(StackReference, "(%r)", 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)) @@ -32,13 +32,6 @@ typedef struct arg_ast_s { } arg_ast_t; typedef enum { - UNOP_UNKNOWN, - UNOP_NOT=1, UNOP_NEGATIVE, - UNOP_HEAP_ALLOCATE, - UNOP_STACK_REFERENCE, -} unop_e; - -typedef enum { BINOP_UNKNOWN, BINOP_POWER=100, BINOP_MULT, BINOP_DIVIDE, BINOP_MOD, BINOP_MOD1, BINOP_PLUS, BINOP_MINUS, BINOP_CONCAT, BINOP_LSHIFT, BINOP_RSHIFT, BINOP_MIN, @@ -94,7 +87,8 @@ typedef enum { Int, Num, StringLiteral, StringJoin, Declare, Assign, - BinaryOp, UnaryOp, UpdateAssign, + BinaryOp, UpdateAssign, + Not, Negative, HeapAllocate, StackReference, Min, Max, Array, Table, TableEntry, FunctionDef, Lambda, @@ -155,9 +149,8 @@ struct ast_s { ast_t *rhs; } BinaryOp, UpdateAssign; struct { - unop_e op; ast_t *value; - } UnaryOp; + } Not, Negative, HeapAllocate, StackReference; struct { ast_t *lhs, *rhs, *key; } Min, Max; diff --git a/builtins/datatypes.h b/builtins/datatypes.h index 133b273f..3a2a9da7 100644 --- a/builtins/datatypes.h +++ b/builtins/datatypes.h @@ -22,7 +22,13 @@ typedef struct { } bucket_info_t; typedef struct table_s { - array_t entries; + union { + array_t entries; + struct { + void *_entry_data; + int64_t length:42; + }; + }; bucket_info_t *bucket_info; struct table_s *fallback; void *default_value; diff --git a/builtins/table.c b/builtins/table.c index e5ab410d..08e14958 100644 --- a/builtins/table.c +++ b/builtins/table.c @@ -21,6 +21,7 @@ #include "../SipHash/halfsiphash.h" #include "../util.h" #include "array.h" +#include "datatypes.h" #include "string.h" #include "table.h" #include "types.h" @@ -6,6 +6,7 @@ #include "ast.h" #include "compile.h" +#include "environment.h" #include "util.h" CORD compile_type(env_t *env, type_ast_t *t) @@ -13,7 +14,7 @@ CORD compile_type(env_t *env, type_ast_t *t) (void)env; switch (t->tag) { case VarTypeAST: return CORD_cat(Match(t, VarTypeAST)->name, "_t"); - default: errx(1, "Not implemented"); + default: code_err(t, "Not implemented"); } } @@ -46,18 +47,10 @@ CORD compile(env_t *env, ast_t *ast) char *buf = asprintfa(Match(ast, Num)->precision == 64 ? "%a" : "%af", Match(ast, Num)->n); return CORD_from_char_star(buf); } - case UnaryOp: { - auto unop = Match(ast, UnaryOp); - CORD expr = compile(env, unop->value); - switch (unop->op) { - case UNOP_NOT: return CORD_asprintf("not(%r)", expr); - case UNOP_NEGATIVE: return CORD_cat("-", expr); - case UNOP_HEAP_ALLOCATE: return CORD_asprintf("$heap(%r)", expr); - case UNOP_STACK_REFERENCE: return CORD_asprintf("$stack(%r)", expr); - default: break; - } - errx(1, "Invalid unop"); - } + case Not: return CORD_asprintf("not(%r)", compile(env, Match(ast, Not)->value)); + case Negative: return CORD_asprintf("-(%r)", compile(env, Match(ast, Not)->value)); + case HeapAllocate: return CORD_asprintf("$heap(%r)", compile(env, Match(ast, Not)->value)); + case StackReference: return CORD_asprintf("$stack(%r)", compile(env, Match(ast, Not)->value)); case BinaryOp: { auto binop = Match(ast, BinaryOp); CORD lhs = compile(env, binop->lhs); @@ -82,7 +75,7 @@ CORD compile(env_t *env, ast_t *ast) case BINOP_XOR: return CORD_asprintf("xor(%r, %r)", lhs, rhs); default: break; } - errx(1, "unimplemented binop"); + code_err(ast, "unimplemented binop"); } case UpdateAssign: { auto update = Match(ast, UpdateAssign); @@ -106,7 +99,7 @@ CORD compile(env_t *env, ast_t *ast) case BINOP_OR: return CORD_asprintf("%r = (%r || %r);", lhs, lhs, rhs); default: break; } - errx(1, "unimplemented binop"); + code_err(ast, "unimplemented binop"); } case StringLiteral: { CORD literal = Match(ast, StringLiteral)->cord; @@ -214,31 +207,31 @@ CORD compile(env_t *env, ast_t *ast) case FunctionDef: { auto fndef = Match(ast, FunctionDef); CORD name = compile(env, fndef->name); - CORD_appendf(&env->staticdefs, "static %r %r_(", fndef->ret_type ? compile_type(env, fndef->ret_type) : "void", name); + CORD_appendf(&env->code->staticdefs, "static %r %r_(", fndef->ret_type ? compile_type(env, fndef->ret_type) : "void", name); for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) { - CORD_appendf(&env->staticdefs, "%r %s", compile_type(env, arg->type), arg->name); - if (arg->next) env->staticdefs = CORD_cat(env->staticdefs, ", "); + CORD_appendf(&env->code->staticdefs, "%r %s", compile_type(env, arg->type), arg->name); + if (arg->next) env->code->staticdefs = CORD_cat(env->code->staticdefs, ", "); } - env->staticdefs = CORD_cat(env->staticdefs, ");\n"); + env->code->staticdefs = CORD_cat(env->code->staticdefs, ");\n"); CORD kwargs = CORD_asprintf("#define %r(...) ({ struct {", name); CORD passed_args = CORD_EMPTY; - CORD_appendf(&env->funcs, "%r %r_(", fndef->ret_type ? compile_type(env, fndef->ret_type) : "void", name); + CORD_appendf(&env->code->funcs, "%r %r_(", fndef->ret_type ? compile_type(env, fndef->ret_type) : "void", name); for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) { CORD arg_type = compile_type(env, arg->type); - CORD_appendf(&env->funcs, "%r %s", arg_type, arg->name); - if (arg->next) env->funcs = CORD_cat(env->funcs, ", "); + CORD_appendf(&env->code->funcs, "%r %s", arg_type, arg->name); + if (arg->next) env->code->funcs = CORD_cat(env->code->funcs, ", "); CORD_appendf(&kwargs, "%r %s; ", arg_type, arg->name); CORD_appendf(&passed_args, "$args.%s", arg->name); if (arg->next) passed_args = CORD_cat(passed_args, ", "); } CORD_appendf(&kwargs, "} $args = {__VA_ARGS__}; %r_(%r); })\n", name, passed_args); - CORD_appendf(&env->staticdefs, "%r", kwargs); + CORD_appendf(&env->code->staticdefs, "%r", kwargs); CORD body = compile(env, fndef->body); if (CORD_fetch(body, 0) != '{') body = CORD_asprintf("{\n%r\n}", body); - CORD_appendf(&env->funcs, ") %r", body); + CORD_appendf(&env->code->funcs, ") %r", body); return CORD_EMPTY; } case FunctionCall: { @@ -285,11 +278,11 @@ CORD compile(env_t *env, ast_t *ast) // For, // Reduction, case Skip: { - if (Match(ast, Skip)->target) errx(1, "Named skips not yet implemented"); + if (Match(ast, Skip)->target) code_err(ast, "Named skips not yet implemented"); return "continue"; } case Stop: { - if (Match(ast, Stop)->target) errx(1, "Named stops not yet implemented"); + if (Match(ast, Stop)->target) code_err(ast, "Named stops not yet implemented"); return "break"; } case Pass: return ";"; @@ -300,16 +293,16 @@ CORD compile(env_t *env, ast_t *ast) // Extern, case StructDef: { auto def = Match(ast, StructDef); - CORD_appendf(&env->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); - CORD_appendf(&env->typedefs, "#define %s(...) ((%s_t){__VA_ARGS__})\n", def->name, def->name); + CORD_appendf(&env->code->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); + CORD_appendf(&env->code->typedefs, "#define %s(...) ((%s_t){__VA_ARGS__})\n", def->name, def->name); - CORD_appendf(&env->typecode, "struct %s_s {\n", def->name); + CORD_appendf(&env->code->typecode, "struct %s_s {\n", def->name); for (arg_ast_t *field = def->fields; field; field = field->next) { CORD type = compile_type(env, field->type); - CORD_appendf(&env->typecode, "%r %s%s;\n", type, field->name, + CORD_appendf(&env->code->typecode, "%r %s%s;\n", type, field->name, CORD_cmp(type, "Bool_t") ? "" : ":1"); } - CORD_appendf(&env->typecode, "};\n"); + CORD_appendf(&env->code->typecode, "};\n"); CORD cord_func = CORD_asprintf("CORD %s$cord(%s_t *obj, bool use_color) {\n" "\tif (!obj) return \"%s\";\n", def->name, def->name, def->name); @@ -334,28 +327,28 @@ CORD compile(env_t *env, ast_t *ast) cord_func = CORD_cat(cord_func, ");\n}"); } - env->funcs = CORD_cat(env->funcs, cord_func); + env->code->funcs = CORD_cat(env->code->funcs, cord_func); return CORD_EMPTY; } case EnumDef: { auto def = Match(ast, EnumDef); - CORD_appendf(&env->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); - CORD_appendf(&env->typecode, "struct %s_s {\nenum {", def->name); + CORD_appendf(&env->code->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); + CORD_appendf(&env->code->typecode, "struct %s_s {\nenum {", def->name); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - CORD_appendf(&env->typecode, "%s$%s = %ld, ", def->name, tag->name, tag->value); + CORD_appendf(&env->code->typecode, "%s$%s = %ld, ", def->name, tag->name, tag->value); } - env->typecode = CORD_cat(env->typecode, "} tag;\nunion {\n"); + env->code->typecode = CORD_cat(env->code->typecode, "} tag;\nunion {\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - env->typecode = CORD_cat(env->typecode, "struct {\n"); + env->code->typecode = CORD_cat(env->code->typecode, "struct {\n"); for (arg_ast_t *field = tag->fields; field; field = field->next) { CORD type = compile_type(env, field->type); - CORD_appendf(&env->typecode, "%r %s%s;\n", type, field->name, + CORD_appendf(&env->code->typecode, "%r %s%s;\n", type, field->name, CORD_cmp(type, "Bool_t") ? "" : ":1"); } - CORD_appendf(&env->typecode, "} %s;\n", tag->name); + CORD_appendf(&env->code->typecode, "} %s;\n", tag->name); } - env->typecode = CORD_cat(env->typecode, "} $data;\n};\n"); + env->code->typecode = CORD_cat(env->code->typecode, "} $data;\n};\n"); return CORD_EMPTY; } case DocTest: { @@ -409,7 +402,7 @@ CORD compile(env_t *env, ast_t *ast) // DocTest, // Use, // LinkerDirective, - case Unknown: errx(1, "Unknown AST"); + case Unknown: code_err(ast, "Unknown AST"); default: break; } return NULL; diff --git a/environment.c b/environment.c index 7c4e47c2..d6bb4c65 100644 --- a/environment.c +++ b/environment.c @@ -1,5 +1,6 @@ #include <stdlib.h> +#include <signal.h> #include "environment.h" #include "builtins/table.h" @@ -21,9 +22,13 @@ static type_t *namespace_type(table_t *ns) return Type(StructType, .fields=fields); } -env_t *new_environment(void) +env_t *new_compilation_unit(void) { env_t *env = new(env_t); + env->code = new(compilation_unit_t); + env->types = new(table_t); + env->globals = new(table_t); + env->locals = new(table_t, .fallback=env->globals); struct { const char *name; @@ -35,7 +40,7 @@ env_t *new_environment(void) }; for (size_t i = 0; i < sizeof(global_vars)/sizeof(global_vars[0]); i++) { - Table_str_set(&env->globals, global_vars[i].name, &global_vars[i].binding); + Table_str_set(env->globals, global_vars[i].name, &global_vars[i].binding); } struct { @@ -53,11 +58,50 @@ env_t *new_environment(void) }; for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) { - Table_str_set(&env->globals, global_types[i].name, namespace_type(&global_types[i].namespace)); - Table_str_set(&env->types, global_types[i].name, global_types[i].type); + Table_str_set(env->globals, global_types[i].name, namespace_type(&global_types[i].namespace)); + Table_str_set(env->types, global_types[i].name, global_types[i].type); } return env; } +env_t *fresh_scope(env_t *env) +{ + env_t *scope = new(env_t); + *scope = *env; + scope->locals = new(table_t, .fallback=env->locals); + return scope; +} + +binding_t *get_binding(env_t *env, const char *name) +{ + return Table_str_get(env->locals, name); +} + +void set_binding(env_t *env, const char *name, binding_t *binding) +{ + Table_str_set(env->locals, name, binding); +} + +void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...) +{ + if (isatty(STDERR_FILENO) && !getenv("NO_COLOR")) + fputs("\x1b[31;7;1m", stderr); + if (f && start && end) + fprintf(stderr, "%s:%ld.%ld: ", f->relative_filename, get_line_number(f, start), + get_line_column(f, start)); + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + if (isatty(STDERR_FILENO) && !getenv("NO_COLOR")) + fputs(" \x1b[m", stderr); + fputs("\n\n", stderr); + if (f && start && end) + fprint_span(stderr, f, start, end, "\x1b[31;1m", 2, isatty(STDERR_FILENO) && !getenv("NO_COLOR")); + + raise(SIGABRT); + exit(1); +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/environment.h b/environment.h index a03ccd42..64b59594 100644 --- a/environment.h +++ b/environment.h @@ -6,21 +6,30 @@ #include "builtins/table.h" typedef struct { - table_t globals, types; - table_t *locals; - CORD imports; - CORD typedefs; - CORD typecode; - CORD staticdefs; - CORD funcs; - CORD main; + CORD imports; + CORD typedefs; + CORD typecode; + CORD staticdefs; + CORD funcs; + CORD main; +} compilation_unit_t; + +typedef struct { + table_t *types, *globals, *locals; + compilation_unit_t *code; } env_t; typedef struct { - CORD code; - type_t *type; + CORD code; + type_t *type; } binding_t; -env_t *new_environment(void); +env_t *new_compilation_unit(void); +env_t *fresh_scope(env_t *env); +__attribute__((noreturn)) +void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...); +binding_t *get_binding(env_t *env, const char *name); +void set_binding(env_t *env, const char *name, binding_t *binding); +#define code_err(ast, ...) compiler_err((ast)->file, (ast)->start, (ast)->end, __VA_ARGS__) // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -42,30 +42,30 @@ int main(int argc, char *argv[]) fclose(out); } - env_t *env = new_environment(); + env_t *env = new_compilation_unit(); - CORD_appendf(&env->imports, "#include \"nextlang.h\"\n"); - CORD_appendf(&env->staticdefs, "static bool USE_COLOR = true;\n"); + CORD_appendf(&env->code->imports, "#include \"nextlang.h\"\n"); + CORD_appendf(&env->code->staticdefs, "static bool USE_COLOR = true;\n"); // Main body: for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { CORD code = compile_statement(env, stmt->ast); if (code) - CORD_appendf(&env->main, "%r\n", code); + CORD_appendf(&env->code->main, "%r\n", code); } CORD fileinfo = CORD_asprintf("#line 0 \"%s\"\n", f->filename); CORD program = CORD_all( fileinfo, "// Generated code:\n", - env->imports, "\n", - env->typedefs, "\n", - env->typecode, "\n", - env->staticdefs, "\n", - env->funcs, "\n" + env->code->imports, "\n", + env->code->typedefs, "\n", + env->code->typecode, "\n", + env->code->staticdefs, "\n", + env->code->funcs, "\n" "\n" "static void $load(void) {\n", - env->main, + env->code->main, "}\n" "\n" "int main(int argc, const char *argv[]) {\n" @@ -723,8 +723,8 @@ PARSER(parse_reduction) { if (op == BINOP_UNKNOWN) return NULL; ast_t *combination; - ast_t *lhs = NewAST(ctx->file, pos, pos, Var, .name="lhs.0"); - ast_t *rhs = NewAST(ctx->file, pos, pos, Var, .name="rhs.0"); + ast_t *lhs = NewAST(ctx->file, pos, pos, Var, .name="$lhs"); + ast_t *rhs = NewAST(ctx->file, pos, pos, Var, .name="$rhs"); if (op == BINOP_MIN || op == BINOP_MAX) { for (bool progress = true; progress; ) { ast_t *new_term; @@ -844,7 +844,7 @@ PARSER(parse_heap_alloc) { if (!match(&pos, "@")) return NULL; spaces(&pos); ast_t *val = expect(ctx, start, &pos, parse_expr, "I expected an expression for this '@'"); - return NewAST(ctx->file, start, pos, UnaryOp, .op=UNOP_HEAP_ALLOCATE, .value=val); + return NewAST(ctx->file, start, pos, HeapAllocate, .value=val); } PARSER(parse_stack_reference) { @@ -852,7 +852,7 @@ PARSER(parse_stack_reference) { if (!match(&pos, "&")) return NULL; spaces(&pos); ast_t *val = expect(ctx, start, &pos, parse_expr, "I expected an expression for this '&'"); - return NewAST(ctx->file, start, pos, UnaryOp, .op=UNOP_STACK_REFERENCE, .value=val); + return NewAST(ctx->file, start, pos, StackReference, .value=val); } PARSER(parse_not) { @@ -860,7 +860,7 @@ PARSER(parse_not) { if (!match_word(&pos, "not")) return NULL; spaces(&pos); ast_t *val = expect(ctx, start, &pos, parse_expr, "I expected an expression for this 'not'"); - return NewAST(ctx->file, start, pos, UnaryOp, .op=UNOP_NOT, .value=val); + return NewAST(ctx->file, start, pos, Not, .value=val); } PARSER(parse_negative) { @@ -868,7 +868,7 @@ PARSER(parse_negative) { if (!match(&pos, "-")) return NULL; spaces(&pos); ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this '-'"); - return NewAST(ctx->file, start, pos, UnaryOp, .op=UNOP_NEGATIVE, .value=val); + return NewAST(ctx->file, start, pos, Negative, .value=val); } PARSER(parse_bool) { @@ -333,6 +333,9 @@ bool can_promote(type_t *actual, type_t *needed) return true; } + if (needed->tag == ClosureType && actual->tag == FunctionType) + return can_promote(actual, Match(needed, ClosureType)->fn); + // Function promotion: if (needed->tag == FunctionType && actual->tag == FunctionType) { auto needed_fn = Match(needed, FunctionType); @@ -489,4 +492,113 @@ type_t *replace_type(type_t *t, type_t *target, type_t *replacement) #undef REPLACED_MEMBER } +size_t type_size(type_t *t) +{ + switch (t->tag) { + case UnknownType: case AbortType: case VoidType: return 0; + case MemoryType: errx(1, "Memory has undefined type size"); + case BoolType: return sizeof(bool); + case IntType: return Match(t, IntType)->bits/8; + case NumType: return Match(t, NumType)->bits/8; + case StringType: return sizeof(CORD); + case ArrayType: return sizeof(array_t); + case TableType: return sizeof(table_t); + case FunctionType: return sizeof(void*); + case ClosureType: return sizeof(struct {void *fn, *userdata;}); + case PointerType: return sizeof(void*); + case StructType: { + errx(1, "Not implemented"); + } + case EnumType: { + errx(1, "Not implemented"); + } + case TypeInfoType: return sizeof(TypeInfo); + case PlaceholderType: errx(1, "This should not be reachable"); + } + errx(1, "This should not be reachable"); +} + +size_t type_align(type_t *t) +{ + switch (t->tag) { + case UnknownType: case AbortType: case VoidType: return 0; + case MemoryType: errx(1, "Memory has undefined type alignment"); + case BoolType: return alignof(bool); + case IntType: return Match(t, IntType)->bits/8; + case NumType: return Match(t, NumType)->bits/8; + case StringType: return alignof(CORD); + case ArrayType: return alignof(array_t); + case TableType: return alignof(table_t); + case FunctionType: return alignof(void*); + case ClosureType: return alignof(void*); + case PointerType: return alignof(void*); + case StructType: { + errx(1, "Not implemented"); + } + case EnumType: { + errx(1, "Not implemented"); + } + case TypeInfoType: return alignof(TypeInfo); + case PlaceholderType: errx(1, "This should not be reachable"); + } + errx(1, "This should not be reachable"); +} + +type_t *get_field_type(type_t *t, const char *field_name) +{ + t = value_type(t); + switch (t->tag) { + case StructType: { + auto struct_t = Match(t, StructType); + for (arg_t *field = struct_t->fields; field; field = field->next) { + if (streq(field->name, field_name)) + return field->type; + } + return NULL; + } + case EnumType: { + auto e = Match(t, EnumType); + for (tag_t *tag = e->tags; tag; tag = tag->next) { + if (streq(field_name, tag->name)) + return tag->type; + } + return NULL; + } + case ArrayType: { + if (streq(field_name, "length")) + return Type(IntType, .bits=64); + return NULL; + } + case TableType: { + if (streq(field_name, "length")) + return Type(IntType, .bits=64); + else if (streq(field_name, "keys")) + return Type(ArrayType, Match(t, TableType)->key_type); + else if (streq(field_name, "values")) + return Type(ArrayType, Match(t, TableType)->value_type); + return NULL; + } + default: return NULL; + } +} + +type_t *iteration_key_type(type_t *iterable) +{ + switch (iterable->tag) { + case IntType: case ArrayType: return Type(IntType, .bits=64); + case TableType: return Match(iterable, TableType)->key_type; + default: return NULL; + } +} + +type_t *iteration_value_type(type_t *iterable) +{ + switch (iterable->tag) { + case IntType: return iterable; + case ArrayType: return Match(iterable, ArrayType)->item_type; + case TableType: return Match(iterable, TableType)->value_type; + default: return NULL; + } +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -41,6 +41,7 @@ struct type_s { ArrayType, TableType, FunctionType, + ClosureType, PointerType, StructType, EnumType, @@ -71,6 +72,9 @@ struct type_s { type_t *ret; } FunctionType; struct { + type_t *fn; + } ClosureType; + struct { type_t *pointed; bool is_optional:1, is_stack:1, is_readonly:1; } PointerType; @@ -95,9 +99,9 @@ struct type_s { int printf_pointer_size(const struct printf_info *info, size_t n, int argtypes[n], int size[n]); int printf_type(FILE *stream, const struct printf_info *info, const void *const args[]); -const char* type_to_string_concise(type_t *t); -const char* type_to_typeof_string(type_t *t); -const char* type_to_string(type_t *t); +const char *type_to_string_concise(type_t *t); +const char *type_to_typeof_string(type_t *t); +const char *type_to_string(type_t *t); bool type_eq(type_t *a, type_t *b); bool type_is_a(type_t *t, type_t *req); type_t *type_or_type(type_t *a, type_t *b); @@ -112,5 +116,10 @@ bool can_leave_uninitialized(type_t *t); bool can_have_cycles(type_t *t); type_t *table_entry_type(type_t *table_t); type_t *replace_type(type_t *t, type_t *target, type_t *replacement); +size_t type_size(type_t *t); +size_t type_align(type_t *t); +type_t *iteration_key_type(type_t *iterable); +type_t *iteration_value_type(type_t *iterable); +type_t *get_field_type(type_t *t, const char *field_name); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
