static size_t _co_tree_change_length(co_obj_t *tree, const int delta) { if(CO_TYPE(tree) == _tree16) { ((co_tree16_t *)tree)->_len += delta; return (size_t)(((co_tree16_t *)tree)->_len); } else if(CO_TYPE(tree) == _tree32) { ((co_tree32_t *)tree)->_len += delta; return (size_t)(((co_tree32_t *)tree)->_len); } ERROR("Not a tree object."); return -1; }
int co_response_get_int(co_obj_t *response, signed long *output, const char *key, const size_t klen) { co_obj_t *obj = co_response_get(response, key, klen); CHECK(obj != NULL, "Response value %s does not exist.", key); switch(CO_TYPE(obj)) { case _int8: *output = (unsigned long)(((co_int8_t *)obj)->data); break; case _int16: *output = (unsigned long)(((co_int16_t *)obj)->data); break; case _int32: *output = (unsigned long)(((co_int32_t *)obj)->data); break; case _int64: *output = (unsigned long)(((co_int64_t *)obj)->data); break; default: SENTINEL("Not an unsigned integer."); break; } return 1; error: return 0; }
size_t co_tree_raw(char *output, const size_t olen, const co_obj_t *tree) { char *out = output; size_t written = 0; switch(CO_TYPE(tree)) { case _tree16: memmove(out, &(tree->_type), sizeof(tree->_type)); out += sizeof(tree->_type); written += sizeof(tree->_type); memmove(out, &(((co_tree16_t *)tree)->_len), sizeof(((co_tree16_t *)tree)->_len)); out += sizeof(((co_tree16_t *)tree)->_len); written += sizeof(((co_tree16_t *)tree)->_len); break; case _tree32: memmove(out, &(tree->_type), sizeof(tree->_type)); out += sizeof(tree->_type); written += sizeof(tree->_type); memmove(out, &(((co_tree32_t *)tree)->_len), sizeof(((co_tree32_t *)tree)->_len)); out += sizeof(((co_tree32_t *)tree)->_len); written += sizeof(((co_tree32_t *)tree)->_len); break; default: SENTINEL("Not a tree object."); break; } _co_tree_raw_r(&out, &olen, &written, co_tree_root(tree)); DEBUG("Tree bytes written: %d", (int)written); return written; error: return -1; }
static int _co_node_set_uint(_treenode_t *n, const unsigned long value) { CHECK(n != NULL, "Invalid node supplied."); switch(CO_TYPE(n->value)) { case _uint8: (((co_uint8_t *)(n->value))->data) = value; break; case _uint16: (((co_uint16_t *)(n->value))->data) = value; break; case _uint32: (((co_uint32_t *)(n->value))->data) = value; break; case _uint64: (((co_uint64_t *)(n->value))->data) = value; break; default: SENTINEL("Specified object is not a unsigned integer."); break; } return 1; error: return 0; }
static int _co_node_set_float(_treenode_t *n, const double value) { CHECK(n != NULL, "Invalid node supplied."); if(CO_TYPE(n->value) == _float32) { (((co_float32_t *)(n->value))->data) = value; } else if(CO_TYPE(n->value) == _float64) { (((co_float64_t *)(n->value))->data) = value; } else ERROR("Specified object is not a floating-point value."); return 1; error: return 0; }
_treenode_t * co_tree_root(const co_obj_t *tree) { CHECK_MEM(tree); _treenode_t *n = NULL; if(CO_TYPE(tree) == _tree16) { n = ((co_tree16_t *)tree)->root; } else if(CO_TYPE(tree) == _tree32) { n = ((co_tree32_t *)tree)->root; } else SENTINEL("Specified object is not a tree."); return n; error: return NULL; }
co_obj_t * co_tree_delete(co_obj_t *root, const char *key, const size_t klen) { co_obj_t *value = NULL; if(CO_TYPE(root) == _tree16) { ((co_tree16_t *)root)->root = _co_tree_delete_r(((co_tree16_t *)root)->root, \ ((co_tree16_t *)root)->root, key, klen, &value); } else if(CO_TYPE(root) == _tree32) { ((co_tree32_t *)root)->root = _co_tree_delete_r(((co_tree32_t *)root)->root, \ ((co_tree32_t *)root)->root, key, klen, &value); } CHECK(value != NULL, "Failed to delete value."); CHECK(_co_tree_decrement(root), "Failed to decrement value."); return value; error: return NULL; }
static int _co_tree_insert(co_obj_t *root, const char *key, const size_t klen, co_obj_t *value) { _treenode_t *n = NULL; if(CO_TYPE(root) == _tree16) { ((co_tree16_t *)root)->root = _co_tree_insert_r(((co_tree16_t *)root)->root, \ ((co_tree16_t *)root)->root, key, klen, key, klen, value); n = ((co_tree16_t *)root)->root; } else if(CO_TYPE(root) == _tree32) { ((co_tree32_t *)root)->root = _co_tree_insert_r(((co_tree32_t *)root)->root, \ ((co_tree32_t *)root)->root, key, klen, key, klen, value); n = ((co_tree32_t *)root)->root; } CHECK(n != NULL, "Failed to insert value."); CHECK(_co_tree_increment(root), "Failed to increment value."); return 1; error: return 0; }
int co_tree_process(co_obj_t *tree, const co_iter_t iter, void *context) { switch(CO_TYPE(tree)) { case _tree16: _co_tree_process_r(tree, ((co_tree16_t *)tree)->root, iter, context); break; case _tree32: _co_tree_process_r(tree, ((co_tree32_t *)tree)->root, iter, context); break; default: SENTINEL("Object is not a tree."); break; } return 1; error: return 0; }
static int _co_node_set_str(_treenode_t *n, const char *value, const size_t vlen) { CHECK(n != NULL, "Invalid node supplied."); CHECK(n->value != NULL, "Invalid node supplied."); switch(CO_TYPE(n->value)) { case _str8: CHECK(vlen <= UINT8_MAX, "Value too large for type str8."); if(vlen != (((co_str8_t *)(n->value))->_len)) { n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str8_t) - 1)); } CHECK_MEM(memmove((((co_str8_t *)(n->value))->data), value, vlen)); (((co_str8_t *)(n->value))->_len) = (uint8_t)vlen; break; case _str16: CHECK(vlen <= UINT16_MAX, "Value too large for type str16."); if(vlen != (((co_str16_t *)(n->value))->_len)) { n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str16_t) - 1)); } CHECK_MEM(memmove((((co_str16_t *)(n->value))->data), value, vlen)); (((co_str16_t *)(n->value))->_len) = (uint16_t)vlen; break; case _str32: CHECK(vlen <= UINT32_MAX, "Value too large for type str32."); if(vlen != (((co_str32_t *)(n->value))->_len)) { n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str32_t) - 1)); } CHECK_MEM(memmove((((co_str32_t *)(n->value))->data), value, vlen)); (((co_str32_t *)(n->value))->_len) = (uint32_t)vlen; break; default: SENTINEL("Specified object is not a string."); break; } return 1; error: return 0; }
int co_response_get_bool(co_obj_t *response, bool *output, const char *key, const size_t klen) { co_obj_t *obj = co_response_get(response, key, klen); CHECK(obj != NULL, "Response value %s does not exist.", key); switch(CO_TYPE(obj)) { case _false: *output = false; break; case _true: *output = true; break; default: SENTINEL("Not a boolean."); break; } return 1; error: return 0; }
/* * Evaluate a function object into a object. */ COObject * vm_eval(COObject *func, COObject *globals) { #define JUMPBY(offset) next_code += offset #define JUMPTO(offset) next_code = first_code + offset #define NEXTOP() (*next_code++) #define NEXTARG() (next_code += 2, (next_code[-1]<<8) + next_code[-2]) #define GETITEM(v, i) COTuple_GET_ITEM((COTupleObject *)(v), i) #define GETLOCAL(i) (fastlocals[i]) #define SETLOCAL(i, v) \ do { \ COObject *tmp = GETLOCAL(i); \ GETLOCAL(i) = v; \ CO_XDECREF(tmp); \ } while (0); #define PUSH(o) (*stack_top++ = (o)) #define POP() (*--stack_top) #define TOP() (stack_top[-1]) #define SET_TOP(o) (stack_top[-1] = (o)) #define SECOND() (stack_top[-2]) #define THIRD() (stack_top[-3]) #define FOURTH() (stack_top[-4]) #define PEEK(n) (stack_top[-(n)]) #define STACK_ADJ(n) (stack_top += n) #define STACK_LEVEL() ((int)(stack_top - TS(frame)->f_stack)) #define UNWIND_BLOCK(b) \ do { \ while (STACK_LEVEL() > (b)->fb_level) { \ COObject *o = POP(); \ CO_XDECREF(o); \ } \ } while (0) COCodeObject *code; COObject *names; COObject *consts; COObject *localnames; COObject *funcargs = COList_New(0); COObject **fastlocals; COObject **stack_top; /* Stack top, points to next free slot in stack */ unsigned char *next_code; unsigned char *first_code; unsigned char opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ COObject *x; /* Result object -- NULL if error */ COObject *o1, *o2, *o3; /* Temporary objects popped of stack */ int status; /* VM status */ int err; /* C function error code */ status = STATUS_NONE; TS(frame) = (COFrameObject *)COFrame_New((COObject *)TS(frame), func, globals); new_frame: /* reentry point when function call/return */ code = (COCodeObject *)((COFunctionObject *)TS(frame)->f_func)->func_code; stack_top = TS(frame)->f_stacktop; names = code->co_names; localnames = code->co_localnames; consts = code->co_consts; first_code = (unsigned char *)COBytes_AsString(code->co_code); next_code = first_code + TS(frame)->f_lasti; fastlocals = TS(frame)->f_extraplus; /* Parse arguments. */ if (COList_GET_SIZE(funcargs)) { // check arguments count if (code->co_argcount != COList_GET_SIZE(funcargs)) { COErr_Format(COException_ValueError, "takes exactly %d arguments (%d given)", code->co_argcount, COList_Size(funcargs)); status = STATUS_EXCEPTION; goto fast_end; } size_t n = COList_Size(funcargs); for (int i = 0; i < n; i++) { x = COList_GetItem(funcargs, 0); CO_INCREF(x); SETLOCAL(n - i - 1, x); COList_DelItem(funcargs, 0); } } for (;;) { opcode = NEXTOP(); switch (opcode) { case OP_BINARY_ADD: o1 = POP(); o2 = TOP(); if (COStr_Check(o1) && COStr_Check(o2)) { COStr_Concat(&o2, o1); x = o2; goto skip_decref_o2; } else { x = COInt_Type.tp_int_interface->int_add(o1, o2); } CO_DECREF(o2); skip_decref_o2: CO_DECREF(o1); SET_TOP(x); if (!x) { status = STATUS_EXCEPTION; goto fast_end; } break; case OP_BINARY_SUB: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_sub(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_MUL: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_mul(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_DIV: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_div(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_MOD: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_mod(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_SL: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_lshift(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_SR: o1 = POP(); o2 = TOP(); x = COInt_Type.tp_int_interface->int_rshift(o2, o1); CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_BINARY_SUBSCRIPT: o1 = POP(); o2 = TOP(); if (!CO_TYPE(o2)->tp_mapping_interface) { COErr_Format(COException_TypeError, "'%.200s' object is not subscriptable", CO_TYPE(o2)->tp_name); status = STATUS_EXCEPTION; } else { x = CO_TYPE(o2)->tp_mapping_interface->mp_subscript(o2, o1); if (!x) { status = STATUS_EXCEPTION; goto fast_end; } } CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_CMP: o1 = POP(); o2 = TOP(); oparg = NEXTARG(); x = vm_cmp(oparg, o1, o2); if (!x) { status = STATUS_EXCEPTION; goto fast_end; } CO_DECREF(o1); CO_DECREF(o2); SET_TOP(x); break; case OP_UNARY_NEGATE: o1 = TOP(); x = COInt_Type.tp_int_interface->int_neg(o1); CO_DECREF(o1); SET_TOP(x); break; case OP_UNARY_INVERT: o1 = TOP(); x = COInt_Type.tp_int_interface->int_invert(o1); CO_DECREF(o1); SET_TOP(x); break; case OP_LOAD_LOCAL: oparg = NEXTARG(); x = GETLOCAL(oparg); CO_INCREF(x); PUSH(x); break; case OP_LOAD_NAME: oparg = NEXTARG(); o1 = GETITEM(names, oparg); x = COObject_get(o1); if (!x) { COErr_Format(COException_NameError, "name '%s' is not defined", COStr_AsString(o1)); status = STATUS_EXCEPTION; goto fast_end; } CO_INCREF(x); PUSH(x); break; case OP_LOAD_UPVAL: oparg = NEXTARG(); o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues, oparg); o2 = COCell_Get(o1); PUSH(o2); break; case OP_LOAD_CONST: oparg = NEXTARG(); x = GETITEM(consts, oparg); CO_INCREF(x); PUSH(x); break; case OP_BUILD_TUPLE: oparg = NEXTARG(); x = COTuple_New(oparg); if (x != NULL) { for (; --oparg >= 0;) { o1 = POP(); COTuple_SetItem(x, oparg, o1); CO_DECREF(o1); } PUSH(x); } break; case OP_BUILD_LIST: oparg = NEXTARG(); x = COList_New(oparg); if (x != NULL) { for (; --oparg >= 0;) { o1 = POP(); COList_SetItem(x, oparg, o1); CO_DECREF(o1); } PUSH(x); } break; case OP_DICT_BUILD: oparg = NEXTARG(); x = CODict_New(); PUSH(x); break; case OP_DICT_ADD: o1 = POP(); o2 = POP(); o3 = POP(); CODict_SetItem(o3, o2, o1); x = o3; CO_DECREF(o1); CO_DECREF(o2); PUSH(x); break; case OP_STORE_NAME: oparg = NEXTARG(); o1 = GETITEM(names, oparg); o2 = POP(); COObject_set(o1, o2); CO_DECREF(o2); break; case OP_STORE_UPVAL: oparg = NEXTARG(); o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues, oparg); o2 = POP(); COCell_Set(o1, o2); CO_DECREF(o2); break; case OP_STORE_LOCAL: oparg = NEXTARG(); o1 = POP(); SETLOCAL(oparg, o1); break; case OP_JMPZ: oparg = NEXTARG(); o1 = POP(); if (o1 == CO_True) { } else if (o1 == CO_False) { JUMPTO(oparg); } else { err = COObject_IsTrue(o1); if (err > 0) err = 0; else if (err == 0) JUMPTO(oparg); } CO_DECREF(o1); break; case OP_JMP: oparg = NEXTARG(); JUMPBY(oparg); break; case OP_JMPX: oparg = NEXTARG(); JUMPTO(oparg); break; case OP_DECLARE_FUNCTION: o1 = POP(); x = COFunction_New(o1); COCodeObject *c = (COCodeObject *)o1; for (int i = 0; i < CO_SIZE(c->co_upvals); i++) { COObject *name = COTuple_GET_ITEM(c->co_upvals, i); COObject *upvalue = COObject_get(name); if (!upvalue) { // local variables for (int j = 0; j < COTuple_Size(localnames); j++) { if (COObject_CompareBool (COTuple_GET_ITEM(localnames, j), name, Cmp_EQ)) { upvalue = GETLOCAL(j); } } } COObject *cell = COCell_New(upvalue); COTuple_SET_ITEM(((COFunctionObject *)x)->func_upvalues, i, cell); } CO_DECREF(o1); PUSH(x); break; case OP_CALL_FUNCTION: o1 = POP(); oparg = NEXTARG(); COObject *args = COTuple_New(oparg); while (--oparg >= 0) { o2 = POP(); COTuple_SetItem(args, oparg, o2); CO_DECREF(o2); } if (COCFunction_Check(o1)) { COCFunction cfunc = COCFunction_GET_FUNCTION(o1); x = cfunc(NULL, args); CO_DECREF(o1); CO_DECREF(args); PUSH(x); } else if (COFunction_Check(o1)) { ssize_t i = CO_SIZE(args); while (--i >= 0) { COList_Append(funcargs, COTuple_GET_ITEM(args, i)); } CO_DECREF(args); TS(frame)->f_stacktop = stack_top; TS(frame)->f_lasti = (int)(next_code - first_code); TS(frame) = (COFrameObject *)COFrame_New((COObject *)TS(frame), o1, globals); CO_DECREF(o1); func = o1; goto new_frame; } else { x = COObject_Call(o1, args); CO_DECREF(args); CO_DECREF(o1); PUSH(x); } break; case OP_RETURN: o1 = POP(); TS(frame)->f_stacktop = stack_top; TS(frame)->f_lasti = (int)(next_code - first_code); COFrameObject *old_frame = (COFrameObject *)TS(frame); TS(frame) = (COFrameObject *)old_frame->f_prev; CO_DECREF(old_frame); if (!TS(frame)) { CO_DECREF(o1); goto vm_exit; } // init function return *(TS(frame)->f_stacktop++) = o1; goto new_frame; break; case OP_SETUP_LOOP: oparg = NEXTARG(); COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL()); break; case OP_SETUP_TRY: oparg = NEXTARG(); COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL()); break; case OP_POP_BLOCK: { COFrameBlock *fb = COFrameBlock_Pop(TS(frame)); UNWIND_BLOCK(fb); } break; case OP_POP_TRY: { COFrameBlock *fb = COFrameBlock_Pop(TS(frame)); UNWIND_BLOCK(fb); } break; case OP_BREAK_LOOP: status = STATUS_BREAK; break; case OP_CONTINUE_LOOP: oparg = NEXTARG(); status = STATUS_CONTINUE; break; case OP_THROW: oparg = NEXTARG(); if (oparg == 1) { o1 = POP(); } else if (oparg == 0) { o1 = CO_None; } else { error("error oparg"); } status = STATUS_EXCEPTION; COErr_SetObject(COException_SystemError, o1); break; case OP_DUP_TOP: o1 = TOP(); CO_INCREF(o1); PUSH(o1); break; case OP_POP_TOP: o1 = POP(); CO_DECREF(o1); break; case OP_END_TRY: o1 = POP(); COErr_SetString(COException_SystemError, COStr_AsString(o1)); status = STATUS_EXCEPTION; CO_DECREF(o1); break; case OP_SETUP_FINALLY: oparg = NEXTARG(); COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL()); break; case OP_END_FINALLY: o1 = POP(); if (o1 != CO_None) { COErr_SetString(COException_SystemError, COStr_AsString(o1)); status = STATUS_EXCEPTION; } CO_DECREF(o1); break; case OP_STORE_SUBSCRIPT: o1 = TOP(); o2 = SECOND(); o3 = THIRD(); STACK_ADJ(-3); if (COList_Check(o3)) { err = COList_SetItem(o3, COInt_AsSsize_t(o2), o1); } else if (CODict_Check(o3)) { CODict_SetItem(o3, o2, o1); } else { error("wrong store subscript"); } CO_DECREF(o1); CO_DECREF(o2); CO_DECREF(o3); break; case OP_GET_ITER: o1 = TOP(); x = COObject_GetIter(o1); CO_DECREF(o1); SET_TOP(x); break; case OP_FOR_ITER: oparg = NEXTARG(); o1 = TOP(); x = (*o1->co_type->tp_iternext) (o1); if (x) { PUSH(x); break; } o1 = POP(); CO_DECREF(o1); JUMPTO(oparg); break; default: error("unknown handle for opcode(%ld)\n", opcode); } fast_end: while (status != STATUS_NONE && TS(frame)->f_iblock > 0) { COFrameBlock *fb = &TS(frame)->f_blockstack[TS(frame)->f_iblock - 1]; if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_CONTINUE) { status = STATUS_NONE; JUMPTO(oparg); break; } TS(frame)->f_iblock--; UNWIND_BLOCK(fb); if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_BREAK) { status = STATUS_NONE; JUMPTO(fb->fb_handler); break; } if (fb->fb_type == OP_SETUP_TRY && status == STATUS_EXCEPTION) { status = STATUS_NONE; COObject *exc, *val, *tb; COErr_Fetch(&exc, &val, &tb); PUSH(val); JUMPTO(fb->fb_handler); break; } } /* End the loop if we still have an error (or return) */ x = NULL; if (status != STATUS_NONE) break; } vm_exit: /* Clear frame stack. */ while (TS(frame)) { COFrameObject *tmp_frame = (COFrameObject *)TS(frame)->f_prev; CO_DECREF(TS(frame)); TS(frame) = tmp_frame; } return x; }