aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--ast.c7
-rw-r--r--ast.h13
-rw-r--r--builtins/datatypes.h8
-rw-r--r--builtins/table.c1
-rw-r--r--compile.c75
-rw-r--r--environment.c52
-rw-r--r--environment.h31
-rw-r--r--nextlang.c20
-rw-r--r--parse.c12
-rw-r--r--types.c112
-rw-r--r--types.h15
12 files changed, 258 insertions, 90 deletions
diff --git a/Makefile b/Makefile
index 61e25237..4d708bd3 100644
--- a/Makefile
+++ b/Makefile
@@ -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 $@
diff --git a/ast.c b/ast.c
index b5bb64bc..17707da9 100644
--- a/ast.c
+++ b/ast.c
@@ -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))
diff --git a/ast.h b/ast.h
index dade182d..b6f2b985 100644
--- a/ast.h
+++ b/ast.h
@@ -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"
diff --git a/compile.c b/compile.c
index 3cdd39d2..66efd1d6 100644
--- a/compile.c
+++ b/compile.c
@@ -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
diff --git a/nextlang.c b/nextlang.c
index b8d175f1..429c0573 100644
--- a/nextlang.c
+++ b/nextlang.c
@@ -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"
diff --git a/parse.c b/parse.c
index 79c1e2a7..b9d4ef9b 100644
--- a/parse.c
+++ b/parse.c
@@ -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) {
diff --git a/types.c b/types.c
index 2dea1990..43f3da37 100644
--- a/types.c
+++ b/types.c
@@ -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
diff --git a/types.h b/types.h
index fa0c7bff..af42c38a 100644
--- a/types.h
+++ b/types.h
@@ -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