1 |
|
|
#include <stdlib.h> |
2 |
|
|
#include <string.h> |
3 |
|
|
#include "gwion_util.h" |
4 |
|
|
#include "gwion_ast.h" |
5 |
|
|
#include "gwion_env.h" |
6 |
|
|
#include "vm.h" |
7 |
|
|
#include "gwion.h" |
8 |
|
|
#include "instr.h" |
9 |
|
|
#include "object.h" |
10 |
|
|
#include "operator.h" |
11 |
|
|
#include "import.h" |
12 |
|
|
#include "emit.h" |
13 |
|
|
#include "traverse.h" |
14 |
|
|
#include "parse.h" |
15 |
|
|
#include "gwi.h" |
16 |
|
|
|
17 |
|
8 |
static m_bool ptr_access(const Env env, const Exp e) { |
18 |
|
8 |
const m_str access = exp_access(e); |
19 |
✓✓ |
8 |
if(!access) |
20 |
|
6 |
return GW_OK; |
21 |
|
2 |
ERR_B(e->pos, _("operand is %s"), access); |
22 |
|
|
} |
23 |
|
|
|
24 |
|
5 |
static OP_CHECK(opck_ptr_assign) { |
25 |
|
5 |
const Exp_Binary* bin = (Exp_Binary*)data; |
26 |
✓✓ |
5 |
CHECK_BO(ptr_access(env, bin->lhs)) |
27 |
✗✓ |
3 |
CHECK_BO(ptr_access(env, bin->rhs)) |
28 |
|
3 |
exp_setvar(bin->lhs, 1); |
29 |
|
3 |
Type t = bin->lhs->info->type; |
30 |
|
|
do { |
31 |
|
|
// t = unflag_type(t); |
32 |
|
7 |
Type u = bin->rhs->info->type; |
33 |
|
|
do { |
34 |
|
|
// u = unflag_type(u); |
35 |
|
22 |
const m_str str = get_type_name(env, u, 1); |
36 |
✓✓✓✓
|
22 |
if(str && !strcmp(t->name, str)) |
37 |
|
2 |
return bin->lhs->info->type; // use rhs? |
38 |
✓✓ |
20 |
} while((u = u->e->parent)); |
39 |
✓✓ |
5 |
} while((t = t->e->parent)); |
40 |
|
1 |
return env->gwion->type[et_null]; |
41 |
|
|
} |
42 |
|
|
|
43 |
|
2 |
static INSTR(instr_ptr_assign) { |
44 |
|
2 |
POP_REG(shred, SZ_INT) |
45 |
|
2 |
const M_Object o = *(M_Object*)REG(0); |
46 |
|
2 |
*(m_uint**)o->data = *(m_uint**)REG(-SZ_INT); |
47 |
|
2 |
_release(o, shred); |
48 |
|
2 |
} |
49 |
|
|
|
50 |
|
6 |
static OP_CHECK(opck_ptr_deref) { |
51 |
|
6 |
const Exp_Unary* unary = (Exp_Unary*)data; |
52 |
✗✓ |
6 |
DECL_ON(const m_str, str, = get_type_name(env, unary->exp->info->type, 1)) |
53 |
|
6 |
return exp_self(unary)->info->type = nspc_lookup_type1(env->curr, insert_symbol(str)); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
2 |
static OP_CHECK(opck_ptr_cast) { |
57 |
|
2 |
const Exp_Cast* cast = (Exp_Cast*)data; |
58 |
✓✗✗✓
|
2 |
if(!cast->td->types || !cast->td->types->td) |
59 |
|
|
ERR_N(exp_self(cast)->pos, "'Ptr' needs types to cast") |
60 |
✗✓ |
2 |
DECL_ON(const Type, t, = known_type(env, cast->td)) |
61 |
|
2 |
const Type _t = get_type(t); |
62 |
✓✗✓✗
|
2 |
if(_t->e->def && !GET_FLAG(_t, check)) |
63 |
✗✓ |
2 |
CHECK_BN(ensure_traverse(env, _t)) |
64 |
|
2 |
const Type to = known_type(env, cast->td->types->td); |
65 |
✓✓ |
2 |
if(isa(cast->exp->info->type, to) > 0) |
66 |
|
1 |
return t; |
67 |
|
1 |
ERR_N(exp_self(cast)->pos, "invalid pointer cast") |
68 |
|
|
} |
69 |
|
|
|
70 |
|
3 |
static OP_CHECK(opck_ptr_implicit) { |
71 |
|
3 |
const struct Implicit* imp = (struct Implicit*)data; |
72 |
|
3 |
const Exp e = imp->e; |
73 |
✗✓ |
3 |
DECL_OO(const m_str, name, = get_type_name(env, imp->t, 1)) |
74 |
✓✗ |
3 |
if(!strcmp(get_type_name(env, imp->t, 1), e->info->type->name)) { |
75 |
|
3 |
const m_str access = exp_access(e); |
76 |
✓✓ |
3 |
if(access) |
77 |
|
2 |
ERR_N(e->pos, _("can't cast %s value to Ptr"), access); |
78 |
|
1 |
e->info->cast_to = imp->t; |
79 |
|
1 |
exp_setvar(e, 1); |
80 |
|
1 |
const Type t = get_type(imp->t); |
81 |
✓✗ |
1 |
if(!GET_FLAG(t, check)) |
82 |
✗✓ |
1 |
CHECK_BN(traverse_class_def(env, t->e->def)) |
83 |
|
1 |
return imp->t; |
84 |
|
|
} |
85 |
|
|
return NULL; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
8 |
static INSTR(instr_ptr_deref) { |
89 |
|
8 |
const M_Object o = *(M_Object*)REG(-SZ_INT); |
90 |
✓✓ |
8 |
if(!*(m_bit**)o->data) |
91 |
|
1 |
Except(shred, _("EmptyPointerException")); |
92 |
✓✓ |
7 |
if(instr->m_val2) |
93 |
|
1 |
memcpy(REG(-SZ_INT), o->data, SZ_INT); |
94 |
|
|
else { |
95 |
|
6 |
shred->reg -= SZ_INT - instr->m_val; |
96 |
|
6 |
memcpy(REG(-instr->m_val), *(m_bit**)o->data, instr->m_val); |
97 |
|
|
} |
98 |
|
|
} |
99 |
|
|
|
100 |
|
2 |
static INSTR(Cast2Ptr) { |
101 |
|
2 |
const M_Object o = new_object(shred->info->mp, shred, (Type)instr->m_val); |
102 |
|
2 |
*(m_uint**)o->data = *(m_uint**)REG(-SZ_INT); |
103 |
|
2 |
*(M_Object*)REG(-SZ_INT) = o; |
104 |
|
2 |
} |
105 |
|
|
|
106 |
|
1 |
static OP_EMIT(opem_ptr_cast) { |
107 |
|
1 |
const Exp_Cast* cast = (Exp_Cast*)data; |
108 |
|
1 |
const Instr instr = emit_add_instr(emit, Cast2Ptr); |
109 |
|
1 |
instr->m_val = (m_uint)exp_self(cast)->info->type; |
110 |
|
1 |
return instr; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
1 |
static OP_EMIT(opem_ptr_implicit) { |
114 |
|
1 |
const struct Implicit* imp = (struct Implicit*)data; |
115 |
|
1 |
const Instr instr = emit_add_instr(emit, Cast2Ptr); |
116 |
|
1 |
instr->m_val = (m_uint)imp->t; |
117 |
|
1 |
return instr; |
118 |
|
|
} |
119 |
|
|
|
120 |
|
5 |
static OP_EMIT(opem_ptr_deref) { |
121 |
|
5 |
const Exp_Unary* unary = (Exp_Unary*)data; |
122 |
|
5 |
const Instr instr = emit_add_instr(emit, instr_ptr_deref); |
123 |
|
5 |
instr->m_val = exp_self(unary)->info->type->size; |
124 |
|
5 |
instr->m_val2 = exp_getvar(exp_self(unary)); |
125 |
|
5 |
return instr; |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
ANN Type scan_class(const Env env, const Type t, const Type_Decl* td); |
129 |
|
|
|
130 |
|
1 |
static DTOR(ptr_object_dtor) { |
131 |
|
1 |
release(*(M_Object*)o->data, shred); |
132 |
|
1 |
} |
133 |
|
|
|
134 |
|
|
static DTOR(ptr_struct_dtor) { |
135 |
|
|
const Type t = (Type)vector_front(&o->type_ref->e->tuple->types); |
136 |
|
|
struct_release(shred, t, *(m_bit**)o->data); |
137 |
|
|
} |
138 |
|
|
|
139 |
|
17 |
static OP_CHECK(opck_ptr_scan) { |
140 |
|
17 |
struct TemplateScan *ts = (struct TemplateScan*)data; |
141 |
|
17 |
const Type t = (Type)scan_class(env, ts->t, ts->td); |
142 |
|
17 |
const Type base = known_type(env, t->e->def->base.tmpl->call->td); |
143 |
✓✓✓✓
|
17 |
if(isa(base, env->gwion->type[et_compound]) > 0 && !t->nspc->dtor) { |
144 |
|
4 |
t->nspc->dtor = new_vm_code(env->gwion->mp, NULL, SZ_INT, ae_flag_member | ae_flag_builtin, "@PtrDtor"); |
145 |
✓✗ |
4 |
if(!GET_FLAG(t, struct)) |
146 |
|
4 |
t->nspc->dtor->native_func = (m_uint)ptr_object_dtor; |
147 |
|
|
else |
148 |
|
|
t->nspc->dtor->native_func = (m_uint)ptr_struct_dtor; |
149 |
|
4 |
SET_FLAG(t, dtor); |
150 |
|
|
} |
151 |
|
17 |
return t; |
152 |
|
|
} |
153 |
|
|
|
154 |
|
711 |
GWION_IMPORT(ptr) { |
155 |
|
711 |
const Type _t_ptr = gwi_class_ini(gwi, "@Ptr", NULL); |
156 |
|
711 |
GWI_BB(gwi_class_end(gwi)) |
157 |
|
711 |
SET_FLAG(_t_ptr, unary); |
158 |
|
711 |
GWI_BB(gwi_oper_ini(gwi, "@Ptr", NULL, NULL)) |
159 |
|
711 |
GWI_BB(gwi_oper_add(gwi, opck_ptr_scan)) |
160 |
|
711 |
GWI_BB(gwi_oper_end(gwi, "@scan", NULL)) |
161 |
|
711 |
const Type t_ptr = gwi_class_ini(gwi, "Ptr<~A~>", "@Ptr"); |
162 |
|
711 |
gwi->gwion->type[et_ptr] = t_ptr; |
163 |
|
711 |
GWI_BB(gwi_item_ini(gwi, "@internal", "@val")) |
164 |
|
711 |
GWI_BB(gwi_item_end(gwi, 0, NULL)) |
165 |
|
711 |
GWI_BB(gwi_class_end(gwi)) |
166 |
|
711 |
SET_FLAG(t_ptr, unary); |
167 |
|
711 |
GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "nonnull Ptr", NULL)) |
168 |
|
711 |
GWI_BB(gwi_oper_add(gwi, opck_ptr_assign)) |
169 |
|
711 |
GWI_BB(gwi_oper_end(gwi, ":=>", instr_ptr_assign)) |
170 |
|
711 |
GWI_BB(gwi_oper_add(gwi, opck_ptr_implicit)) |
171 |
|
711 |
GWI_BB(gwi_oper_emi(gwi, opem_ptr_implicit)) |
172 |
|
711 |
GWI_BB(gwi_oper_end(gwi, "@implicit", Cast2Ptr)) |
173 |
|
711 |
GWI_BB(gwi_oper_add(gwi, opck_ptr_cast)) |
174 |
|
711 |
GWI_BB(gwi_oper_emi(gwi, opem_ptr_cast)) |
175 |
|
711 |
GWI_BB(gwi_oper_end(gwi, "$", Cast2Ptr)) |
176 |
|
711 |
GWI_BB(gwi_oper_ini(gwi, NULL, "nonnull Ptr", NULL)) |
177 |
|
711 |
GWI_BB(gwi_oper_add(gwi, opck_ptr_deref)) |
178 |
|
711 |
GWI_BB(gwi_oper_emi(gwi, opem_ptr_deref)) |
179 |
|
711 |
GWI_BB(gwi_oper_end(gwi, "*", instr_ptr_deref)) |
180 |
|
711 |
return GW_OK; |
181 |
|
|
} |