]> Nishi Git Mirror - gwion.git/commitdiff
:art: using statement
authorfennecdjay <fennecdjay@gmail.com>
Thu, 16 May 2024 04:15:22 +0000 (06:15 +0200)
committerfennecdjay <fennecdjay@gmail.com>
Thu, 16 May 2024 04:15:22 +0000 (06:15 +0200)
22 files changed:
ast
fmt
include/env/nspc.h
include/parse.h
src/clean.c
src/emit/emit.c
src/env/env_utils.c
src/env/nspc.c
src/parse/check.c
src/parse/scan0.c
src/parse/scan1.c
src/parse/scan2.c
src/parse/validate.c
src/sema/sema.c
tests/using/using.gw [new file with mode: 0644]
tests/using/using2.gw [new file with mode: 0644]
tests/using/using_extend.gw [new file with mode: 0644]
tests/using/using_known.gw [new file with mode: 0644]
tests/using/using_known2.gw [new file with mode: 0644]
tests/using/using_not_type.gw [new file with mode: 0644]
tests/using/using_scoping.gw [new file with mode: 0644]
tests/using/using_simple_alias.gw [new file with mode: 0644]

diff --git a/ast b/ast
index ecdd2a8aabed7f730f7ef06cc32d48a2c431134f..4a237db7d547d5b132ffcdb4489ed67126e67e69 160000 (submodule)
--- a/ast
+++ b/ast
@@ -1 +1 @@
-Subproject commit ecdd2a8aabed7f730f7ef06cc32d48a2c431134f
+Subproject commit 4a237db7d547d5b132ffcdb4489ed67126e67e69
diff --git a/fmt b/fmt
index 4287d6bba515c6d9a304341f43a759352778ce68..01aa72eaba624e348de046ab573f498861e2103f 160000 (submodule)
--- a/fmt
+++ b/fmt
@@ -1 +1 @@
-Subproject commit 4287d6bba515c6d9a304341f43a759352778ce68
+Subproject commit 01aa72eaba624e348de046ab573f498861e2103f
index a02c3ea2942816cb02856226142b2e8709e2ca24..3a7f7abc2eb69319b1cb617d7071cdb6f5ce4d17 100644 (file)
@@ -5,6 +5,7 @@ typedef struct NspcInfo_ {
   Scope          type;
   Scope          func;
   Scope          trait;
+  MP_Vector *using;
 } NspcInfo;
 
 typedef struct NspcOp_ {
index 6a66929e7676e7290f31302503449b8aae114bcf..a8b8d65050df7812ab7e3171b73d47c887c03249 100644 (file)
 
 #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;
 
index d5905c34b854046411f9c89b99b0559a35df9150..6ba7155151024f76c2fb9dca2c8da969cf18c336 100644 (file)
@@ -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);
index b4564bb3c3b505e03b6d9f5723335ff20d74026c..947b10dcae2e8889a335727c61d5ba64e1edc28c 100644 (file)
@@ -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);
 
index a328dc44989c4b35a395bd60d9ee0fab0f1d0a55..92cf65f15b670698bc55b1ab9ad63fedebb4b8fb 100644 (file)
@@ -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;
 
   }
index ff96d59628692726714371f0a69241cf287b70ac..6bf4c684f3aa46b2af6008ec9d697abd5c2782f9 100644 (file)
@@ -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);
index dd307a037a148c9484bb9ce0847143f70274005d..2a412d44710d4887da8f94d3d1d70ddeb25fe6f1 100644 (file)
@@ -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;
 }
 
index 5a52787fc8e02fc887e19d541950204f97772b84..231251eb1c2b38c4988828169e438cd8f0117b75 100644 (file)
@@ -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;
 }
 
index 6f57bdaf65f0672f983ef65f7da9e0f0a2e4cf79..f54912e87301b764ef42b66b6da82b4b40a0f19c 100644 (file)
@@ -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;
 }
index dcf6c5d992e57b983d011bdc3e63f46fa6f40652..fb318edfedf9b3b360ec65925dfe10c53bffc1f6 100644 (file)
@@ -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;
 }
 
index e83665d3334599f82775a0f4b544c223491d7718..cd0226c7e1fadf77434faea787f3e5a90f20a85e 100644 (file)
@@ -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;
index 30ae094a192ca9fab3805ba539142c45491c2621..ecd027d9d9c988f668e4ae58b6f02fae230ff1e4 100644 (file)
@@ -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 (file)
index 0000000..54c8f28
--- /dev/null
@@ -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 (file)
index 0000000..4e33b98
--- /dev/null
@@ -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 (file)
index 0000000..73eab3a
--- /dev/null
@@ -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 (file)
index 0000000..57b42cb
--- /dev/null
@@ -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 (file)
index 0000000..4a300bc
--- /dev/null
@@ -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 (file)
index 0000000..a6b903e
--- /dev/null
@@ -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 (file)
index 0000000..96a0b72
--- /dev/null
@@ -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 (file)
index 0000000..f74aa0d
--- /dev/null
@@ -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 >>>;