Skip to content

Commit

Permalink
🎨 using statement
Browse files Browse the repository at this point in the history
  • Loading branch information
fennecdjay committed May 16, 2024
1 parent 9dad0ff commit 0a48a24
Show file tree
Hide file tree
Showing 22 changed files with 224 additions and 13 deletions.
2 changes: 1 addition & 1 deletion ast
2 changes: 1 addition & 1 deletion fmt
Submodule fmt updated 1 files
+13 −0 src/lint.c
1 change: 1 addition & 0 deletions include/env/nspc.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ typedef struct NspcInfo_ {
Scope type;
Scope func;
Scope trait;
MP_Vector *using;
} NspcInfo;

typedef struct NspcOp_ {
Expand Down
5 changes: 5 additions & 0 deletions include/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions src/clean.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/emit/emit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
31 changes: 21 additions & 10 deletions src/env/env_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}
Expand Down
2 changes: 2 additions & 0 deletions src/env/nspc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
61 changes: 61 additions & 0 deletions src/parse/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -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."),
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
9 changes: 9 additions & 0 deletions src/parse/scan0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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;
}

Expand Down
18 changes: 17 additions & 1 deletion src/parse/scan1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;}
Expand All @@ -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;
}
Expand Down
13 changes: 13 additions & 0 deletions src/parse/scan2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions src/parse/validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/sema/sema.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions tests/using/using.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#! [contains] 12
class Foo {
12 :=> var static int bar;
}

12 :=> Foo.bar;
using bar : Foo.bar;

<<< bar >>>;

10 changes: 10 additions & 0 deletions tests/using/using2.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#! [contains] 12
class Foo {
12 :=> var static int bar;
}

12 :=> Foo.bar;
using Foo;

<<< bar >>>;

12 changes: 12 additions & 0 deletions tests/using/using_extend.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#! [contains] foo
class C {
class D {
<<< "foo" >>>;
}
}

using C;
#!var D d;
class E extends D {};

var E e;
9 changes: 9 additions & 0 deletions tests/using/using_known.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#! [contains] already defined
class C {
class D {}
}
class D {}

using C : D;


11 changes: 11 additions & 0 deletions tests/using/using_known2.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#! [contains] from this `using` statement
class C {
class D {
}
}

class D {}

using C;


8 changes: 8 additions & 0 deletions tests/using/using_not_type.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#! [contains] found an alias
class C {
var static int i;
}

using i : C.i;

var i j;
11 changes: 11 additions & 0 deletions tests/using/using_scoping.gw
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#! [contains] not legit
class C {
var static int testUsingScoping;
}

fun void test() {
using C;
<<< testUsingScoping >>>;
}

<<< testUsingScoping >>>;
Loading

0 comments on commit 0a48a24

Please sign in to comment.