From: fennecdjay Date: Thu, 16 May 2024 04:15:22 +0000 (+0200) Subject: :art: using statement X-Git-Tag: nightly~10 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=0a48a247f9963f6c2c08754c683045602c8a9d61;p=gwion.git :art: using statement --- diff --git a/ast b/ast index ecdd2a8a..4a237db7 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit ecdd2a8aabed7f730f7ef06cc32d48a2c431134f +Subproject commit 4a237db7d547d5b132ffcdb4489ed67126e67e69 diff --git a/fmt b/fmt index 4287d6bb..01aa72ea 160000 --- a/fmt +++ b/fmt @@ -1 +1 @@ -Subproject commit 4287d6bba515c6d9a304341f43a759352778ce68 +Subproject commit 01aa72eaba624e348de046ab573f498861e2103f diff --git a/include/env/nspc.h b/include/env/nspc.h index a02c3ea2..3a7f7abc 100644 --- a/include/env/nspc.h +++ b/include/env/nspc.h @@ -5,6 +5,7 @@ typedef struct NspcInfo_ { Scope type; Scope func; Scope trait; + MP_Vector *using; } NspcInfo; typedef struct NspcOp_ { diff --git a/include/parse.h b/include/parse.h index 6a66929e..a8b8d650 100644 --- a/include/parse.h +++ b/include/parse.h @@ -50,9 +50,14 @@ #define RET_NSPC(exp) \ ++env->scope->depth; \ + const uint32_t nusing = env->curr->info->using \ + ? env->curr->info->using->len \ + : 0; \ nspc_push_value(env->gwion->mp, env->curr); \ const bool ret = exp; \ nspc_pop_value(env->gwion->mp, env->curr); \ + if(nusing) \ + env->curr->info->using->len = nusing; \ --env->scope->depth; \ return ret; diff --git a/src/clean.c b/src/clean.c index d5905c34..6ba71551 100644 --- a/src/clean.c +++ b/src/clean.c @@ -248,6 +248,9 @@ ANN static void clean_dummy(Clean *a NUSED, void *b NUSED) {} #define clean_stmt_retry clean_dummy #define clean_stmt_spread clean_dummy +// TODO: check me +#define clean_stmt_using clean_dummy + DECL_STMT_FUNC(clean, void, Clean *) ANN static void clean_stmt(Clean *a, Stmt* b) { clean_stmt_func[b->stmt_type](a, &b->d); diff --git a/src/emit/emit.c b/src/emit/emit.c index b4564bb3..947b10dc 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -2576,6 +2576,7 @@ ANN static bool emit_stmt_retry(const Emitter emit, #define emit_stmt_while emit_stmt_flow #define emit_stmt_until emit_stmt_flow #define emit_stmt_spread dummy_func +#define emit_stmt_using dummy_func DECL_STMT_FUNC(emit, bool, Emitter); diff --git a/src/env/env_utils.c b/src/env/env_utils.c index a328dc44..92cf65f1 100644 --- a/src/env/env_utils.c +++ b/src/env/env_utils.c @@ -50,28 +50,39 @@ ANN Type find_initial(const Env env, const Symbol xid) { const Nspc nspc = (Nspc)vector_at(v, i - 1); RETURN_TYPE(nspc_lookup_type1(nspc, xid)); } - return NULL; + if(env->curr->info->using) { + for(uint32_t i = 0; i < env->curr->info->using->len; i++) { + Stmt_Using using = *mp_vector_at(env->curr->info->using, Stmt_Using, i); + if(!using->alias.sym) { + const Type owner = known_type(env, using->d.td); + if(owner) { + const Type ret = nspc_lookup_type0(owner->nspc, xid); + if(ret) return ret; + } + } else if(xid == using->alias.sym) { + if(!using->d.exp->type) + CHECK_B(traverse_exp(env, using->d.exp)); + if(is_class(env->gwion, using->d.exp->type)) + return using->d.exp->type->info->base_type; + ERR_B(using->alias.loc, "found an alias %s but it's not a type", s_name(using->alias.sym)); + } +}} + return NULL; } #undef RETURN_TYPE ANN Type find_type(const Env env, Type_Decl *td) { DECL_O(Type, type, = find_initial(env, td->tag.sym)); while ((td = td->next) && type && type->nspc) { -// const Nspc nspc = type->nspc; -// if(!(type = find_in_parent(type, td->tag.sym))) -// - //enERR_O(td->tag.loc, _("...(cannot find class '%s' in nspc '%s')"), -//s_name(td->tag.sym), nspc->name); - - Type_Decl *next = td->next; td->next = NULL; -env_push_type(env, type); + const uint32_t scope = env->scope->depth; + env_push_type(env, type); type = known_type(env, td); if(!type) ERR_O(td->tag.loc, _("...(cannot find class '%s' in nspc '%s')"), s_name(td->tag.sym), env->class_def->name); -env_pop(env, 0); // respect scope depth // use env scope + env_pop(env, scope); td->next = next; } diff --git a/src/env/nspc.c b/src/env/nspc.c index ff96d596..6bf4c684 100644 --- a/src/env/nspc.c +++ b/src/env/nspc.c @@ -48,6 +48,8 @@ ANN void free_nspc(const Nspc a, const Gwion gwion) { nspc_free_trait(a, gwion); if(a->operators) free_operators(a->operators, gwion); nspc_free_type(a, gwion); + if (a->info->using) + free_mp_vector(gwion->mp, Stmt_Using, a->info->using); if (a->class_data && a->class_data_size) mp_free2(gwion->mp, a->class_data_size, a->class_data); if (a->vtable.ptr) vector_release(&a->vtable); diff --git a/src/parse/check.c b/src/parse/check.c index dd307a03..2a412d44 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -398,6 +398,30 @@ ANN static Type prim_id_non_res(const Env env, const Symbol *data) { return v->type; } } + if(env->curr->info->using) { + for(uint32_t i = 0; i < env->curr->info->using->len; i++) { + Stmt_Using using = *mp_vector_at(env->curr->info->using, Stmt_Using, i); + if(!using->alias.sym) { + // NOTE: we know type is valid and has nspc + const Type type = known_type(env, using->d.td); + Value value = nspc_lookup_value1(type->nspc, sym); + if(value) { + Exp *exp = prim_exp(data); + exp->exp_type = ae_exp_dot; + Type_Decl *td = cpy_type_decl(env->gwion->mp, using->d.td); + exp->d.exp_dot.base = new_exp_td(env->gwion->mp, td, exp->loc); + exp->d.exp_dot.xid = insert_symbol(value->name); + return check_exp(env, exp); + } + } else if(sym == using->alias.sym) { + Exp *exp = prim_exp(data); + Exp *base = cpy_exp(env->gwion->mp, using->d.exp); + *exp = *base; + mp_free2(env->gwion->mp, sizeof(Exp), base); + return check_exp(env, exp); + } + } + } m_str str = NULL; gw_asprintf(env->gwion->mp, &str, "Invalid variable {R}%s{0}\n", name); gwlog_error(str, _("not legit at this point."), @@ -1724,6 +1748,38 @@ ANN static bool check_stmt_defer(const Env env, const Stmt_Defer stmt) { return check_stmt(env, stmt->stmt); } +ANN static bool check_stmt_using(const Env env, const Stmt_Using stmt) { + if(!stmt->alias.sym) { + DECL_B(const Type, type, = known_type(env, stmt->d.td)); + for(m_uint i = 0; i < map_size(&type->nspc->info->value->map); ++i) { + const Symbol sym = (Symbol)VKEY(&type->nspc->info->value->map, i); + const Value value = nspc_lookup_value1(env->curr, sym); + if(value) { + char msg[256]; + sprintf(msg, "{Y}%s{0} is already defined", value->name); + gwlog_error(_(msg), "from this `using` statement", env->name, stmt->d.td->tag.loc, 0); + declared_here(value); + const Value other = nspc_lookup_value1(type->nspc, sym); + declared_here(other); + return false; + } + } + } else { + const Value value = nspc_lookup_value1(env->curr, stmt->alias.sym); + if(value) { + char msg[256]; + sprintf(msg, "{Y}%s{0} is already defined", value->name); + gwlog_error(_(msg), NULL, env->name, stmt->alias.loc, 0); + declared_here(value); + return false; + } + if(!stmt->d.exp->type) + CHECK_B(check_exp(env, stmt->d.exp)); + } + mp_vector_add(env->gwion->mp, &env->curr->info->using, Stmt_Using, stmt); + return true; +} + #define check_stmt_retry dummy_func #define check_stmt_spread dummy_func DECL_STMT_FUNC(check, bool, Env) @@ -1734,12 +1790,17 @@ ANN bool check_stmt(const Env env, Stmt* stmt) { ANN bool check_stmt_list(const Env env, Stmt_List l) { bool ok = true; + const uint32_t nusing = env->curr->info->using + ? env->curr->info->using->len + : 0; for(m_uint i = 0; i < l->len; i++) { Stmt* stmt = mp_vector_at(l, Stmt, i); if(stmt->poison) { ok = false; continue;} if(!check_stmt(env, stmt)) POISON_NODE(ok, env, stmt); } + if(env->curr->info->using) + env->curr->info->using->len = nusing; return ok; } diff --git a/src/parse/scan0.c b/src/parse/scan0.c index 5a52787f..231251eb 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -371,6 +371,9 @@ ANN static Type scan0_class_def_init(const Env env, const Class_Def cdef) { ANN static bool scan0_stmt_list(const Env env, Stmt_List l) { bool ok = true; + const uint32_t nusing = env->curr->info->using + ? env->curr->info->using->len + : 0; for(m_uint i = 0; i < l->len; i++) { Stmt* stmt = mp_vector_at(l, Stmt, i); if(stmt->poison) { ok = false; continue; } @@ -381,11 +384,17 @@ ANN static bool scan0_stmt_list(const Env env, Stmt_List l) { if(!plugin_ini(env->gwion, stmt->d.stmt_pp.data, stmt->loc)) POISON_NODE(ok, env, stmt); } + } else if(stmt->stmt_type == ae_stmt_using) { + if(!env->curr->info->using) + env->curr->info->using = new_mp_vector(env->gwion->mp, Stmt_Using, 0); + mp_vector_add(env->gwion->mp, &env->curr->info->using, Stmt_Using, &stmt->d.stmt_using); } /*else if (stmt->stmt_type == ae_stmt_spread) { if(!spreadable(env)) // TODO: we can prolly get rid of this ERR_OK_NODE(ok, stmt, stmt->loc, "spread statement outside of variadic environment"); }*/ } + if(env->curr->info->using && env->scope->depth) + env->curr->info->using->len = nusing; return ok; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 6f57bdaf..f54912e8 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -261,7 +261,18 @@ ANN static inline bool _scan1_stmt_match_case(const restrict Env env, ANN static inline bool scan1_stmt_match_case(const restrict Env env, const Stmt_Match stmt) { - RET_NSPC(_scan1_stmt_match_case(env, stmt))} + RET_NSPC(_scan1_stmt_match_case(env, stmt)); +} + +ANN static inline bool scan1_stmt_using(const restrict Env env, + const Stmt_Using stmt) { + if(stmt->alias.sym) + CHECK_B(scan1_exp(env, stmt->d.exp)); + if(!env->curr->info->using) + env->curr->info->using = new_mp_vector(env->gwion->mp, Stmt_Using, 0); + mp_vector_add(env->gwion->mp, &env->curr->info->using, Stmt_Using, stmt); + return true; +} ANN static inline bool _scan1_stmt_match(const restrict Env env, const Stmt_Match stmt) { @@ -641,6 +652,9 @@ ANN static void dead_code(const Env env, Stmt_List l, uint32_t len) { ANN static bool scan1_stmt_list(const Env env, Stmt_List l) { uint32_t i; bool ok = true; + const uint32_t nusing = env->curr->info->using + ? env->curr->info->using->len + : 0; for(i = 0; i < l->len; i++) { Stmt* stmt = mp_vector_at(l, Stmt, i); if(stmt->poison) { ok = false; continue;} @@ -650,6 +664,8 @@ ANN static bool scan1_stmt_list(const Env env, Stmt_List l) { } if(end_flow(stmt)) break; } + if(env->curr->info->using) + env->curr->info->using->len = nusing; if(++i < l->len) dead_code(env, l, i); return ok; } diff --git a/src/parse/scan2.c b/src/parse/scan2.c index dcf6c5d9..fb318edf 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -261,6 +261,14 @@ ANN static bool scan2_stmt_defer(const Env env, const Stmt_Defer stmt) { return scan2_stmt(env, stmt->stmt); } +ANN static inline bool scan2_stmt_using(const restrict Env env, + const Stmt_Using stmt) { + if(stmt->alias.sym) + CHECK_B(scan2_exp(env, stmt->d.exp)); + mp_vector_add(env->gwion->mp, &env->curr->info->using, Stmt_Using, stmt); + return true; +} + #define scan2_stmt_spread dummy_func DECL_STMT_FUNC(scan2, bool, Env) @@ -271,12 +279,17 @@ ANN static bool scan2_stmt(const Env env, Stmt* stmt) { ANN static bool scan2_stmt_list(const Env env, Stmt_List l) { bool ok = true; + const uint32_t nusing = env->curr->info->using + ? env->curr->info->using->len + : 0; for(m_uint i = 0; i < l->len; i++) { Stmt* stmt = mp_vector_at(l, Stmt, i); if(stmt->poison) { ok = false; continue; } if(!scan2_stmt(env, stmt)) POISON_NODE(ok, env, stmt); } + if(env->curr->info->using) + env->curr->info->using->len = nusing; return ok; } diff --git a/src/parse/validate.c b/src/parse/validate.c index e83665d3..cd0226c7 100644 --- a/src/parse/validate.c +++ b/src/parse/validate.c @@ -380,6 +380,9 @@ ANN static bool validate_stmt_defer(Validate *a, Stmt_Defer b) { ANN static bool validate_stmt_spread(Validate *a NUSED, Spread_Def b NUSED) { return true; } + +#define validate_stmt_using dummy_func + DECL_STMT_FUNC(validate, bool, Validate*) ANN static bool validate_stmt(Validate *a, Stmt* b) { if(b->poison) return false; diff --git a/src/sema/sema.c b/src/sema/sema.c index 30ae094a..ecd027d9 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -567,6 +567,8 @@ ANN static bool sema_stmt_spread(Sema *a, Spread_Def b) { return ok; } +#define sema_stmt_using dummy_func + DECL_STMT_FUNC(sema, bool, Sema*) ANN static bool sema_stmt(Sema *a, Stmt* b, bool in_list) { Stmt_List *stmt_list = a->stmt_list; diff --git a/tests/using/using.gw b/tests/using/using.gw new file mode 100644 index 00000000..54c8f28a --- /dev/null +++ b/tests/using/using.gw @@ -0,0 +1,10 @@ +#! [contains] 12 +class Foo { + 12 :=> var static int bar; +} + +12 :=> Foo.bar; +using bar : Foo.bar; + +<<< bar >>>; + diff --git a/tests/using/using2.gw b/tests/using/using2.gw new file mode 100644 index 00000000..4e33b98b --- /dev/null +++ b/tests/using/using2.gw @@ -0,0 +1,10 @@ +#! [contains] 12 +class Foo { + 12 :=> var static int bar; +} + +12 :=> Foo.bar; +using Foo; + +<<< bar >>>; + diff --git a/tests/using/using_extend.gw b/tests/using/using_extend.gw new file mode 100644 index 00000000..73eab3a8 --- /dev/null +++ b/tests/using/using_extend.gw @@ -0,0 +1,12 @@ +#! [contains] foo +class C { + class D { + <<< "foo" >>>; + } +} + +using C; +#!var D d; +class E extends D {}; + +var E e; diff --git a/tests/using/using_known.gw b/tests/using/using_known.gw new file mode 100644 index 00000000..57b42cb0 --- /dev/null +++ b/tests/using/using_known.gw @@ -0,0 +1,9 @@ +#! [contains] already defined +class C { + class D {} +} +class D {} + +using C : D; + + diff --git a/tests/using/using_known2.gw b/tests/using/using_known2.gw new file mode 100644 index 00000000..4a300bca --- /dev/null +++ b/tests/using/using_known2.gw @@ -0,0 +1,11 @@ +#! [contains] from this `using` statement +class C { + class D { + } +} + +class D {} + +using C; + + diff --git a/tests/using/using_not_type.gw b/tests/using/using_not_type.gw new file mode 100644 index 00000000..a6b903ef --- /dev/null +++ b/tests/using/using_not_type.gw @@ -0,0 +1,8 @@ +#! [contains] found an alias +class C { + var static int i; +} + +using i : C.i; + +var i j; diff --git a/tests/using/using_scoping.gw b/tests/using/using_scoping.gw new file mode 100644 index 00000000..96a0b721 --- /dev/null +++ b/tests/using/using_scoping.gw @@ -0,0 +1,11 @@ +#! [contains] not legit +class C { + var static int testUsingScoping; +} + +fun void test() { + using C; + <<< testUsingScoping >>>; +} + +<<< testUsingScoping >>>; diff --git a/tests/using/using_simple_alias.gw b/tests/using/using_simple_alias.gw new file mode 100644 index 00000000..f74aa0d6 --- /dev/null +++ b/tests/using/using_simple_alias.gw @@ -0,0 +1,13 @@ +#! [contains] Foo.Bar ctor +class Foo { + class Bar { + <<< "Foo.Bar ctor" >>>; + var int i; + } +} + +using Bar : Foo.Bar; + +var Bar bar; + +<<< bar.i >>>;