From 3b777341fc3bc9950168078d98eb533b53f783dc Mon Sep 17 00:00:00 2001 From: Andrew Byers Date: Sun, 21 Jul 2024 17:56:17 -0500 Subject: [PATCH] Fix container for loops and some tests --- .clang-format | 2 +- README.md | 26 ++- src/api.c | 183 ++++++---------- src/ast.c | 183 ++++++++-------- src/ast.h | 126 ++++++----- src/auxlib.c | 3 +- src/call.c | 6 +- src/call.h | 6 +- src/check.c | 402 ++++++++++++++++------------------ src/code.c | 10 + src/code.h | 14 +- src/codegen.c | 104 ++++----- src/config.h | 2 +- src/debug.c | 51 +++-- src/env.h | 2 +- src/gc_aux.h | 10 +- src/iolib.c | 12 +- src/lib.c | 120 +++++----- src/lib.h | 4 +- src/map.c | 7 +- src/mem.h | 22 +- src/meta.c | 54 ++++- src/opcode.h | 34 +-- src/parse.c | 174 ++++++++------- src/parse.h | 7 +- src/paw.c | 2 +- src/paw.h | 18 +- src/rt.c | 186 +++++++++------- src/test.h | 12 +- src/type.h | 4 +- src/unify.c | 11 +- src/value.c | 24 +- src/value.h | 11 +- src/vector.c | 5 +- test/CMakeLists.txt | 7 +- test/scripts/binary_trees.paw | 10 +- test/scripts/bubble.paw | 12 +- test/scripts/closure.paw | 90 ++------ test/scripts/error.paw | 41 ---- test/scripts/loop.paw | 258 +++++++++++----------- test/scripts/struct.paw | 208 ++++++++++++++++++ test/scripts/vector.paw | 115 +++++----- test/test_oom.c | 6 +- test/test_rt.c | 6 +- test/test_so.c | 7 +- 45 files changed, 1355 insertions(+), 1242 deletions(-) delete mode 100644 test/scripts/error.paw create mode 100644 test/scripts/struct.paw diff --git a/.clang-format b/.clang-format index aaa66ee..d0ee51d 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ BasedOnStyle: LLVM AccessModifierOffset: -4 BreakBeforeBraces: Linux -ColumnLimit: 80 +ColumnLimit: 0 IndentCaseLabels: true IndentWidth: 4 SpaceBeforeCaseColon: false diff --git a/README.md b/README.md index 399bf1c..5df6711 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,11 @@ fn fib(n: int) -> int { return fib(n - 2) + fib(n - 1) } fib(10) + +// use closure syntax to capture variables +let run_fib = || -> int { + return fib(5) +} ``` ### Structures @@ -145,7 +150,7 @@ break continue // Numeric 'for' loop: -for i in 0, 10, 2 { // start, end[, step] +for i = 0, 10, 2 { // start, end[, step] } @@ -182,7 +187,7 @@ Variables with generic types must be treated generically, that is, they can only This allows each template to be type checked a single time, rather than once for each unique instantiation, and makes it easier to generate meaningful error messages. ``` fn map(f: fn(A) -> B, vec: [A]) -> [B] { - let result: [B] = [] + let result = [] for a in vec { result.push(f(a)) } @@ -233,8 +238,9 @@ let c = triplet.2 ``` let empty: [int] = [] +// infer T = string let empty = [] -empty.push('a') +empty.push('a') let vec = [ [[1, 2, 3], [0]], @@ -242,7 +248,6 @@ let vec = [ [[7, 8, 9], [2]], ] -// infer T = int let vec = [1, 2, 3] assert(vec[:1] == [1]) assert(vec[1:-1] == [2]) @@ -253,10 +258,10 @@ assert(vec[-1:] == [3]) ``` let empty: [int: string] = [:] +// infer K = int, V = string let empty = [:] empty[0] = 'abc' -// infer K = int, V = string let map = [1: 'a', 2: 'b'] map[3] = 42 map.erase(1) @@ -296,24 +301,27 @@ assert(status != 0) |1 |`=` |Assignment |Right | ## Roadmap -+ [x] static typing ++ [x] static, string typing + [x] special-cased builtin containers (`[T]` and `[K: V]`) -+ [x] type inference for structure templates (including builtin containers) -+ [ ] type inference for enumeration templates ++ [x] type inference for `struct` templates and builtin containers ++ [ ] methods using `impl` blocks ++ [ ] module system and `import` keyword ++ [ ] type inference for `enum` templates + [ ] pattern matching (`switch` construct) + [ ] pattern matching (`if let`, `let` bindings) + [ ] constness (`var` vs `let`) + [ ] split `string` into `str` and `String`, where `str` is a byte array and `String` is always valid UTF-8 + [x] sum types/discriminated unions (`enum`) + [x] product types (tuple) ++ [ ] compiler optimization passes + [ ] custom garbage collector (using Boehm GC for now) -+ [ ] methods + [ ] metamethods + [ ] generic constraints/bounds + [ ] associated types on `struct`s (`A::B`) + [ ] existential types ## Known problems ++ The C API has pretty much 0 type safety + Compiler will allow functions that don't return a value in all code paths + Likely requires a CFG and some data flow analysis: it would be very difficult to get right otherwise + It isn't possible to create an empty vector or map of a specific known type without creating a temporary: `let vec: [int] = []` diff --git a/src/api.c b/src/api.c index ca1371e..0b2d67e 100644 --- a/src/api.c +++ b/src/api.c @@ -93,83 +93,6 @@ void paw_close(paw_Env *P) P->alloc(P->ud, P, sizeof *P, 0); } -paw_Bool paw_is_bool(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TBOOL; -} - -paw_Bool paw_is_int(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TINT; -} - -paw_Bool paw_is_float(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TFLOAT; -} - -paw_Bool paw_is_string(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TSTRING; -} - -paw_Bool paw_is_function(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TFUNCTION; -} - -paw_Bool paw_is_tuple(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TTUPLE; -} - -paw_Bool paw_is_struct(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TSTRUCT; -} - -paw_Bool paw_is_foreign(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TFOREIGN; -} - -int paw_type(paw_Env *P, int index) -{ - const Value v = *access(P, index); - return 0; - // switch (v_type(v)) { - // case VNULL: - // return PAW_NULL; - // case VTRUE: - // case VFALSE: - // return PAW_TBOOL; - // case VCLOSURE: - // case VMETHOD: - // case VNATIVE: - // return PAW_TFUNCTION; - // case VSTRING: - // return PAW_TSTRING; - // case VARRAY: - // return PAW_TARRAY; - // case VMAP: - // return PAW_TMAP; - // case VSTRUCT: - // return PAW_TSTRUCT; - // case VBIGINT: - // case VNUMBER: - // return PAW_TINT; - // case VFOREIGN: - // return PAW_TFOREIGN; - // default: - // return PAW_TFLOAT; - // } -} - -const char *paw_typename(paw_Env *P, int index) -{ - return api_typename(paw_type(P, index)); -} - void paw_push_value(paw_Env *P, int index) { const Value v = *access(P, index); @@ -183,11 +106,20 @@ void paw_push_unit(paw_Env *P, int n) } } -void paw_push_boolean(paw_Env *P, paw_Bool b) { pawC_pushb(P, b); } +void paw_push_boolean(paw_Env *P, paw_Bool b) +{ + pawC_pushb(P, b); +} -void paw_push_float(paw_Env *P, paw_Float f) { pawC_pushf(P, f); } +void paw_push_float(paw_Env *P, paw_Float f) +{ + pawC_pushf(P, f); +} -void paw_push_int(paw_Env *P, paw_Int i) { pawC_pushi(P, i); } +void paw_push_int(paw_Env *P, paw_Int i) +{ + pawC_pushi(P, i); +} void paw_push_native(paw_Env *P, paw_Function fn, int n) { @@ -234,9 +166,15 @@ const char *paw_push_fstring(paw_Env *P, const char *fmt, ...) return s; } -paw_Bool paw_bool(paw_Env *P, int index) { return v_true(*access(P, index)); } +paw_Bool paw_bool(paw_Env *P, int index) +{ + return v_true(*access(P, index)); +} -paw_Int paw_int(paw_Env *P, int index) { return v_int(*access(P, index)); } +paw_Int paw_int(paw_Env *P, int index) +{ + return v_int(*access(P, index)); +} paw_Float paw_float(paw_Env *P, int index) { @@ -360,7 +298,10 @@ int paw_call(paw_Env *P, int argc) return status; } -int paw_get_count(paw_Env *P) { return P->top.p - P->cf->base.p; } +int paw_get_count(paw_Env *P) +{ + return P->top.p - P->cf->base.p; +} static int upvalue_index(int nup, int index) { @@ -372,35 +313,33 @@ static int upvalue_index(int nup, int index) return index; } -// void paw_get_upvalue(paw_Env *P, int ifn, int index) -//{ -// Value *pv = pawC_push0(P); -// const Value fn = *access(P, ifn); -// switch (v_type(fn)) { -// case VNATIVE: { -// Native *f = v_native(fn); -// *pv = f->up[upvalue_index(f->nup, index)]; -// break; -// } -// case VCLOSURE: { -// Closure *f = v_closure(fn); -// UpValue *u = f->up[upvalue_index(f->nup, index)]; -// *pv = *u->p.p; -// break; -// } -// default: -// pawR_error(P, PAW_ETYPE, "'%s' has no upvalues", -// api_typename(api_type(fn))); -// } -// } -// -// void paw_get_global(paw_Env *P, const char *name) -//{ -// if (!paw_check_global(P, name)) { -// pawR_error(P, PAW_ENAME, "global '%s' does not exist", name); -// } -// } -// +void paw_get_upvalue(paw_Env *P, int ifn, int index) +{ + Value *pv = pawC_push0(P); + const Value fn = *access(P, ifn); + switch (v_object(fn)->gc_kind) { + case VNATIVE: { + Native *f = v_native(fn); + *pv = f->up[upvalue_index(f->nup, index)]; + break; + } + case VCLOSURE: { + Closure *f = v_closure(fn); + UpValue *u = f->up[upvalue_index(f->nup, index)]; + *pv = *u->p.p; + break; + } + default: + pawR_error(P, PAW_ETYPE, "type has no upvalues"); + } +} + +void paw_get_global(paw_Env *P, int index) +{ + GlobalVar *var = pawE_get_global(P, index); + pawC_pushv(P, var->value); +} + // paw_Bool paw_check_global(paw_Env *P, const char *name) //{ // paw_push_string(P, name); @@ -499,6 +438,8 @@ static int upvalue_index(int nup, int index) // void paw_set_global(paw_Env *P, const char *name) { + paw_unused(P); + paw_unused(name); // paw_push_string(P, name); // paw_rotate(P, -2, 1); // Swap // @@ -531,6 +472,8 @@ void paw_set_global(paw_Env *P, const char *name) // void paw_create_array(paw_Env *P, int n) { + paw_unused(P); + paw_unused(n); // pawR_literal_array(P, n); } // @@ -615,13 +558,13 @@ void paw_shift(paw_Env *P, int n) paw_pop(P, n); } -// void paw_call_global(paw_Env *P, const char *name, int argc) -//{ -// paw_get_global(P, name); -// paw_insert(P, -argc - 2); -// paw_call(P, argc); -// } -// +void paw_call_global(paw_Env *P, int index, int argc) +{ + paw_get_global(P, index); + paw_insert(P, -argc - 2); + paw_call(P, argc); +} + // void paw_call_attr(paw_Env *P, int index, const char *name, int argc) //{ // paw_push_value(P, index); @@ -644,6 +587,6 @@ void paw_raw_equals(paw_Env *P) { const Value x = P->top.p[-2]; const Value y = P->top.p[-1]; - // paw_push_boolean(P, pawV_equal(x, y)); + paw_push_boolean(P, x.u == y.u); paw_shift(P, 2); } diff --git a/src/ast.c b/src/ast.c index 2f21f32..1ebd4f5 100644 --- a/src/ast.c +++ b/src/ast.c @@ -67,7 +67,7 @@ make_node_constructor(pat, AstPat) #define LIST_MIN_ALLOC 8 -AstType *pawA_new_type(Ast *ast, AstTypeKind kind) + AstType *pawA_new_type(Ast *ast, AstTypeKind kind) { AstType *r = pawK_pool_alloc(env((ast)->lex), &(ast)->nodes, sizeof(AstType), paw_alignof(AstType)); @@ -85,8 +85,7 @@ AstPath *pawA_path_new(Ast *ast) AstSegment *pawA_segment_new(Ast *ast) { - return pawK_pool_alloc(env((ast)->lex), &(ast)->nodes, - sizeof(AstSegment), + return pawK_pool_alloc(env((ast)->lex), &(ast)->nodes, sizeof(AstSegment), paw_alignof(AstSegment)); } @@ -154,9 +153,9 @@ void pawA_list_push(Ast *ast, AstList **plist, void *node) void pawA_path_push(Ast *ast, AstList **ppath, String *name, AstList *types) { Lex *lex = ast->lex; - AstSegment *segment = pawK_pool_alloc(env(lex), &lex->pm->ast->nodes, - sizeof(AstSegment), - paw_alignof(Symbol)); + AstSegment *segment = + pawK_pool_alloc(env(lex), &lex->pm->ast->nodes, sizeof(AstSegment), + paw_alignof(Symbol)); segment->name = name; segment->types = types; pawA_list_push(ast, ppath, segment); @@ -196,8 +195,9 @@ static Scope *new_scope(Ast *ast) SymbolTable *pawA_new_symtab(Ast *ast) { - SymbolTable *symtab = pawK_pool_alloc(env(ast->lex), &ast->symbols, sizeof(SymbolTable), - paw_alignof(SymbolTable)); + SymbolTable *symtab = + pawK_pool_alloc(env(ast->lex), &ast->symbols, sizeof(SymbolTable), + paw_alignof(SymbolTable)); symtab->globals = new_scope(ast); symtab->scopes = pawA_list_new(ast); return symtab; @@ -239,13 +239,13 @@ int pawA_find_symbol(Scope *scope, const String *name) return -1; } -#define make_list_visitor(name, T) \ - static void visit_##name##_list_aux(AstVisitor *V, AstList *list, \ - T##Pass cb) \ - { \ - for (int i = 0; i < list->count; ++i) { \ - cb(V, list->data[i]); \ - } \ +#define make_list_visitor(name, T) \ + static void visit_##name##_list_aux(AstVisitor *V, AstList *list, \ + T##Pass cb) \ + { \ + for (int i = 0; i < list->count; ++i) { \ + cb(V, list->data[i]); \ + } \ } make_list_visitor(decl, AstDecl) make_list_visitor(expr, AstExpr) make_list_visitor(stmt, AstStmt) @@ -754,22 +754,21 @@ void pawA_visit(AstVisitor *V) } // Generate code for folding a list of AST nodes -#define make_list_folder(name, T) \ - static void fold_##name##_list(AstFolder *F, AstList *list, T##Fold cb) \ - { \ - for (int i = 0; i < list->count; ++i) { \ - list->data[i] = cb(F, list->data[i]); \ - } \ - } \ - static void fold_##name##s(AstFolder *F, AstList *list) \ - { \ - fold_##name##_list(F, list, F->fold_##name); \ - } -make_list_folder(decl, AstDecl) -make_list_folder(expr, AstExpr) -make_list_folder(stmt, AstStmt) - -static AstStmt *fold_block_stmt(AstFolder *F, Block *s) +#define make_list_folder(name, T) \ + static void fold_##name##_list(AstFolder *F, AstList *list, T##Fold cb) \ + { \ + for (int i = 0; i < list->count; ++i) { \ + list->data[i] = cb(F, list->data[i]); \ + } \ + } \ + static void fold_##name##s(AstFolder *F, AstList *list) \ + { \ + fold_##name##_list(F, list, F->fold_##name); \ + } +make_list_folder(decl, AstDecl) make_list_folder(expr, AstExpr) + make_list_folder(stmt, AstStmt) + + static AstStmt *fold_block_stmt(AstFolder *F, Block *s) { fold_stmts(F, s->stmts); return cast_stmt(s); @@ -1802,6 +1801,8 @@ static void enter_scope(AstFolder *F, ScopeState *state, Scope *source) Stenciler *S = F->state.S; state->source = source; state->target = new_scope(F->ast); + state->target->bk_depth = source->bk_depth; + state->target->fn_depth = source->fn_depth; state->outer = S->scope; S->scope = state; } @@ -1858,33 +1859,29 @@ static void link_decls(AstFolder *F, AstDecl *old_decl, AstDecl *new_decl) } //clang-format off -#define make_stencil_prep(name, T, body) \ - static T *stencil_prep_##name##_aux(AstFolder *F, T *t) \ - { \ - T *r = pawA_new_##name(F->ast, a_kind(t)); \ - r->hdr.kind = t->hdr.kind; \ - r->hdr.line = t->hdr.line; \ - body return r; \ - } -make_stencil_prep(expr, AstExpr, - { - r->hdr.type = subst_type(F, a_type(t)); - }) -make_stencil_prep(decl, AstDecl, - { - r->hdr.name = t->hdr.name; - r->hdr.def = pawA_add_decl(F->ast, r); - link_decls(F, t, r); // subst_type() is dependant - AstType *type = subst_type(F, a_type(t)); - if (a_is_func_decl(r)) { - type->func.did = r->hdr.def; - } else if (a_is_struct_decl(r)) { - type->adt.did = r->hdr.def; - } - r->hdr.type = type; - return r; - }) -make_stencil_prep(stmt, AstStmt, {}) +#define make_stencil_prep(name, T, body) \ + static T *stencil_prep_##name##_aux(AstFolder *F, T *t) \ + { \ + T *r = pawA_new_##name(F->ast, a_kind(t)); \ + r->hdr.kind = t->hdr.kind; \ + r->hdr.line = t->hdr.line; \ + body return r; \ + } +make_stencil_prep(expr, AstExpr, { r->hdr.type = subst_type(F, a_type(t)); }) + make_stencil_prep(decl, AstDecl, + { + r->hdr.name = t->hdr.name; + r->hdr.def = pawA_add_decl(F->ast, r); + link_decls(F, t, r); // subst_type() is dependant + AstType *type = subst_type(F, a_type(t)); + if (a_is_func_decl(r)) { + type->func.did = r->hdr.def; + } else if (a_is_struct_decl(r)) { + type->adt.did = r->hdr.def; + } + r->hdr.type = type; + return r; + }) make_stencil_prep(stmt, AstStmt, {}) //clang-format on // Helpers for stenciling: create a new node of the given type and kind, @@ -1893,21 +1890,20 @@ make_stencil_prep(stmt, AstStmt, {}) #define stencil_prep_decl(F, d) stencil_prep_decl_aux(F, cast_decl(d)) #define stencil_prep_stmt(F, s) stencil_prep_stmt_aux(F, cast_stmt(s)) -#define make_stencil_list(name, T) \ - static AstList *stencil_##name##s(AstFolder *F, AstList *old_list) \ - { \ - AstList *new_list = pawA_list_new(F->ast); \ - for (int i = 0; i < old_list->count; ++i) { \ - T *decl = F->fold_##name(F, old_list->data[i]); \ - pawA_list_push(F->ast, &new_list, decl); \ - } \ - return new_list; \ +#define make_stencil_list(name, T) \ + static AstList *stencil_##name##s(AstFolder *F, AstList *old_list) \ + { \ + AstList *new_list = pawA_list_new(F->ast); \ + for (int i = 0; i < old_list->count; ++i) { \ + T *decl = F->fold_##name(F, old_list->data[i]); \ + pawA_list_push(F->ast, &new_list, decl); \ + } \ + return new_list; \ } -make_stencil_list(expr, AstExpr) -make_stencil_list(decl, AstDecl) -make_stencil_list(stmt, AstStmt) + make_stencil_list(expr, AstExpr) make_stencil_list(decl, AstDecl) + make_stencil_list(stmt, AstStmt) -static AstStmt *stencil_block_stmt(AstFolder *F, Block *s) + static AstStmt *stencil_block_stmt(AstFolder *F, Block *s) { ScopeState state; enter_scope(F, &state, s->scope); @@ -2156,9 +2152,7 @@ static AstPath *stencil_path(AstFolder *F, AstPath *e) AstPath *r = pawA_path_new(F->ast); for (int i = 0; i < e->list->count; ++i) { AstSegment *seg = pawA_path_get(e, i); - AstList *args = seg->types - ? stencil_exprs(F, seg->types) - : NULL; + AstList *args = seg->types ? stencil_exprs(F, seg->types) : NULL; AstType *type = subst_type(F, seg->type); pawA_path_add(F->ast, r, seg->name, args, type); } @@ -2276,10 +2270,9 @@ static AstStmt *stencil_for_stmt(AstFolder *F, ForStmt *s) transfer_symbols(F, &state, 3); } else { r->for_.forin.target = F->fold_expr(F, s->forin.target); - transfer_symbols(F, &state, 1); + transfer_symbols(F, &state, 2); // includes implicit '(for iter)' } r->for_.block = stencil_forbody(F, s->block); - r->for_.scope = leave_scope(F); return r; } @@ -2582,7 +2575,7 @@ static void indent_line(Printer *P) } } -#define dump_fmt(P, fmt, ...) \ +#define dump_fmt(P, fmt, ...) \ (indent_line(P), fprintf((P)->out, fmt, __VA_ARGS__)) #define dump_msg(P, msg) (indent_line(P), fprintf((P)->out, msg)) @@ -2601,7 +2594,11 @@ static void dump_binder(Printer *P, AstList *binder) static void dump_type_aux(Printer *P, AstType *type) { const char *basic[] = { - "()", "bool", "int", "float", "string", + "()", + "bool", + "int", + "float", + "string", }; switch (y_kind(type)) { case AST_TYPE_UNKNOWN: { @@ -2821,8 +2818,8 @@ static int predump_node(Printer *P, void *node, return -1; } -#define dump_block(P, b) check_exp((b)->kind == STMT_BLOCK, \ - dump_stmt(P, cast_stmt(b))) +#define dump_block(P, b) \ + check_exp((b)->kind == STMT_BLOCK, dump_stmt(P, cast_stmt(b))) #define dump_name(P, s) dump_fmt(P, "name: %s\n", s ? s->text : NULL) static void dump_expr(Printer *P, AstExpr *e); @@ -2850,9 +2847,9 @@ make_list_dumper(expr, AstExpr) make_list_dumper(decl, AstDecl) make_list_dumper(stmt, AstStmt) make_list_dumper(pat, AstPat) -// clang-format on + // clang-format on -static void dump_path(Printer *P, AstPath *p) + static void dump_path(Printer *P, AstPath *p) { for (int i = 0; i < p->list->count; ++i) { AstSegment *seg = p->list->data[i]; @@ -3054,20 +3051,25 @@ static void dump_expr(Printer *P, AstExpr *e) break; case PAW_TBOOL: dump_msg(P, "type: bool\n"); - dump_fmt(P, "value: %s\n", v_true(e->literal.basic.value) ? "true" : "false"); + dump_fmt(P, "value: %s\n", + v_true(e->literal.basic.value) ? "true" + : "false"); break; case PAW_TINT: dump_msg(P, "type: int\n"); - dump_fmt(P, "value: %" PRId64 "\n", v_int(e->literal.basic.value)); + dump_fmt(P, "value: %" PRId64 "\n", + v_int(e->literal.basic.value)); break; case PAW_TFLOAT: dump_msg(P, "type: float\n"); - dump_fmt(P, "value: %f\n", v_float(e->literal.basic.value)); + dump_fmt(P, "value: %f\n", + v_float(e->literal.basic.value)); break; default: paw_assert(e->literal.basic.t == PAW_TSTRING); dump_msg(P, "type: string\n"); - dump_fmt(P, "value: %s\n", v_string(e->literal.basic.value)->text); + dump_fmt(P, "value: %s\n", + v_string(e->literal.basic.value)->text); break; } break; @@ -3157,11 +3159,12 @@ static void dump_expr(Printer *P, AstExpr *e) // TODO: Have this output a String, or fill a Buffer, move somewhere else void pawA_repr_type(FILE *out, const AstType *type) { + Printer P = {.out = out}; switch (a_kind(type)) { case AST_TYPE_TUPLE: fprintf(out, "("); for (int i = 0; i < type->tuple.elems->count; ++i) { - dump_type(out, type->tuple.elems->data[i]); + dump_type(&P, type->tuple.elems->data[i]); if (i < type->tuple.elems->count - 1) { fprintf(out, ", "); } @@ -3172,13 +3175,13 @@ void pawA_repr_type(FILE *out, const AstType *type) case AST_TYPE_FUNC: fprintf(out, "fn("); for (int i = 0; i < type->fptr.params->count; ++i) { - dump_type(out, type->fptr.params->data[i]); + dump_type(&P, type->fptr.params->data[i]); if (i < type->fptr.params->count - 1) { fprintf(out, ", "); } } fprintf(out, ") -> "); - dump_type(out, type->fptr.result); + dump_type(&P, type->fptr.result); break; case AST_TYPE_ADT: fprintf(out, "%d", type->adt.base); // TODO: Print the name @@ -3186,7 +3189,7 @@ void pawA_repr_type(FILE *out, const AstType *type) fprintf(out, "<"); const AstList *binder = type->adt.types; for (int i = 0; i < binder->count; ++i) { - dump_type(out, binder->data[i]); + dump_type(&P, binder->data[i]); if (i < binder->count - 1) { fprintf(out, ", "); } diff --git a/src/ast.h b/src/ast.h index 031dd80..d3233af 100644 --- a/src/ast.h +++ b/src/ast.h @@ -99,7 +99,7 @@ typedef struct AstPath { } AstPath; typedef struct AstSegment { - String *name; + String *name; AstList *types; AstType *type; } AstSegment; @@ -107,13 +107,14 @@ typedef struct AstSegment { AstPath *pawA_path_new(Ast *ast); AstSegment *pawA_segment_new(Ast *ast); -static inline AstSegment *pawA_path_get(AstPath *path, int index) +static inline AstSegment *pawA_path_get(AstPath *path, int index) { paw_assert(index < path->list->count); - return path->list->data[index]; + return path->list->data[index]; } -static inline AstPath *pawA_path_add(Ast *ast, AstPath *p, String *name, AstList *args, AstType *type) +static inline AstPath *pawA_path_add(Ast *ast, AstPath *p, String *name, + AstList *args, AstType *type) { AstSegment *seg = pawA_segment_new(ast); seg->name = name; @@ -159,21 +160,22 @@ typedef struct AstUnknown { // Represents a structure or enumeration type typedef struct AstAdt { AST_TYPE_HEADER; // common initial sequence - AstList *types; + AstList *types; DefId base; DefId did; } AstAdt; -#define AST_FUNC_HEADER AST_TYPE_HEADER; \ - AstList *params; \ - AstType *result +#define AST_FUNC_HEADER \ + AST_TYPE_HEADER; \ + AstList *params; \ + AstType *result typedef struct AstFuncPtr { AST_FUNC_HEADER; // common initial sequence } AstFuncPtr; typedef struct AstFuncDef { AST_FUNC_HEADER; // common initial sequence - AstList *types; + AstList *types; DefId base; DefId did; } AstFuncDef; @@ -183,18 +185,6 @@ typedef struct AstTupleType { AstList *elems; // element types } AstTupleType; -// Represents the type of a Paw module -// Note that basic types ('int', 'float', etc.) are created only once, at the -// start of the root module's type vector. Included modules reference these -// AstType objects in the root. -typedef struct AstModule { - AST_TYPE_HEADER; // common initial sequence - struct AstModule *includes; // included modules - AstType **types; - int ntypes; - int capacity; -} AstModule; - struct AstType { union { AstTypeHeader hdr; @@ -204,7 +194,6 @@ struct AstType { AstAdt adt; AstFuncPtr fptr; AstFuncDef func; - AstModule mod; }; }; @@ -241,9 +230,10 @@ typedef enum AstPatKind { AST_PAT_VARIANT, } AstPatKind; -#define AST_PAT_HEADER AstType *type; \ - int line; \ - AstPatKind kind: 8 +#define AST_PAT_HEADER \ + AstType *type; \ + int line; \ + AstPatKind kind : 8 typedef struct AstPatHdr { AST_PAT_HEADER; // common fields } AstPatHdr; @@ -292,15 +282,15 @@ typedef struct AstFieldPat { struct AstPat { union { - AstPatHdr hdr; - AstWildcardPat wildcard; - AstLiteralPat literal; - AstBindingPat binding; - AstPathPat path; - AstTuplePat tuple; - AstFieldPat field; - AstStructPat struct_; - AstVariantPat variant; + AstPatHdr hdr; + AstWildcardPat wildcard; + AstLiteralPat literal; + AstBindingPat binding; + AstPathPat path; + AstTuplePat tuple; + AstFieldPat field; + AstStructPat struct_; + AstVariantPat variant; }; }; @@ -319,11 +309,11 @@ typedef enum AstDeclKind { DECL_INSTANCE, } AstDeclKind; -#define DECL_HEADER \ - AstType *type; \ - String *name; \ - int line; \ - DefId def; \ +#define DECL_HEADER \ + AstType *type; \ + String *name; \ + int line; \ + DefId def; \ AstDeclKind kind : 8 typedef struct AstDeclHeader { DECL_HEADER; // common initial sequence @@ -360,9 +350,7 @@ typedef struct FuncDecl { // TODO: Call this AdtDecl? // Need to prevent recursive structures, or introduce the concept of -// indirection (otherwise, structs that -// contain an instance of themselves as a field will become infinitely -// large)... +// indirection typedef struct StructDecl { DECL_HEADER; // common initial sequence paw_Bool is_global : 1; // uses 'global' keyword @@ -450,9 +438,9 @@ typedef enum AstExprKind { EXPR_PATHTYPE, } AstExprKind; -#define EXPR_HEADER \ - int line; \ - AstExprKind kind : 8; \ +#define EXPR_HEADER \ + int line; \ + AstExprKind kind : 8; \ AstType *type typedef struct AstExprHeader { EXPR_HEADER; @@ -503,7 +491,7 @@ typedef struct LiteralExpr { typedef struct ClosureExpr { EXPR_HEADER; // common initial sequence - Scope *scope; // scope for parameters + Scope *scope; // scope for parameters AstList *params; // parameter declarations AstExpr *result; // return type Block *body; // function body @@ -542,8 +530,8 @@ typedef struct LogicalExpr { AstExpr *rhs; } LogicalExpr; -#define SUFFIXED_HEADER \ - EXPR_HEADER; \ +#define SUFFIXED_HEADER \ + EXPR_HEADER; \ AstExpr *target typedef struct SuffixedExpr { SUFFIXED_HEADER; @@ -561,7 +549,7 @@ typedef struct CallExpr { typedef struct Selector { SUFFIXED_HEADER; // common fields - paw_Bool is_index: 1; + paw_Bool is_index : 1; union { String *name; paw_Int index; @@ -570,7 +558,7 @@ typedef struct Selector { typedef struct Index { SUFFIXED_HEADER; // common fields - paw_Bool is_slice: 1; + paw_Bool is_slice : 1; AstExpr *first; AstExpr *second; } Index; @@ -666,8 +654,8 @@ typedef enum AstStmtKind { STMT_RETURN, } AstStmtKind; -#define STMT_HEADER \ - int line; \ +#define STMT_HEADER \ + int line; \ AstStmtKind kind : 8 typedef struct AstStmtHeader { STMT_HEADER; @@ -986,16 +974,44 @@ AstDecl *pawA_get_decl(Ast *ast, DefId id); #define a_is_func_decl(d) (a_kind(d) == DECL_FUNC) #define a_has_receiver(d) (a_is_func_decl(d) && (d)->func.receiver != NULL) -#define a_is_template_decl(d) \ +#define a_is_template_decl(d) \ (a_is_func_template_decl(d) || a_is_struct_template_decl(d)) -#define a_is_func_template_decl(d) \ +#define a_is_func_template_decl(d) \ (a_is_func_decl(d) && (d)->func.generics->count > 0) -#define a_is_struct_template_decl(d) \ +#define a_is_struct_template_decl(d) \ (a_is_struct_decl(d) && (d)->struct_.generics->count > 0) #define a_adt_id(t) check_exp(a_is_adt(t), (t)->adt.base - PAW_TSTRING) +static inline paw_Bool is_vector_t(const AstType *t) +{ + return a_is_adt(t) && t->adt.base == PAW_TVECTOR; +} + +static inline paw_Bool is_map_t(const AstType *t) +{ + return a_is_adt(t) && t->adt.base == PAW_TMAP; +} + +static inline AstType *vector_elem(const AstType *t) +{ + paw_assert(is_vector_t(t)); + return t->adt.types->data[0]; +} + +static inline AstType *map_key(const AstType *t) +{ + paw_assert(is_map_t(t)); + return t->adt.types->data[0]; +} + +static inline AstType *map_value(const AstType *t) +{ + paw_assert(is_map_t(t)); + return t->adt.types->data[1]; +} + void pawA_repr_type(FILE *out, const AstType *type); void pawA_dump_type(FILE *out, AstType *type); void pawA_dump_path(FILE *out, AstPath *path); diff --git a/src/auxlib.c b/src/auxlib.c index 9eee68d..07b7582 100644 --- a/src/auxlib.c +++ b/src/auxlib.c @@ -79,7 +79,8 @@ void pawL_add_value(paw_Env *P, Buffer *buf, paw_Type type) const char *str = pawV_to_string(P, P->top.p[-1], type, &len); if (str == NULL) { // add the type name and address - str = paw_push_fstring(P, "%s (%p)", paw_typename(P, -1), + str = paw_push_fstring(P, "%s (%p)", + "" /*TODO: paw_typename(P, -1)*/, paw_pointer(P, -1)); len = paw_length(P, -1); } diff --git a/src/call.c b/src/call.c index 6f05e94..2c3561a 100644 --- a/src/call.c +++ b/src/call.c @@ -21,9 +21,9 @@ // Lua-style error handling #define c_throw(P, c) longjmp((c)->jmp, 1) -#define c_try(P, c, a) \ - if (!setjmp((c)->jmp)) { \ - a \ +#define c_try(P, c, a) \ + if (!setjmp((c)->jmp)) { \ + a \ } struct Jump { diff --git a/src/call.h b/src/call.h index 9a46b92..fb71388 100644 --- a/src/call.h +++ b/src/call.h @@ -11,9 +11,9 @@ #define STACK_EXTRA 1 /* number of slots reserved for errors */ #define save_offset(P, ptr) ((ptr) - (P)->stack.p) #define restore_pointer(P, ofs) ((P)->stack.p + (ofs)) -#define ensure_stack(P, n) \ - ((P)->bound.p - (P)->top.p < (n) + STACK_EXTRA \ - ? pawC_stack_grow(P, n + STACK_EXTRA) \ +#define ensure_stack(P, n) \ + ((P)->bound.p - (P)->top.p < (n) + STACK_EXTRA \ + ? pawC_stack_grow(P, n + STACK_EXTRA) \ : (void)0) typedef void (*Call)(paw_Env *P, void *arg); diff --git a/src/check.c b/src/check.c index 7f113be..5ac01e3 100644 --- a/src/check.c +++ b/src/check.c @@ -19,38 +19,32 @@ #include "unify.h" // Helper macros -#define name_error(R, line, ...) pawE_error(env((R)->lex), PAW_ENAME, line, __VA_ARGS__) +#define name_error(R, line, ...) \ + pawE_error(env((R)->lex), PAW_ENAME, line, __VA_ARGS__) #define syntax_error(R, ...) pawX_error((R)->lex, __VA_ARGS__) #define type_error(R, ...) pawE_error(env((R)->lex), PAW_ETYPE, -1, __VA_ARGS__) #define resolve_pat(V, p) ((V)->visit_pat(V, p), a_type(p)) #define cached_str(R, i) pawE_cstr(env((R)->lex), cast_size(i)) #define basic_decl(R, code) basic_symbol(R, code)->decl #define is_unit(e) (type2code(e) == PAW_TUNIT) -//#define normalize(table, type) pawU_normalize(table, type) +// #define normalize(table, type) pawU_normalize(table, type) #define flag2code(flag) (-(flag) - 1) -struct ContainerState { - struct ContainerState *outer; - struct Resolver *R; - AstType *type; -}; - // Common state for type-checking routines typedef struct Resolver { Lex *lex; // lexical state + Ast *ast; // AST being checked AstType *adt; // enclosing ADT AstType *result; // enclosing function return type SymbolTable *sym; // scoped symbol table - Ast *ast; // AST being checked - ParseMemory *pm; // dynamic memory Unifier *U; // unification tables - struct AstList *clist; // list of container type variables - struct ContainerState *cs; // info about current container + ParseMemory *pm; // dynamic memory struct MatchState *ms; // info about current match expression int func_depth; // number of nested functions - int option_did; - int result_did; - int cdepth; + int vector_gid; + int map_gid; + DefId option_did; + DefId result_did; paw_Bool in_closure; } Resolver; @@ -67,7 +61,7 @@ static void unify(Resolver *R, AstType *a, AstType *b) } //// Entrypoint for type unification -//#define unify(R, a, b) pawU_unify((R)->U, a, b) +// #define unify(R, a, b) pawU_unify((R)->U, a, b) static AstType *get_type(Resolver *R, DefId did) { @@ -91,21 +85,20 @@ static paw_Bool is_unit_variant(struct Resolver *R, const struct AstType *type) { if (a_is_fdef(type)) { struct AstDecl *decl = get_decl(R, type->func.did); - return a_kind(decl) == DECL_VARIANT && - decl->variant.fields->count == 0; + return a_kind(decl) == DECL_VARIANT && decl->variant.fields->count == 0; } return PAW_FALSE; } static AstType *new_vector_t(Resolver *R, AstType *elem_t) { - AstType *type = pawA_new_type(R->ast, AST_TYPE_ADT); - type->adt.base = PAW_TVECTOR; - type->adt.did = NO_DECL; // TODO: Cannonicalize vector instantiations - AstList *types = pawA_list_new(R->ast); - pawA_list_push(R->ast, &types, elem_t); - type->adt.types = types; - return type; + AstType *type = pawA_new_type(R->ast, AST_TYPE_ADT); + type->adt.base = PAW_TVECTOR; + type->adt.did = NO_DECL; // TODO: Cannonicalize vector instantiations + AstList *types = pawA_list_new(R->ast); + pawA_list_push(R->ast, &types, elem_t); + type->adt.types = types; + return type; } static AstType *new_map_t(Resolver *R, AstType *key_t, AstType *value_t) @@ -123,36 +116,7 @@ static AstType *new_map_t(Resolver *R, AstType *key_t, AstType *value_t) return type; } -static paw_Bool is_vector_t(const AstType *t) -{ - return a_is_adt(t) && t->adt.base == PAW_TVECTOR; -} - -static paw_Bool is_map_t(const AstType *t) -{ - return a_is_adt(t) && t->adt.base == PAW_TMAP; - -} - -static AstType *vector_elem(const AstType *t) -{ - paw_assert(is_vector_t(t)); - return t->adt.types->data[0]; -} - -static AstType *map_key(const AstType *t) -{ - paw_assert(is_map_t(t)); - return t->adt.types->data[0]; -} - -static AstType *map_value(const AstType *t) -{ - paw_assert(is_map_t(t)); - return t->adt.types->data[1]; -} - -static AstType *resolve_expr(struct AstVisitor *V, struct AstExpr *expr) +static AstType *resolve_expr(struct AstVisitor *V, struct AstExpr *expr) { struct Resolver *R = V->state.R; V->visit_expr(V, expr); @@ -172,7 +136,8 @@ static void visit_stmts(struct AstVisitor *V, struct AstList *list) #define are_types_same(a, b) ((a) == (b)) -// TODO: move to unify.c/reuse logic in that file (write idempotent version of unify()) +// TODO: move to unify.c/reuse logic in that file (write idempotent version of +// unify()) static paw_Bool test_types(Resolver *R, const AstType *a, const AstType *b); static paw_Bool test_binders(Resolver *R, const AstList *a, const AstList *b) @@ -201,15 +166,16 @@ static paw_Bool test_types(Resolver *R, const AstType *a, const AstType *b) case AST_TYPE_ADT: { if (a->adt.base == b->adt.base) { if (!a->adt.types == !b->adt.types) { - return a->adt.types != NULL - ? test_binders(R, a->adt.types, b->adt.types) - : PAW_TRUE; + return a->adt.types != NULL + ? test_binders(R, a->adt.types, b->adt.types) + : PAW_TRUE; } } break; } default: - paw_assert(a_kind(a) == AST_TYPE_GENERIC); + paw_assert(a_kind(a) == AST_TYPE_GENERIC || + a_kind(a) == AST_TYPE_UNKNOWN); return are_types_same(a, b); } return PAW_FALSE; @@ -217,16 +183,23 @@ static paw_Bool test_types(Resolver *R, const AstType *a, const AstType *b) static Symbol *basic_symbol(Resolver *R, paw_Type code) { - paw_assert(code >= 0 && code <= PAW_TSTRING); + paw_assert(code >= 0 && code <= PAW_TMAP); // basic types have fixed locations Scope *pub = R->sym->globals; - return pub->symbols->data[1 + code]; // TODO + switch (code) { + case PAW_TVECTOR: + return pub->symbols->data[R->vector_gid]; + case PAW_TMAP: + return pub->symbols->data[R->map_gid]; + default: + return pub->symbols->data[1 + code]; // TODO + } } -static Scope *push_symbol_table(Resolver *R) +static Scope *push_symbol_table(Resolver *R) { - return pawA_new_scope(R->ast, R->sym); + return pawA_new_scope(R->ast, R->sym); } static void pop_symbol_table(Resolver *R) @@ -295,33 +268,30 @@ static AstType *generic_collector(AstVisitor *V, AstDecl *decl) return d->type; } -#define make_collector(name, T, collect) \ - static AstList *collect_##name(AstVisitor *V, AstList *list) \ - { \ - Resolver *R = V->state.R; \ - AstList *binder = pawA_list_new(R->ast); \ - const int count = list ? list->count : 0; \ - for (int i = 0; i < count; ++i) { \ - AstType *type = collect(V, list->data[i]); \ - pawA_list_push(R->ast, &binder, type); \ - } \ - return binder; \ +#define make_collector(name, T, collect) \ + static AstList *collect_##name(AstVisitor *V, AstList *list) \ + { \ + Resolver *R = V->state.R; \ + AstList *binder = pawA_list_new(R->ast); \ + const int count = list ? list->count : 0; \ + for (int i = 0; i < count; ++i) { \ + AstType *type = collect(V, list->data[i]); \ + pawA_list_push(R->ast, &binder, type); \ + } \ + return binder; \ } make_collector(decl_types, AstDecl, decl_type_collector) -make_collector(expr_types, AstExpr, expr_type_collector) -make_collector(params, AstDecl, param_collector) -make_collector(params2, AstDecl, param_collector2) -make_collector(generics, AstDecl, generic_collector) + make_collector(expr_types, AstExpr, expr_type_collector) + make_collector(params, AstDecl, param_collector) + make_collector(params2, AstDecl, param_collector2) + make_collector(generics, AstDecl, generic_collector) -static void enter_inference_ctx(Resolver *R) + static void enter_inference_ctx(Resolver *R) { pawU_enter_binder(R->U); } -static void leave_inference_ctx(Resolver *R) -{ - pawU_leave_binder(R->U); -} +static void leave_inference_ctx(Resolver *R) { pawU_leave_binder(R->U); } static Scope *enclosing_scope(Resolver *R) { @@ -349,14 +319,15 @@ static Symbol *add_global(Resolver *R, String *name, AstDecl *decl) for (int i = 0; i < st->symbols->count; ++i) { Symbol *symbol = st->symbols->data[i]; if (pawS_eq(symbol->name, name)) { - name_error(R, decl->hdr.line, "duplicate global '%s' (declared previously on line %d)", + name_error(R, decl->hdr.line, + "duplicate global '%s' (declared previously on line %d)", name->text, symbol->decl->hdr.line); } } return add_symbol(R, st, name, decl); } -static Symbol *try_resolve_symbol(Resolver *R, String *name) +static Symbol *try_resolve_symbol(Resolver *R, const String *name) { // search the scoped symbols SymbolTable *scopes = R->sym; @@ -366,13 +337,15 @@ static Symbol *try_resolve_symbol(Resolver *R, String *name) const int index = pawA_find_symbol(scope, name); if (index >= 0) { Symbol *symbol = scope->symbols->data[index]; - if (scope->fn_depth != R->func_depth - && !symbol->is_type - && !R->in_closure) { - // TODO: replace is_type with more specific flag, this will mess up function templates! - // Types are not captured as upvalues - type_error(R, "attempt to reference non-local variable '%s' " - "(consider using a closure)", name->text); + if (scope->fn_depth != R->func_depth && !symbol->is_type && + !R->in_closure) { + // TODO: replace is_type with more specific flag, this will mess + // up function templates! + // Types are not captured as upvalues + type_error(R, + "attempt to reference non-local variable '%s' " + "(consider using a closure)", + name->text); } return scope->symbols->data[index]; } @@ -385,7 +358,7 @@ static Symbol *try_resolve_symbol(Resolver *R, String *name) return scopes->globals->symbols->data[index]; } -static Symbol *resolve_symbol(Resolver *R, String *name) +static Symbol *resolve_symbol(Resolver *R, const String *name) { Symbol *symbol = try_resolve_symbol(R, name); if (symbol == NULL) { @@ -426,7 +399,7 @@ static Symbol *new_symbol(Resolver *R, String *name, AstDecl *decl, } #define new_local(R, name, decl) new_symbol(R, name, decl, PAW_FALSE) -#define new_global(R, name, decl) new_symbol(R, name, decl, PAW_FALSE) +#define new_global(R, name, decl) new_symbol(R, name, decl, PAW_TRUE) static Scope *leave_block(Resolver *R) { @@ -565,7 +538,8 @@ static AstType *subst_unknown(AstTypeFolder *F, AstUnknown *t) // template) type variables replaced with inference variables. The types // returned by this function can be unified with the type of each argument // passed at the call site to determine a concrete type for each unknown. -static AstList *prep_func_inference(AstVisitor *V, AstList *before, AstList *after, AstList *target) +static AstList *prep_func_inference(AstVisitor *V, AstList *before, + AstList *after, AstList *target) { Subst subst = { .before = before, @@ -623,7 +597,8 @@ static void register_base_func(AstVisitor *V, FuncDecl *d) d->scope = leave_block(R); } -static AstList *transfer_fields(AstVisitor *V, AstList *list, AstDeclPass callback) +static AstList *transfer_fields(AstVisitor *V, AstList *list, + AstDeclPass callback) { AstList *copy = pawA_list_new(V->ast); for (int i = 0; i < list->count; ++i) { @@ -678,18 +653,18 @@ static void visit_variant_decl(AstVisitor *V, VariantDecl *d) { Resolver *R = V->state.R; add_decl(V->state.R, cast_decl(d)); - - // An enum variant name can be thought of as a function from the type of the variant's - // fields to the type of the enumeration. For example, given 'enum E {X(string)}', - // E::X has type 'fn(string) -> E'. - d->type = new_type(R, d->def, AST_TYPE_FUNC); - d->type->func.base = R->adt->adt.did; - d->type->func.types = pawA_list_new(V->ast); - d->type->func.params = collect_params(V, d->fields); - d->type->func.result = R->adt; - new_local(R, d->name, cast_decl(d)); - d->scope = collect_fields(V, d->fields); + // An enum variant name can be thought of as a function from the type of the + // variant's fields to the type of the enumeration. For example, given 'enum + // E {X(string)}', E::X has type 'fn(string) -> E'. + d->type = new_type(R, d->def, AST_TYPE_FUNC); + d->type->func.base = R->adt->adt.did; + d->type->func.types = pawA_list_new(V->ast); + d->type->func.params = collect_params(V, d->fields); + d->type->func.result = R->adt; + + new_local(R, d->name, cast_decl(d)); + d->scope = collect_fields(V, d->fields); } static void register_field_decl(AstVisitor *V, AstDecl *decl) @@ -910,13 +885,15 @@ static AstType *init_func_template(AstVisitor *V, FuncDecl *base, return a_type(inst); } -static AstType *explicit_func_template(AstVisitor *V, FuncDecl *base, AstList *elems) +static AstType *explicit_func_template(AstVisitor *V, FuncDecl *base, + AstList *elems) { AstList *types = collect_expr_types(V, elems); return init_func_template(V, base, types); } -static AstType *explicit_struct_template(AstVisitor *V, StructDecl *base, AstList *elems) +static AstType *explicit_struct_template(AstVisitor *V, StructDecl *base, + AstList *elems) { AstList *types = collect_expr_types(V, elems); return init_struct_template(V, base, types); @@ -926,12 +903,12 @@ static AstType *instantiate(AstVisitor *V, AstDecl *base, AstList *types) { if (types == NULL) { return a_type(base); - } + } if (a_is_struct_template_decl(base)) { return explicit_struct_template(V, &base->struct_, types); } else if (a_is_func_template_decl(base)) { return explicit_func_template(V, &base->func, types); - } + } return a_type(base); } @@ -957,6 +934,9 @@ static struct StructPack unpack_struct(Resolver *R, AstType *type) .type = decl->variant.type, .decl = decl, }; + } else if (a_is_basic(type) || type->adt.did == NO_DECL) { + type_error( + R, "fields/methods not yet implemented on builtin types"); // TODO } AstDecl *decl = get_decl(R, type->adt.did); if (a_is_struct_decl(decl)) { @@ -980,12 +960,13 @@ static struct StructPack unpack_struct(Resolver *R, AstType *type) }; } -static AstDecl *expect_attr(Resolver *R, const struct StructPack *pack, String *name) +static AstDecl *expect_attr(Resolver *R, const struct StructPack *pack, + String *name) { AstDecl *attr = resolve_attr(pack->fields, name); if (attr == NULL) { - name_error(R, -1, "field '%s' does not exist in type '%s'", - name->text, pack->name->text); + name_error(R, -1, "field '%s' does not exist in type '%s'", name->text, + pack->name->text); } return attr; } @@ -1069,9 +1050,7 @@ static void visit_match_expr(AstVisitor *V, MatchExpr *e) V->visit_expr_list(V, e->arms, V->visit_expr); R->ms = ms.outer; - e->type = ms.value == NULL - ? get_type(R, PAW_TUNIT) - : ms.value; + e->type = ms.value == NULL ? get_type(R, PAW_TUNIT) : ms.value; } static void visit_arm_expr(AstVisitor *V, MatchArm *e) @@ -1119,7 +1098,7 @@ static void visit_chain_expr(AstVisitor *V, ChainExpr *e) AstType *result = resolve_expr(V, e->target); if (R->result == NULL) { syntax_error(R, "'?' outside function body"); - } + } if (is_option_t(R, result) || is_result_t(R, result)) { e->type = result->adt.types->data[0]; } else { @@ -1130,13 +1109,11 @@ static void visit_chain_expr(AstVisitor *V, ChainExpr *e) static AstType *get_value_type(AstType *target) { - if (a_is_adt(target)) { - if (is_vector_t(target)) { - return vector_elem(target); - } else if (is_map_t(target)) { - return map_value(target); - } - } + if (is_vector_t(target)) { + return vector_elem(target); + } else if (is_map_t(target)) { + return map_value(target); + } return NULL; } @@ -1239,7 +1216,7 @@ static void visit_binop_expr(AstVisitor *V, BinOpExpr *e) if (e->op == BINARY_IN) { e->type = visit_in_expr(R, lhs, rhs); return; - } + } unify(R, lhs, rhs); const paw_Type left = type2code(lhs); @@ -1327,7 +1304,8 @@ static void visit_var_decl(AstVisitor *V, VarDecl *d) static void visit_type_decl(AstVisitor *V, TypeDecl *d) { // TODO: generic parameters for aliases - Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), PAW_FALSE); + Symbol *symbol = + declare_symbol(V->state.R, d->name, cast_decl(d), PAW_FALSE); d->type = resolve_expr(V, d->rhs); // unify(R, d->name, d->type); define_symbol(symbol); @@ -1349,7 +1327,8 @@ struct Generalization { AstList *fields; }; -static struct Generalization generalize(AstVisitor *V, AstList *generics, AstList *fields) +static struct Generalization generalize(AstVisitor *V, AstList *generics, + AstList *fields) { if (generics->count > 0) { generics = collect_decl_types(V, generics); @@ -1364,22 +1343,8 @@ static struct Generalization generalize(AstVisitor *V, AstList *generics, AstLis }; } -static void check_inference(Resolver *R, AstList *unknowns, AstList *generics) -{ - if (unknowns == NULL) { - return; // no inference - } - for (int i = 0; i < unknowns->count; ++i) { - AstType *type = unknowns->data[i]; - if (a_is_unknown(type)) { - AstDecl *generic = generics->data[i]; - const String *name = generic->generic.name; - type_error(R, "unable to infer generic parameter '%s'", name->text); - } - } -} - -static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, AstList *args) +static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, + AstList *args) { struct Generalization g = generalize(V, base->generics, base->params); @@ -1391,7 +1356,6 @@ static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, AstList *args AstType *b = resolve_expr(V, arg); unify(R, a, b); } - check_inference(R, g.types, base->generics); AstDecl *inst = instantiate_func(V, base, g.types); return a_type(inst); } @@ -1430,7 +1394,7 @@ static void visit_call_expr(AstVisitor *V, CallExpr *e) const AstList *params = params = e->func->fptr.params; e->type = e->func->fptr.result; - + if (is_unit_variant(R, e->func)) { type_error(R, "cannot call unit variant (omit '()' to construct)"); } @@ -1446,8 +1410,9 @@ static void visit_conversion_expr(AstVisitor *V, ConversionExpr *e) { Resolver *R = V->state.R; AstType *arg = resolve_expr(V, e->arg); - if (!a_is_adt(arg) || arg->adt.did == PAW_TUNIT || arg->adt.did == PAW_TSTRING) { - type_error(R, "argument to conversion must be scalar"); + if (!a_is_adt(arg) || arg->adt.did == PAW_TUNIT || + arg->adt.did == PAW_TSTRING) { + type_error(R, "argument to conversion must be scalar"); } e->type = get_type(R, e->to); } @@ -1461,16 +1426,16 @@ static AstType *visit_tuple_lit(AstVisitor *V, LiteralExpr *lit) static AstType *visit_vector_lit(AstVisitor *V, ContainerLit *e) { - struct Resolver *R = V->state.R; - struct Unifier *U = R->U; + struct Resolver *R = V->state.R; + struct Unifier *U = R->U; - struct AstType *elem_t = pawU_new_unknown(U); - for (int i = 0; i < e->items->count; ++i) { - AstExpr *expr = e->items->data[i]; - AstType *type = resolve_expr(V, expr); - unify(R, type, elem_t); - } - return new_vector_t(R, elem_t); + struct AstType *elem_t = pawU_new_unknown(U); + for (int i = 0; i < e->items->count; ++i) { + AstExpr *expr = e->items->data[i]; + AstType *type = resolve_expr(V, expr); + unify(R, type, elem_t); + } + return new_vector_t(R, elem_t); } static AstType *visit_map_lit(AstVisitor *V, ContainerLit *e) @@ -1501,7 +1466,8 @@ static AstType *visit_container_lit(AstVisitor *V, LiteralExpr *lit) } } -static String *resolve_item(AstVisitor *V, const struct StructPack *pack, StructItem *item, int index) +static String *resolve_item(AstVisitor *V, const struct StructPack *pack, + StructItem *item, int index) { item->type = resolve_expr(V, item->value); if (item->name == NULL) { @@ -1521,7 +1487,8 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) if (!a_is_adt(target)) { type_error(R, "expected structure type"); } - // Use a temporary Map to avoid searching repeatedly through the list of fields. + // Use a temporary Map to avoid searching repeatedly through the list of + // fields. paw_Env *P = env(lex); Value *pv = pawC_push0(P); Map *map = pawH_new(P); @@ -1546,8 +1513,9 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) String *k = resolve_item(V, &pack, &item->sitem, i); v_set_object(&key, k); if (pawH_contains(P, map, key)) { - name_error(R, item->hdr.line, "duplicate field '%s' in struct literal '%s'", - k->text, pack.name->text); + name_error(R, item->hdr.line, + "duplicate field '%s' in struct literal '%s'", k->text, + pack.name->text); } Value *value = pawH_action(P, map, key, MAP_ACTION_CREATE); v_set_int(value, i); @@ -1559,13 +1527,14 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) v_set_object(&key, field->name); Value *value = pawH_get(P, map, key); if (value == NULL) { - name_error(R, field->line, "missing initializer for field '%s' in struct '%s'", + name_error(R, field->line, + "missing initializer for field '%s' in struct '%s'", field->name->text, pack.name->text); } const paw_Int index = v_int(*value); AstType *field_t = is_inference - ? field_types->data[i] - : a_type(cast_decl(pack.fields->data[i])); + ? field_types->data[i] + : a_type(cast_decl(pack.fields->data[i])); AstExpr *item = order->data[index]; item->sitem.index = i; // index of attribute in struct unify(R, a_type(item), field_t); @@ -1579,7 +1548,6 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) pawA_list_free(R->ast, order); pawC_pop(P); // pop map if (is_inference) { - check_inference(R, g.types, pack.decl->struct_.generics); AstDecl *inst = instantiate_struct(V, &pack.decl->struct_, g.types); target = a_type(inst); } @@ -1602,7 +1570,8 @@ static void visit_literal_expr(AstVisitor *V, LiteralExpr *e) static void visit_func_decl(AstVisitor *V, FuncDecl *d) { - Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), d->is_global); + Symbol *symbol = + declare_symbol(V->state.R, d->name, cast_decl(d), d->is_global); symbol->is_type = d->generics->count > 0; register_base_func(V, d); visit_func(V, d, FUNC_FUNCTION); @@ -1641,7 +1610,8 @@ static void visit_dowhile_stmt(AstVisitor *V, WhileStmt *s) s->scope = leave_block(V->state.R); } -static void visit_forbody(AstVisitor *V, String *iname, AstType *itype, Block *b) +static void visit_forbody(AstVisitor *V, String *iname, AstType *itype, + Block *b) { Resolver *R = V->state.R; enter_block(R, NULL); @@ -1671,21 +1641,19 @@ static void visit_fornum(AstVisitor *V, ForStmt *s) visit_forbody(V, s->name, get_type(R, PAW_TINT), s->block); } -static void visit_forin( - AstVisitor *V, - ForStmt *s) // TODO: forin would need to encode the type of object being - // iterated over. look into function call for loop? +// TODO: allow function with signature fn iter(I) -> (fn(int) -> T) +static void visit_forin(AstVisitor *V, ForStmt *s) { - // Lex *lex = R->lex; - // ForIn *forin = &s->forin; - // new_local_literal(R, "(for target)", PAW_TINT); - // new_local_literal(R, "(for iterator)", PAW_TINT); - // V->visit_expr(V, forin->target); - // - // AstType *inner = pawY_unwrap(env(lex), forin->target->type); - // new_local(R, s->name, inner); - // - // V->visit_forbody(V, s->name, s->block); + Resolver *R = V->state.R; + AstType *iter_t = resolve_expr(V, s->forin.target); + AstType *elem_t = get_value_type(iter_t); + if (elem_t == NULL) { + type_error(R, "'for..in' not supported for type"); + } + new_local_literal(R, "(for target)", iter_t->adt.base); + new_local_literal(R, "(for iter)", PAW_TINT); + + visit_forbody(V, s->name, elem_t, s->block); } static void visit_for_stmt(AstVisitor *V, ForStmt *s) @@ -1721,7 +1689,7 @@ static void visit_index_expr(AstVisitor *V, Index *e) expect = get_type(R, PAW_TINT); e->type = get_type(R, PAW_TSTRING); } else { -not_container: + not_container: type_error(R, "type cannot be indexed (not a container)"); } if (e->is_slice) { @@ -1756,7 +1724,7 @@ static void visit_selector_expr(AstVisitor *V, Selector *e) Resolver *R = V->state.R; AstType *type = resolve_expr(V, e->target); if (a_is_tuple(type)) { - visit_tuple_selector(V, type, e); + visit_tuple_selector(V, type, e); return; } const struct StructPack pack = unpack_struct(R, type); @@ -1798,8 +1766,10 @@ static void try_bind_var(Resolver *R, AstPat *pat, AstType *want) AstSegment *segment = pat->path.path->list->data[0]; if (segment->types->count == 0) { Symbol *symbol = try_resolve_symbol(R, segment->name); - if (symbol == NULL || !symbol->is_type || a_is_func_decl(symbol->decl)) { - // TODO: don't abuse 'is_type' flag for function templates, shouldn't need to check if the symbol + if (symbol == NULL || !symbol->is_type || + a_is_func_decl(symbol->decl)) { + // TODO: don't abuse 'is_type' flag for function templates, + // shouldn't need to check if the symbol // is a function or not here AstDecl *r = pawA_new_decl(R->ast, DECL_VAR); r->var.name = segment->name; @@ -1807,13 +1777,14 @@ static void try_bind_var(Resolver *R, AstPat *pat, AstType *want) add_decl(R, r); } else { AstType *have = a_type(symbol->decl); - unify(R, have, want); + unify(R, have, want); } } } } -static AstType *resolve_sfield_pat(AstVisitor *V, const struct StructPack *pack, AstFieldPat *p) +static AstType *resolve_sfield_pat(AstVisitor *V, const struct StructPack *pack, + AstFieldPat *p) { Resolver *R = V->state.R; paw_assert(pack->is_struct); @@ -1828,7 +1799,8 @@ static AstType *resolve_sfield_pat(AstVisitor *V, const struct StructPack *pack, return p->type; } -static AstType *resolve_vfield_pat(AstVisitor *V, const struct StructPack *pack, AstFieldPat *p, int index) +static AstType *resolve_vfield_pat(AstVisitor *V, const struct StructPack *pack, + AstFieldPat *p, int index) { Resolver *R = V->state.R; paw_assert(!pack->is_struct); @@ -1848,7 +1820,8 @@ static void visit_struct_pat(AstVisitor *V, AstStructPat *p) if (!pack.is_struct) { type_error(R, "expected struct '%s'", pack.name->text); } else if (pack.fields->count != p->fields->count) { - name_error(R, p->line, "missing fields from struct pattern for '%s'", pack.name->text); + name_error(R, p->line, "missing fields from struct pattern for '%s'", + pack.name->text); } for (int i = 0; i < p->fields->count; ++i) { AstPat *pat = p->fields->data[i]; @@ -1871,7 +1844,8 @@ static void visit_variant_pat(AstVisitor *V, AstVariantPat *p) if (pack.is_struct) { type_error(R, "expected variant '%s'", pack.name->text); } else if (pack.fields->count != p->elems->count) { - name_error(R, p->line, "missing fields from variant pattern for '%s'", pack.name->text); + name_error(R, p->line, "missing fields from variant pattern for '%s'", + pack.name->text); } for (int i = 0; i < p->elems->count; ++i) { AstPat *pat = p->elems->data[i]; @@ -1885,7 +1859,8 @@ static void visit_variant_pat(AstVisitor *V, AstVariantPat *p) static void visit_prelude_func(AstVisitor *V, FuncDecl *d) { - Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), PAW_TRUE); + Symbol *symbol = + declare_symbol(V->state.R, d->name, cast_decl(d), PAW_TRUE); register_base_func(V, d); define_symbol(symbol); } @@ -1914,15 +1889,18 @@ static void add_basic_builtin(Resolver *R, String *name) add_decl(R, d); d->hdr.type = type; - Symbol *symbol = new_local(R, name, d); + Symbol *symbol = new_global(R, name, d); symbol->is_type = PAW_TRUE; + symbol->is_init = PAW_TRUE; } -static void add_container_builtin(Resolver *R, const char *name, paw_Type code, const char **generics) +static DefId add_container_builtin(Resolver *R, const char *name, paw_Type code, + const char **generics) { - AstDecl *d = pawA_new_decl(R->ast, DECL_TYPE); - d->type.generics = pawA_list_new(R->ast); - d->type.name = scan_string(R->lex, name); + AstDecl *d = pawA_new_decl(R->ast, DECL_STRUCT); + d->struct_.line = 0; + d->struct_.generics = pawA_list_new(R->ast); + d->struct_.name = scan_string(R->lex, name); for (const char **pname = generics; *pname != NULL; ++pname) { AstDecl *g = pawA_new_decl(R->ast, DECL_GENERIC); g->generic.name = scan_string(R->lex, *pname); @@ -1930,11 +1908,15 @@ static void add_container_builtin(Resolver *R, const char *name, paw_Type code, g->generic.type->generic.name = g->generic.name; g->generic.type->generic.did = add_decl(R, g); g->generic.line = 0; - pawA_list_push(R->ast, &d->type.generics, g); + pawA_list_push(R->ast, &d->struct_.generics, g); } - d->type.type = R->ast->builtin[code]; - d->type.line = 0; - add_decl(R, d); + d->struct_.type = R->ast->builtin[code]; + d->struct_.def = add_decl(R, d); + const int gid = R->sym->globals->symbols->count; + Symbol *symbol = new_global(R, d->struct_.name, d); + symbol->is_type = PAW_TRUE; + symbol->is_init = PAW_TRUE; + return gid; } static void visit_prelude(AstVisitor *V, Resolver *R) @@ -1956,14 +1938,18 @@ static void visit_prelude(AstVisitor *V, Resolver *R) static void setup_module(AstVisitor *V, Resolver *R, AstDecl *r) { SymbolTable *symtab = R->ast->symtab; - enter_block(R, symtab->globals); add_basic_builtin(R, cached_str(R, CSTR_UNIT)); add_basic_builtin(R, cached_str(R, CSTR_BOOL)); add_basic_builtin(R, cached_str(R, CSTR_INT)); add_basic_builtin(R, cached_str(R, CSTR_FLOAT)); add_basic_builtin(R, cached_str(R, CSTR_STRING)); - add_container_builtin(R, "(Vector)", PAW_TVECTOR, (const char *[]){"T", NULL}); - add_container_builtin(R, "(Map)", PAW_TMAP, (const char *[]){"K", "V", NULL}); + R->vector_gid = add_container_builtin(R, "(Vector)", PAW_TVECTOR, + (const char *[]){"T", NULL}); + R->map_gid = add_container_builtin(R, "(Map)", PAW_TMAP, + (const char *[]){"K", "V", NULL}); + + enter_block(R, symtab->globals); + visit_prelude(V, R); symtab->globals = leave_block(R); r->func.type = new_type(R, NO_DECL, AST_TYPE_FUNC); @@ -1972,11 +1958,11 @@ static void setup_module(AstVisitor *V, Resolver *R, AstDecl *r) r->func.type->func.result = get_type(R, PAW_TUNIT); r->func.params = pawA_list_new(R->ast); - visit_prelude(V, R); - - Symbol *symbol = resolve_symbol(R, scan_string(R->lex, "Option")); + const String *option_name = scan_string(R->lex, "Option"); + const String *result_name = scan_string(R->lex, "Result"); + const Symbol *symbol = resolve_symbol(R, option_name); R->option_did = symbol->decl->struct_.def; - symbol = resolve_symbol(R, scan_string(R->lex, "Result")); + symbol = resolve_symbol(R, result_name); R->result_did = symbol->decl->struct_.def; const AstState state = {.R = R}; diff --git a/src/code.c b/src/code.c index 72e4517..f6e7d92 100644 --- a/src/code.c +++ b/src/code.c @@ -63,6 +63,16 @@ void pawK_code_AB(FuncState *fs, Op op, int a, int b) add_opcode(fs, create_AB(op, a, b)); } +typedef struct Arena { + struct Arena *prev; + size_t used; + size_t size; + + // Must be aligned to at least the strictest alignment required + // by an AST or IR node. + _Alignas(void *) char data[]; +} Arena; + // Create a new arena large enough to allocate memory of the 'required_size' // Alignment is not considered, since the start of an Arena is suitably-aligned // for any objects created by the compiler. diff --git a/src/code.h b/src/code.h index e92ba1b..f8c2b46 100644 --- a/src/code.h +++ b/src/code.h @@ -10,19 +10,9 @@ typedef int NodeId; -typedef struct Arena { - struct Arena *prev; - size_t used; - size_t size; - - // Must be aligned to at least the strictest alignment required - // by an AST or IR node. - _Alignas(void *) char data[]; -} Arena; - typedef struct Pool { - Arena *filled; // list of filled arenas - Arena *arena; // list of available arenas + struct Arena *filled; // list of filled arenas + struct Arena *arena; // list of available arenas size_t last_size; // size of last arena allocated size_t min_size; // minimum allocation size } Pool; diff --git a/src/codegen.c b/src/codegen.c index a2e9d26..38f458d 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -13,7 +13,7 @@ #define syntax_error(G, ...) pawX_error((G)->lex, __VA_ARGS__) #define is_global(lex) (is_toplevel(lex) && (lex)->fs->bs->outer == NULL) -#define code_block(V, b) \ +#define code_block(V, b) \ check_exp((b)->kind == STMT_BLOCK, V->visit_stmt(V, cast_stmt(b))) #define basic_decl(G, code) basic_symbol(G, code)->decl #define basic_type(G, code) basic_decl(G, code)->type.type @@ -192,8 +192,10 @@ static VarInfo transfer_local(FuncState *fs) Symbol *symbol; // Find the next symbol that belongs on the stack. SymbolTable *scopes = fs->scopes; // all function scopes - Scope *scope = scopes->scopes->data[scopes->scopes->count - 1]; // last scope - while (symbol_iter(scope, &fs->bs->isymbol, &symbol)) {} + Scope *scope = + scopes->scopes->data[scopes->scopes->count - 1]; // last scope + while (symbol_iter(scope, &fs->bs->isymbol, &symbol)) { + } return add_local(fs, symbol); } @@ -201,7 +203,8 @@ static VarInfo transfer_global(Generator *G) { Symbol *symbol; Scope *scope = G->globals; - while (symbol_iter(scope, &G->iglobal, &symbol)) {} + while (symbol_iter(scope, &G->iglobal, &symbol)) { + } const int g = pawE_new_global(env(G->lex), symbol->name, a_type(symbol->decl)->adt.did); // TODO return (VarInfo){ @@ -317,10 +320,7 @@ static void adjust_to(FuncState *fs, LabelKind kind, int to) } } -static void begin_local_scope(FuncState *fs, int n) -{ - fs->level += n; -} +static void begin_local_scope(FuncState *fs, int n) { fs->level += n; } static void end_local_scope(FuncState *fs, BlockState *bs) { @@ -488,7 +488,8 @@ static void add_upvalue(FuncState *fs, VarInfo *info, paw_Bool is_local) info->kind = VAR_UPVALUE; } -static paw_Bool resolve_upvalue(FuncState *fs, const String *name, VarInfo *pinfo) +static paw_Bool resolve_upvalue(FuncState *fs, const String *name, + VarInfo *pinfo) { FuncState *caller = fs->outer; if (!caller) { @@ -523,7 +524,7 @@ static void define_var(FuncState *fs, VarInfo info) } } -static VarInfo code_var(Generator *G, paw_Bool global) +static VarInfo new_var(Generator *G, paw_Bool global) { FuncState *fs = G->fs; VarInfo info = declare_var(fs, global); @@ -537,20 +538,23 @@ static VarInfo find_var(Generator *G, const String *name) Lex *lex = G->lex; FuncState *fs = G->fs; if (!resolve_local(fs, name, &info) && // not local - !resolve_upvalue(fs, name, &info) && // not local to caller - !resolve_global(G, name, &info)) { // not found + !resolve_upvalue(fs, name, &info) && // not local to caller + !resolve_global(G, name, &info)) { // not found pawX_error(lex, "undefined variable '%s'", name->text); } return info; } -#define code_op(fs, op, subop, type) \ +#define code_op(fs, op, subop, type) \ pawK_code_AB(fs, op, cast(subop, int), basic_code(type)) -// TODO: OP_PUSHFALSE is a hack to avoid creating unnecessary constants, essentially pushes integer 0 -// we would otherwise have to create a new constant for integer 0, else do it at the beginning and stash it somewhere -// need to cannonicalize constants, otherwise we end up with a huge amount of redundancy -static void code_slice_indices(AstVisitor *V, AstExpr *first, AstExpr *second, const AstType *target) +// TODO: OP_PUSHFALSE is a hack to avoid creating unnecessary constants, +// essentially pushes integer 0 +// we would otherwise have to create a new constant for integer 0, else do +// it at the beginning and stash it somewhere need to cannonicalize +// constants, otherwise we end up with a huge amount of redundancy +static void code_slice_indices(AstVisitor *V, AstExpr *first, AstExpr *second, + const AstType *target) { Generator *G = V->state.G; FuncState *fs = G->fs; @@ -559,7 +563,7 @@ static void code_slice_indices(AstVisitor *V, AstExpr *first, AstExpr *second, c V->visit_expr(V, first); } else { // default to the start of the sequence - pawK_code_0(fs, OP_PUSHFALSE); + pawK_code_0(fs, OP_PUSHFALSE); } if (second != NULL) { V->visit_expr(V, second); @@ -683,9 +687,7 @@ static void code_container_lit(AstVisitor *V, LiteralExpr *e) visit_exprs(V, lit->items); FuncState *fs = V->state.G->fs; - const Op op = lit->code == PAW_TVECTOR - ? OP_NEWVECTOR - : OP_NEWMAP; + const Op op = lit->code == PAW_TVECTOR ? OP_NEWVECTOR : OP_NEWMAP; pawK_code_U(fs, op, lit->items->count); } @@ -868,7 +870,7 @@ static void monomorphize_func(AstVisitor *V, FuncDecl *d) static void code_field_decl(AstVisitor *V, FieldDecl *d) { - code_var(V->state.G, PAW_FALSE); + new_var(V->state.G, PAW_FALSE); paw_unused(d); } @@ -930,13 +932,12 @@ static int code_match_guard(AstVisitor *V, AstPat *guard) if (a_kind(guard) == AST_PAT_VARIANT) { return code_variant_guard(V, &guard->variant); } else if (a_kind(guard) == AST_PAT_STRUCT) { - + } else if (a_kind(guard) == AST_PAT_PATH) { - - } else { + } else { } - return -1; + return -1; } static void code_arm_expr(AstVisitor *V, MatchArm *e) @@ -980,11 +981,12 @@ static void code_instance_getter(AstVisitor *V, AstType *type) AstDecl *decl = get_decl(G, type->func.did); String *name = decl->hdr.name; if (!pawS_eq(name, scan_string(G->lex, "_vector_push")) && - !pawS_eq(name, scan_string(G->lex, "_vector_pop")) && - !pawS_eq(name, scan_string(G->lex, "_vector_insert")) && - !pawS_eq(name, scan_string(G->lex, "_vector_erase")) && - !pawS_eq(name, scan_string(G->lex, "_vector_clone"))) { - // TODO: These functions are native. They use the same code for all instantiations (they + !pawS_eq(name, scan_string(G->lex, "_vector_pop")) && + !pawS_eq(name, scan_string(G->lex, "_vector_insert")) && + !pawS_eq(name, scan_string(G->lex, "_vector_erase")) && + !pawS_eq(name, scan_string(G->lex, "_vector_clone"))) { + // TODO: These functions are native. They use the same code for all + // instantiations (they // only move parameters around as 'union Value') paw_assert(a_is_func_decl(decl)); name = mangle_name(G, name, type->func.types); @@ -1015,14 +1017,15 @@ static paw_Bool is_instance_call(const AstType *type) static paw_Bool is_variant_constructor(Generator *G, const AstType *type) { if (a_is_fdef(type)) { - const AstDecl *decl = get_decl(G, type->func.did); + const AstDecl *decl = get_decl(G, type->func.did); return a_kind(decl) == DECL_VARIANT; } return PAW_FALSE; } // Generate code for an enumerator -static void code_variant_constructor(AstVisitor *V, AstType *type, AstList *args) +static void code_variant_constructor(AstVisitor *V, AstType *type, + AstList *args) { Generator *G = V->state.G; FuncState *fs = G->fs; @@ -1040,7 +1043,7 @@ static void code_variant_constructor(AstVisitor *V, AstType *type, AstList *args static void code_path_expr(AstVisitor *V, PathExpr *e) { Generator *G = V->state.G; - if (is_variant_constructor(G, e->type) ) { + if (is_variant_constructor(G, e->type)) { code_variant_constructor(V, e->type, NULL); } else { const VarInfo info = resolve_short_path(G, e->path); @@ -1055,7 +1058,7 @@ static void code_call_expr(AstVisitor *V, CallExpr *e) FuncState *fs = G->fs; if (is_variant_constructor(G, e->func)) { - code_variant_constructor(V, e->func, e->args); + code_variant_constructor(V, e->func, e->args); return; } else if (is_instance_call(e->func)) { code_instance_getter(V, e->func); @@ -1070,10 +1073,10 @@ static void code_conversion_expr(AstVisitor *V, ConversionExpr *e) { Generator *G = V->state.G; const AstType *from = a_type(e->arg); - const Op op = e->to == PAW_TBOOL - ? OP_CASTBOOL : e->to == PAW_TINT - ? OP_CASTINT : OP_CASTFLOAT; - + const Op op = e->to == PAW_TBOOL ? OP_CASTBOOL + : e->to == PAW_TINT ? OP_CASTINT + : OP_CASTFLOAT; + V->visit_expr(V, e->arg); pawK_code_U(G->fs, op, from->adt.base); } @@ -1183,10 +1186,10 @@ static void code_forbody(AstVisitor *V, Block *block, Op opinit, Op oploop) const int loop = fs->pc; // Put the control variable in the same scope as any locals declared inside - // the loop. If the control variable is captured in a closure, the upvalue + // the loop. If the control variable is captured in a closure, the upvalue // must be closed at the end of the iteration. enter_block(fs, &bs, block->scope, PAW_FALSE); - code_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); V->visit_stmt_list(V, block->stmts, V->visit_stmt); leave_block(fs); @@ -1204,9 +1207,9 @@ static void code_fornum_stmt(AstVisitor *V, ForStmt *s) V->visit_expr(V, fornum->begin); V->visit_expr(V, fornum->end); V->visit_expr(V, fornum->step); - code_var(G, PAW_FALSE); - code_var(G, PAW_FALSE); - code_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); code_forbody(V, s->block, OP_FORNUM0, OP_FORNUM); } @@ -1217,9 +1220,13 @@ static void code_forin_stmt(AstVisitor *V, ForStmt *s) ForIn *forin = &s->forin; V->visit_expr(V, forin->target); - code_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); + new_var(G, PAW_FALSE); - code_forbody(V, s->block, OP_FORIN0, OP_FORIN); + const AstType *t = a_type(forin->target); + const Op init = is_vector_t(t) ? OP_FORVECTOR0 : OP_FORMAP0; + const Op loop = is_vector_t(t) ? OP_FORVECTOR : OP_FORMAP; + code_forbody(V, s->block, init, loop); } static void code_for_stmt(AstVisitor *V, ForStmt *s) @@ -1288,9 +1295,7 @@ static void code_field_pat(AstVisitor *V, AstFieldPat *p) static void code_struct_pat(AstVisitor *V, AstStructPat *p) { - Generator *G = V->state.G; - const int target = G->fs->level; - + paw_unused(V); paw_unused(p); } @@ -1372,7 +1377,6 @@ static void code_module(Generator *G) fs.name = lex->modname; fs.proto = lex->main->p; - Scope *toplevel = ast->symtab->toplevel; enter_function(G, &fs, &bs, toplevel, FUNC_MODULE); diff --git a/src/config.h b/src/config.h index bdb62a1..28f010b 100644 --- a/src/config.h +++ b/src/config.h @@ -9,7 +9,7 @@ #define PAW_INT_WIDTH (sizeof(paw_Int) * 8) #define PAW_INT_MAX INT64_MAX #define PAW_INT_MIN INT64_MIN -#define PAW_SIZE_MAX \ +#define PAW_SIZE_MAX \ (sizeof(size_t) < sizeof(paw_Int) ? SIZE_MAX : (size_t)PAW_INT_MAX) #define paw_cast_int(x) ((paw_Int)(x)) #define paw_int_c(x) INT64_C(x) diff --git a/src/debug.c b/src/debug.c index 45623e9..e10ab3a 100644 --- a/src/debug.c +++ b/src/debug.c @@ -139,10 +139,14 @@ const char *paw_op_name(Op op) return "FORNUM0"; case OP_FORNUM: return "FORNUM"; - case OP_FORIN0: - return "FORIN0"; - case OP_FORIN: - return "FORIN"; + case OP_FORVECTOR0: + return "FORVECTOR0"; + case OP_FORVECTOR: + return "FORVECTOR"; + case OP_FORMAP0: + return "FORMAP0"; + case OP_FORMAP: + return "FORMAP"; case OP_UNOP: return "UNOP"; case OP_BINOP: @@ -275,11 +279,17 @@ void paw_dump_opcode(OpCode opcode) case OP_FORNUM: printf("FORNUM\n"); break; - case OP_FORIN0: - printf("FORIN0\n"); + case OP_FORVECTOR0: + printf("FORVECTOR0\n"); break; - case OP_FORIN: - printf("FORIN\n"); + case OP_FORVECTOR: + printf("FORVECTOR\n"); + break; + case OP_FORMAP0: + printf("FORMAP0\n"); + break; + case OP_FORMAP: + printf("FORMAP\n"); break; case OP_UNOP: printf("UNOP %s %d\n", paw_unop_name(get_A(opcode)), get_B(opcode)); @@ -355,8 +365,7 @@ void dump_aux(paw_Env *P, Proto *proto, Buffer *print) } case OP_CLOSE: { - pawL_add_fstring(P, print, " ; count = %d", - get_U(opcode)); + pawL_add_fstring(P, print, " ; count = %d", get_U(opcode)); break; } @@ -382,22 +391,12 @@ void dump_aux(paw_Env *P, Proto *proto, Buffer *print) break; } - case OP_FORNUM0: { - pawL_add_fstring(P, print, " ; offset = %d", get_S(opcode)); - break; - } - - case OP_FORIN0: { - pawL_add_fstring(P, print, " ; offset = %d", get_S(opcode)); - break; - } - - case OP_FORNUM: { - pawL_add_fstring(P, print, " ; offset = %d", get_S(opcode)); - break; - } - - case OP_FORIN: { + case OP_FORNUM0: + case OP_FORNUM: + case OP_FORVECTOR0: + case OP_FORVECTOR: + case OP_FORMAP0: + case OP_FORMAP: { pawL_add_fstring(P, print, " ; offset = %d", get_S(opcode)); break; } diff --git a/src/env.h b/src/env.h index 659f7d0..7ff0142 100644 --- a/src/env.h +++ b/src/env.h @@ -11,8 +11,8 @@ #include "type.h" #include "value.h" #include -#include #include +#include struct Jump; // call.c diff --git a/src/gc_aux.h b/src/gc_aux.h index b4a047b..c094f56 100644 --- a/src/gc_aux.h +++ b/src/gc_aux.h @@ -12,11 +12,11 @@ #define g_incref(o) (++(o)->gc_nrefs) #define g_decref(o) check_exp(g_hasref(o), --(o)->gc_nrefs) -#define check_gc(P) \ - do { \ - if ((P)->gc_bytes > (P)->gc_limit) { \ - pawG_collect(P); \ - } \ +#define check_gc(P) \ + do { \ + if ((P)->gc_bytes > (P)->gc_limit) { \ + pawG_collect(P); \ + } \ } while (0) void pawG_init(paw_Env *P); diff --git a/src/iolib.c b/src/iolib.c index 9bd5fef..d3d1029 100644 --- a/src/iolib.c +++ b/src/iolib.c @@ -128,10 +128,14 @@ static int io_tell(paw_Env *P) } static const pawL_Attr kIOLib[] = { - {"open", io_open}, {"close", io_close}, - {"flush", io_flush}, {"read", io_read}, - {"write", io_write}, {"seek", io_seek}, - {"tell", io_tell}, {0}, + {"open", io_open}, + {"close", io_close}, + {"flush", io_flush}, + {"read", io_read}, + {"write", io_write}, + {"seek", io_seek}, + {"tell", io_tell}, + {0}, }; void pawL_require_iolib(paw_Env *P) diff --git a/src/lib.c b/src/lib.c index 3673b14..faf549c 100644 --- a/src/lib.c +++ b/src/lib.c @@ -31,10 +31,7 @@ void lib_error(paw_Env *P, int error, const char *fmt, ...) pawC_throw(P, error); } -static int get_argc(paw_Env *P) -{ - return paw_get_count(P) - 1 /* context */; -} +static int get_argc(paw_Env *P) { return paw_get_count(P) - 1 /* context */; } void pawL_check_argc(paw_Env *P, int argc) { @@ -48,88 +45,88 @@ int pawL_check_varargc(paw_Env *P, int min, int max) return narg; } -//static void try_aux(paw_Env *P, void *arg) +// static void try_aux(paw_Env *P, void *arg) //{ -// const int argc = *cast(arg, int *); -// const Value f = cf_base(1); -// pawC_call(P, v_object(f), argc - 1); -// } +// const int argc = *cast(arg, int *); +// const Value f = cf_base(1); +// pawC_call(P, v_object(f), argc - 1); +// } // -//static int base_try(paw_Env *P) +// static int base_try(paw_Env *P) //{ -// int argc = pawL_check_varargc(P, 1, UINT8_MAX); -// const int status = pawC_try(P, try_aux, &argc); -// paw_push_int(P, status); -// return 1; -// } +// int argc = pawL_check_varargc(P, 1, UINT8_MAX); +// const int status = pawC_try(P, try_aux, &argc); +// paw_push_int(P, status); +// return 1; +// } // -// static int base_require(paw_Env *P) +// static int base_require(paw_Env *P) //{ -// pawL_check_argc(P, 1); -// const char *name = pawL_check_string(P, 1); -// pawL_require_lib(P, name); -// return 1; -// } +// pawL_check_argc(P, 1); +// const char *name = pawL_check_string(P, 1); +// pawL_require_lib(P, name); +// return 1; +// } // -// #def ine make_to_bool(suffix, T) \ +// #de f in e make_to_bool(suffix, T) \ // static int base_to_bool_ ## suffix(paw_Env *P) \ // { \ // pawL_check_argc(P, 1); \ // pawR_to_bool(P, T); \ // return 1; \ // } -// make_to_bool(s, PAW_TSTRING) -// make_to_bool(i, PAW_TINT) -// make_to_bool(f, PAW_TFLOAT) +// make_to_bool(s, PAW_TSTRING) +// make_to_bool(i, PAW_TINT) +// make_to_bool(f, PAW_TFLOAT) // -// #def ine make_to_int(suffix, T) \ +// #de f in e make_to_int(suffix, T) \ // static int base_to_int_ ## suffix(paw_Env *P) \ // { \ // pawL_check_argc(P, 1); \ // pawR_to_int(P, T); \ // return 1; \ // } -// make_to_int(s, PAW_TSTRING) -// make_to_int(i, PAW_TINT) -// make_to_int(f, PAW_TFLOAT) +// make_to_int(s, PAW_TSTRING) +// make_to_int(i, PAW_TINT) +// make_to_int(f, PAW_TFLOAT) // -// #def ine make_to_float(suffix, T) \ +// #de f in e make_to_float(suffix, T) \ // static int base_to_float_ ## suffix(paw_Env *P) \ // { \ // pawL_check_argc(P, 1); \ // pawR_to_float(P, T); \ // return 1; \ // } -// make_to_float(s, PAW_TSTRING) -// make_to_float(i, PAW_TINT) -// make_to_float(f, PAW_TFLOAT) +// make_to_float(s, PAW_TSTRING) +// make_to_float(i, PAW_TINT) +// make_to_float(f, PAW_TFLOAT) // -// static int base_chr(paw_Env *P) +// static int base_chr(paw_Env *P) //{ -// pawL_check_argc(P, 1); -// const paw_Int ord = pawL_check_int(P, 1); -// if (0x00 <= ord && ord <= 0xFF) { -// const uint8_t chr[] = {ord}; -// paw_push_nstring(P, (const char *)chr, 1); -// } else { -// // TODO: Encode UTF-8 codepoint -// pawR_error(P, PAW_EOVERFLOW, "FIXME: Support UTF-8!"); -// } -// return 1; -// } +// pawL_check_argc(P, 1); +// const paw_Int ord = pawL_check_int(P, 1); +// if (0x00 <= ord && ord <= 0xFF) { +// const uint8_t chr[] = {ord}; +// paw_push_nstring(P, (const char *)chr, 1); +// } else { +// // TODO: Encode UTF-8 codepoint +// pawR_error(P, PAW_EOVERFLOW, "FIXME: Support UTF-8!"); +// } +// return 1; +// } // -// static int base_ord(paw_Env *P) +// static int base_ord(paw_Env *P) //{ -// pawL_check_argc(P, 1); -// const char *str = pawL_check_string(P, 1); -// const size_t len = paw_length(P, 1); -// if (!len || len > 4) { -// pawR_error(P, PAW_EVALUE, "invalid UTF-8"); -// } -// // TODO: Decode UTF-8 codepoint -// paw_push_int(P, str[0]); -// return 1; -// } +// pawL_check_argc(P, 1); +// const char *str = pawL_check_string(P, 1); +// const size_t len = paw_length(P, 1); +// if (!len || len > 4) { +// pawR_error(P, PAW_EVALUE, "invalid UTF-8"); +// } +// // TODO: Decode UTF-8 codepoint +// paw_push_int(P, str[0]); +// return 1; +// } static int base_assert(paw_Env *P) { @@ -232,14 +229,15 @@ static int vector_pop(paw_Env *P) static paw_Int clamped_index(paw_Env *P, int loc, paw_Int n) { const paw_Int i = v_int(cf_base(loc)); - return i < 0 ? 0 : i >= n ? n - 1 : i; + return i < 0 ? 0 : i >= n ? n - 1 + : i; } // TODO: It would be nice to let pop() take an optional parameter indicating the -// index at which to erase an element. To me, 'remove' seems like it -// should remove the first matching element using something akin to operator==. -// Attempting this will break, since we have no concept of equality between -// user-defined types right now. +// index at which to erase an element. To me, 'remove' seems like it +// should remove the first matching element using something akin to +// operator==. Attempting this will break, since we have no concept of +// equality between user-defined types right now. static int vector_remove(paw_Env *P) { Vector *vec = v_vector(cf_base(1)); diff --git a/src/lib.h b/src/lib.h index 10cf04e..7f1d432 100644 --- a/src/lib.h +++ b/src/lib.h @@ -33,9 +33,9 @@ int pawL_load_chunk(paw_Env *P, const char *name, const char *source); #define L_SELF (INT_MIN + 1) #define l_generic(i) (-(i) - 1) -#define l_list(...) \ +#define l_list(...) \ (paw_Type[]) { __VA_ARGS__, L_LIST_END } -#define l_list_0() \ +#define l_list_0() \ (paw_Type[]) { L_LIST_END } #endif // PAW_LIB_H diff --git a/src/map.c b/src/map.c index 3476ccb..098e450 100644 --- a/src/map.c +++ b/src/map.c @@ -80,6 +80,10 @@ static void grow_map(paw_Env *P, Map *m) pawM_check_size(P, 0, n, MAP_ITEM_TOTAL); const size_t new_size = n * MAP_ITEM_TOTAL; void *buffer = pawM_alloc(P, NULL, 0, new_size); + if (buffer == NULL) { + pawE_error(P, PAW_EMEMORY, -1, + "cannot allocate map table (out of memory)"); + } memset(buffer, MAP_ITEM_VACANT, n * sizeof(MapMeta)); const Map old_m = *m; @@ -125,7 +129,8 @@ void pawH_clone(paw_Env *P, StackPtr sp, Map *m) static paw_Bool items_equal(Value x, Value y) { - // TODO: Only allowed for 'basic' types right now. Compiler set to complain otherwise. + // TODO: Only allowed for 'basic' types right now. Compiler set to complain + // otherwise. return x.u == y.u; } diff --git a/src/mem.h b/src/mem.h index e042c73..902d5d1 100644 --- a/src/mem.h +++ b/src/mem.h @@ -10,37 +10,37 @@ // Throw an 'out of memory' error // The error message is allocated on startup, and there is always an extra // stack slot to hold it. -#define pawM_error(P) \ +#define pawM_error(P) \ (*(P)->top.p++ = (P)->mem_errmsg, pawC_throw(P, PAW_EMEMORY)) #define pawM_new(P, type) pawM_new_vec(P, 1, type) #define pawM_free(P, ptr) pawM_free_vec(P, ptr, 1) -#define pawM_new_vec(P, n, type) \ +#define pawM_new_vec(P, n, type) \ (type *)pawM_new_vec_(P, cast_size(n), sizeof(type)) -#define pawM_free_vec(P, ptr, n) \ +#define pawM_free_vec(P, ptr, n) \ pawM_free_(P, ptr, cast_size(n) * sizeof((ptr)[0])) -#define pawM_new_flex(P, tobj, n, e) \ +#define pawM_new_flex(P, tobj, n, e) \ (tobj *)pawM_new_flex_(P, sizeof(tobj), cast_size(n), e) -#define pawM_free_flex(P, ptr, n, e) \ +#define pawM_free_flex(P, ptr, n, e) \ pawM_free_(P, ptr, sizeof(*(ptr)) + (cast_size(n) * cast_size(e))) -#define pawM_grow(P, ptr, size, alloc) \ +#define pawM_grow(P, ptr, size, alloc) \ ((ptr) = pawM_grow_(P, ptr, size, &(alloc), sizeof((ptr)[0]))) -#define pawM_shrink(P, ptr, alloc0, alloc) \ +#define pawM_shrink(P, ptr, alloc0, alloc) \ ((ptr) = pawM_shrink_(P, ptr, &(alloc0), alloc, sizeof((ptr)[0]))) -#define pawM_resize(P, ptr, alloc0, alloc) \ +#define pawM_resize(P, ptr, alloc0, alloc) \ ((ptr) = pawM_resize_aux(P, ptr, cast_size(alloc0), cast_size(alloc))) // Ensure that the expression 'o + n * e' will not wrap -#define pawM_check_size(P, o, n, e) \ +#define pawM_check_size(P, o, n, e) \ (n) > (SIZE_MAX - o) / (e) ? pawM_error(P) : paw_unused(0) // Resize a chunk of memory, ensuring that the new allocation size will // not overflow -#define pawM_resize_aux(P, p, n0, n) \ - ((n) > (n0) && pawM_check_size(P, 0, n, sizeof((p)[0])), \ +#define pawM_resize_aux(P, p, n0, n) \ + ((n) > (n0) && pawM_check_size(P, 0, n, sizeof((p)[0])), \ pawM_resize_(P, p, n0, n, sizeof((p)[0]))) // Low-level memory allocation routine diff --git a/src/meta.c b/src/meta.c index 150dd4f..31f9543 100644 --- a/src/meta.c +++ b/src/meta.c @@ -13,24 +13,58 @@ const char *pawT_name(Metamethod mm) static const char *kMetaNames[] = { "__call", - "__getattr", "__setattr", "__getitem", "__setitem", "__getslice", + "__getattr", + "__setattr", + "__getitem", + "__setitem", + "__getslice", "__setslice", - "__bool", "__int", "__float", "__string", "__array", + "__bool", + "__int", + "__float", + "__string", + "__array", "__map", - "__len", "__neg", "__not", "__bnot", + "__len", + "__neg", + "__not", + "__bnot", - "__eq", "__ne", "__lt", "__le", "__gt", - "__ge", "__contains", "__cast", + "__eq", + "__ne", + "__lt", + "__le", + "__gt", + "__ge", + "__contains", + "__cast", - "__add", "__sub", "__mul", "__div", "__mod", - "__bxor", "__band", "__bor", "__shl", "__shr", + "__add", + "__sub", + "__mul", + "__div", + "__mod", + "__bxor", + "__band", + "__bor", + "__shl", + "__shr", - "__radd", "__rsub", "__rmul", "__rdiv", "__rmod", - "__rbxor", "__rband", "__rbor", "__rshl", "__rshr", + "__radd", + "__rsub", + "__rmul", + "__rdiv", + "__rmod", + "__rbxor", + "__rband", + "__rbor", + "__rshl", + "__rshr", - "__init", "__null", + "__init", + "__null", }; _Static_assert(paw_countof(kMetaNames) == NMETAMETHODS, "metamethod names re inconsistent"); diff --git a/src/opcode.h b/src/opcode.h index 45dc510..f4e0f5c 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -7,27 +7,27 @@ #include "paw.h" #ifndef UPVALUE_MAX -# define UPVALUE_MAX 64 +#define UPVALUE_MAX 64 #endif #ifndef LOCAL_MAX -# define LOCAL_MAX 1024 +#define LOCAL_MAX 1024 #endif #ifndef FIELD_MAX -# define FIELD_MAX 4096 +#define FIELD_MAX 4096 #endif #ifndef PARAM_MAX -# define PARAM_MAX 256 +#define PARAM_MAX 256 #endif #ifndef ITEM_MAX -# define ITEM_MAX A_MAX +#define ITEM_MAX A_MAX #endif #ifndef JUMP_MAX -# define JUMP_MAX S_MAX +#define JUMP_MAX S_MAX #endif #define decode_jump(x) ((int)(x) - JUMP_MAX) @@ -59,20 +59,20 @@ #define create_U(o, u) ((OpCode)(o) | ((OpCode)(u) << U_OFFSET)) #define get_U(v) (((v) >> U_OFFSET) & mask1(U_WIDTH, 0)) -#define set_U(v, u) \ +#define set_U(v, u) \ (*(v) = (*(v) & mask0(U_WIDTH, U_OFFSET)) | ((OpCode)(u) << U_OFFSET)) #define create_S(o, s) create_U(o, (int)(s) + S_MAX) #define get_S(v) ((int)get_U(v) - S_MAX) #define set_S(v, s) set_U(v, (int)(s) + S_MAX) -#define create_AB(o, a, b) \ +#define create_AB(o, a, b) \ ((OpCode)(op) | ((OpCode)(a) << A_OFFSET) | ((OpCode)(b) << B_OFFSET)) #define get_A(v) ((v) >> A_OFFSET) -#define set_A(v, a) \ +#define set_A(v, a) \ (*(v) = (*(v) & mask0(A_WIDTH, A_OFFSET)) | ((OpCode)(a) << A_OFFSET)) #define get_B(v) (((v) >> B_OFFSET) & mask1(B_WIDTH, 0)) -#define set_B(v, b) \ +#define set_B(v, b) \ (*(v) = (*(v) & mask0(B_WIDTH, B_OFFSET)) | ((OpCode)(b) << B_OFFSET)) typedef uint32_t OpCode; @@ -136,10 +136,12 @@ OP_NEWMAP,// U v_2n..v1 {v_2n..v1} - OP_UNWRAP,// - v t throws an error if disc(v) != 0 -OP_FORNUM0,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* -OP_FORNUM,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* -OP_FORIN0,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* -OP_FORIN,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* +OP_FORNUM0,// S *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* +OP_FORNUM,// S *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* +OP_FORVECTOR0,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* +OP_FORVECTOR,// S *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* +OP_FORMAP0,// S *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* +OP_FORMAP,// S *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* OP_UNOP,// A B v ops[a](v) - OP_BINOP,// A B l r ops[a](l, r) - @@ -309,8 +311,8 @@ enum MapOp { MO_ERASE, }; -_Static_assert(NOPCODES <= ((1 << OP_WIDTH) - 1), - "too many opcodes (see opcode.h)"); +_Static_assert(NOPCODES <= ((1 << OP_WIDTH) - 1), + "too many opcodes (see opcode.h)"); // sanity check opcode format _Static_assert(OP_WIDTH + A_WIDTH + B_WIDTH == sizeof(OpCode) * 8 && diff --git a/src/parse.c b/src/parse.c index 809140e..8e48f4a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -34,8 +34,10 @@ #define list_push(lex, list, node) pawA_list_push((lex)->pm->ast, &(list), node) #define new_path(lex) pawA_path_new((lex)->pm->ast) -#define new_segment(lex, name, types) pawA_segment_new((lex)->pm->ast, name, types) -#define path_add(lex, path, name, types) pawA_path_add((lex)->pm->ast, path, name, types, NULL) +#define new_segment(lex, name, types) \ + pawA_segment_new((lex)->pm->ast, name, types) +#define path_add(lex, path, name, types) \ + pawA_path_add((lex)->pm->ast, path, name, types, NULL) static String *unpack_name(const AstExpr *expr) { @@ -57,17 +59,15 @@ static AstPat *pattern(Lex *lex); static AstExpr *expression(Lex *lex, unsigned prec); static AstStmt *statement(Lex *lex); -static AstExpr *expression0(Lex *lex) -{ - return expression(lex, 0); -} +static AstExpr *expression0(Lex *lex) { return expression(lex, 0); } static void expected_symbol(Lex *lex, const char *want) { pawX_error(lex, "expected %s", want); } -static void missing_delim(Lex *lex, TokenKind want, TokenKind open, int open_line) +static void missing_delim(Lex *lex, TokenKind want, TokenKind open, + int open_line) { pawX_error(lex, "expected '%c' to match '%c' on line %d", want, open, open_line); @@ -130,39 +130,33 @@ static const struct { uint8_t left; uint8_t right; } kInfixPrec[NINFIX] = { - [INFIX_AS] = {14, 14}, - [INFIX_MUL] = {13, 13}, + [INFIX_AS] = {14, 14}, + [INFIX_MUL] = {13, 13}, [INFIX_DIV] = {13, 13}, - [INFIX_MOD] = {13, 13}, + [INFIX_MOD] = {13, 13}, [INFIX_ADD] = {12, 12}, - [INFIX_SUB] = {12, 12}, + [INFIX_SUB] = {12, 12}, [INFIX_SHL] = {10, 10}, - [INFIX_SHR] = {10, 10}, + [INFIX_SHR] = {10, 10}, [INFIX_BAND] = {9, 9}, - [INFIX_BXOR] = {8, 8}, + [INFIX_BXOR] = {8, 8}, [INFIX_BOR] = {7, 7}, - [INFIX_IN] = {6, 6}, + [INFIX_IN] = {6, 6}, [INFIX_LT] = {6, 6}, - [INFIX_LE] = {6, 6}, + [INFIX_LE] = {6, 6}, [INFIX_GT] = {6, 6}, - [INFIX_GE] = {6, 6}, + [INFIX_GE] = {6, 6}, [INFIX_EQ] = {5, 5}, - [INFIX_NE] = {5, 5}, + [INFIX_NE] = {5, 5}, [INFIX_AND] = {4, 4}, - [INFIX_OR] = {3, 3}, + [INFIX_OR] = {3, 3}, }; static const uint8_t kUnOpPrecedence = 15; -static unsigned left_prec(InfixOp op) -{ - return kInfixPrec[op].left; -} +static unsigned left_prec(InfixOp op) { return kInfixPrec[op].left; } -static unsigned right_prec(InfixOp op) -{ - return kInfixPrec[op].right; -} +static unsigned right_prec(InfixOp op) { return kInfixPrec[op].right; } static UnOp get_unop(TokenKind kind) { @@ -255,10 +249,7 @@ static paw_Bool test_next(Lex *lex, TokenKind kind) } // Eat a semicolon, if one exists -static void semicolon(Lex *lex) -{ - test_next(lex, ';'); -} +static void semicolon(Lex *lex) { test_next(lex, ';'); } static String *parse_name(Lex *lex) { @@ -300,25 +291,27 @@ static AstDecl *vfield_decl(Lex *lex) return r; } -#define make_list_parser(name, a, b, limit, what, func, T) \ - static void parse_ ## name ## _list(Lex *lex, AstList **plist, int line) \ - { \ - do { \ - if (test(lex, b)) { \ - break; \ - } else if ((*plist)->count == (limit)) { \ - limit_error(lex, what, (limit)); \ - } \ - T *next = (func)(lex); \ - list_push(lex, *plist, next); \ - } while (test_next(lex, ',')); \ - delim_next(lex, b, a, line); \ +#define make_list_parser(name, a, b, limit, what, func, T) \ + static void parse_##name##_list(Lex *lex, AstList **plist, int line) \ + { \ + do { \ + if (test(lex, b)) { \ + break; \ + } else if ((*plist)->count == (limit)) { \ + limit_error(lex, what, (limit)); \ + } \ + T *next = (func)(lex); \ + list_push(lex, *plist, next); \ + } while (test_next(lex, ',')); \ + delim_next(lex, b, a, line); \ } make_list_parser(arg, '(', ')', LOCAL_MAX, "arguments", expression0, AstExpr) -make_list_parser(vfield, '(', ')', LOCAL_MAX, "variant fields", vfield_decl, AstDecl) -make_list_parser(type, '<', '>', LOCAL_MAX, "type arguments", type_expr, AstExpr) + make_list_parser(vfield, '(', ')', LOCAL_MAX, "variant fields", vfield_decl, + AstDecl) + make_list_parser(type, '<', '>', LOCAL_MAX, "type arguments", type_expr, + AstExpr) -static AstList *vfield_list(Lex *lex, int line) + static AstList *vfield_list(Lex *lex, int line) { ++lex->expr_depth; AstList *list = new_list(lex); @@ -382,7 +375,7 @@ static void parse_typelist(Lex *lex, AstExpr *pe, int line) do { if (test(lex, ')')) { - break; + break; } else if (elems->count == FIELD_MAX) { limit_error(lex, "tuple elements", FIELD_MAX); } @@ -400,7 +393,7 @@ static AstExpr *parse_paren_type(Lex *lex) } AstExpr *e = type_expr(lex); if (test_next(lex, ',')) { - parse_typelist(lex, e, line); + parse_typelist(lex, e, line); } return e; } @@ -441,7 +434,7 @@ static AstPath *parse_pathexpr(Lex *lex) { AstPath *p = new_path(lex); do { -next_segment: + next_segment: if (p->list->count == LOCAL_MAX) { limit_error(lex, "path segments", LOCAL_MAX); } @@ -581,14 +574,18 @@ static AstDecl *generic_param(Lex *lex) return r; } -make_list_parser(index, '[', ']', LOCAL_MAX, "elements", expression0, AstExpr) -make_list_parser(func_param, '(', ')', LOCAL_MAX, "function parameters", param_decl, AstDecl) -make_list_parser(clos_param, '|', '|', LOCAL_MAX, "closure parameters", param_decl, AstDecl) -make_list_parser(generic, '<', '>', LOCAL_MAX, "generics", generic_param, AstDecl) -make_list_parser(vfield_pat, '(', ')', LOCAL_MAX, "variant fields", vfield_pat, AstPat) -make_list_parser(sfield_pat, '{', '}', LOCAL_MAX, "struct fields", sfield_pat, AstPat) +make_list_parser(func_param, '(', ')', LOCAL_MAX, "function parameters", + param_decl, AstDecl) + make_list_parser(clos_param, '|', '|', LOCAL_MAX, "closure parameters", + param_decl, AstDecl) + make_list_parser(generic, '<', '>', LOCAL_MAX, "generics", + generic_param, AstDecl) + make_list_parser(vfield_pat, '(', ')', LOCAL_MAX, "variant fields", + vfield_pat, AstPat) + make_list_parser(sfield_pat, '{', '}', LOCAL_MAX, + "struct fields", sfield_pat, AstPat) -static AstPat *compound_pat(Lex *lex) + static AstPat *compound_pat(Lex *lex) { AstPat *r = new_pat(lex, AST_PAT_PATH); AstPath *path = parse_pathtype(lex); @@ -599,7 +596,7 @@ static AstPat *compound_pat(Lex *lex) pawX_error(lex, "expected at least 1 field in variant pattern " "(remove parenthesis for unit variant)"); } - r->variant.kind = AST_PAT_VARIANT; + r->variant.kind = AST_PAT_VARIANT; r->variant.path = path; r->variant.elems = fields; } else if (test_next(lex, '{')) { @@ -608,7 +605,7 @@ static AstPat *compound_pat(Lex *lex) pawX_error(lex, "expected at least 1 field in struct pattern " "(remove curly braces for unit struct)"); } - r->struct_.kind = AST_PAT_STRUCT; + r->struct_.kind = AST_PAT_STRUCT; r->struct_.path = path; r->struct_.fields = fields; } else { @@ -629,7 +626,7 @@ static AstPat *pattern(Lex *lex) if (test(lex, TK_NAME)) { return compound_pat(lex); } else { - return literal_pat(lex); + return literal_pat(lex); } } @@ -661,9 +658,10 @@ static AstExpr *sitem_expr(Lex *lex) return r; } -make_list_parser(sitem, '{', '}', LOCAL_MAX, "struct items", sitem_expr, AstExpr) +make_list_parser(sitem, '{', '}', LOCAL_MAX, "struct items", sitem_expr, + AstExpr) -static AstExpr *unop_expr(Lex *lex, UnOp op) + static AstExpr *unop_expr(Lex *lex, UnOp op) { AstExpr *result = new_expr(lex, EXPR_UNOP); UnOpExpr *r = &result->unop; @@ -811,7 +809,7 @@ static AstExpr *try_composite_lit(Lex *lex, AstExpr *path) } return composite_lit(lex, path); } - return path; + return path; } static AstExpr *selector_expr(Lex *lex, AstExpr *target) @@ -942,7 +940,8 @@ static AstExpr *suffixed_expr(Lex *lex) { AstExpr *e = primary_expr(lex); if (e == NULL) { - expected_symbol(lex, "operand (path, literal, or parenthesized expression)"); + expected_symbol(lex, + "operand (path, literal, or parenthesized expression)"); } else if (lex->t.kind == '{') { e = try_composite_lit(lex, e); } @@ -989,7 +988,7 @@ static AstExpr *simple_expr(Lex *lex) } case TK_PIPE2: lex->t.kind = '|'; - lex->t2.kind = '|'; + lex->t2.kind = '|'; // (fallthrough) case '|': return closure(lex); @@ -1004,8 +1003,7 @@ static AstExpr *simple_expr(Lex *lex) static AstExpr *conversion_expr(Lex *lex, AstExpr *lhs, AstExpr *rhs) { - if (a_kind(rhs) != EXPR_PATH || - rhs->path.path->list->count != 1) { + if (a_kind(rhs) != EXPR_PATH || rhs->path.path->list->count != 1) { pawX_error(lex, "expected basic type name"); } AstExpr *r = new_expr(lex, EXPR_CONVERSION); @@ -1014,18 +1012,17 @@ static AstExpr *conversion_expr(Lex *lex, AstExpr *lhs, AstExpr *rhs) AstPath *path = rhs->path.path; AstSegment *seg = pawA_path_get(path, 0); if (equals_cstr(lex, seg->name, CSTR_BOOL)) { - r->conv.to = PAW_TBOOL; + r->conv.to = PAW_TBOOL; } else if (equals_cstr(lex, seg->name, CSTR_INT)) { - r->conv.to = PAW_TINT; + r->conv.to = PAW_TINT; } else if (equals_cstr(lex, seg->name, CSTR_FLOAT)) { - r->conv.to = PAW_TFLOAT; + r->conv.to = PAW_TFLOAT; } else { pawX_error(lex, "expected basic type"); } return r; } - static AstExpr *binop_expr(Lex *lex, InfixOp op, AstExpr *lhs) { skip(lex); // binary operator token @@ -1281,7 +1278,8 @@ static void parse_variant_list(Lex *lex, AstList **plist, int line) } else if ((*plist)->count == LOCAL_MAX) { limit_error(lex, "variants", LOCAL_MAX); } - // NOTE: 'variant_decl' requires a second argument, so 'make_list_parser' + // NOTE: 'variant_decl' requires a second argument, so + // 'make_list_parser' // cannot be used as-is. AstDecl *next = variant_decl(lex, (*plist)->count); list_push(lex, *plist, next); @@ -1493,24 +1491,24 @@ static AstList *load_prelude(Lex *lex) // // ORDER TokenKind static const char *kKeywords[] = { - "fn", - "type", - "enum", - "struct", - "global", - "match", - "let", - "if", - "else", + "fn", + "type", + "enum", + "struct", + "global", + "match", + "let", + "if", + "else", "for", - "do", - "while", - "break", - "continue", - "return", - "in", - "as", - "true", + "do", + "while", + "break", + "continue", + "return", + "in", + "as", + "true", "false", }; diff --git a/src/parse.h b/src/parse.h index 434f9bb..dc1e427 100644 --- a/src/parse.h +++ b/src/parse.h @@ -25,7 +25,8 @@ #define env(x) ((x)->P) #define is_toplevel(lex) ((lex)->fs->outer == NULL) #define scan_string(lex, s) pawX_scan_string(lex, s, strlen(s)) -#define limit_error(x, what, limit) pawX_error(x, "too many %s (limit is %d)", what, limit) +#define limit_error(x, what, limit) \ + pawX_error(x, "too many %s (limit is %d)", what, limit) typedef enum LabelKind { LBREAK, @@ -55,7 +56,7 @@ struct MatchState { typedef struct BlockState { struct BlockState *outer; - paw_Bool is_loop: 1; + paw_Bool is_loop : 1; int isymbol; int level; int label0; @@ -64,7 +65,7 @@ typedef struct BlockState { typedef struct LocalSlot { struct Symbol *symbol; int index; - paw_Bool is_captured: 1; + paw_Bool is_captured : 1; } LocalSlot; typedef struct LocalStack { diff --git a/src/paw.c b/src/paw.c index ad83a36..d869b41 100644 --- a/src/paw.c +++ b/src/paw.c @@ -192,7 +192,7 @@ int main(int argc, const char **argv) } if (status == PAW_OK) { paw_close(P); - } else if (paw_get_count(P) && paw_is_string(P, -1)) { + } else if (paw_get_count(P) && 1 /*TODO: paw_is_string(P, -1)*/) { // error() doesn't return error(status, "%s\n", paw_string(P, -1)); } else { diff --git a/src/paw.h b/src/paw.h index 96ba818..7d918a4 100644 --- a/src/paw.h +++ b/src/paw.h @@ -77,21 +77,6 @@ int paw_call(paw_Env *P, int argc); #define PAW_TMODULE 12 #define PAW_NTYPES 13 -paw_Bool paw_is_truthy(paw_Env *P, int index); -paw_Bool paw_is_null(paw_Env *P, int index); -paw_Bool paw_is_bool(paw_Env *P, int index); -paw_Bool paw_is_float(paw_Env *P, int index); -paw_Bool paw_is_int(paw_Env *P, int index); -paw_Bool paw_is_string(paw_Env *P, int index); -paw_Bool paw_is_array(paw_Env *P, int index); -paw_Bool paw_is_map(paw_Env *P, int index); -paw_Bool paw_is_function(paw_Env *P, int index); -paw_Bool paw_is_class(paw_Env *P, int index); -paw_Bool paw_is_foreign(paw_Env *P, int index); -paw_Bool paw_is_number(paw_Env *P, int index); -int paw_type(paw_Env *P, int index); -const char *paw_typename(paw_Env *P, int index); - void paw_push_value(paw_Env *P, int index); void paw_push_unit(paw_Env *P, int n); void paw_push_bool(paw_Env *P, paw_Bool b); @@ -203,8 +188,7 @@ void paw_set_global(paw_Env *P, const char *name); void paw_set_attr(paw_Env *P, int index, const char *s); void paw_set_item(paw_Env *P, int index); void paw_set_itemi(paw_Env *P, int index, paw_Int i); - -void paw_call_global(paw_Env *P, const char *name, int argc); +void paw_call_global(paw_Env *P, int index, int argc); void paw_call_attr(paw_Env *P, int index, const char *name, int argc); void *paw_create_foreign(paw_Env *P, size_t size, int nbound); diff --git a/src/rt.c b/src/rt.c index abb567e..5a243ed 100644 --- a/src/rt.c +++ b/src/rt.c @@ -25,11 +25,11 @@ // Helpers for the VM: #define vm_switch(x) switch (x) -#define vm_case(x) \ - break; \ +#define vm_case(x) \ + break; \ case OP_##x -#define vm_default \ - break; \ +#define vm_default \ + break; \ default #define vm_continue continue #define vm_shift(n) (*vm_top((n) + 1) = *vm_top(1), vm_pop(n)) @@ -53,20 +53,20 @@ // the GC doesn't get confused. Both the vm_push0(), and the pawV_vec_new calls // might fail and cause an error to be thrown, so we have to be careful not // to leave a junk value on top of the stack. -#define vm_vector_init(pa, pv) \ - pv = vm_push0(); \ - pa = pawV_vec_new(P); \ +#define vm_vector_init(pa, pv) \ + pv = vm_push0(); \ + pa = pawV_vec_new(P); \ v_set_object(pv, pa); -#define vm_map_init(pm, pv) \ - pv = vm_push0(); \ - pm = pawH_new(P); \ +#define vm_map_init(pm, pv) \ + pv = vm_push0(); \ + pm = pawH_new(P); \ v_set_object(pv, pm); static void add_zeros(paw_Env *P, int n) { for (int i = 0; i < n; ++i) { - vm_push0(); + vm_push0(); } } @@ -152,8 +152,8 @@ void pawR_error(paw_Env *P, int error, const char *fmt, ...) // Convert a paw_Float to a paw_Int (from Lua) // Assumes 2's complement, which means PAW_INT_MIN is a power-of-2 with // an exact paw_Float representation. -#define float2int_aux(f, pv) \ - ((f) >= (paw_Float)(PAW_INT_MIN) && (f) < -(paw_Float)(PAW_INT_MIN) && \ +#define float2int_aux(f, pv) \ + ((f) >= (paw_Float)(PAW_INT_MIN) && (f) < -(paw_Float)(PAW_INT_MIN) && \ (v_set_int(pv, paw_cast_int(f)), 1)) static void float2int(paw_Env *P, paw_Float f, Value *pv) @@ -189,7 +189,7 @@ void pawR_cast_int(paw_Env *P, paw_Type type) { paw_assert(type < PAW_TSTRING); if (type == PAW_TFLOAT) { - // NOTE: Other primitives have a value representation compatible with + // NOTE: Other primitives have a value representation compatible with // that of the 'int' type. Value *pv = vm_top(1); const paw_Float f = v_float(*pv); @@ -347,18 +347,21 @@ void pawR_setitem(paw_Env *P, paw_Type t) vm_pop(3); } -static size_t check_index(paw_Env *P, paw_Int index, size_t length, const char *what) +static size_t check_index(paw_Env *P, paw_Int index, size_t length, + const char *what) { const paw_Int n = paw_cast_int(length); index = pawV_abs_index(index, length); if (index < 0 || index > n) { - pawE_error(P, PAW_ERUNTIME, -1, "index %I is out of bounds for %s of length %I", - index, what, paw_cast_int(length)); + pawE_error(P, PAW_ERUNTIME, -1, + "index %I is out of bounds for %s of length %I", index, what, + paw_cast_int(length)); } return cast_size(index); } -static void setslice_vector(paw_Env *P, Vector *va, paw_Int i, paw_Int j, const Vector *vb) +static void setslice_vector(paw_Env *P, Vector *va, paw_Int i, paw_Int j, + const Vector *vb) { const size_t na = pawV_vec_length(va); const size_t nb = pawV_vec_length(vb); @@ -402,7 +405,7 @@ void pawR_init(paw_Env *P) v_set_object(&P->mem_errmsg, errmsg); } -#define stop_loop(i, i2, d) \ +#define stop_loop(i, i2, d) \ (((d) < 0 && (i) <= (i2)) || ((d) > 0 && (i) >= (i2))) static paw_Bool fornum_init(paw_Env *P) @@ -437,52 +440,60 @@ static paw_Bool fornum(paw_Env *P) return PAW_TRUE; } -static paw_Bool forin_init(paw_Env *P, paw_Type t) -{ - // const Value v = *vm_top(1); - // paw_Int itr = PAW_ITER_INIT; - // if (t == PAW_TVECTOR) { - // Vector *arr = v_vector(v); - // if (pawV_vec_iter(arr, &itr)) { - // vm_pushi(itr); - // vm_pushv(arr->begin[itr]); - // return PAW_FALSE; - // } - // } else { - //// paw_assert(t == PAW_TMAP); - //// Map *map = v_map(v); - //// if (pawH_iter(map, &itr)) { - //// vm_pushi(itr); - //// vm_pushv(map->keys[itr]); - //// return PAW_FALSE; - //// } - // } +static paw_Bool forvector_init(paw_Env *P) +{ + const Value v = *vm_top(1); + paw_Int itr = PAW_ITER_INIT; + Vector *arr = v_vector(v); + if (pawV_vec_iter(arr, &itr)) { + vm_pushi(itr); + vm_pushv(arr->begin[itr]); + return PAW_FALSE; + } + return PAW_TRUE; +} + +static paw_Bool forvector(paw_Env *P) +{ + const Value obj = *vm_top(2); + const Value itr = *vm_top(1); + Vector *arr = v_vector(obj); + paw_Int i = v_int(itr); + if (pawV_vec_iter(arr, &i)) { + v_set_int(vm_top(1), i); + vm_pushv(arr->begin[i]); return PAW_TRUE; + } + return PAW_FALSE; } -static paw_Bool forin(paw_Env *P, paw_Type t) -{ - // const Value obj = *vm_top(2); - // const Value itr = *vm_top(1); - // if (t == PAW_TVECTOR) { - // Vector *arr = v_vector(obj); - // paw_Int i = v_int(itr); - // if (pawV_vec_iter(arr, &i)) { - // v_set_int(vm_top(1), i); - // vm_pushv(arr->begin[i]); - // return PAW_TRUE; - // } - // } else { - //// paw_assert(t == PAW_TMAP); - //// Map *map = v_map(obj); - //// paw_Int i = v_int(itr); - //// if (pawH_iter(map, &i)) { - //// v_set_int(vm_top(1), i); - //// vm_pushv(map->keys[i]); - //// return PAW_TRUE; - //// } - // } - return PAW_FALSE; // stop the loop +static paw_Bool formap_init(paw_Env *P) +{ + const Value v = *vm_top(1); + paw_Int itr = PAW_ITER_INIT; + Map *map = v_map(v); + if (pawH_iter(map, &itr)) { + const Value v = *pawH_key(map, cast_size(itr)); + vm_pushi(itr); + vm_pushv(v); + return PAW_FALSE; + } + return PAW_TRUE; +} + +static paw_Bool formap(paw_Env *P) +{ + const Value obj = *vm_top(2); + const Value itr = *vm_top(1); + Map *map = v_map(obj); + paw_Int i = v_int(itr); + if (pawH_iter(map, &i)) { + const Value v = *pawH_key(map, cast_size(i)); + v_set_int(vm_top(1), i); + vm_pushv(v); + return PAW_TRUE; + } + return PAW_FALSE; // stop the loop } #define finish_strcmp(x, y, op) (pawS_cmp(x, y) op 0) @@ -683,7 +694,8 @@ static void float_binop(paw_Env *P, BinaryOp binop, paw_Float x, paw_Float y) vm_pop(1); } -static void other_binop(paw_Env *P, BinaryOp binop, paw_Type t, Value x, Value y) +static void other_binop(paw_Env *P, BinaryOp binop, paw_Type t, Value x, + Value y) { if (binop == BINARY_IN) { Value *pv = vm_top(2); @@ -821,7 +833,7 @@ int pawR_getitem(paw_Env *P, paw_Type t) { const Value obj = *vm_top(2); const Value key = *vm_top(1); - if (t == PAW_TMAP) { + if (t == PAW_TMAP) { return getitem_map(P, v_map(obj), key); } if (t == PAW_TVECTOR) { @@ -864,10 +876,10 @@ void pawR_getslice(paw_Env *P, paw_Type t) const Value obj = *vm_top(3); const paw_Int i = v_int(*vm_top(2)); const paw_Int j = v_int(*vm_top(1)); - if (t == PAW_TVECTOR) { + if (t == PAW_TVECTOR) { getslice_vector(P, v_vector(obj), i, j); } else { - paw_assert(t == PAW_TSTRING); + paw_assert(t == PAW_TSTRING); getslice_string(P, v_string(obj), i, j); } vm_shift(3); @@ -1302,26 +1314,32 @@ void pawR_execute(paw_Env *P, CallFrame *cf) } } - vm_case(FORIN0) : - { - if (forin_init(P, get_U(opcode))) { - // Skip the loop. We need to add a dummy value to the stack, - // since there was an 'OP_POP' generated to pop it. See - // forin() in parse.c for details. - vm_push0(); - pc += get_S(opcode); - } +// clang-format off +#define vm_forin0(t, T) \ + vm_case(FOR##T##0) : \ + { \ + vm_protect(); \ + if (for##t##_init(P)) { \ + vm_push0(); \ + pc += get_S(opcode); \ + } \ } - - vm_case(FORIN) : - { - if (forin(P, get_U(opcode))) { - pc += get_S(opcode); // continue - } +#define vm_forin(t, T) \ + vm_case(FOR##T) : \ + { \ + if (for##t(P)) { \ + pc += get_S(opcode); \ + } \ } - - vm_default: - paw_assert(PAW_FALSE); + vm_forin0(vector, VECTOR) + vm_forin0(map, MAP) + vm_forin(vector, VECTOR) + vm_forin(map, MAP) +#undef vm_forin0 +#undef vm_forin + // clang-format on + + vm_default : paw_assert(PAW_FALSE); } // clang-format on } diff --git a/src/test.h b/src/test.h index 93e6963..7a08e3c 100644 --- a/src/test.h +++ b/src/test.h @@ -9,12 +9,12 @@ #include #include -#define CHECK(expr) \ - do { \ - if (!(expr)) { \ - fprintf(stderr, "error in %s on line %d\n", __func__, __LINE__); \ - abort(); \ - } \ +#define CHECK(expr) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, "error in %s on line %d\n", __func__, __LINE__); \ + abort(); \ + } \ } while (0) #endif // SHELL_TEST_H diff --git a/src/type.h b/src/type.h index 5155616..fb92b5d 100644 --- a/src/type.h +++ b/src/type.h @@ -23,8 +23,8 @@ typedef enum TypeKind { // type->... TYPE_MODULE, // mod } TypeKind; -#define TYPE_HEADER \ - DefId def; \ +#define TYPE_HEADER \ + DefId def; \ TypeKind kind : 8 typedef struct TypeHeader { TYPE_HEADER; diff --git a/src/unify.c b/src/unify.c index de0dc25..e679d64 100644 --- a/src/unify.c +++ b/src/unify.c @@ -231,8 +231,8 @@ AstType *pawU_new_unknown(Unifier *U) // NOTE: inference variables require a stable address, since they point to // each other - InferenceVar *ivar = pawK_pool_alloc(P, &U->ast->sequences, sizeof(InferenceVar), - paw_alignof(InferenceVar)); + InferenceVar *ivar = pawK_pool_alloc( + P, &U->ast->sequences, sizeof(InferenceVar), paw_alignof(InferenceVar)); const int index = table->ivars->count; pawA_list_push(U->ast, &table->ivars, ivar); @@ -248,10 +248,9 @@ AstType *pawU_new_unknown(Unifier *U) void pawU_enter_binder(Unifier *U) { paw_Env *P = env(U->lex); - UnificationTable *table = pawK_pool_alloc( - P, &U->ast->symbols, - sizeof(UnificationTable), - paw_alignof(UnificationTable)); + UnificationTable *table = + pawK_pool_alloc(P, &U->ast->symbols, sizeof(UnificationTable), + paw_alignof(UnificationTable)); table->ivars = pawA_list_new(U->ast); table->depth = U->depth; table->outer = U->table; diff --git a/src/value.c b/src/value.c index a4bdc51..661f591 100644 --- a/src/value.c +++ b/src/value.c @@ -195,8 +195,8 @@ void pawV_unlink_upvalue(UpValue *u) Tuple *pawV_new_tuple(paw_Env *P, int nelems) { - Tuple *tuple = pawM_new_flex(P, Tuple, cast_size(nelems), - sizeof(tuple->elems[0])); + Tuple *tuple = + pawM_new_flex(P, Tuple, cast_size(nelems), sizeof(tuple->elems[0])); pawG_add_object(P, cast_object(tuple), VTUPLE); return tuple; } @@ -233,7 +233,8 @@ void pawV_free_struct(paw_Env *P, Struct *struct_) { pawM_free(P, struct_); } Instance *pawV_new_instance(paw_Env *P, int nfields) { - Instance *ins = pawM_new_flex(P, Instance, cast_size(nfields), sizeof(ins->attrs[0])); + Instance *ins = + pawM_new_flex(P, Instance, cast_size(nfields), sizeof(ins->attrs[0])); pawG_add_object(P, cast_object(ins), VINSTANCE); return ins; } @@ -245,7 +246,8 @@ void pawV_free_instance(paw_Env *P, Instance *ins, int nfields) Enum *pawV_new_enum(paw_Env *P, int nvariants) { - Enum *e = pawM_new_flex(P, Enum, cast_size(nvariants), sizeof(e->variants[0])); + Enum *e = + pawM_new_flex(P, Enum, cast_size(nvariants), sizeof(e->variants[0])); pawG_add_object(P, cast_object(e), VENUM); return e; } @@ -257,7 +259,8 @@ void pawV_free_enum(paw_Env *P, Enum *e, int nvariants) Variant *pawV_new_variant(paw_Env *P, int k, int nfields) { - Variant *var = pawM_new_flex(P, Variant, cast_size(nfields), sizeof(var->fields[0])); + Variant *var = + pawM_new_flex(P, Variant, cast_size(nfields), sizeof(var->fields[0])); pawG_add_object(P, cast_object(var), VVARIANT); var->k = k; return var; @@ -363,10 +366,7 @@ static uint32_t hash_u64(uint64_t u) return (uint32_t)u; } -uint32_t pawV_hash(Value v) -{ - return hash_u64(v.u); -} +uint32_t pawV_hash(Value v) { return hash_u64(v.u); } void pawV_set_default(paw_Env *P, Value *pv, paw_Type type) { @@ -479,9 +479,9 @@ int pawV_parse_integer(paw_Env *P, const char *text) return 0; } -#define skip_digits(p) \ - while (ISDIGIT(*(p))) { \ - ++(p); \ +#define skip_digits(p) \ + while (ISDIGIT(*(p))) { \ + ++(p); \ } int pawV_parse_float(paw_Env *P, const char *text) diff --git a/src/value.h b/src/value.h index d174d7b..d40b624 100644 --- a/src/value.h +++ b/src/value.h @@ -104,10 +104,10 @@ typedef enum ValueKind { NVTYPES } ValueKind; -#define GC_HEADER \ - struct Object *gc_next; \ - uint64_t gc_nrefs; \ - ValueKind gc_kind: 8 +#define GC_HEADER \ + struct Object *gc_next; \ + uint64_t gc_nrefs; \ + ValueKind gc_kind : 8 typedef struct Object { GC_HEADER; } Object; @@ -164,7 +164,6 @@ int pawV_num2float(Value *pv, paw_Type type); uint32_t pawV_hash(Value v); const char *pawV_name(ValueKind type); - static paw_Int pawV_abs_index(paw_Int index, size_t length) { return index + (index < 0 ? paw_cast_int(length) : 0); @@ -284,7 +283,7 @@ typedef struct Tuple { Tuple *pawV_new_tuple(paw_Env *P, int nelems); -typedef struct Vector { +typedef struct Vector { GC_HEADER; Value *begin; Value *end; diff --git a/src/vector.c b/src/vector.c index 8cd53f3..5cd2263 100644 --- a/src/vector.c +++ b/src/vector.c @@ -74,7 +74,7 @@ void pawV_vec_push(paw_Env *P, Vector *a, Value v) void pawV_vec_resize(paw_Env *P, Vector *a, size_t length) { pawV_vec_reserve(P, a, length); - // avoid 'Nullptr with offset' from UBSan + // avoid 'Nullptr with offset' from UBSan a->end = length ? a->begin + length : a->begin; } @@ -131,7 +131,8 @@ Vector *pawV_vec_clone(paw_Env *P, Value *pv, const Vector *a) static paw_Bool elems_equal(Value x, Value y) { - // TODO: Only allowed for 'basic' types right now. Compiler set to complain otherwise. + // TODO: Only allowed for 'basic' types right now. Compiler set to complain + // otherwise. return x.u == y.u; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 540f526..e964451 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,11 +20,12 @@ function(test_script NAME ARGS) endfunction() build_test(test_impl) -#build_test(test_api) build_test(test_rt) -#build_test(test_oom) -#build_test(test_so) +build_test(test_oom) +build_test(test_so) build_test(test_error) +message("TODO: fix test_api and test_limits") +#build_test(test_api) #build_test(test_limits) #test_script(bubble "500") diff --git a/test/scripts/binary_trees.paw b/test/scripts/binary_trees.paw index 3ade4df..ceb6179 100644 --- a/test/scripts/binary_trees.paw +++ b/test/scripts/binary_trees.paw @@ -1,9 +1,9 @@ --- The Computer Language Benchmarks Game --- http://benchmarksgame.alioth.debian.org/ --- contributed by Mike Pall --- modified by Andrew Byers +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// contributed by Mike Pall +// modified by Andrew Byers -fn Tree(item, depth) { +fn Tree(item, depth: int) -> (int) { if depth > 0 { let i = item + item depth = depth - 1 diff --git a/test/scripts/bubble.paw b/test/scripts/bubble.paw index 1e8f5be..bc49efe 100644 --- a/test/scripts/bubble.paw +++ b/test/scripts/bubble.paw @@ -1,16 +1,16 @@ --- bubble.paw +// bubble.paw -fn random(n): [int] { - let a: [int] = [] +fn random(n: int) -> [int] { + let a = [] let x = n for _ = 0, n { x = (140671485 * x + 12820163) % 16777216 - a.push(x) + _vector_push(a, x) } return a } -fn bubble(n: int): [int] { +let bubble = |n: int| -> [int] { let a = random(n) while true { let swapped = false @@ -29,4 +29,4 @@ fn bubble(n: int): [int] { return a } -bubble(#argv > 1 ?? int(argv[1]) :: 500) +bubble(500) diff --git a/test/scripts/closure.paw b/test/scripts/closure.paw index 5b5eee3..04f4281 100644 --- a/test/scripts/closure.paw +++ b/test/scripts/closure.paw @@ -1,24 +1,20 @@ // closure.paw { - let f - let g - + let f = None { - let s = 'abc' let i = 123 let a = [] - fn closure() { - a.push(s) - a.push(i) + f = Some(|v: int| -> [int] { + i = v + _vector_push(a, i) return a - } - f = closure + }) } - assert(f()[0] == 'abc') - assert(f()[1] == 123) - assert(#f() == 6) // 3 calls == 6 pushes + assert(f.unwrap()(1)[0] == 1) + assert(f.unwrap()(2)[1] == 2) + assert(#f.unwrap()(3) == 3) } { @@ -40,7 +36,7 @@ { { let a = [] - fn closure() { + let closure = || { a.push(#a) return a } @@ -48,7 +44,7 @@ } // Close a { let a = [] - fn closure() { + let closure = || { a.push(#a) return a } @@ -65,7 +61,7 @@ let f let g - fn test() { + let test = || { assert(f(1) == 1) assert(f(2) == 3) assert(g(1) == 4) @@ -75,9 +71,9 @@ { let x = 0 - fn _1(n) { - fn _2() { - fn _3() { + let _1 = |n| { { + let _2 = || { + let _3 = || { x = x + n return x } @@ -93,15 +89,15 @@ { let x = 0 - fn _1a(n) { - fn _2() { + let _1a = |n: int| { { + let _2 = || { x = x + n return x } return _2() } - fn _1b(n) { - fn _2() { + let _1b = |n: int| { { + let _2 = || { x = x + n return x } @@ -117,7 +113,7 @@ let f { let a = [0, 1] - fn fib(n) { + let fib = |n: int| { { assert(n >= 0) if n < #a { return a[n] @@ -132,51 +128,3 @@ assert(f(30) == 832040) } -// Test vararg functions: -{ - fn test(n) { - return fn(...) { - assert(#argv == n) - } - } - test(0)() - test(1)(1) - test(2)(1, 2) - test(3)(1, 2, 3) - - fn test(n, ...) { - assert(#argv == n) - } - test(0) - test(1, '1') - test(2, '1', '2') - test(3, '1', '2', '3') - - fn test(...) { - let temp = argv[0]; - return temp + argv[-1] - } - assert(0 == test(0)) - assert(20 == test(10)) - assert(100 == test(1, 99)) - assert(500 == test(200, 100, 300)) - - fn test(a, ...) { - let temp = argv[0]; - return a + temp + argv[-1] - } - assert(2 == test(0, 1)) // 0 + 1 + 1 - assert(21 == test(1, 10)) - assert(102 == test(2, 1, 99)) - assert(503 == test(3, 200, 100, 300)) - - fn test(a, b, ...) { - let temp = argv[0]; - return a + b + temp + argv[-1] - } - assert(3 == test(0, 1, 1)) // 0 + 1 + 1 - assert(23 == test(1, 2, 10)) - assert(105 == test(2, 3, 1, 99)) - assert(507 == test(3, 4, 200, 100, 300)) -} - diff --git a/test/scripts/error.paw b/test/scripts/error.paw deleted file mode 100644 index 62765b7..0000000 --- a/test/scripts/error.paw +++ /dev/null @@ -1,41 +0,0 @@ --- error.paw - -fn check_error(code) { - fn f(code) { - load(code)() - } - assert(0 != try(f, code)) -} - --- Relational comparison errors: -{ - check_error('let x = 1 < "a"') - check_error('let x = "a" < 1') -} - --- Name too long: -{ - let name = 'a' * 1000 - check_error('let ' ++ name) -} - --- For loop errors: -{ - check_error('for i = 0,10,0 {}') - --check_error('for i = 0.0,10,1 {}') - --check_error('for i = 0,10.0,1 {}') - --check_error('for i = 0,10,1.0 {}') - --check_error('for i = 1<<100,1,1 {}') - --check_error('for i = 1,1<<100,1 {}') - --check_error('for i = 1,1,1<<100 {}') -} - --- Conversion errors: -{ - check_error('let x = int([])') - check_error('let x = float([])') - -- '1.0' is not a valid integer string. int(1.0) works fine, - -- however, since 1.0 is a float. - check_error('let x = int("1.0")') - assert(int(1.0) == 1) -} diff --git a/test/scripts/loop.paw b/test/scripts/loop.paw index 487a357..7d3b23f 100644 --- a/test/scripts/loop.paw +++ b/test/scripts/loop.paw @@ -1,19 +1,20 @@ // loop.paw +// Make sure loop code cleans the stack up when finished { + let one = 1 for i = 0, 8 { let a = -1 let b = -1 } -} - -// Make sure loop code cleans the stack up when finished -{ + let two = 2 for i = 1, 8 { for j = 1, i {} } - fn test() -> int {return 123} - assert(test() == 123) + let test = || -> int { + return one + two + } + assert(test() == 3) } // Numeric for loop: @@ -110,31 +111,30 @@ } } -// TODO: Get this working, once data structures are working again -//// Iterator for loop: -//{ -// let i = 1 -// for e in [1, 2, 3] { -// assert(e == i) -// i = i + 1 -// } -// -// let i = 0 -// for k in {1: 1, 2: 2, 3: 3} { -// i = i + 1 -// } -// assert(i == 3) -// -// let a = [1, 2, 3] -// let b: [int] -// for e in a { -// b.push(e) -// a.pop() -// } -// assert(#b == 2) -// assert(b[0] == 1) -// assert(b[1] == 2) -//} +// Iterator for loop: +{ + let i = 1 + for e in [1, 2, 3] { + assert(e == i) + i = i + 1 + } + + let i = 0 + for k in [1: 1, 2: 2, 3: 3] { + i = i + 1 + } + assert(i == 3) + + let a = [1, 2, 3] + let b = [] + for e in a { + _vector_push(b, e) + _vector_pop(a) + } + assert(#b == 2) + assert(b[0] == 1) + assert(b[1] == 2) +} // While loop: { @@ -169,7 +169,7 @@ // 'break' and 'continue' statements: { let n = -1 - for i = 0,3 { + for i = 0, 3 { if i == 2 { break } @@ -178,7 +178,7 @@ assert(n == 1) let n = -1 - for i = 0,3 { + for i = 0, 3 { if i == 2 { continue } @@ -192,7 +192,7 @@ return -1 } let f = default - for i = 0,100 { + for i = 0, 100 { if i == n { let u = i f = || -> int { @@ -271,53 +271,54 @@ assert(n == 10) } -//{ -// let N = 2 -// -// let a = [] -// for i = 0,N { -// for j in [0] { -// a.push(i + j) -// } -// } -// assert(#a == 2) -// assert(a[0] == 0) -// assert(a[1] == 1) -// -// let a = [] -// for i = 0, N { -// let j = 0 -// while j < N { -// a.push(i + j) -// j = j + 1 -// } -// } -// assert(#a == 4) -// assert(a[0] == 0) -// assert(a[1] == 1) -// assert(a[2] == 1) -// assert(a[3] == 2) -// -// let a = [] -// for i = 0,N { -// for j in [0] { -// let k = 0 -// while k < N { -// a.push(i + j + k) -// k = k + 1 -// } -// } -// } -// assert(#a == 4) -// assert(a[0] == 0) -// assert(a[1] == 1) -// assert(a[2] == 1) -// assert(a[3] == 2) -//} +{ + let N = 2 + + let a = [] + for i = 0, N { + for j in [0] { + _vector_push(a, i + j) + } + } + assert(#a == 2) + assert(a[0] == 0) + assert(a[1] == 1) + + let a = [] + for i = 0, N { + let j = 0 + while j < N { + _vector_push(a, i + j) + j = j + 1 + } + } + assert(#a == 4) + assert(a[0] == 0) + assert(a[1] == 1) + assert(a[2] == 1) + assert(a[3] == 2) + + let a = [] + for i = 0, N { + for j in [0] { + let k = 0 + while k < N { + _vector_push(a, i + j + k) + k = k + 1 + } + } + } + assert(#a == 4) + assert(a[0] == 0) + assert(a[1] == 1) + assert(a[2] == 1) + assert(a[3] == 2) +} + { let n = 0 - for i = 0,8 { + for i = 0, 8 { n = n + 1 break } @@ -327,7 +328,7 @@ { fn test(n: int) -> int { let count = 0 - for i = 0,100 { + for i = 0, 100 { if i == n { break } @@ -346,7 +347,7 @@ let i = -1 // 'i' shadowed by loop variable. - for i = 0,8 {} + for i = 0, 8 {} assert(i == -1) } @@ -358,26 +359,26 @@ // } //} -//{ -// let I = [0, 1, 2, 3] -// for i = 0,4 { -// assert(i == I[i]) -// } -// -// let n = 0 -// let I = [2, 3] -// for i = 2,4 { -// assert(i == I[n]) -// n = n + 1 -// } -// -// let n = 0 -// let I = [1, 3] -// for i = 1,4,2 { -// assert(i == I[n]) -// n = n + 1 -// } -//} +{ + let I = [0, 1, 2, 3] + for i = 0, 4 { + assert(i == I[i]) + } + + let n = 0 + let I = [2, 3] + for i = 2, 4 { + assert(i == I[n]) + n = n + 1 + } + + let n = 0 + let I = [1, 3] + for i = 1, 4, 2 { + assert(i == I[n]) + n = n + 1 + } +} { let n = 0 @@ -401,40 +402,41 @@ // assert(n == 8) //} -//{ -// fn test(n: int) -> int { -// let f -// for i = 0, 100 { -// if i == n {{{ // <-- NOTE: Nested blocks here -// let a = [i] -// fn check() { -// // Capture 'a' as an upvalue. -// let m = a[0] -// a[0] = a[0] + 1 -// // Equivalent to '3 * n' on the first call. Increases by 1 -// // each time. -// return i + n + m -// } -// f = check -// break -// }}} -// } -// return f -// } -// assert(test(-1) == null) -// -// let t = test(10) -// assert(t() == 30) -// assert(t() == 31) -// assert(t() == 32) -//} +{ + fn test(n: int) -> fn() -> int { + let f = || -> int { + return -1 + } + for i = 0, 100 { + if i == n { + let a = [i] + f = || -> int { + // Capture 'a' as an upvalue. + let m = a[0] + a[0] = a[0] + 1 + // Equivalent to '3 * n' on the first call. Increases by 1 + // each time. + return i + n + m + } + break + } + } + return f + } + assert(test(-1)() == -1) + + let t = test(10) + assert(t() == 30) + assert(t() == 31) + assert(t() == 32) +} { fn test(b: bool) -> int { fn hack() -> int {return -1} // TODO: Option[T] type, then this is not necessary let f = hack let n = 0 - for i = 0,8 { + for i = 0, 8 { let _0 = -1 let _1 = -1 { diff --git a/test/scripts/struct.paw b/test/scripts/struct.paw new file mode 100644 index 0000000..5194cf3 --- /dev/null +++ b/test/scripts/struct.paw @@ -0,0 +1,208 @@ +// struct.paw + +{ + struct Inner { + a: int + b: float + c: string + } + struct Outer { + a: bool + b: Inner + } + + let o = Outer{ + a: false, + b: Inner{ + a: 1, + b: 2.0, + c: 'three', + }, + } + assert(o.b.a == 1) + assert(o.b.b == 2.0) + assert(o.b.c == 'three') +} + +{ + fn func(a: A) { + struct Adt { + a: A + b: B + } + let adt = Adt::{a: a, b: false} + let adt = Adt::{a: a, b: 1} + let adt = Adt::{a: a, b: 2.0} + let adt = Adt::{a: a, b: 'three'} + let adt = Adt::{a: a, b: a} + } + func(true) + func(2) + func(3.0) + func('four') +} +{ + struct A {x: X} + let a: A = A::{x: 1} + let a = A::{x: 1} +} +{ + struct A {} + fn f(a: A) {} + + f::(A::{}) + let a = A::{} + f::(a) + f(A::{}) + f(a) + + f::>(A::>{}) + let a = A::>{} + f::>(a) + f(A::>{}) + f(a) + + f::>>(A::>>{}) + let a = A::>>{} + f::>>(a) + f(A::>>{}) + f(a) + + fn f(a: A>) {} + f(A::>{}) + f(A::>>{}) + + fn func(t: T, f: fn(T) -> T2) -> T2 { + return f(t) + } + fn f(i: int) -> float { + return 1.0 + } + let r = func::(1, f) + assert(r == 1.0) + + let r = func(1, f) + assert(r == 1.0) +} +{ + struct A { + t: T + } + let a = A:: {t: 42} + let b = A::> {t: a} + let c = A::>> {t: b} + let d = A::>>> {t: c} + let e = d.t + let f = e.t + let g = f.t + let h = g.t + assert(h == 42) + +// TODO: This should not be allowed: requires indirection, which is not yet possible +// struct B { +// b: B:: +// } + + struct A { + a: A + } + let a = A::{a: 123} + assert(a.a == 123) +} +{ + struct A { + v: T + } + let a = A::{v: 'abc'} + assert(a.v == 'abc') + + a.v = a.v + 'def' + assert(a.v == 'abcdef') +} +{ + struct Pair { + first: First + second: Second + } + fn new_pair(a: A, b: B) -> Pair { + return Pair::{ + first: a, + second: b, + } + } + assert(false == new_pair(false, true).first) + assert(1 == new_pair(1, 2).first) + assert(3.0 == new_pair(2.0, 3.0).second) + assert('five' == new_pair('four', 'five').second) +} +// Type inference for structure templates: +{ + struct A { + v: T + } + let a = A{v: 123} + assert(a.v == 123) + + struct B { + v: A + } + let b = B{v: a} + assert(b.v.v == 123) + + struct C { + v: B + } + let c = C{v: b} + assert(c.v.v.v == 123) +} +{ + struct A { + v: [T] + } + fn test(n: int, a: A) { + assert(#a.v == n) + } + + test(1, A{v: [1]}) + test(2, A{v: [[], [2]]}) + test(3, A{v: [[], [[]], [[3]]]}) +} +{ + struct A { + v: [T] + } + fn test(v: T, a: A) {} + + test(['a', 'b'], A{v: []}) + test([[], ['c']], A{v: []}) + test('a', A{v: ['a']}) + test([], A{v: [['b']]}) +} +{ + struct Triplet { + a: (A, B) + b: (B, C) + c: (C, A) + } + let t = Triplet{ + a: (true, 2), + b: (2, 3.0), + c: (3.0, true), + } + assert(t.a.1 == t.b.0) + assert(t.b.1 == t.c.0) + assert(t.a.0 == t.c.1) +} +{ + struct Pair { + a: T + b: [T] + } + let p = Pair{ + a: true, + b: [], + } + _vector_push(p.b, true) + assert(p.a == p.b[0]) +} + diff --git a/test/scripts/vector.paw b/test/scripts/vector.paw index cf0dceb..58291ed 100644 --- a/test/scripts/vector.paw +++ b/test/scripts/vector.paw @@ -510,62 +510,61 @@ assert(3 == test(vec, test(vec, test(vec, 3)))) } +// Slice syntax: +{ + let vec = [1, 2, 3] + assert(vec[0:] == vec[-3:3]) + assert(vec[1:] == vec[-2:3]) + assert(vec[2:] == vec[-1:3]) + assert(vec[:3] == vec[0:3]) + assert(vec[:2] == vec[0:-1]) + assert(vec[:1] == vec[0:-2]) + + assert(vec[:0] == []) + assert(vec[3:] == []) + assert(vec[1:1] == []) + assert(vec[:3] == vec) + assert(vec[0:] == vec) + assert(vec[0:3] == vec) +} + +{ + fn map(vec: [T], f: fn(T) -> T) -> [T] { + let result = [] + for elem in vec { + _vector_push(result, f(elem)) + } + return result + } + let vec = [ + 'abc', + 'def', + 'ghi', + ] + let vec = map(vec, |val: string| -> string { + return val + val + }) + let result = '' + for val in vec { + result = result + val + } + assert(result == 'abcabcdefdefghighi') -//// Slice syntax: -//{ -// fn check(vec: Vector::, begin: int, end: int) { -// let b = vec[begin:end] -// begin = begin ?: 0 // vec[None:n] == vec[:n] == vec[0:n] -// end = end ?: #vec // vec[n:None] == vec[n:] == vec[n:#vec] -// for i = begin, end { -// assert(vec[i] == b[0]) -// b.pop(0) -// } -// } -// let vec = [1, 2, 3] -// -// for i = 0, 3 { -// for j = 0, 3 { -// check(vec, i, j) -// } -// } -// let result = vec.clone() -// result.pop() -// assert(vec[0:-1] == result) -// result.pop() -// assert(vec[0:-2] == result) -// result.pop() -// assert(vec[0:-3] == result) -// -// let result = vec.clone() -// result.pop(0) -// assert(vec[1:#vec] == result) -// result.pop(0) -// assert(vec[2:#vec] == result) -// result.pop(0) -// assert(vec[3:#vec] == result) -// -// let result = vec.clone() -// result.pop() -// assert(vec[:-1] == result) -// result.pop() -// assert(vec[:-2] == result) -// result.pop() -// assert(vec[:-3] == result) -// -// let result = vec.clone() -// result.pop(0) -// assert(vec[1:] == result) -// result.pop(0) -// assert(vec[2:] == result) -// result.pop(0) -// assert(vec[3:] == result) -// -// let result = vec.clone() -// assert(vec[0:] == result) -// assert(vec[:#vec] == result) -// assert(vec[:] == result) -// assert(vec[:1] == [1]) -// assert(vec[1:-1] == [2]) -// assert(vec[-1:] == [3]) -//} + let vec = [ + ['a', 'b', 'c'], + ['d', 'e', 'f'], + ['g', 'h', 'i'], + ] + let vec = map(vec, |row: [string]| -> [string] { + return map(row, |val: string| -> string { + return val + val + val + }) + }) + let result = '' + for row in vec { + for val in row { + result = result + val + } + } + assert(result == 'aaabbbcccdddeeefffggghhhiii') +} diff --git a/test/test_oom.c b/test/test_oom.c index e4288e1..107955f 100644 --- a/test/test_oom.c +++ b/test/test_oom.c @@ -46,11 +46,9 @@ int main(void) { script("basic"); script("operator"); - script("integer"); script("block"); script("loop"); - script("closure"); - script("array"); + script("vector"); script("map"); - script("class"); + script("struct"); } diff --git a/test/test_rt.c b/test/test_rt.c index 112fc93..385168c 100644 --- a/test/test_rt.c +++ b/test/test_rt.c @@ -13,16 +13,16 @@ int main(void) script("block"); script("loop"); script("operator"); + script("struct"); script("vector"); script("map"); + script("bubble"); script("mandelbrot"); - printf("TODO: fix remaining tests in test_rt.c"); + printf("TODO: fix remaining tests in test_rt.c\n"); return 0; // TODO script("string"); script("integer"); script("float"); script("closure"); - script("class"); - script("error"); script("misc"); } diff --git a/test/test_so.c b/test/test_so.c index b580c17..ce7d395 100644 --- a/test/test_so.c +++ b/test/test_so.c @@ -15,18 +15,13 @@ int main(void) " f(n - 1) \n" " } \n" "} \n" - "return f \n"; + "f(1 << 50) \n"; struct TestAlloc a = {0}; paw_Env *P = test_open(NULL, &a); int status = test_open_string(P, source); handle_error(P, status, 1); status = paw_call(P, 0); - handle_error(P, status, 1); - - // 'f' is on top of the stack - paw_push_int(P, PAW_STACK_MAX); - status = paw_call(P, 1); check(status == PAW_EMEMORY); handle_error(P, status, 0); test_close(P, &a);