diff --git a/Makefile b/Makefile index 54a44f212..90eed62c1 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ src := $(wildcard src/*.c) src += $(wildcard src/*/*.c) CFLAGS += -Iutil/include -Iast/include -D_GNU_SOURCE -CFLAGS += -Iast/libprettyerr/src -Ifmt/include +CFLAGS += -Ifmt/include # add commit hash to version for now CFLAGS += -DGWION_VERSION="\"$(shell git log -n1 --format="%h%m%cs")\"" @@ -64,7 +64,7 @@ include embed/embed.mk endif ALMOST_LIBS := fmt/libgwion_fmt.a -ALMOST_LIBS += ast/libgwion_ast.a ast/libprettyerr/libprettyerr.a +ALMOST_LIBS += ast/libgwion_ast.a ALMOST_LIBS += util/libgwion_util.a GWLIBS := lib${PRG}.a ${ALMOST_LIBS} LDFLAGS := ${GWLIBS} ${LDFLAGS} @@ -114,9 +114,6 @@ ast/libgwion_ast.a: util/libgwion_util.a fmt/libgwion_fmt.a: ast/libgwion_ast.a @+${MAKE} -s -C fmt libgwion_fmt.a -ast/libprettyerr/libprettyerr.a: options-show - @+CFLAGS=-I$(shell pwd)/util/include ${MAKE} -s -C ast/libprettyerr static - ast: ast/libgwion_ast.a @(info build ast) @@ -133,7 +130,6 @@ clean_core: clean-all: clean ${MAKE} -s -C fmt clean ${MAKE} -s -C ast clean - ${MAKE} -s -C ast/libprettyerr clean ${MAKE} -s -C util clean update: clean-all diff --git a/ast b/ast index 03d756298..d02001835 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit 03d756298a20ad5629520c2edba71a92325403bb +Subproject commit d0200183583ab6124c722503bde947730cfb6f04 diff --git a/compile_flags.txt b/compile_flags.txt index 8de19c2d2..c3061ca83 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,3 +1,5 @@ +-Wall +-Wextra -Iutil/include -Iast/include -Iast/libprettyerr/src diff --git a/include/env/func.h b/include/env/func.h index 17db4102d..3836052db 100644 --- a/include/env/func.h +++ b/include/env/func.h @@ -50,4 +50,6 @@ ANN static inline m_uint captures_sz(const Capture_List captures) { ANN static inline bool is_ctor(const Func_Def fdef) { return !strcmp(s_name(fdef->base->tag.sym), "@ctor"); } + +ANN void print_signature(const Gwion gwion, const Func f); #endif diff --git a/include/env/type.h b/include/env/type.h index b215a0b6a..be29078a5 100644 --- a/include/env/type.h +++ b/include/env/type.h @@ -82,6 +82,7 @@ ANN Type actual_type(const struct Gwion_ *gwion, const Type t); ANN static inline m_uint env_push_type(const Env env, const Type type) { return env_push(env, type, type->nspc); } +ANN bool is_object(const struct Gwion_ *, const Type t); ANN bool is_func(const struct Gwion_ *, const Type t); ANN bool is_class(const struct Gwion_ *, const Type t); ANN __attribute__((returns_nonnull)) static inline Type _class_base(Type t) { diff --git a/include/gwion_env.h b/include/gwion_env.h index cf17aa7d6..0de1a33fb 100644 --- a/include/gwion_env.h +++ b/include/gwion_env.h @@ -39,5 +39,6 @@ ANN static inline void defined_here(const Value v) { } +#define is_new(a) !strcmp(s_name((a)->base->tag.sym), "new") #endif diff --git a/include/operator.h b/include/operator.h index 4f3b5cca1..e1f40d4fc 100644 --- a/include/operator.h +++ b/include/operator.h @@ -87,11 +87,6 @@ ANN static inline void operator_resume(struct Op_Import *opi) { *(uintptr_t *)opi->ret = opi->data; } -ANN static inline void set_decl_ref(Exp* e) { - if (e->exp_type == ae_exp_decl) - SET_FLAG(e->d.exp_decl.var.vd.value, late); -} - ANN void func_operator(const Func_Def fdef, struct Op_Import *opi); ANN bool add_op_func_check(const Env env, const Type t, const struct Op_Func *opfunc, const m_uint idx); #endif diff --git a/include/parse.h b/include/parse.h index 4edcfb798..6a66929e7 100644 --- a/include/parse.h +++ b/include/parse.h @@ -171,5 +171,4 @@ ANN static inline bool is_static_call(const Gwion gwion, Exp* e) { member->base->exp_type == ae_exp_cast; } -#define is_new(a) !strcmp(s_name((a)->base->tag.sym), "new") #endif diff --git a/include/partial.h b/include/partial.h index 0966a81ce..88aa1439e 100644 --- a/include/partial.h +++ b/include/partial.h @@ -2,7 +2,6 @@ #define __PARTIAL_APPLICATION ANN Type partial_type(const Env, Exp_Call *const); -ANN void print_signature(const Func f); ANN static inline bool func_match_inner(const Env env, Exp* e, const Type t, const bool implicit, diff --git a/include/specialid.h b/include/specialid.h index 787010608..5bddb5155 100644 --- a/include/specialid.h +++ b/include/specialid.h @@ -1,6 +1,9 @@ #ifndef __SPECIALID #define __SPECIALID +ANN struct SpecialId_ *specialid_get(const Gwion, const Symbol); +#ifndef __NO_EMIT + typedef Type (*idck)(const Env, const Exp_Primary *); typedef bool (*idem)(const Emitter, const Exp_Primary *); @@ -26,3 +29,4 @@ ANN static inline Type specialid_type(const Env env, struct SpecialId_ *spid, ANN struct SpecialId_ *specialid_get(const Gwion, const Symbol); #endif +#endif diff --git a/include/validate.h b/include/validate.h new file mode 100644 index 000000000..885930bd3 --- /dev/null +++ b/include/validate.h @@ -0,0 +1,10 @@ +#pragma once + +ANN bool exp_validation(Env env, Exp* b); +ANN bool func_def_validation(Env env, Func_Def b); +ANN bool union_def_validation(Env env, Union_Def b); +ANN bool enum_def_validation(Env env, Enum_Def b); +ANN bool fptr_def_validation(Env env, Fptr_Def b); +ANN bool type_def_validation(Env env, Type_Def b); +ANN bool class_def_validation(Env env, Class_Def b); +ANN bool ast_validation(Env env, Ast *ast); diff --git a/src/emit/emit.c b/src/emit/emit.c index 0e7c031f7..892576d55 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -452,8 +452,7 @@ ANN static bool emit_symbol_builtin(const Emitter emit, const Symbol *data) { const m_uint size = v->type->size; emit_dotstatic(emit, (m_uint)&v->d.ptr, size, emit_addr); // prevent invalid access to global variables - if(!emit_addr && - isa(v->type, emit->gwion->type[et_object])) + if(!emit_addr && is_object(emit->gwion, v->type)) emit_fast_except(emit, v->from, prim_pos(data)); } else { const m_uint size = v->type->size; @@ -464,7 +463,7 @@ ANN static bool emit_symbol_builtin(const Emitter emit, const Symbol *data) { return true; } -ANN static bool _emit_symbol(const Emitter emit, const Symbol *data) { +ANN static bool emit_symbol(const Emitter emit, const Symbol *data) { const Value v = prim_self(data)->value; if (is_class(emit->gwion, v->type)) { emit_pushimm(emit, (m_uint)actual_type(emit->gwion, v->type)); @@ -502,17 +501,11 @@ ANN static bool _emit_symbol(const Emitter emit, const Symbol *data) { else emit_regpushbase(emit, v->from->offset, size, exp_getvar(prim_exp(data))); if (GET_FLAG(v, late) && !exp_getvar(prim_exp(data)) && - isa(v->type, emit->gwion->type[et_object])) + is_object(emit->gwion, v->type)) emit_fast_except(emit, v->from, prim_pos(data)); return true; } -ANN static bool emit_symbol(const Emitter emit, const Exp_Primary *prim) { - if (!prim->value) // assume it's an operator - ERR_B(exp_self(prim)->loc, "missing value for operator"); - return _emit_symbol(emit, &prim->d.var); -} - ANN VM_Code finalyze(const Emitter emit, const f_instr exec) { emit_add_instr(emit, exec); const VM_Code code = emit->info->emit_code(emit); @@ -725,7 +718,7 @@ ANN static bool emit_prim_id(const Emitter emit, const Symbol *data) { struct SpecialId_ *spid = specialid_get(emit->gwion, *data); if (unlikely(spid)) return specialid_instr(emit, spid, prim_self(data)); - return emit_symbol(emit, prim_self(data)); + return emit_symbol(emit, data); } ANN static bool emit_prim_perform(const Emitter emit, const Symbol *xid) { @@ -783,7 +776,7 @@ ANN static void emit_gack_type(const Emitter emit, Exp* e) { if (e->exp_type == ae_exp_cast || (e->exp_type == ae_exp_primary && e->d.prim.prim_type == ae_prim_str)) return; - const bool isobj = isa(e->type, emit->gwion->type[et_object]); + const bool isobj = is_object(emit->gwion, e->type); if (isobj && (tflag(e->type, tflag_ref) || !GET_FLAG(e->type, final))) emit_add_instr(emit, GackType); } @@ -943,11 +936,12 @@ ANN static bool emit_exp_decl_static(const Emitter emit, const Exp_Decl *decl, const bool is_ref, const bool emit_addr) { const Value v = var_decl->value; - if (isa(v->type, emit->gwion->type[et_object]) && !is_ref) + bool isobj = is_object(emit->gwion, v->type); + if (isobj && !is_ref) CHECK_B(decl_static(emit, decl, var_decl, 0)); CHECK_B(emit_dot_static_data(emit, v, !struct_ctor(v) ? emit_addr : 1)); if (tflag(v->type, tflag_struct)) CHECK_B(struct_finish(emit, decl)); - if (isa(v->type, emit->gwion->type[et_object]) && !is_ref) { + if (isobj && !is_ref) { if(safe_tflag(emit->env->class_def, tflag_struct) && GET_FLAG(emit->env->class_def, global)) emit_object_addref(emit, 0, emit_addr); } @@ -1009,7 +1003,7 @@ ANN static bool emit_exp_decl_non_static(const Emitter emit, const uint emit_var) { const Value v = var_decl->value; const Type type = v->type; - const bool is_obj = isa(type, emit->gwion->type[et_object]); + const bool is_obj = is_object(emit->gwion, type); const bool emit_addr = (!is_obj || is_ref) ? emit_var : true; if (is_obj && !is_ref && !exp_self(decl)->ref) { if(!decl->args) CHECK_B(emit_instantiate_decl(emit, type, decl->var.td, is_ref)); @@ -1052,7 +1046,7 @@ ANN static bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, const uint is_ref, const bool emit_var) { const Value v = var_decl->value; const Type type = v->type; - const bool is_obj = isa(type, emit->gwion->type[et_object]); + const bool is_obj = is_object(emit->gwion, type); const bool emit_addr = (!is_obj || is_ref) ? emit_var : true; if (is_obj && !is_ref) { if(!decl->args) CHECK_B(emit_instantiate_decl(emit, type, decl->var.td, is_ref)); @@ -1074,18 +1068,6 @@ ANN static bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, return true; } -ANN static void set_late(const Exp_Decl *decl, const Var_Decl *var) { - const Value v = var->value; - if (!exp_getvar(exp_self(decl)) && - (GET_FLAG(array_base_simple(v->type), abstract) || GET_FLAG(decl->var.td, late))) - SET_FLAG(v, late); - else UNSET_FLAG(v, late); -} - -static inline bool late_array(const Type_Decl* td) { - return !td->array || !td->array->exp; -} - ANN static bool emit_decl(const Emitter emit, Exp_Decl *const decl) { const bool global = GET_FLAG(decl->var.td, global); const uint var = exp_getvar(exp_self(decl)); @@ -1106,26 +1088,8 @@ ANN static bool emit_decl(const Emitter emit, Exp_Decl *const decl) { .op = insert_symbol("@implicit"), .rhs = t}; CHECK_B(op_emit(emit, &opi)); - } - set_late(decl, vd); - if (!decl->args && !exp_getvar(exp_self(decl)) && GET_FLAG(array_base_simple(v->type), abstract) && !GET_FLAG(decl->var.td, late) && - GET_FLAG(v, late) && late_array(decl->var.td) - && GET_FLAG(v->type, abstract)) { - env_err(emit->env, decl->var.td->tag.loc, _("Type '%s' is abstract, use {+G}late{0} instead of {G+}%s{0}"), - v->type->name, !GET_FLAG(decl->var.td, const) ? "var" : "const"); - if(v->type->nspc->vtable.ptr) { - const Vector vec = &v->type->nspc->vtable; - for(m_uint i = 0; i < vector_size(vec); i++) { - const Func f = (Func)vector_at(vec, i); - if(is_new(f->def)) { - gw_err(_("maybe use a constructor?\n")); - break; - } - } - } - return false; - } - if(isa(v->type, emit->gwion->type[et_object]) && GET_FLAG(v, late) && exp_getuse(exp_self(decl))) + } + if(is_object(emit->gwion, v->type) /*&& GET_FLAG(v, late) */&& exp_getuse(exp_self(decl)) && !exp_getvar(exp_self(decl))) emit_add_instr(emit, GWOP_EXCEPT); return true; } @@ -1140,7 +1104,7 @@ ANN /*static */ bool emit_exp_decl(const Emitter emit, Exp_Decl *const decl) { !global ? emit->env->scope->depth : emit_push_global(emit); const bool ret = emit_decl(emit, decl); if (global) emit_pop(emit, scope); - if(emit->status.in_return && GET_FLAG(decl->var.vd.value, late) && isa(t, emit->gwion->type[et_object])) + if(emit->status.in_return && GET_FLAG(decl->var.vd.value, late) && is_object(emit->gwion, t)) emit_add_instr(emit, GWOP_EXCEPT); return ret; } @@ -1957,8 +1921,8 @@ ANN2(1) /*static */ bool emit_exp(const Emitter emit, /* const */ Exp* e) { } CHECK_B(emit_exp_func[exp->exp_type](emit, &exp->d)); if (exp->cast_to) CHECK_B(emit_implicit_cast(emit, exp, exp->cast_to)); - if (isa(e->type, emit->gwion->type[et_object]) && - (e->cast_to ? isa(e->cast_to, emit->gwion->type[et_object]) : 1) && + if (is_object(emit->gwion, exp->type) && + (e->cast_to ? is_object(emit->gwion, e->cast_to) : true) && e->exp_type == ae_exp_decl && GET_FLAG(e->d.exp_decl.var.td, late) && exp_getuse(e) && !exp_getvar(e) && GET_FLAG(e->d.exp_decl.var.vd.value, late)) diff --git a/src/env/func.c b/src/env/func.c index fba8b6b8e..54e9dc32e 100644 --- a/src/env/func.c +++ b/src/env/func.c @@ -1,6 +1,7 @@ #include "gwion_util.h" #include "gwion_ast.h" #include "gwion_env.h" +#include "gwfmt.h" #include "vm.h" #include "gwion.h" #include "clean.h" @@ -54,7 +55,17 @@ ANN void builtin_func(const Gwion gwion, const Func f, void *func_ptr) { if(likely(arg.type == tmplarg_td)) mp_vector_set(f->code->types, Type, n++, known_type(gwion->env, arg.d.td)); } -// f->code->types->len = n; } } } + +ANN void print_signature(const Gwion gwion, const Func f) { + struct GwfmtState ls = {.minimize=true, .ppa = gwion->ppa}; + text_init(&ls.text, gwion->mp); + Gwfmt l = {.mp = gwion->mp, .st = gwion->st, .ls = &ls, .line = 1, .last = cht_nl }; + gwfmt_func_def(&l, f->def); + gwlog_related_from(ls.text.str, f->value_ref->from); + text_release(&ls.text); +} + + diff --git a/src/env/type.c b/src/env/type.c index a30ce4a76..ffd2f39cb 100644 --- a/src/env/type.c +++ b/src/env/type.c @@ -139,6 +139,10 @@ ANN bool is_func(const struct Gwion_ *gwion, const Type t) { return isa(actual_type(gwion, t), gwion->type[et_function]); } +ANN bool is_object(const struct Gwion_ *gwion, const Type t) { + return isa(t, gwion->type[et_object]); +} + ANN inline bool is_class(const struct Gwion_ *gwion, const Type t) { // return isa(t, gwion->type[et_class]); return t->info->parent == gwion->type[et_class]; diff --git a/src/import/import_cdef.c b/src/import/import_cdef.c index 18c5726f6..b7e227030 100644 --- a/src/import/import_cdef.c +++ b/src/import/import_cdef.c @@ -26,7 +26,8 @@ ANN static void mk_dtor(MemPool p, const Type t, const m_uint d) { ANN2(1, 2) static void import_class_ini(const Env env, const Type t) { t->nspc = new_nspc(env->gwion->mp, t->name); t->nspc->parent = env->curr; - if (isa(t, env->gwion->type[et_object])) inherit(t); + if (is_object(env->gwion, t)) + inherit(t); env_push_type(env, t); } diff --git a/src/lib/array.c b/src/lib/array.c index cf399a268..2d4142517 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -403,7 +403,7 @@ ANN static inline bool array_do(const Emitter emit, const Array_Sub array, access = emit_add_instr(emit, ArrayAccess); access->m_val = (i+1) * SZ_INT - offset; access->udata.one = offset; - if(i < get_depth(t) || isa(array_base(t), emit->gwion->type[et_object])) { + if(i < get_depth(t) || is_object(emit->gwion, array_base(t))) { const Instr ex = emit_add_instr(emit, GWOP_EXCEPT); ex->m_val = -SZ_INT; } diff --git a/src/lib/object_op.c b/src/lib/object_op.c index 4e3446376..37962697a 100644 --- a/src/lib/object_op.c +++ b/src/lib/object_op.c @@ -264,7 +264,7 @@ OP_EMIT(opem_object_dot) { assert(GET_FLAG(value, static)); emit_dot_static_import_data(emit, value, exp_getvar(exp_self(member))); } - if(isa(value->type, emit->gwion->type[et_object]) && + if(is_object(emit->gwion, value->type) && !exp_getvar(exp_self(member)) && (GET_FLAG(value, static) || GET_FLAG(value, late))) emit_fast_except(emit, value->from, exp_self(member)->loc); diff --git a/src/lib/opfunc.c b/src/lib/opfunc.c index b6ce9ced9..794ca80b6 100644 --- a/src/lib/opfunc.c +++ b/src/lib/opfunc.c @@ -152,7 +152,7 @@ OP_CHECK(opck_new) { (!array || (array->exp && exp_is_zero(array->exp)))) ERR_N(unary->ctor.td->tag.loc, _("can't use 'new' on abstract type '%s'\n"), t->name); - if (!isa(t, env->gwion->type[et_object])) + if (!is_object(env->gwion, t)) ERR_N(exp_self(unary)->loc, _("can't use 'new' on non-object types...\n")); return t; } diff --git a/src/parse/check.c b/src/parse/check.c index 17106ef14..131dd8cd7 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -189,7 +189,7 @@ ANN Type check_exp_decl(const Env env, Exp_Decl *const decl) { env_pop(env, scope); set_vflag(decl->var.vd.value, vflag_direct); } - env_weight(env, 1 + isa(decl->type, env->gwion->type[et_object])); + env_weight(env, 1 + is_object(env->gwion, decl->type)); return ret ? decl->var.vd.value->type : NULL; } @@ -709,9 +709,9 @@ static void function_alternative(const Env env, const Type t, Exp* args, gwlog_error("Argument type mismatch", "call site", env->name, loc, 0); // TODO: hint valid alternatives - do print_signature(f); + do print_signature(env->gwion, f); while ((f = f->next)); - gw_err(_("and not\n ")); + gw_err(_("and not:\n ")); if (args) print_current_args(args); else @@ -1144,7 +1144,7 @@ ANN static Type check_exp_post(const Env env, const Exp_Postfix *post) { CHECK_O(opi.lhs); exp_setuse(post->exp, 1); const Type t = op_check(env, &opi); - if (t && !isa(t, env->gwion->type[et_object])) + if (t && !is_object(env->gwion, t)) exp_setmeta(exp_self(post), 1); return t; } diff --git a/src/parse/partial.c b/src/parse/partial.c index f96893a32..60df61ea7 100644 --- a/src/parse/partial.c +++ b/src/parse/partial.c @@ -114,30 +114,11 @@ ANN Func find_match_actual(const Env env, const Func up, Exp* args) { ANN static Func partial_match(const Env env, const Func up, Exp* args, const loc_t loc); -ANN static void print_arg(Arg_List args) { - for(uint32_t i = 0; i < args->len; i++) { - Arg *arg = mp_vector_at(args, Arg, i); - gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL, - arg->var.vd.tag.sym ? s_name(arg->var.vd.tag.sym) : ""); - if(i < args->len - 1) gw_err(", "); - } -} - -ANN void print_signature(const Func f) { - gw_err(" {-}(%s){0} ", f->name); - const Arg_List args = f->def->base->args; - if (args) - print_arg(args); - else - gw_err("{G}void{0}"); - gw_err("\n"); -} - ANN void ambiguity(const Env env, Func f, Exp* args, const loc_t loc) { - print_signature(f); + print_signature(env->gwion, f); while(f->next) { const Func next = partial_match(env, f->next, args, loc); - if(next) print_signature(next); + if(next) print_signature(env->gwion, next); f = f->next; } } @@ -154,7 +135,7 @@ ANN static Func partial_match(const Env env, const Func up, Exp* args, const loc gwlog_error(_("can't resolve ambiguity"), _("in this partial application"), env->name, loc, 0); gwlog_hint(_("use typed holes: `_ $ type`"), env->name, loc); gw_err(_("\nthose functions could match:\n")); - print_signature(f); + print_signature(env->gwion, f); ambiguity(env, next, args, loc); env_set_error(env, true); return NULL; diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 122a6b330..7a70b2a15 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -133,7 +133,7 @@ ANN static bool scan1_decl(const Env env, Exp_Decl *const decl) { set_vflag(v, vflag_member); if(tflag(t, tflag_release)) set_tflag(env->class_def, tflag_release); - if(isa(t, env->gwion->type[et_object])) + if(is_object(env->gwion, t)) set_vflag(v, vflag_release); if (tflag(env->class_def, tflag_struct)) { v->from->offset = env->class_def->size; @@ -815,7 +815,7 @@ ANN static bool scan1_parent(const Env env, const Class_Def cdef) { if (cdef->base.ext->array && cdef->base.ext->array->exp) CHECK_B(scan1_exp(env, cdef->base.ext->array->exp)); DECL_B(const Type, parent, = scan1_get_parent(env, &cdef->base)); - if (!isa(parent, env->gwion->type[et_object]) && + if (!is_object(env->gwion, parent) && // !(tflag(cdef->base.type, tflag_cdef) || tflag(cdef->base.type, tflag_udef))) !(tflag(cdef->base.type, tflag_cdef) || tflag(cdef->base.type, tflag_union))) ERR_B(loc, _("cannot extend primitive type '%s'"), parent->name); diff --git a/src/parse/traverse.c b/src/parse/traverse.c index 0e6024925..83012cae2 100644 --- a/src/parse/traverse.c +++ b/src/parse/traverse.c @@ -2,19 +2,13 @@ #include "gwion_ast.h" #include "gwion_env.h" #include "traverse.h" - -ANN bool traverse_ast(const Env env, Ast *const ast) { - CHECK_B(scan0_ast(env, ast)); - CHECK_B(scan1_ast(env, ast)); - CHECK_B(scan2_ast(env, ast)); - CHECK_B(check_ast(env, ast)); - return true; -} +#include "validate.h" ANN bool traverse_exp(const Env env, Exp* exp) { CHECK_B(scan1_exp(env, exp)); CHECK_B(scan2_exp(env, exp)); CHECK_B(check_exp(env, exp)); + CHECK_B(exp_validation(env, exp)); return true; } @@ -23,6 +17,7 @@ ANN static bool _traverse_func_def(const Env env, const Func_Def fdef) { CHECK_B(scan1_func_def(env, fdef)); CHECK_B(scan2_func_def(env, fdef)); CHECK_B(check_func_def(env, fdef)); + CHECK_B(func_def_validation(env, fdef)); return true; } @@ -40,6 +35,7 @@ ANN bool traverse_union_def(const Env env, const Union_Def def) { CHECK_B(scan2_union_def(env, def)); // if(!GET_FLAG(def, check)) CHECK_B(check_union_def(env, def)); + CHECK_B(union_def_validation(env, def)); return true; } @@ -48,6 +44,7 @@ ANN bool traverse_enum_def(const Env env, const Enum_Def def) { CHECK_B(scan1_enum_def(env, def)); // CHECK_B(scan2_enum_def(env, def)); // CHECK_B(check_enum_def(env, def)); + CHECK_B(enum_def_validation(env, def)); return true; } @@ -56,6 +53,7 @@ ANN bool traverse_fptr_def(const Env env, const Fptr_Def def) { CHECK_B(scan1_fptr_def(env, def)); CHECK_B(scan2_fptr_def(env, def)); CHECK_B(check_fptr_def(env, def)); + CHECK_B(fptr_def_validation(env, def)); return true; } @@ -64,6 +62,7 @@ ANN bool traverse_type_def(const Env env, const Type_Def def) { CHECK_B(scan1_type_def(env, def)); CHECK_B(scan2_type_def(env, def)); CHECK_B(check_type_def(env, def)); + CHECK_B(type_def_validation(env, def)); return true; } @@ -72,5 +71,15 @@ ANN bool traverse_class_def(const Env env, const Class_Def def) { if (!tflag(t, tflag_scan1)) CHECK_B(scan1_class_def(env, def)); if (!tflag(t, tflag_scan2)) CHECK_B(scan2_class_def(env, def)); if (!tflag(t, tflag_check)) CHECK_B(check_class_def(env, def)); + CHECK_B(class_def_validation(env, def)); + return true; +} + +ANN bool traverse_ast(const Env env, Ast *const ast) { + CHECK_B(scan0_ast(env, ast)); + CHECK_B(scan1_ast(env, ast)); + CHECK_B(scan2_ast(env, ast)); + CHECK_B(check_ast(env, ast)); + CHECK_B(ast_validation(env, ast)); return true; } diff --git a/src/parse/validate.c b/src/parse/validate.c new file mode 100644 index 000000000..e83665d33 --- /dev/null +++ b/src/parse/validate.c @@ -0,0 +1,537 @@ +#include "gwion_util.h" +#include "gwion_ast.h" +#include "gwion_env.h" +#include "validate.h" +#define __NO_EMIT +#include "specialid.h" + +typedef struct { + Env env; + uint32_t jumps; +} Validate; + +ANN static bool validate_type_decl(Validate *a, Type_Decl *b); +ANN static bool validate_exp(Validate *a, Exp* b); +ANN static bool validate_stmt(Validate *a, Stmt* b); +ANN static bool validate_stmt_list(Validate *a, Stmt_List b); +ANN static bool validate_func_def(Validate *a, Func_Def b); +ANN static bool validate_type_def(Validate *a, Type_Def b); +ANN static bool validate_ast(Validate *a, Ast b); + +#define CHECK_RET(a, ret) \ +do { \ + if(!(a)) \ + ret = false; \ +} while(0) + +ANN static bool validate_array_sub(Validate *a, Array_Sub b) { + return b->exp ? validate_exp(a, b->exp) : true; +} + +ANN static bool validate_specialized(Validate *a, Specialized *b) { + return b->td ? validate_type_decl(a, b->td) : true; +} + +ANN static bool validate_specialized_list(Validate *a, Specialized_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Specialized * c = mp_vector_at(b, Specialized , i); + if(!validate_specialized(a, c)) + ret = false; + } + return ret; +} + +ANN static bool validate_tmplarg(Validate *a, TmplArg *b) { + bool ret = true; + if (b->type == tmplarg_td) + CHECK_RET(validate_type_decl(a, b->d.td), ret); + else CHECK_RET(validate_exp(a, b->d.exp), ret); + return ret; +} + +ANN static bool validate_tmplarg_list(Validate *a, TmplArg_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + TmplArg *c = mp_vector_at(b, TmplArg, i); + if(!validate_tmplarg(a, c)) + ret = false; + } + return ret; +} + +ANN static bool validate_tmpl(Validate *a, Tmpl *b) { + bool ret = true; + if(b->list) CHECK_RET(validate_specialized_list(a, b->list), ret); + if(b->call) CHECK_RET(validate_tmplarg_list(a, b->call), ret); + return ret; +} + +ANN static bool validate_range(Validate *a, Range *b) { + bool ret = true; + if(b->start) CHECK_RET(validate_exp(a, b->start), ret); + if(b->end) CHECK_RET(validate_exp(a , b->end), ret); + return ret; +} + +ANN static bool validate_type_decl(Validate *a, Type_Decl *b) { + bool ret = true; + if(b->array) CHECK_RET(validate_array_sub(a, b->array), ret); + if(b->types) CHECK_RET(validate_tmplarg_list(a, b->types), ret); + return ret; +} + +ANN static bool validate_prim_id(Validate *a, Exp_Primary *b) { + struct SpecialId_ *spid = specialid_get(a->env->gwion, b->d.var); + if(spid) return true; + if (!b->value) {// assume it's an operator + env_err(a->env, exp_self(b)->loc, "missing value for operator"); + return false; + } + return true; +} + +ANN static bool validate_prim(Validate *a, Exp_Primary *b) { + if(b->prim_type == ae_prim_id) + return validate_prim_id(a, b); + if(b->prim_type == ae_prim_dict || + b->prim_type == ae_prim_hack || + b->prim_type == ae_prim_interp) + return validate_exp(a, b->d.exp); + if(b->prim_type == ae_prim_array) + return validate_array_sub(a, b->d.array); + if(b->prim_type == ae_prim_range) + return validate_range(a, b->d.range); + return true; +} + +ANN static bool validate_variable(Validate *a, Variable *b) { + return b->td ? validate_type_decl(a, b->td) : true; +} + +ANN static void set_late(const Exp_Decl *decl, const Var_Decl *var) { + const Value v = var->value; + if (!decl->args && + (GET_FLAG(array_base_simple(v->type), abstract) || GET_FLAG(decl->var.td, late))) + SET_FLAG(v, late); + else UNSET_FLAG(v, late); +} + +static inline bool late_array(const Type_Decl* td) { + return !td->array || !td->array->exp; +} + +ANN static bool validate_exp_decl(Validate *a, Exp_Decl *b) { + if(b->args && !strncmp(b->args->type->name, "partial:", 8)) { + env_err(a->env, b->args->loc, "unresolved partial"); + return false; + } + CHECK_B(validate_variable(a, &b->var)); + Var_Decl *vd = &b->var.vd; + Value v = vd->value; + if(!v) return true; + if(is_object(a->env->gwion, v->type) && !b->args) { + set_late(b, vd); + if (!exp_getvar(exp_self(b)) && GET_FLAG(array_base_simple(v->type), abstract) && !GET_FLAG(b->var.td, late) && + /*GET_FLAG(v, late) && */late_array(b->var.td) + && GET_FLAG(v->type, abstract)) { + env_err(a->env, b->var.td->tag.loc, _("Type '%s' is abstract, use {+G}late{0} instead of {G+}%s{0}"), + v->type->name, !GET_FLAG(b->var.td, const) ? "var" : "const"); + if(v->type->nspc->vtable.ptr) { + bool has_new = false; + const Vector vec = &v->type->nspc->vtable; + for(m_uint i = 0; i < vector_size(vec); i++) { + const Func f = (Func)vector_at(vec, i); + if(is_new(f->def)) { + if(!has_new) { + gwlog_hint(_("maybe use a constructor?"), a->env->name, b->var.td->tag.loc); + has_new = true; + } + print_signature(a->env->gwion, f); + } + } + } + return false; + } + } + return true; +} + +ANN static bool validate_exp_binary(Validate *a, Exp_Binary *b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->lhs), ret); + CHECK_RET(validate_exp(a, b->rhs), ret); + return ret; +} + +ANN static bool validate_exp_unary(Validate *a, Exp_Unary *b) { + bool ret = true; + const enum unary_type type = b->unary_type; + if(type == unary_exp) + CHECK_RET(validate_exp(a, b->exp), ret); + else if(type == unary_td) + CHECK_RET(validate_type_decl(a, b->ctor.td), ret); + else + CHECK_RET(validate_stmt_list(a, b->code), ret); + return ret; +} + +ANN static bool validate_exp_cast(Validate *a, Exp_Cast *b) { + bool ret = true; + CHECK_RET(validate_type_decl(a, b->td), ret); + CHECK_RET(validate_exp(a, b->exp), ret); + return ret; +} + +ANN static bool validate_exp_post(Validate *a, Exp_Postfix *b) { + return validate_exp(a, b->exp); +} + +ANN static bool validate_exp_call(Validate *a, Exp_Call *b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->func), ret); + if(b->args) CHECK_RET(validate_exp(a, b->args), ret); + if(b->tmpl) CHECK_RET(validate_tmpl(a, b->tmpl), ret); + return ret; +} + +ANN static bool validate_exp_array(Validate *a, Exp_Array *b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->base), ret); + CHECK_RET(validate_array_sub(a, b->array), ret); + return ret; +} + +ANN static bool validate_exp_slice(Validate *a, Exp_Slice *b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->base), ret); + CHECK_RET(validate_range(a, b->range), ret); + return ret; +} + +ANN static bool validate_exp_if(Validate *a, Exp_If *b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + if(b->if_exp) CHECK_RET(validate_exp(a, b->if_exp), ret); + CHECK_RET(validate_exp(a, b->else_exp), ret); + return ret; +} + +ANN static bool validate_exp_dot(Validate *a, Exp_Dot *b) { + return validate_exp(a, b->base); +} + +ANN static bool validate_exp_lambda(Validate *a, Exp_Lambda *b) { + return validate_func_def(a, b->def); +} + +ANN static bool validate_exp_td(Validate *a, Type_Decl *b) { + return validate_type_decl(a, b); +} + +DECL_EXP_FUNC(validate, bool, Validate*) +ANN static bool validate_exp(Validate *a, Exp* b) { + bool ret = true; + if(!b->poison) + CHECK_RET(validate_exp_func[b->exp_type](a, &b->d), ret); + if(b->next) CHECK_RET(validate_exp(a, b ->next), ret); + return ret; +} + +ANN static bool validate_stmt_exp(Validate *a, Stmt_Exp b) { + bool ret = true; + if(b->val) CHECK_RET(validate_exp(a, b->val), ret); + return ret; +} + +ANN static bool validate_stmt_jump(Validate *a, Stmt *stmt) { + a->jumps++; + const bool ret = validate_stmt(a, stmt); + a->jumps--; + return ret; +} + +ANN static bool validate_stmt_flow(Validate *a, Stmt_Flow b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + CHECK_RET(validate_stmt_jump(a, b->body), ret); + return ret; +} +#define validate_stmt_while validate_stmt_flow +#define validate_stmt_until validate_stmt_flow + +ANN static bool validate_stmt_for(Validate *a, Stmt_For b) { + CHECK_B(validate_stmt(a, b->c1)); + if(b->c2) CHECK_B(validate_stmt(a, b->c2)); + if(b->c3) CHECK_B(validate_exp(a, b->c3)); + CHECK_B(validate_stmt_jump(a, b->body)); + return true; +} + +ANN static bool validate_stmt_each(Validate *a, Stmt_Each b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->exp), ret); + CHECK_RET(validate_stmt_jump(a, b->body), ret); + return ret; +} + +ANN static bool validate_stmt_loop(Validate *a, Stmt_Loop b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + CHECK_RET(validate_stmt_jump(a, b->body), ret); + return ret; +} + +ANN static bool validate_stmt_if(Validate *a, Stmt_If b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + CHECK_RET(validate_stmt(a, b->if_body), ret); + if(b->else_body) CHECK_RET(validate_stmt(a, b->else_body), ret); + return ret; +} + +ANN static bool validate_stmt_code(Validate *a, Stmt_Code b) { + bool ret = true; + if(b->stmt_list) CHECK_RET(validate_stmt_list(a, b->stmt_list), ret); + return ret; +} + +ANN static inline bool validate_stmt_index(Validate *a, const Stmt_Index stmt) { + if (stmt->idx > a->jumps) { + env_err(a->env, stmt_self(stmt)->loc, _("too many jumps required.")); + return false; + } + return true; +} + +ANN static bool validate_stmt_break(Validate *a, Stmt_Index b) { + return validate_stmt_index(a, b); +} + +ANN static bool validate_stmt_continue(Validate *a, Stmt_Index b) { + return validate_stmt_index(a, b); +} + +ANN static bool validate_stmt_return(Validate *a, Stmt_Exp b) { + bool ret = true; + if(b->val) CHECK_RET(validate_exp(a, b-> val), ret); + return ret; +} + +ANN static bool validate_stmt_case(Validate *a, Stmt_Match b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + CHECK_RET(validate_stmt_list(a, b->list), ret); + if(b->when) CHECK_RET(validate_exp(a, b->when), ret); + return ret; +} + +ANN static bool validate_case_list(Validate *a, Stmt_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Stmt* c = mp_vector_at(b, Stmt, i); + if(!validate_stmt_case(a, &c->d.stmt_match)) + ret = false; + } + return ret; +} + +ANN static bool validate_stmt_match(Validate *a, Stmt_Match b) { + bool ret = true; + CHECK_RET(validate_exp(a, b->cond), ret); + CHECK_RET(validate_case_list(a, b->list), ret); + if(b->where) CHECK_RET(validate_stmt(a, b->where), ret); + return ret; +} + +ANN static bool validate_stmt_pp(Validate *a NUSED, Stmt_PP b NUSED) { + if(b->pp_type == ae_pp_include) + a->env->name = b->data; + return true; +} + +#define validate_stmt_retry dummy_func + +ANN static bool validate_handler(Validate *a, Handler *b) { + return validate_stmt(a, b->stmt); +} + +ANN static bool validate_handler_list(Validate *a, Handler_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Handler *handler = mp_vector_at(b, Handler, i); + if(!validate_handler(a, handler)) + ret = false; + } + return ret; +} + +ANN static bool validate_stmt_try(Validate *a, Stmt_Try b) { + bool ret = true; + CHECK_RET(validate_stmt(a, b->stmt), ret); + CHECK_RET(validate_handler_list(a, b->handler), ret); + return ret; +} + +ANN static bool validate_stmt_defer(Validate *a, Stmt_Defer b) { + return validate_stmt(a, b->stmt); +} + +ANN static bool validate_stmt_spread(Validate *a NUSED, Spread_Def b NUSED) { + return true; +} +DECL_STMT_FUNC(validate, bool, Validate*) +ANN static bool validate_stmt(Validate *a, Stmt* b) { + if(b->poison) return false; + if(!validate_stmt_func[b->stmt_type](a, &b->d)) + b->poison = true; + return !b->poison; +} + +ANN static bool validate_arg(Validate *a, Arg *b) { + return validate_variable(a, &b->var); +} + +ANN static bool validate_arg_list(Validate *a, Arg_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Arg *c = mp_vector_at(b, Arg, i); + if(!validate_arg(a, c)) + ret = false; + } + return ret; +} + +ANN static bool validate_variable_list(Validate *a, Variable_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Variable *c = mp_vector_at(b, Variable, i); + if(!validate_variable(a, c)) + return true; + } + return ret; +} + +ANN static bool validate_stmt_list(Validate *a, Stmt_List b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Stmt* c = mp_vector_at(b, Stmt, i); + if(!validate_stmt(a, c)) + ret = false; + } + return ret; +} + +ANN static bool validate_func_base(Validate *a, Func_Base *b) { + bool ret = true; + if(b->td) CHECK_RET(validate_type_decl(a, b->td), ret); + if(b->args) CHECK_RET(validate_arg_list(a, b->args), ret); + if(b->tmpl) CHECK_RET(validate_tmpl(a, b->tmpl), ret); + return ret; +} + +ANN static bool validate_func_def(Validate *a, Func_Def b) { + bool ret = true; + CHECK_RET(validate_func_base(a, b->base), ret); + if(!b->builtin && b->d.code) + CHECK_RET(validate_stmt_list(a, b->d.code), ret); + return ret; +} + +ANN static bool validate_class_def(Validate *a, Class_Def b) { + bool ret = true; + CHECK_RET(validate_type_def(a, &b->base), ret); + if(b->body) return validate_ast(a, b->body); + return ret; +} + +ANN static bool validate_trait_def(Validate *a, Trait_Def b) { + bool ret = true; + if(b->body) CHECK_RET(validate_ast(a, b->body), ret); + return ret; +} + +#define validate_enum_def dummy_func + +ANN static bool validate_union_def(Validate *a, Union_Def b) { + bool ret = true; + CHECK_RET(validate_variable_list(a, b->l), ret); + if(b->tmpl) CHECK_RET(validate_tmpl(a, b->tmpl), ret); + return ret; +} + +ANN static bool validate_fptr_def(Validate *a, Fptr_Def b) { + return validate_func_base(a, b->base); +} + +ANN static bool validate_type_def(Validate *a, Type_Def b) { + bool ret = true; + if(b->ext) CHECK_RET(validate_type_decl(a, b->ext), ret); + if(b->tmpl) CHECK_RET(validate_tmpl(a, b->tmpl), ret); + if(b->when) CHECK_RET(validate_exp(a, b->when), ret); + return ret; +} + +ANN static bool validate_extend_def(Validate *a, Extend_Def b) { + return validate_type_decl(a, b->td); +} + +#define validate_prim_def dummy_func + +DECL_SECTION_FUNC(validate, bool, Validate*) +ANN static bool validate_section(Validate *a, Section *b) { + if(b->poison) return false; + if(!validate_section_func[b->section_type](a, *(void**)&b->d)) + b->poison = true; + return !b->poison; +} + +ANN static bool validate_ast(Validate *a, Ast b) { + bool ret = true; + for(uint32_t i = 0; i < b->len; i++) { + Section *c = mp_vector_at(b, Section, i); + if(!validate_section(a, c)) + ret = false; + } + return ret; +} + +ANN bool exp_validation(Env env, Exp* b) { + Validate a = { .env = env }; + return validate_exp(&a , b); +} + +ANN bool func_def_validation(Env env, Func_Def b) { + Validate a = { .env = env }; + return validate_func_def(&a , b); +} + +ANN bool union_def_validation(Env env, Union_Def b) { + Validate a = { .env = env }; + return validate_union_def(&a , b); +} + +ANN bool type_def_validation(Env env, Type_Def b) { + Validate a = { .env = env }; + return validate_type_def(&a , b); +} + +ANN bool enum_def_validation(Env env, Enum_Def b) { + Validate a = { .env = env }; + return validate_enum_def(&a , b); +} + +ANN bool fptr_def_validation(Env env, Fptr_Def b) { + Validate a = { .env = env }; + return validate_fptr_def(&a , b); +} + +ANN bool class_def_validation(Env env, Class_Def b) { + Validate a = { .env = env }; + return validate_class_def(&a , b); +} + +ANN bool ast_validation(Env env, Ast *ast) { + Validate a = { .env = env }; + return validate_ast(&a , *ast); +} diff --git a/src/pass.c b/src/pass.c index 25ffb45f1..cd8ec8051 100644 --- a/src/pass.c +++ b/src/pass.c @@ -8,6 +8,7 @@ #include "pass.h" #include "traverse.h" #include "sema.h" +#include "validate.h" #define N_PASS 3 #define N_SCANPASS 4 @@ -17,6 +18,7 @@ static bool typecheck_ast(const Env env, Ast *ast) { scan1_ast(env, ast); scan2_ast(env, ast); check_ast(env, ast); + ast_validation(env, ast); return !env->context->error; } diff --git a/tests/ctor/maybe_use.gw b/tests/ctor/maybe_use.gw new file mode 100644 index 000000000..10ade3dc4 --- /dev/null +++ b/tests/ctor/maybe_use.gw @@ -0,0 +1,6 @@ +#! [contains] maybe use a constructor? +class C { + operator new() {}; +} + +var C c; diff --git a/util b/util index e774331c8..2cfc28f61 160000 --- a/util +++ b/util @@ -1 +1 @@ -Subproject commit e774331c8086cc62472148fcb6a32cbf8bfee8e6 +Subproject commit 2cfc28f61565287e7dd4c61411bf547a2e268206