// foreachloop static inline void _vm_foreachloop(struct a2_vm* vm_p){ struct a2_obj* _k = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); struct a2_obj* _v = callinfo_sfreg(curr_ci, ir_ga(curr_ir)+1); struct a2_obj* _c = callinfo_sfreg(curr_ci, ir_ga(curr_ir)+2); struct a2_obj* __v = NULL; if(obj_t(_c)!=A2_TMAP && obj_t(_c)!=A2_TARRAY) vm_error("the varable is not map or array."); // dump next switch(obj_t(_c)){ case A2_TMAP: __v = a2_map_next(a2_gcobj2map(obj_vX(_c, obj)), _k); if(__v==NULL) curr_pc++; else{ *_v = *__v; jump(ir_gbx(curr_ir)); } break; case A2_TARRAY: __v = a2_array_next(a2_gcobj2array(obj_vX(_c, obj)), _k); if(__v==NULL) // dump is end curr_pc++; else{ *_v = *__v; jump(ir_gbx(curr_ir)); } break; default: assert(0); } }
// set value static inline void _vm_setvalue(struct a2_vm* vm_p){ struct a2_obj* _c = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); struct a2_obj* _k = _getvalue(vm_p, ir_gb(curr_ir)); struct a2_obj* _v = _getvalue(vm_p, ir_gc(curr_ir)); struct a2_obj* __d = NULL; switch(obj_t(_c)){ case A2_TARRAY: if(obj_t(_k)!=A2_TNUMBER) vm_error("the key is must number at set array."); __d = a2_array_get(a2_gcobj2array(obj_vX(_c, obj)), _k); if(!__d) goto SVALUE_ERROR; *__d = *_v; break; case A2_TMAP: if(obj_t(_k)!=A2_TNUMBER && obj_t(_k)!=A2_TSTRING) vm_error("the key is must number or string at set map."); __d = a2_map_query(a2_gcobj2map(obj_vX(_c, obj)), _k); if(!__d) goto SVALUE_ERROR; *__d = *_v; break; default: vm_error("the varable is not map or array."); } curr_pc++; return; SVALUE_ERROR: vm_error("the key is overfllow."); }
A2_API void a2_setmeta(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* m = a2_getcstack(state->env_p, top); struct a2_obj* v = a2_getcstack(state->env_p, top-1); if(obj_t(v)!=A2_TMAP || obj_t(m)!=A2_TMAP) a2_err(state, "the value and meta should map type."); a2_gc_setmeta(obj_vX(v, obj), obj_vX(m, obj)); a2_topset(state, top-1); }
A2_API inline void* a2_topoint(struct a2_state* state, int idx){ struct a2_obj* obj = a2_getcstack(state->env_p, idx); switch(obj_t(obj)){ case A2_TARRAY: return a2_gcobj2array(obj_vX(obj, obj)); case A2_TMAP: return a2_gcobj2map(obj_vX(obj, obj)); case A2_TCLOSURE: return a2_gcobj2closure(obj_vX(obj, obj)); default: return NULL; } }
// test static inline void _vm_test(struct a2_vm* vm_p){ struct a2_obj* _v = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); if(obj_t(_v)==A2_TNIL || (obj_t(_v)==A2_TBOOL && !(obj_vX(_v, uinteger)))) jump(ir_gbx(curr_ir)); else curr_pc++; }
// mark closure static inline void _gc_mark_closure(struct a2_gc* gc_p, struct a2_gcobj* gcobj, enum gc_mark m){ assert(gcobj->type == A2_TCLOSURE); if(mask(gcobj->mark) == mask(m)) return; gcobj->mark = m; size_t i; struct a2_closure* cls = a2_gcobj2closure(gcobj); // mark upvalue for(i=0; i<cls->uv_size; i++){ if(cls->uv_chain[i].type == uv_gc){ cls->uv_chain[i].v.uv_obj->mark = m; assert(cls->uv_chain[i].v.uv_obj->type == _A2_TUPVALUE); a2_gc_markit(gc_p, cls->uv_chain[i].v.uv_obj->value.uv, m); } } // mark const varable for(i=0; i<cls->xcls_p->c_stack.top; i++){ if(obj_t(&(cls->xcls_p->c_stack.stk_p[i])) == A2_TSTRING){ obj_vX(&(cls->xcls_p->c_stack.stk_p[i]), obj)->mark = m; } } }
A2_API inline a2_cfunction a2_tocfunction(struct a2_state* state, int idx){ struct a2_obj* obj = a2_getcstack(state->env_p, idx); if(obj_t(obj)!=A2_TCFUNCTION) return NULL; else return obj_vX(obj, cfunction); }
void a2_gc_markit(struct a2_gc* gc_p, struct a2_obj* obj, enum gc_mark m){ switch(obj_t(obj)){ case A2_TARRAY: _gc_mark_array(gc_p, obj_vX(obj, obj), m); break; case A2_TMAP: _gc_mark_map(gc_p, obj_vX(obj, obj), m); break; case A2_TSTRING: obj_vX(obj, obj)->mark = m; break; case A2_TCLOSURE: _gc_mark_closure(gc_p, obj_vX(obj, obj), m); break; } }
A2_API inline char* a2_tostring(struct a2_state* state, int idx){ struct a2_obj* obj = a2_getcstack(state->env_p, idx); if(obj_t(obj)!=A2_TSTRING) return ""; else return a2_gcobj2string(obj_vX(obj, obj)); }
// call a2 function static inline void __vm_call_function(struct a2_vm* vm_p, struct a2_obj* _func){ assert(obj_t(_func)==A2_TCLOSURE); struct a2_obj* _obj = NULL; int i, j, params = a2_closure_params(a2_gcobj2closure(obj_vX(_func, obj))); struct a2_array* _args = NULL; struct vm_callinfo* _ci = curr_ci; ir _ir = curr_ir; // new call info int b = ir_ga(curr_ir), n=ir_gc(curr_ir); callinfo_new(vm_p, a2_gcobj2closure(obj_vX(_func, obj)), b, n); // jump call _ci->pc++; // if is mutableargs if(params<0){ params = -1 - params; _obj = callinfo_sfreg(curr_ci, params); if(ir_gb(_ir)>params){ // set _args list _args = a2_array_new(); struct a2_gcobj* _array_gcobj = a2_array2gcobj(_args); a2_gcadd(vm_p->env_p, _array_gcobj); obj_setX(_obj, A2_TARRAY, obj, _array_gcobj); }else{ obj_setX(_obj, A2_TNIL, point, NULL); } } // set params for(i=ir_ga(_ir)+1, j=0; i<=ir_ga(_ir)+ir_gb(_ir) && j<params; j++, i++){ _obj = callinfo_sfreg(curr_ci, j); *_obj = *callinfo_sfreg(_ci, i); } // set clear params for( ;j<params; j++){ _obj = callinfo_sfreg(curr_ci, j); obj_setX(_obj, A2_TNIL, point, NULL); } // if mutable args for(j=0; i<=ir_ga(_ir)+ir_gb(_ir) && _args; i++, j++){ a2_array_add(_args, callinfo_sfreg(_ci, i)); } }
// add array A2_API inline void a2_addarray(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* v = a2_getcstack(state->env_p, top); struct a2_obj* array = a2_getcstack(state->env_p, top-1); check_array(array); a2_array_add(a2_gcobj2array(obj_vX(array, obj)), v); }
A2_API inline int a2_tobool(struct a2_state* state, int idx){ struct a2_obj* obj = a2_getcstack(state->env_p, idx); if(obj_t(obj)!=A2_TBOOL) a2_error(state->env_p, e_run_error, "the type is not bool."); else return (int)(obj_vX(obj, uinteger)); return 0; }
//set list static inline void _vm_setlist(struct a2_vm* vm_p){ int i, end=ir_gb(curr_ir)+ir_gc(curr_ir); struct a2_obj* _d = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); assert(obj_t(_d)==A2_TARRAY); for(i=ir_gb(curr_ir); i<end; i++){ a2_array_add(a2_gcobj2array(obj_vX(_d, obj)), callinfo_sfreg(curr_ci, i)); } curr_pc++; }
// get data size from a2_obj size_t a2_obj_size(struct a2_obj* obj_p){ assert(obj_p); switch(obj_t(obj_p)){ case A2_TSTRING: return a2_string_len(a2_gcobj2string(obj_vX(obj_p, obj))); case A2_TNUMBER: return sizeof(a2_number); case A2_TNIL: return 0; case A2_TBOOL: return sizeof(obj_vX(obj_p, uinteger)); case _A2_TADDR: return sizeof(obj_vX(obj_p, addr)); default: assert(0); return 0; } }
byte* a2_obj_bytes(struct a2_obj* obj_p){ assert(obj_p); switch(obj_t(obj_p)){ case A2_TSTRING: return (byte*)(a2_gcobj2string(obj_vX(obj_p, obj))); case A2_TNUMBER: return (byte*)(&obj_vNum(obj_p)); case A2_TNIL: return NULL; case A2_TBOOL: return (byte*)(&obj_vX(obj_p, uinteger)); case _A2_TADDR: return (byte*)(&obj_vX(obj_p, addr)); default: assert(0); return NULL; } }
// del key/value A2_API inline void a2_delmap(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* k = a2_getcstack(state->env_p, top); struct a2_obj* map = a2_getcstack(state->env_p, top-1); check_map(map); check_key(k); a2_map_del(a2_gcobj2map(obj_vX(map, obj)), k); a2_pop(state, 1); }
A2_API inline void a2_len(struct a2_state* state, int idx){ struct a2_obj* obj = a2_getcstack(state->env_p, idx); size_t len =0; struct a2_obj len_obj; switch(obj_t(obj)){ case A2_TMAP: len = a2_map_len(a2_gcobj2map(obj_vX(obj, obj))); break; case A2_TARRAY: len = a2_array_len(a2_gcobj2array(obj_vX(obj, obj))); break; case A2_TSTRING: len = a2_string_len(a2_gcobj2string(obj_vX(obj, obj))); break; default: a2_error(state->env_p, e_run_error, "the type is not map or array at len function."); } len_obj = a2_number2obj((a2_number)len); a2_pushstack(state->env_p, &len_obj); }
inline char* obj2str(struct a2_obj* obj, char* buf, size_t len){ assert(obj); switch(obj_t(obj)){ case A2_TNUMBER: snprintf(buf, len, "%.14g", obj_vNum(obj)); return buf; case A2_TSTRING: return a2_gcobj2string(obj_vX(obj, obj)); case A2_TBOOL: snprintf(buf, len, "%s", (obj_vX(obj, uinteger))?("true"):("false")); return buf; case A2_TNIL: return "nil"; case _A2_TADDR: _sf(buf, len, "[%zd]", obj_vX(obj, addr)); return buf; case A2_TCLOSURE: snprintf(buf, len, "closure:%p", a2_gcobj2closure(obj_vX(obj, obj))); return buf; case A2_TARRAY: snprintf(buf, len, "array:%p", a2_gcobj2array(obj_vX(obj, obj))); return buf; case A2_TMAP: snprintf(buf, len, "map:%p", a2_gcobj2map(obj_vX(obj, obj))); return buf; default: assert(0); } return NULL; }
// test obj dump void obj_dump(struct a2_obj* obj){ switch(obj_t(obj)){ case A2_TSTRING: printf("%s", a2_gcobj2string(obj_vX(obj, obj))); break; case A2_TNUMBER: printf("%.14g", obj_vNum(obj)); break; default: printf("<null>"); break; } }
// get array A2_API inline void a2_getarray(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* k = a2_getcstack(state->env_p, top); struct a2_obj* array = a2_getcstack(state->env_p, top-1); struct a2_obj* _v = NULL; check_array(array); check_num(k); _v = a2_array_get(a2_gcobj2array(obj_vX(array, obj)), k); if(_v==NULL) obj_setX(k, A2_TNIL, point, NULL); else *k = *_v; }
// get map A2_API inline void a2_getmap(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* k = a2_getcstack(state->env_p, top); struct a2_obj* map = a2_getcstack(state->env_p, top-1); struct a2_obj* v = NULL; check_map(map); check_key(k); v = a2_map_query(a2_gcobj2map(obj_vX(map, obj)), k); if(v==NULL) obj_setX(map, A2_TNIL, point, NULL); else *map = *v; }
// set array A2_API inline void a2_setarray(struct a2_state* state){ int top = a2_top(state)-1; struct a2_obj* v = a2_getcstack(state->env_p, top); struct a2_obj* k = a2_getcstack(state->env_p, top-1); struct a2_obj* array = a2_getcstack(state->env_p, top-2); struct a2_obj* _v = NULL; check_array(array); check_num(k); _v = a2_array_get(a2_gcobj2array(obj_vX(array, obj)), k); if(_v==NULL) a2_error(state->env_p, e_run_error, "the error index at array.\n"); else *_v = *v; a2_topset(state, top-1); }
// not static inline void _vm_not(struct a2_vm* vm_p){ struct a2_obj* _d = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); struct a2_obj* _v = _getvalue(vm_p, ir_gbx(curr_ir)); switch(obj_t(_v)){ case A2_TNIL: *_d = a2_bool2obj(1); break; case A2_TBOOL: *_d = a2_bool2obj(!(obj_vX(_v, uinteger))); break; default: vm_error("the varable is not bool type."); } curr_pc++; }
//set map static inline void _vm_setmap(struct a2_vm* vm_p){ int i, end=ir_gb(curr_ir)+2*ir_gc(curr_ir); struct a2_obj* _d = callinfo_sfreg(curr_ci, ir_ga(curr_ir)); struct a2_obj* _v = NULL; struct a2_map* map = NULL; assert(obj_t(_d)==A2_TMAP); struct a2_kv kv={0}; for(i=ir_gb(curr_ir); i<end; i+=2){ kv.key = callinfo_sfreg(curr_ci, i); kv.vp = callinfo_sfreg(curr_ci, i+1); map = a2_gcobj2map(obj_vX(_d, obj)); if( (_v=a2_map_query(map, kv.key))==NULL ) a2_map_add(map, &kv); else *_v = *kv.vp; } curr_pc++; }
A2_API inline void a2_require(struct a2_state* state){ struct a2_obj* k = a2_getcstack(state->env_p, a2_top(state)-1); check_key(k); struct a2_obj* v = a2_get_envreg(state->env_p, k); if(v) // return obj a2_pushstack(state->env_p, v); else{ // load obj const char* name = a2_gcobj2string(obj_vX(k, obj)); int len = strlen(name); char tmp[len+8]; memcpy(tmp, name, len); memcpy(tmp+len, ".a2", 4); int top = a2_top(state); a2_loadfile(state, tmp); if(a2_top(state)>top) a2_pushvalue(state, top); else a2_pushnil(state); a2_set_envreg(state->env_p, k, a2_getcstack(state->env_p, top)); } }
// call c function static inline void __vm_call_cfunction(struct a2_vm* vm_p, struct a2_obj* _func){ assert(obj_t(_func)==A2_TCFUNCTION); int i, j; struct a2_obj* _obj = NULL; // back bottom int _b = a2_getbottom(vm_p->env_p); int _top = a2_gettop(vm_p->env_p); a2_setbottom(vm_p->env_p, a2_gettop(vm_p->env_p)); // closure arg to cstack for(i=ir_ga(curr_ir)+1; i<=ir_ga(curr_ir)+ir_gb(curr_ir); i++){ _obj = callinfo_sfreg(curr_ci, i); a2_pushstack(vm_p->env_p, _obj); } // call c function callinfo_new(vm_p, NULL, 0, 0); int ret = obj_vX(_func, cfunction)(a2_env2state(vm_p->env_p)); callinfo_free(vm_p); int size = a2_gettop(vm_p->env_p)-a2_getbottom(vm_p->env_p); // set return value for(i=size-ret, j=ir_ga(curr_ir); i<size && j<ir_ga(curr_ir)+ir_gc(curr_ir); j++,i++){ _obj = callinfo_sfreg(curr_ci, j); *_obj = *a2_getcstack(vm_p->env_p, i); } for(; j<ir_ga(curr_ir)+ir_gc(curr_ir); j++){ _obj = callinfo_sfreg(curr_ci, j); obj_setX(_obj, A2_TNIL, point, NULL); } a2_setbottom(vm_p->env_p, _b); a2_settop(vm_p->env_p, _top); curr_pc++; }
int a2_vm_pcall(struct a2_vm* vm_p, struct a2_obj* cls_obj, struct a2_obj* args_obj, int args){ assert(obj_t(cls_obj) == A2_TCLOSURE); struct a2_closure* cls = a2_gcobj2closure(obj_vX(cls_obj, obj)); callinfo_new(vm_p, NULL, 0, 0); callinfo_new(vm_p, cls, 0, 0); // set arg int i, j; for(i=0, j=0; i<args && j<curr_ci->reg_stack.len; j++, i++){ *callinfo_sfreg(curr_ci, j) = args_obj[i]; } // set clear for(; j<curr_ci->reg_stack.len; j++){ *callinfo_sfreg(curr_ci, j) = a2_nil2obj(); } int ret = _vm_prun(vm_p); callinfo_free(vm_p); return ret; }