2022-08-30 18:47:49 +08:00

2564 lines
84 KiB
C

/*
* This file is part of the PikaScript project.
* http://github.com/pikastech/pikascript
*
* MIT License
*
* Copyright (c) 2021 lyon 李昂 liang6516@outlook.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "PikaVM.h"
#include "BaseObj.h"
#include "PikaCompiler.h"
#include "PikaObj.h"
#include "PikaParser.h"
#include "PikaPlatform.h"
#include "dataStrs.h"
#if PIKA_MATH_ENABLE
#include <math.h>
#endif
/* head declear start */
static uint8_t VMState_getInputArgNum(VMState* vm);
static VMParameters* __pikaVM_runByteCodeFrameWithState(
PikaObj* self,
VMParameters* locals,
VMParameters* globals,
ByteCodeFrame* bytecode_frame,
uint16_t pc,
TryInfo* try_info);
/* head declear end */
static InstructUnit* VMState_getInstructNow(VMState* vm) {
return instructArray_getByOffset(&(vm->bytecode_frame->instruct_array),
vm->pc);
}
static void VMState_setErrorCode(VMState* vm, uint8_t error_code) {
vm->error_code = error_code;
}
static InstructUnit* VMState_getInstructWithOffset(VMState* vm,
int32_t offset) {
return instructArray_getByOffset(&(vm->bytecode_frame->instruct_array),
vm->pc + offset);
}
static int VMState_getBlockDeepthNow(VMState* vm) {
/* support run byteCode */
InstructUnit* ins_unit = VMState_getInstructNow(vm);
return instructUnit_getBlockDeepth(ins_unit);
}
static char* VMState_getConstWithInstructUnit(VMState* vm,
InstructUnit* ins_unit) {
return constPool_getByOffset(&(vm->bytecode_frame->const_pool),
instructUnit_getConstPoolIndex(ins_unit));
}
static int VMState_getInvokeDeepthNow(VMState* vm) {
/* support run byteCode */
InstructUnit* ins_unit = VMState_getInstructNow(vm);
return instructUnit_getInvokeDeepth(ins_unit);
}
static int32_t VMState_getAddrOffsetOfJmpBack(VMState* vm) {
int offset = 0;
int loop_deepth = -1;
/* find loop deepth */
while (1) {
offset -= instructUnit_getSize(ins_unit_now);
InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vm, offset);
uint16_t invoke_deepth = instructUnit_getInvokeDeepth(ins_unit_now);
enum Instruct ins = instructUnit_getInstruct(ins_unit_now);
char* data = VMState_getConstWithInstructUnit(vm, ins_unit_now);
if ((0 == invoke_deepth) && (JEZ == ins) && strEqu(data, "2")) {
loop_deepth = instructUnit_getBlockDeepth(ins_unit_now);
break;
}
}
offset = 0;
while (1) {
offset += instructUnit_getSize(ins_unit_now);
InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vm, offset);
enum Instruct ins = instructUnit_getInstruct(ins_unit_now);
char* data = VMState_getConstWithInstructUnit(vm, ins_unit_now);
int block_deepth_now = instructUnit_getBlockDeepth(ins_unit_now);
if ((block_deepth_now == loop_deepth) && (JMP == ins) &&
strEqu(data, "-1")) {
return offset;
}
}
}
static size_t VMState_getInstructArraySize(VMState* vm) {
return instructArray_getSize(&(vm->bytecode_frame->instruct_array));
}
static int32_t VMState_getAddrOffsetFromJmp(VMState* vm) {
int offset = 0;
/* run byte Code */
InstructUnit* this_ins_unit = VMState_getInstructNow(vm);
int thisBlockDeepth = instructUnit_getBlockDeepth(this_ins_unit);
int8_t blockNum = 0;
if (vm->jmp > 0) {
offset = 0;
while (1) {
offset += instructUnit_getSize();
/* reach the end */
if (vm->pc + offset >= (int)VMState_getInstructArraySize(vm)) {
break;
}
this_ins_unit = VMState_getInstructWithOffset(vm, offset);
if (instructUnit_getIsNewLine(this_ins_unit)) {
uint8_t blockDeepth =
instructUnit_getBlockDeepth(this_ins_unit);
if (blockDeepth <= thisBlockDeepth) {
blockNum++;
}
}
if (blockNum >= vm->jmp) {
break;
}
}
}
if (vm->jmp < 0) {
while (1) {
offset -= instructUnit_getSize();
this_ins_unit = VMState_getInstructWithOffset(vm, offset);
if (instructUnit_getIsNewLine(this_ins_unit)) {
uint8_t blockDeepth =
instructUnit_getBlockDeepth(this_ins_unit);
if (blockDeepth == thisBlockDeepth) {
blockNum--;
}
}
if (blockNum <= vm->jmp) {
break;
}
}
}
return offset;
}
static int32_t VMState_getAddrOffsetOfBreak(VMState* vm) {
int32_t offset = VMState_getAddrOffsetOfJmpBack(vm);
/* byteCode */
offset += instructUnit_getSize();
return offset;
}
static int32_t VMState_getAddrOffsetOfRaise(VMState* vm) {
int offset = 0;
InstructUnit* ins_unit_now = VMState_getInstructNow(vm);
while (1) {
offset += instructUnit_getSize(ins_unit_now);
if (vm->pc + offset >= (int)VMState_getInstructArraySize(vm)) {
return 0;
}
ins_unit_now = VMState_getInstructWithOffset(vm, offset);
enum Instruct ins = instructUnit_getInstruct(ins_unit_now);
if ((NTR == ins)) {
return offset;
}
/* if not found except, return */
if (RET == ins) {
return 0;
}
}
}
static int32_t VMState_getAddrOffsetOfContinue(VMState* vm) {
int32_t offset = VMState_getAddrOffsetOfJmpBack(vm);
/* byteCode */
return offset;
}
static void VMState_delLReg(VMState* vm, uint8_t index) {
PikaObj* obj = vm->lreg[index];
if (NULL != obj) {
obj_refcntDec(obj);
vm->lreg[index] = NULL;
if (0 == obj_refcntNow(obj)) {
obj_deinit(obj);
}
}
}
static void VMState_initReg(VMState* vm) {
for (uint8_t i = 0; i < PIKA_REGIST_SIZE; i++) {
vm->lreg[i] = NULL;
vm->ireg[i] = 0;
}
}
static PIKA_BOOL _checkLReg(char* data) {
if ((data[0] == '_') && (data[1] == 'l') && (data[2] >= '0') &&
(data[2] <= '9')) {
return PIKA_TRUE;
}
return PIKA_FALSE;
}
static uint8_t _getLRegIndex(char* data) {
return data[2] - '0';
}
static void VMState_setLReg(VMState* vm, uint8_t index, PikaObj* obj) {
obj_refcntInc(obj);
vm->lreg[index] = obj;
}
typedef Arg* (*VM_instruct_handler)(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg);
static Arg* VM_instruction_handler_NON(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
return NULL;
}
Arg* __vm_get(PikaObj* self, Arg* key, Arg* obj) {
ArgType obj_type = arg_getType(obj);
int index = 0;
if (ARG_TYPE_INT == arg_getType(key)) {
index = arg_getInt(key);
}
if (ARG_TYPE_STRING == obj_type) {
char* str_pyload = arg_getStr(obj);
char char_buff[] = " ";
if (index < 0) {
index = strGetSize(str_pyload) + index;
}
char_buff[0] = str_pyload[index];
return arg_newStr(char_buff);
}
if (ARG_TYPE_BYTES == obj_type) {
uint8_t* bytes_pyload = arg_getBytes(obj);
uint8_t byte_buff[] = " ";
if (index < 0) {
index = arg_getBytesSize(obj) + index;
}
byte_buff[0] = bytes_pyload[index];
return arg_newBytes(byte_buff, 1);
}
if (argType_isObject(obj_type)) {
PikaObj* arg_obj = arg_getPtr(obj);
obj_setArg(arg_obj, "__key", key);
/* clang-format off */
PIKA_PYTHON(
__res = __getitem__(__key)
)
/* clang-format on */
const uint8_t bytes[] = {
0x0c, 0x00, /* instruct array size */
0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x07, 0x00, 0x00, 0x04, 0x13,
0x00,
/* instruct array */
0x19, 0x00, /* const pool size */
0x00, 0x5f, 0x5f, 0x6b, 0x65, 0x79, 0x00, 0x5f, 0x5f, 0x67, 0x65,
0x74, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x72,
0x65, 0x73, 0x00,
/* const pool */
};
pikaVM_runByteCode(arg_obj, (uint8_t*)bytes);
return arg_copy(args_getArg(arg_obj->list, "__res"));
}
return arg_newNull();
}
Arg* __vm_slice(PikaObj* self, Arg* end, Arg* obj, Arg* start, int step) {
#if PIKA_SYNTAX_SLICE_ENABLE
/* No interger index only support __getitem__ */
if (!(arg_getType(start) == ARG_TYPE_INT &&
arg_getType(end) == ARG_TYPE_INT)) {
return __vm_get(self, start, obj);
}
int start_i = arg_getInt(start);
int end_i = arg_getInt(end);
/* __slice__ is equal to __getitem__ */
if (end_i - start_i == 1) {
return __vm_get(self, start, obj);
}
if (ARG_TYPE_STRING == arg_getType(obj)) {
size_t len = strGetSize(arg_getStr(obj));
if (start_i < 0) {
start_i += len;
}
if (end_i < 0) {
end_i += len + 1;
}
Arg* sliced_arg = arg_newStr("");
for (int i = start_i; i < end_i; i++) {
Arg* i_arg = arg_newInt(i);
Arg* item_arg = __vm_get(self, i_arg, obj);
sliced_arg = arg_strAppend(sliced_arg, arg_getStr(item_arg));
arg_deinit(item_arg);
arg_deinit(i_arg);
}
return sliced_arg;
}
if (ARG_TYPE_BYTES == arg_getType(obj)) {
size_t len = arg_getBytesSize(obj);
if (start_i < 0) {
start_i += len;
}
if (end_i < 0) {
end_i += len + 1;
}
Arg* sliced_arg = arg_newBytes(NULL, 0);
for (int i = start_i; i < end_i; i++) {
Arg* i_arg = arg_newInt(i);
Arg* item_arg = __vm_get(self, i_arg, obj);
uint8_t* bytes_origin = arg_getBytes(sliced_arg);
size_t size_origin = arg_getBytesSize(sliced_arg);
Arg* sliced_arg_new = arg_newBytes(NULL, size_origin + 1);
__platform_memcpy(arg_getBytes(sliced_arg_new), bytes_origin,
size_origin);
__platform_memcpy(arg_getBytes(sliced_arg_new) + size_origin,
arg_getBytes(item_arg), 1);
arg_deinit(sliced_arg);
sliced_arg = sliced_arg_new;
arg_deinit(item_arg);
arg_deinit(i_arg);
}
return sliced_arg;
}
return arg_newNull();
#else
return __vm_get(self, start, obj);
#endif
}
static Arg* VM_instruction_handler_SLC(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
#if PIKA_SYNTAX_SLICE_ENABLE
int arg_num_input = VMState_getInputArgNum(vm);
if (arg_num_input < 2) {
return arg_newNull();
}
if (arg_num_input == 2) {
Arg* key = stack_popArg_alloc(&vm->stack);
Arg* obj = stack_popArg_alloc(&vm->stack);
Arg* res = __vm_get(self, key, obj);
arg_deinit(key);
arg_deinit(obj);
return res;
}
if (arg_num_input == 3) {
Arg* end = stack_popArg_alloc(&vm->stack);
Arg* start = stack_popArg_alloc(&vm->stack);
Arg* obj = stack_popArg_alloc(&vm->stack);
Arg* res = __vm_slice(self, end, obj, start, 1);
arg_deinit(end);
arg_deinit(obj);
arg_deinit(start);
return res;
}
return arg_newNull();
#else
Arg* key = stack_popArg_alloc(&vm->stack);
Arg* obj = stack_popArg_alloc(&vm->stack);
Arg* res = __vm_get(self, key, obj);
arg_deinit(key);
arg_deinit(obj);
return res;
#endif
}
static Arg* VM_instruction_handler_TRY(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
pika_assert(NULL != vm->try_info);
vm->try_info->try_state = TRY_STATE_INNER;
return NULL;
}
static Arg* VM_instruction_handler_EXP(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
return NULL;
}
static Arg* VM_instruction_handler_NTR(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
vm->try_info->try_state = TRY_STATE_NONE;
return NULL;
}
static Arg* VM_instruction_handler_NEW(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* origin_arg = obj_getArg(vm->locals, data);
Arg* new_arg = arg_copy(origin_arg);
origin_arg = arg_setType(origin_arg, ARG_TYPE_OBJECT);
arg_setType(new_arg, ARG_TYPE_OBJECT_NEW);
return new_arg;
}
static Arg* VM_instruction_handler_REF(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
if (strEqu(data, (char*)"True")) {
return arg_setInt(arg_ret_reg, "", 1);
}
if (strEqu(data, (char*)"False")) {
return arg_setInt(arg_ret_reg, "", 0);
}
if (strEqu(data, (char*)"None")) {
return arg_setNull(arg_ret_reg);
}
if (strEqu(data, (char*)"RuntimeError")) {
return arg_setInt(arg_ret_reg, "", PIKA_RES_ERR_RUNTIME_ERROR);
}
Arg* arg = NULL;
if (data[0] == '.') {
/* find host from stack */
Arg* host_obj = stack_popArg_alloc(&(vm->stack));
if (argType_isObject(arg_getType(host_obj))) {
arg = arg_copy_noalloc(obj_getArg(arg_getPtr(host_obj), data + 1),
arg_ret_reg);
}
arg_deinit(host_obj);
goto exit;
}
/* find in local list first */
arg = arg_copy_noalloc(obj_getArg(vm->locals, data), arg_ret_reg);
if (NULL == arg) {
/* find in global list second */
arg = arg_copy_noalloc(obj_getArg(vm->globals, data), arg_ret_reg);
}
exit:
if (NULL == arg) {
VMState_setErrorCode(vm, PIKA_RES_ERR_ARG_NO_FOUND);
__platform_printf("NameError: name '%s' is not defined\r\n", data);
}
return arg;
}
static Arg* VM_instruction_handler_GER(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
PIKA_RES err = (PIKA_RES)vm->try_error_code;
Arg* err_arg = arg_newInt(err);
return err_arg;
}
static int32_t __foreach_handler_deinitTuple(Arg* argEach, Args* context) {
if (arg_getType(argEach) == ARG_TYPE_TUPLE) {
PikaTuple* tuple = arg_getPtr(argEach);
tuple_deinit(tuple);
}
return PIKA_RES_OK;
}
Arg* _obj_runMethodArgWithState(PikaObj* self,
PikaObj* method_args_obj,
Arg* method_arg,
TryInfo* try_state,
Arg* ret_arg_reg) {
pika_assert(NULL != try_state);
Arg* return_arg = NULL;
/* get method Ptr */
Method method_ptr = methodArg_getPtr(method_arg);
/* get method type list */
ArgType method_type = arg_getType(method_arg);
/* error */
if (ARG_TYPE_NONE == method_type) {
return NULL;
}
ByteCodeFrame* method_bytecodeFrame =
methodArg_getBytecodeFrame(method_arg);
PikaObj* method_context = methodArg_getDefContext(method_arg);
if (NULL != method_context) {
self = method_context;
}
obj_setErrorCode(self, PIKA_RES_OK);
/* run method */
if (method_type == ARG_TYPE_METHOD_NATIVE) {
/* native method */
method_ptr(self, method_args_obj->list);
/* get method return */
return_arg = arg_copy_noalloc(
args_getArg(method_args_obj->list, (char*)"return"), ret_arg_reg);
} else if (method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) {
/* native method */
method_ptr(self, method_args_obj->list);
/* get method return */
return_arg = arg_copy_noalloc(
args_getArg(method_args_obj->list, (char*)"return"), ret_arg_reg);
} else {
/* static method and object method */
/* byteCode */
uintptr_t insturctArray_start = (uintptr_t)instructArray_getByOffset(
&(method_bytecodeFrame->instruct_array), 0);
uint16_t pc = (uintptr_t)method_ptr - insturctArray_start;
method_args_obj = __pikaVM_runByteCodeFrameWithState(
self, method_args_obj, self, method_bytecodeFrame, pc, try_state);
/* get method return */
return_arg = arg_copy_noalloc(
args_getArg(method_args_obj->list, (char*)"return"), ret_arg_reg);
}
args_foreach(method_args_obj->list, __foreach_handler_deinitTuple, NULL);
return return_arg;
}
Arg* obj_runMethodArgWithState(PikaObj* self,
PikaObj* method_args_obj,
Arg* method_arg,
TryInfo* try_state) {
return _obj_runMethodArgWithState(self, method_args_obj, method_arg,
try_state, NULL);
}
Arg* obj_runMethodArgWithState_noalloc(PikaObj* self,
PikaObj* method_args_obj,
Arg* method_arg,
TryInfo* try_state,
Arg* ret_arg_reg) {
return _obj_runMethodArgWithState(self, method_args_obj, method_arg,
try_state, ret_arg_reg);
}
Arg* obj_runMethodArg(PikaObj* self,
PikaObj* method_args_obj,
Arg* method_arg) {
TryInfo try_info = {.try_state = TRY_STATE_NONE,
.try_result = TRY_RESULT_NONE};
return obj_runMethodArgWithState(self, method_args_obj, method_arg,
&try_info);
}
static int VMState_loadArgsFromMethodArg(VMState* vm,
PikaObj* method_host_obj,
Args* args,
Arg* method_arg,
char* method_name,
int arg_num_used) {
char _buffs1[PIKA_LINE_BUFF_SIZE] = {0};
char* buffs1 = (char*)_buffs1;
char _buffs2[PIKA_LINE_BUFF_SIZE / 2] = {0};
char* buffs2 = (char*)_buffs2;
uint8_t arg_num_dec = 0;
PIKA_BOOL is_variable = PIKA_FALSE;
PIKA_BOOL is_get_variable_arg = PIKA_FALSE;
uint8_t arg_num = 0;
ArgType method_type = ARG_TYPE_UNDEF;
uint8_t arg_num_input = 0;
PikaTuple* tuple = NULL;
char* variable_tuple_name = NULL;
char* type_list_buff = NULL;
int variable_arg_start = 0;
/* get method type list */
char* type_list =
methodArg_getTypeList(method_arg, buffs1, sizeof(_buffs1));
if (NULL == type_list) {
__platform_printf(
"OverflowError: type list is too long, please use bigger "
"PIKA_LINE_BUFF_SIZE\r\n");
while (1)
;
}
method_type = arg_getType(method_arg);
/* check variable */
if (strIsContain(type_list, '*')) {
is_variable = PIKA_TRUE;
}
/* get arg_num_dec */
if (strEqu("", type_list)) {
arg_num_dec = 0;
} else {
arg_num_dec = strCountSign(type_list, ',') + 1;
}
if (method_type == ARG_TYPE_METHOD_OBJECT) {
/* delete the 'self' */
arg_num_dec--;
}
arg_num_input = VMState_getInputArgNum(vm);
/* check arg num */
if (method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR ||
method_type == ARG_TYPE_METHOD_CONSTRUCTOR ||
is_variable == PIKA_TRUE) {
/* skip for constrctor */
/* skip for variable args */
} else {
/* check arg num decleard and input */
if (arg_num_dec != arg_num_input - arg_num_used) {
VMState_setErrorCode(vm, PIKA_RES_ERR_INVALID_PARAM);
__platform_printf(
"TypeError: %s() takes %d positional argument but %d were "
"given\r\n",
method_name, arg_num_dec, arg_num_input);
goto exit;
}
}
if (PIKA_TRUE == is_variable) {
arg_num = arg_num_input;
} else {
arg_num = arg_num_dec;
}
if (is_variable) {
/* get variable tuple name */
type_list_buff = strCopy(buffs2, type_list);
variable_arg_start = 0;
for (int i = 0; i < arg_num_dec; i++) {
char* arg_def = strPopLastToken(type_list_buff, ',');
if (strIsStartWith(arg_def, "*")) {
/* skip the '*' */
variable_tuple_name = arg_def + 1;
variable_arg_start = arg_num_dec - i - 1;
is_get_variable_arg = PIKA_TRUE;
break;
}
}
}
/* found variable arg */
if (PIKA_TRUE == is_get_variable_arg) {
tuple = New_tuple();
strPopLastToken(type_list, ',');
}
/* load pars */
for (int i = 0; i < arg_num; i++) {
char* arg_name = NULL;
if (arg_num - i <= variable_arg_start) {
is_get_variable_arg = PIKA_FALSE;
}
if (PIKA_FALSE == is_get_variable_arg) {
char* arg_def = strPopLastToken(type_list, ',');
strPopLastToken(arg_def, ':');
arg_name = arg_def;
} else {
/* clear the variable arg name */
arg_name = "";
}
Arg* call_arg = stack_popArg_alloc(&(vm->stack));
call_arg = arg_setName(call_arg, arg_name);
/* load the variable arg */
if (PIKA_TRUE == is_get_variable_arg) {
list_append(&tuple->super, call_arg);
/* the append would copy the arg */
arg_deinit(call_arg);
} else {
/* load normal arg */
args_setArg(args, call_arg);
}
}
if (PIKA_TRUE == is_variable) {
list_reverse(&tuple->super);
/* load variable tuple */
PikaObj* New_PikaStdData_Tuple(Args * args);
PikaObj* tuple_obj = newNormalObj(New_PikaStdData_Tuple);
obj_setPtr(tuple_obj, "list", tuple);
args_setPtrWithType(args, variable_tuple_name, ARG_TYPE_OBJECT,
tuple_obj);
}
/* load 'self' as the first arg when call object method */
if (method_type == ARG_TYPE_METHOD_OBJECT) {
Arg* call_arg = arg_setRef(NULL, "self", method_host_obj);
args_setArg(args, call_arg);
}
exit:
return arg_num;
}
void __vm_List_append(PikaObj* self, Arg* arg) {
PikaList* list = obj_getPtr(self, "list");
list_append(list, arg);
}
void __vm_List___init__(PikaObj* self) {
if (!obj_isArgExist(self, "list")) {
PikaList* list = New_list();
obj_setPtr(self, "list", list);
}
}
#if PIKA_BUILTIN_STRUCT_ENABLE
PikaObj* New_PikaStdData_List(Args* args);
PikaObj* New_PikaStdData_Tuple(Args* args);
#endif
static Arg* _vm_create_list_or_tuple(PikaObj* self,
VMState* vm,
PIKA_BOOL is_list) {
#if PIKA_BUILTIN_STRUCT_ENABLE
NewFun constructor = is_list ? New_PikaStdData_List : New_PikaStdData_Tuple;
uint8_t arg_num = VMState_getInputArgNum(vm);
PikaObj* list = newNormalObj(constructor);
__vm_List___init__(list);
Stack stack = {0};
stack_init(&stack);
/* load to local stack to change sort */
for (int i = 0; i < arg_num; i++) {
Arg* arg = stack_popArg_alloc(&(vm->stack));
pika_assert(arg != NULL);
stack_pushArg(&stack, arg);
}
for (int i = 0; i < arg_num; i++) {
Arg* arg = stack_popArg_alloc(&stack);
pika_assert(arg != NULL);
__vm_List_append(list, arg);
arg_deinit(arg);
}
stack_deinit(&stack);
return arg_newPtr(ARG_TYPE_OBJECT, list);
#else
return VM_instruction_handler_NON(self, vm, "", NULL);
#endif
}
static Arg* VM_instruction_handler_LST(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
return _vm_create_list_or_tuple(self, vm, PIKA_TRUE);
}
void __vm_Dict___init__(PikaObj* self) {
PikaDict* dict = New_dict();
PikaDict* keys = New_dict();
obj_setPtr(self, "dict", dict);
obj_setPtr(self, "_keys", keys);
}
void __vm_Dict_set(PikaObj* self, Arg* arg, char* key) {
PikaDict* dict = obj_getPtr(self, "dict");
PikaDict* keys = obj_getPtr(self, "_keys");
Arg* arg_key = arg_setStr(NULL, key, key);
Arg* arg_new = arg_copy(arg);
arg_setName(arg_new, key);
dict_setArg(dict, arg_new);
dict_setArg(keys, arg_key);
}
#if PIKA_BUILTIN_STRUCT_ENABLE
PikaObj* New_PikaStdData_Dict(Args* args);
#endif
static Arg* VM_instruction_handler_DCT(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
#if PIKA_BUILTIN_STRUCT_ENABLE
uint8_t arg_num = VMState_getInputArgNum(vm);
PikaObj* dict = newNormalObj(New_PikaStdData_Dict);
__vm_Dict___init__(dict);
Stack stack = {0};
stack_init(&stack);
/* load to local stack to change sort */
for (int i = 0; i < arg_num; i++) {
Arg* arg = stack_popArg_alloc(&(vm->stack));
stack_pushArg(&stack, arg);
}
for (int i = 0; i < arg_num / 2; i++) {
Arg* key_arg = stack_popArg_alloc(&stack);
Arg* val_arg = stack_popArg_alloc(&stack);
__vm_Dict_set(dict, val_arg, arg_getStr(key_arg));
arg_deinit(key_arg);
arg_deinit(val_arg);
}
stack_deinit(&stack);
return arg_newPtr(ARG_TYPE_OBJECT, dict);
#else
return VM_instruction_handler_NON(self, vm, data, arg_ret_reg);
#endif
}
static Arg* VM_instruction_handler_RET(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
/* exit jmp signal */
vm->jmp = VM_JMP_EXIT;
Arg* return_arg = stack_popArg_alloc(&(vm->stack));
method_returnArg(vm->locals->list, return_arg);
return NULL;
}
static Arg* VM_instruction_handler_RUN(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* return_arg = NULL;
VMParameters* sub_locals = NULL;
char* methodPath = data;
PikaObj* method_host_obj = NULL;
Arg* method_arg = NULL;
Arg* host_arg = NULL;
PIKA_BOOL isClass = PIKA_FALSE;
char* sys_out;
int arg_num_used = 0;
arg_newReg(arg_reg1, 64);
TryInfo sub_try_info = {.try_state = TRY_STATE_NONE,
.try_result = TRY_RESULT_NONE};
pika_assert(NULL != vm->try_info);
/* transfer try_state */
sub_try_info.try_state = vm->try_info->try_state;
/* tuple or single arg */
if (data[0] == 0) {
if (VMState_getInputArgNum(vm) < 2) {
/* return arg directly */
Arg* arg1 = stack_popArg(&(vm->stack), &arg_reg1);
return_arg = arg_copy_noalloc(arg1, arg_ret_reg);
arg_deinit(arg1);
goto exit;
}
/* create a tuple */
return_arg = _vm_create_list_or_tuple(self, vm, PIKA_FALSE);
goto exit;
}
/* return tiny obj */
if (strEqu(data, "TinyObj")) {
return_arg = arg_newMetaObj(New_TinyObj);
goto exit;
}
/* get method host obj from reg */
if (NULL == method_host_obj && _checkLReg(data)) {
uint8_t reg_index = _getLRegIndex(data);
method_host_obj = vm->lreg[reg_index];
}
/* get method host obj from stack */
if (NULL == method_host_obj && methodPath[0] == '.') {
/* get method host obj from stack */
Arg* stack_tmp[PIKA_ARG_NUM_MAX] = {0};
int arg_num = VMState_getInputArgNum(vm);
if (arg_num > PIKA_ARG_NUM_MAX) {
__platform_printf(
"[ERROR] Too many args in RUN instruction, please use bigger "
"#define PIKA_ARG_NUM_MAX\n");
while (1) {
}
}
for (int i = 0; i < arg_num; i++) {
stack_tmp[i] = stack_popArg_alloc(&(vm->stack));
}
host_arg = stack_tmp[arg_num - 1];
if (argType_isObject(arg_getType(host_arg))) {
method_host_obj = arg_getPtr(host_arg);
arg_num_used++;
}
/* push back other args to stack */
for (int i = arg_num - 2; i >= 0; i--) {
stack_pushArg(&(vm->stack), stack_tmp[i]);
}
}
/* get method host obj from self */
if (NULL == method_host_obj) {
method_host_obj = obj_getHostObjWithIsClass(self, methodPath, &isClass);
}
/* get method host obj from local scope */
if (NULL == method_host_obj) {
method_host_obj =
obj_getHostObjWithIsClass(vm->locals, methodPath, &isClass);
}
/* method host obj is not found */
if (NULL == method_host_obj) {
/* error, not found object */
VMState_setErrorCode(vm, PIKA_RES_ERR_ARG_NO_FOUND);
__platform_printf("Error: method '%s' no found.\r\n", data);
goto exit;
}
/* get method in local */
method_arg =
obj_getMethodArg_noalloc(method_host_obj, methodPath, &arg_reg1);
if (NULL == method_arg) {
/* get method in locals */
method_arg =
obj_getMethodArg_noalloc(vm->locals, methodPath, &arg_reg1);
}
if (NULL == method_arg) {
/* get method in global */
method_arg =
obj_getMethodArg_noalloc(vm->globals, methodPath, &arg_reg1);
}
/* assert method type */
if (NULL == method_arg || ARG_TYPE_NONE == arg_getType(method_arg)) {
/* error, method no found */
VMState_setErrorCode(vm, PIKA_RES_ERR_ARG_NO_FOUND);
__platform_printf("NameError: name '%s' is not defined\r\n", data);
goto exit;
}
/* create sub local scope */
sub_locals = New_PikaObj();
/* load args from vmState to sub_local->list */
arg_num_used += VMState_loadArgsFromMethodArg(
vm, method_host_obj, sub_locals->list, method_arg, data, arg_num_used);
/* load args faild */
if (vm->error_code != 0) {
goto exit;
}
/* run method arg */
return_arg = obj_runMethodArgWithState_noalloc(
method_host_obj, sub_locals, method_arg, &sub_try_info, arg_ret_reg);
if (sub_try_info.try_result != TRY_RESULT_NONE) {
/* try result */
vm->error_code = sub_try_info.try_result;
}
/* __init__() */
if (ARG_TYPE_OBJECT_NEW == arg_getType(return_arg)) {
arg_setType(return_arg, ARG_TYPE_OBJECT);
/* init object */
PikaObj* new_obj = arg_getPtr(return_arg);
Arg* method_arg =
obj_getMethodArg_noalloc(new_obj, "__init__", &arg_reg1);
PikaObj* sub_locals = New_PikaObj();
Arg* return_arg_init = NULL;
if (NULL == method_arg) {
goto init_exit;
}
VMState_loadArgsFromMethodArg(vm, new_obj, sub_locals->list, method_arg,
"__init__", arg_num_used);
/* load args faild */
if (vm->error_code != 0) {
goto init_exit;
}
return_arg_init = obj_runMethodArgWithState(new_obj, sub_locals,
method_arg, &sub_try_info);
init_exit:
if (NULL != return_arg_init) {
arg_deinit(return_arg_init);
}
obj_deinit(sub_locals);
arg_deinit(method_arg);
}
/* transfer sysOut */
sys_out = obj_getSysOut(method_host_obj);
if (NULL != sys_out) {
args_setSysOut(vm->locals->list, sys_out);
}
/* transfer errCode */
if (0 != obj_getErrorCode(method_host_obj)) {
/* method error */
VMState_setErrorCode(vm, PIKA_RES_ERR_RUNTIME_ERROR);
}
goto exit;
exit:
if (NULL != method_arg) {
arg_deinit(method_arg);
}
if (NULL != sub_locals) {
obj_deinit(sub_locals);
}
if (NULL != host_arg) {
arg_deinit(host_arg);
}
if (NULL != method_host_obj && isClass) {
/* class method */
obj_deinit(method_host_obj);
}
return return_arg;
}
static char* __get_transferd_str(Args* buffs, char* str, size_t* iout_p) {
char* str_rep = strsReplace(buffs, str, "\\n", "\n");
str_rep = strsReplace(buffs, str_rep, "\\r", "\r");
str_rep = strsReplace(buffs, str_rep, "\\t", "\t");
str_rep = strsReplace(buffs, str_rep, "\\\\", "\\");
char* transfered_str = args_getBuff(buffs, strGetSize(str_rep));
size_t i_out = 0;
for (size_t i = 0; i < strGetSize(str_rep); i++) {
/* eg. replace '\x33' to '3' */
if ((str_rep[i] == '\\') && (str_rep[i + 1] == 'x')) {
char hex_str[] = "0x00";
hex_str[2] = str_rep[i + 2];
hex_str[3] = str_rep[i + 3];
char hex = (char)strtol(hex_str, NULL, 0);
transfered_str[i_out++] = hex;
i += 3;
continue;
}
/* normal char */
transfered_str[i_out++] = str_rep[i];
}
*iout_p = i_out;
return transfered_str;
}
static Arg* VM_instruction_handler_STR(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
if (strIsContain(data, '\\')) {
Args buffs = {0};
size_t i_out = 0;
char* transfered_str = __get_transferd_str(&buffs, data, &i_out);
Arg* return_arg = arg_ret_reg;
return_arg = arg_setStr(return_arg, "", transfered_str);
strsDeinit(&buffs);
return return_arg;
}
return arg_setStr(arg_ret_reg, "", data);
}
static Arg* VM_instruction_handler_BYT(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
if (strIsContain(data, '\\')) {
Args buffs = {0};
size_t i_out = 0;
char* transfered_str = __get_transferd_str(&buffs, data, &i_out);
Arg* return_arg = New_arg(NULL);
return_arg =
arg_setBytes(return_arg, "", (uint8_t*)transfered_str, i_out);
strsDeinit(&buffs);
return return_arg;
}
return arg_newBytes((uint8_t*)data, strGetSize(data));
}
static Arg* VM_instruction_handler_OUT(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
arg_newReg(outArg_reg, PIKA_ARG_BUFF_SIZE);
Arg* outArg = stack_popArg(&vm->stack, &outArg_reg);
// Arg* outArg = stack_popArg_alloc(&vm->stack);
ArgType outArg_type = arg_getType(outArg);
if (VMState_getInvokeDeepthNow(vm) > 0) {
/* in block, is a keyword arg */
arg_setIsKeyword(outArg, PIKA_TRUE);
arg_setName(outArg, data);
return arg_copy_noalloc(outArg, arg_ret_reg);
}
if (_checkLReg(data)) {
uint8_t index = _getLRegIndex(data);
if (argType_isObject(outArg_type)) {
PikaObj* obj = arg_getPtr(outArg);
VMState_setLReg(vm, index, obj);
arg_deinit(outArg);
}
return NULL;
}
PikaObj* hostObj = vm->locals;
/* match global_list */
if (args_isArgExist(vm->locals->list, "__gl")) {
char* global_list = args_getStr(vm->locals->list, "__gl");
/* use a arg as buff */
Arg* global_list_arg = arg_newStr(global_list);
char* global_list_buff = arg_getStr(global_list_arg);
/* for each arg arg in global_list */
char token_buff[32] = {0};
for (int i = 0; i < strCountSign(global_list, ',') + 1; i++) {
char* global_arg = strPopToken(token_buff, global_list_buff, ',');
/* matched global arg, hostObj set to global */
if (strEqu(global_arg, data)) {
hostObj = vm->globals;
}
}
arg_deinit(global_list_arg);
}
/* use RunAs object */
if (args_isArgExist(vm->locals->list, "__runAs")) {
hostObj = args_getPtr(vm->locals->list, "__runAs");
}
/* set free object to nomal object */
if (ARG_TYPE_OBJECT_NEW == outArg_type) {
arg_setType(outArg, ARG_TYPE_OBJECT);
}
/* ouput arg to locals */
obj_setArg_noCopy(hostObj, data, outArg);
return NULL;
}
/* run as */
static Arg* VM_instruction_handler_RAS(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
if (strEqu(data, "$origin")) {
/* use origin object to run */
obj_removeArg(vm->locals, "__runAs");
return NULL;
}
/* use "data" object to run */
PikaObj* runAs = obj_getObj(vm->locals, data);
args_setRef(vm->locals->list, "__runAs", runAs);
return NULL;
}
static Arg* VM_instruction_handler_NUM(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* numArg = arg_ret_reg;
/* hex */
if (data[1] == 'x' || data[1] == 'X') {
return arg_setInt(numArg, "", strtol(data, NULL, 0));
}
if (data[1] == 'o' || data[1] == 'O') {
char strtol_buff[10] = {0};
strtol_buff[0] = '0';
__platform_memcpy(strtol_buff + 1, data + 2, strGetSize(data) - 2);
return arg_setInt(numArg, "", strtol(strtol_buff, NULL, 0));
}
if (data[1] == 'b' || data[1] == 'B') {
char strtol_buff[10] = {0};
__platform_memcpy(strtol_buff, data + 2, strGetSize(data) - 2);
return arg_setInt(numArg, "", strtol(strtol_buff, NULL, 2));
}
/* float */
if (strIsContain(data, '.') ||
(strIsContain(data, 'e') || strIsContain(data, 'E'))) {
return arg_setFloat(numArg, "", strtod(data, NULL));
}
/* int */
return arg_setInt(numArg, "", fast_atoi(data));
}
static Arg* VM_instruction_handler_JMP(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
vm->jmp = fast_atoi(data);
return NULL;
}
static Arg* VM_instruction_handler_SER(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
vm->try_error_code = fast_atoi(data);
return NULL;
}
static Arg* VM_instruction_handler_JEZ(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
int thisBlockDeepth = VMState_getBlockDeepthNow(vm);
int jmp_expect = fast_atoi(data);
arg_newReg(pika_assertArg_reg, PIKA_ARG_BUFF_SIZE);
Arg* pika_assertArg = stack_popArg(&(vm->stack), &pika_assertArg_reg);
int pika_assert = 0;
if (NULL != pika_assertArg) {
pika_assert = arg_getInt(pika_assertArg);
}
arg_deinit(pika_assertArg);
vm->ireg[thisBlockDeepth] = !pika_assert;
if (0 == pika_assert) {
/* jump */
vm->jmp = jmp_expect;
}
/* restore loop deepth */
if (2 == jmp_expect && 0 == pika_assert) {
int block_deepth_now = VMState_getBlockDeepthNow(vm);
vm->loop_deepth = block_deepth_now;
}
return NULL;
}
static uint8_t VMState_getInputArgNum(VMState* vm) {
InstructUnit* ins_unit_now = VMState_getInstructNow(vm);
uint8_t invoke_deepth_this = instructUnit_getInvokeDeepth(ins_unit_now);
int32_t pc_this = vm->pc;
uint8_t num = 0;
while (1) {
ins_unit_now--;
pc_this -= instructUnit_getSize(ins_unit_now);
uint8_t invode_deepth = instructUnit_getInvokeDeepth(ins_unit_now);
if (pc_this < 0) {
break;
}
if (invode_deepth == invoke_deepth_this + 1) {
if (instructUnit_getInstruct(ins_unit_now) == OUT) {
continue;
}
num++;
}
if (instructUnit_getIsNewLine(ins_unit_now)) {
break;
}
if (invode_deepth <= invoke_deepth_this) {
break;
}
}
return num;
}
void operatorInfo_init(OperatorInfo* info,
PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
info->opt = data;
info->res = arg_ret_reg;
info->t1 = arg_getType(info->a1);
info->t2 = arg_getType(info->a2);
info->vm = vm;
if (info->t1 == ARG_TYPE_INT) {
info->i1 = arg_getInt(info->a1);
info->f1 = (float)info->i1;
} else if (info->t1 == ARG_TYPE_FLOAT) {
info->f1 = arg_getFloat(info->a1);
info->i1 = (int)info->f1;
}
if (info->t2 == ARG_TYPE_INT) {
info->i2 = arg_getInt(info->a2);
info->f2 = (float)info->i2;
} else if (info->t2 == ARG_TYPE_FLOAT) {
info->f2 = arg_getFloat(info->a2);
info->i2 = (int)info->f2;
}
}
static void _OPT_ADD(OperatorInfo* op) {
if (argType_isObject(op->t1)) {
if (!argType_isObject(op->t2)) {
VMState_setErrorCode(op->vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf("TypeError: unsupported operand +\n");
op->res = NULL;
return;
}
PikaObj* obj1 = arg_getPtr(op->a1);
Arg* method_add = obj_getMethodArg(obj1, "__add__");
if (NULL == method_add) {
VMState_setErrorCode(op->vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf("TypeError: unsupported operand +\n");
op->res = NULL;
return;
}
arg_deinit(method_add);
PikaObj* obj2 = arg_getPtr(op->a2);
obj_setPtr(obj1, "__others", obj2);
/* clang-format off */
PIKA_PYTHON(
__res = __add__(__others)
)
/* clang-format on */
const uint8_t bytes[] = {
0x0c, 0x00, /* instruct array size */
0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x04, 0x12,
0x00,
/* instruct array */
0x18, 0x00, /* const pool size */
0x00, 0x5f, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x73, 0x00, 0x5f,
0x5f, 0x61, 0x64, 0x64, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x72, 0x65,
0x73, 0x00, /* const pool */
};
pikaVM_runByteCode(obj1, (uint8_t*)bytes);
Arg* __res = arg_copy(obj_getArg(obj1, "__res"));
op->res = __res;
obj_removeArg(obj1, "__others");
obj_removeArg(obj1, "__res");
return;
}
if ((op->t1 == ARG_TYPE_STRING) && (op->t2 == ARG_TYPE_STRING)) {
char* num1_s = NULL;
char* num2_s = NULL;
Args str_opt_buffs = {0};
num1_s = arg_getStr(op->a1);
num2_s = arg_getStr(op->a2);
char* opt_str_out = strsAppend(&str_opt_buffs, num1_s, num2_s);
op->res = arg_setStr(op->res, "", opt_str_out);
strsDeinit(&str_opt_buffs);
return;
}
/* match float */
if ((op->t1 == ARG_TYPE_FLOAT) || op->t2 == ARG_TYPE_FLOAT) {
op->res = arg_setFloat(op->res, "", op->f1 + op->f2);
return;
}
/* int is default */
op->res = arg_setInt(op->res, "", op->i1 + op->i2);
return;
}
static void _OPT_SUB(OperatorInfo* op) {
if (argType_isObject(op->t1)) {
if (!argType_isObject(op->t2)) {
VMState_setErrorCode(op->vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf("TypeError: unsupported operand +\n");
op->res = NULL;
return;
}
PikaObj* obj1 = arg_getPtr(op->a1);
Arg* method_sub = obj_getMethodArg(obj1, "__sub__");
if (NULL == method_sub) {
VMState_setErrorCode(op->vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf("TypeError: unsupported operand +\n");
op->res = NULL;
return;
}
arg_deinit(method_sub);
PikaObj* obj2 = arg_getPtr(op->a2);
obj_setPtr(obj1, "__others", obj2);
/* clang-format off */
PIKA_PYTHON(
__res = __sub__(__others)
)
/* clang-format on */
const uint8_t bytes[] = {
0x0c, 0x00, /* instruct array size */
0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x04, 0x12,
0x00,
/* instruct array */
0x18, 0x00, /* const pool size */
0x00, 0x5f, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x73, 0x00, 0x5f,
0x5f, 0x73, 0x75, 0x62, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x72, 0x65,
0x73, 0x00, /* const pool */
};
pikaVM_runByteCode(obj1, (uint8_t*)bytes);
Arg* __res = arg_copy(obj_getArg(obj1, "__res"));
op->res = __res;
obj_removeArg(obj1, "__others");
obj_removeArg(obj1, "__res");
return;
}
if (op->t2 == ARG_TYPE_NONE) {
if (op->t1 == ARG_TYPE_INT) {
op->res = arg_setInt(op->res, "", -op->i1);
return;
}
if (op->t1 == ARG_TYPE_FLOAT) {
op->res = arg_setFloat(op->res, "", -op->f1);
return;
}
}
if ((op->t1 == ARG_TYPE_FLOAT) || op->t2 == ARG_TYPE_FLOAT) {
op->res = arg_setFloat(op->res, "", op->f1 - op->f2);
return;
}
op->res = arg_setInt(op->res, "", op->i1 - op->i2);
return;
}
static void _OPT_EQU(OperatorInfo* op) {
int8_t is_equ = -1;
if (op->t1 == ARG_TYPE_NONE && op->t2 == ARG_TYPE_NONE) {
is_equ = 1;
goto exit;
}
/* type not equl, and type is not int or float */
if (op->t1 != op->t2) {
if ((op->t1 != ARG_TYPE_FLOAT) && (op->t1 != ARG_TYPE_INT)) {
is_equ = 0;
goto exit;
}
if ((op->t2 != ARG_TYPE_FLOAT) && (op->t2 != ARG_TYPE_INT)) {
is_equ = 0;
goto exit;
}
}
/* string compire */
if (op->t1 == ARG_TYPE_STRING) {
is_equ = strEqu(arg_getStr(op->a1), arg_getStr(op->a2));
goto exit;
}
/* bytes compire */
if (op->t1 == ARG_TYPE_BYTES) {
if (arg_getBytesSize(op->a1) != arg_getBytesSize(op->a2)) {
is_equ = 0;
goto exit;
}
is_equ = 1;
for (size_t i = 0; i < arg_getBytesSize(op->a1); i++) {
if (arg_getBytes(op->a1)[i] != arg_getBytes(op->a2)[i]) {
is_equ = 0;
goto exit;
}
}
goto exit;
}
/* default: int and float */
is_equ = ((op->f1 - op->f2) * (op->f1 - op->f2) < (float)0.000001);
goto exit;
exit:
if (strEqu("==", op->opt)) {
op->res = arg_setInt(op->res, "", is_equ);
} else {
op->res = arg_setInt(op->res, "", !is_equ);
}
return;
}
static void _OPT_POW(OperatorInfo* op) {
if (op->t1 == ARG_TYPE_INT && op->t2 == ARG_TYPE_INT) {
int res = 1;
for (int i = 0; i < op->i2; i++) {
res = res * op->i1;
}
op->res = arg_setInt(op->res, "", res);
return;
} else if (op->t1 == ARG_TYPE_FLOAT && op->t2 == ARG_TYPE_INT) {
float res = 1;
for (int i = 0; i < op->i2; i++) {
res = res * op->f1;
}
op->res = arg_setFloat(op->res, "", res);
return;
} else {
#if PIKA_MATH_ENABLE
float res = 1;
res = pow(op->f1, op->f2);
op->res = arg_setFloat(op->res, "", res);
return;
#else
VMState_setErrorCode(op->vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"Operation float ** float is not enabled, please set "
"PIKA_MATH_ENABLE\n");
#endif
}
}
static Arg* VM_instruction_handler_OPT(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
OperatorInfo op = {0};
op.num = VMState_getInputArgNum(vm);
arg_newReg(arg_reg1, PIKA_ARG_BUFF_SIZE);
arg_newReg(arg_reg2, PIKA_ARG_BUFF_SIZE);
if (op.num == 2) {
/* tow input */
op.a2 = stack_popArg(&(vm->stack), &arg_reg2);
op.a1 = stack_popArg(&(vm->stack), &arg_reg1);
} else if (op.num == 1) {
/* only one input */
op.a2 = stack_popArg(&(vm->stack), &arg_reg2);
op.a1 = NULL;
}
/* init operator info */
operatorInfo_init(&op, self, vm, data, arg_ret_reg);
if (strEqu("+", data)) {
_OPT_ADD(&op);
goto exit;
}
if (strEqu("-", data)) {
_OPT_SUB(&op);
goto exit;
}
if (strEqu("*", data)) {
if ((op.t1 == ARG_TYPE_FLOAT) || op.t2 == ARG_TYPE_FLOAT) {
op.res = arg_setFloat(op.res, "", op.f1 * op.f2);
goto exit;
}
op.res = arg_setInt(op.res, "", op.i1 * op.i2);
goto exit;
}
if (strEqu(" in ", data)) {
if (op.t1 == ARG_TYPE_STRING && op.t2 == ARG_TYPE_STRING) {
if (strstr(arg_getStr(op.a2), arg_getStr(op.a1))) {
op.res = arg_setInt(op.res, "", 1);
} else {
op.res = arg_setInt(op.res, "", 0);
}
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
args_setSysOut(vm->locals->list,
"Operation 'in' is not supported for this "
"type\n");
op.res = NULL;
goto exit;
}
if (strEqu("/", data)) {
if (0 == op.f2) {
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
args_setSysOut(vm->locals->list,
"ZeroDivisionError: division by zero");
op.res = NULL;
goto exit;
}
op.res = arg_setFloat(op.res, "", op.f1 / op.f2);
goto exit;
}
if (strEqu("<", data)) {
op.res = arg_setInt(op.res, "", op.f1 < op.f2);
goto exit;
}
if (strEqu(">", data)) {
op.res = arg_setInt(op.res, "", op.f1 > op.f2);
goto exit;
}
if (strEqu("%", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 % op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for %: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu("**", data)) {
_OPT_POW(&op);
goto exit;
}
if (strEqu("//", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 / op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for //: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu("==", data) || strEqu("!=", data)) {
_OPT_EQU(&op);
goto exit;
}
if (strEqu(" is ", data)) {
if (argType_isObject(op.t1) && argType_isObject(op.t2)) {
if (arg_getPtr(op.a1) == arg_getPtr(op.a2)) {
op.res = arg_setInt(op.res, "", 1);
} else {
op.res = arg_setInt(op.res, "", 0);
}
goto exit;
}
op.opt = "==";
_OPT_EQU(&op);
goto exit;
}
if (strEqu(">=", data)) {
op.res = arg_setInt(
op.res, "",
(op.f1 > op.f2) ||
((op.f1 - op.f2) * (op.f1 - op.f2) < (float)0.000001));
goto exit;
}
if (strEqu("<=", data)) {
op.res = arg_setInt(
op.res, "",
(op.f1 < op.f2) ||
((op.f1 - op.f2) * (op.f1 - op.f2) < (float)0.000001));
goto exit;
}
if (strEqu("&", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 & op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for &: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu("|", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 | op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for |: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu("~", data)) {
if (op.t2 == ARG_TYPE_INT) {
op.res = arg_setInt(op.res, "", ~op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for ~: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu(">>", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 >> op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for >>: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu("<<", data)) {
if ((op.t1 == ARG_TYPE_INT) && (op.t2 == ARG_TYPE_INT)) {
op.res = arg_setInt(op.res, "", op.i1 << op.i2);
goto exit;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf(
"TypeError: unsupported operand type(s) for <<: 'float'\n");
op.res = NULL;
goto exit;
}
if (strEqu(" and ", data)) {
op.res = arg_setInt(op.res, "", op.i1 && op.i2);
goto exit;
}
if (strEqu(" or ", data)) {
op.res = arg_setInt(op.res, "", op.i1 || op.i2);
goto exit;
}
if (strEqu(" not ", data)) {
op.res = arg_setInt(op.res, "", !op.i2);
goto exit;
}
if (strEqu(" import ", data)) {
op.res = NULL;
goto exit;
}
exit:
arg_deinit(op.a1);
arg_deinit(op.a2);
if (NULL != op.res) {
return op.res;
}
return NULL;
}
static Arg* __VM_instruction_handler_DEF(PikaObj* self,
VMState* vm,
char* data,
uint8_t is_class) {
int thisBlockDeepth = VMState_getBlockDeepthNow(vm);
PikaObj* hostObj = vm->locals;
uint8_t is_in_class = 0;
/* use RunAs object */
if (args_isArgExist(vm->locals->list, "__runAs")) {
hostObj = args_getPtr(vm->locals->list, "__runAs");
is_in_class = 1;
}
int offset = 0;
/* byteCode */
while (1) {
InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vm, offset);
if (!instructUnit_getIsNewLine(ins_unit_now)) {
offset += instructUnit_getSize();
continue;
}
if (instructUnit_getBlockDeepth(ins_unit_now) == thisBlockDeepth + 1) {
if (is_in_class) {
class_defineObjectMethod(hostObj, data, (Method)ins_unit_now,
self, vm->bytecode_frame);
} else {
if (is_class) {
class_defineRunTimeConstructor(hostObj, data,
(Method)ins_unit_now, self,
vm->bytecode_frame);
} else {
class_defineStaticMethod(hostObj, data,
(Method)ins_unit_now, self,
vm->bytecode_frame);
}
}
break;
}
offset += instructUnit_getSize();
}
return NULL;
}
static Arg* VM_instruction_handler_DEF(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
return __VM_instruction_handler_DEF(self, vm, data, 0);
}
static Arg* VM_instruction_handler_CLS(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
return __VM_instruction_handler_DEF(self, vm, data, 1);
}
static Arg* VM_instruction_handler_RIS(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* err_arg = stack_popArg_alloc(&(vm->stack));
PIKA_RES err = (PIKA_RES)arg_getInt(err_arg);
VMState_setErrorCode(vm, err);
arg_deinit(err_arg);
return NULL;
}
static Arg* VM_instruction_handler_ASS(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
arg_newReg(reg1, PIKA_ARG_BUFF_SIZE);
arg_newReg(reg2, PIKA_ARG_BUFF_SIZE);
Arg* arg1 = NULL;
Arg* arg2 = NULL;
Arg* res = NULL;
int arg_num = VMState_getInputArgNum(vm);
if (arg_num == 1) {
arg1 = stack_popArg(&vm->stack, &reg1);
}
if (arg_num == 2) {
arg2 = stack_popArg(&vm->stack, &reg2);
arg1 = stack_popArg(&vm->stack, &reg1);
}
/* assert faild */
if (arg_getType(arg1) == ARG_TYPE_INT && arg_getInt(arg1) == 0) {
stack_pushArg(&vm->stack, arg_newInt(PIKA_RES_ERR_ASSERT));
res = VM_instruction_handler_RIS(self, vm, data, arg_ret_reg);
if (vm->try_info->try_state == TRY_STATE_NONE) {
if (arg_num == 1) {
__platform_printf("AssertionError\n", data);
}
if (arg_num == 2) {
__platform_printf("AssertionError: %s\n", arg_getStr(arg2));
}
}
goto exit;
}
exit:
arg_deinit(arg1);
arg_deinit(arg2);
return res;
}
static Arg* VM_instruction_handler_NEL(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
int thisBlockDeepth = VMState_getBlockDeepthNow(vm);
if (0 == vm->ireg[thisBlockDeepth]) {
/* set __else flag */
vm->jmp = fast_atoi(data);
}
return NULL;
}
static Arg* VM_instruction_handler_DEL(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
if (_checkLReg(data)) {
uint8_t reg_index = _getLRegIndex(data);
VMState_delLReg(vm, reg_index);
return NULL;
}
if (obj_isArgExist(vm->locals, data)) {
obj_removeArg(vm->locals, data);
return NULL;
}
if (obj_isArgExist(vm->globals, data)) {
obj_removeArg(vm->globals, data);
return NULL;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_OPERATION_FAILED);
__platform_printf("NameError: name '%s' is not defined\n", data);
return NULL;
}
static Arg* VM_instruction_handler_EST(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* arg = obj_getArg(vm->locals, data);
if (arg == NULL) {
return arg_setInt(arg_ret_reg, "", 0);
}
if (ARG_TYPE_NONE == arg_getType(arg)) {
return arg_setInt(arg_ret_reg, "", 0);
}
return arg_setInt(arg_ret_reg, "", 1);
}
static Arg* VM_instruction_handler_BRK(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
/* break jmp signal */
vm->jmp = VM_JMP_BREAK;
return NULL;
}
static Arg* VM_instruction_handler_CTN(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
/* continue jmp signal */
vm->jmp = VM_JMP_CONTINUE;
return NULL;
}
static Arg* VM_instruction_handler_GLB(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
Arg* global_list_buff = NULL;
char* global_list = args_getStr(vm->locals->list, "__gl");
/* create new global_list */
if (NULL == global_list) {
args_setStr(vm->locals->list, "__gl", data);
goto exit;
}
/* append to exist global_list */
global_list_buff = arg_newStr(global_list);
global_list_buff = arg_strAppend(global_list_buff, ",");
global_list_buff = arg_strAppend(global_list_buff, data);
args_setStr(vm->locals->list, "__gl", arg_getStr(global_list_buff));
goto exit;
exit:
if (NULL != global_list_buff) {
arg_deinit(global_list_buff);
}
return NULL;
}
static Arg* VM_instruction_handler_IMP(PikaObj* self,
VMState* vm,
char* data,
Arg* arg_ret_reg) {
/* the module is already imported, skip. */
if (obj_isArgExist(self, data)) {
return NULL;
}
/* find cmodule in root object */
extern PikaObj* __pikaMain;
if (obj_isArgExist(__pikaMain, data)) {
obj_setArg(self, data, obj_getArg(__pikaMain, data));
return NULL;
}
/* import module from '__lib' */
if (0 == obj_importModule(self, data)) {
return NULL;
}
VMState_setErrorCode(vm, PIKA_RES_ERR_ARG_NO_FOUND);
__platform_printf("ModuleNotFoundError: No module named '%s'\r\n", data);
return NULL;
}
const VM_instruct_handler VM_instruct_handler_table[__INSTRCUTION_CNT] = {
#define __INS_TABLE
#include "__instruction_table.cfg"
};
enum Instruct pikaVM_getInstructFromAsm(char* ins_str) {
#define __INS_COMPIRE
#include "__instruction_table.cfg"
return NON;
}
static int pikaVM_runInstructUnit(PikaObj* self,
VMState* vm,
InstructUnit* ins_unit) {
enum Instruct instruct = instructUnit_getInstruct(ins_unit);
arg_newReg(ret_reg, PIKA_ARG_BUFF_SIZE);
Arg* return_arg = &ret_reg;
// char invode_deepth1_str[2] = {0};
int32_t pc_next = vm->pc + instructUnit_getSize();
char* data = VMState_getConstWithInstructUnit(vm, ins_unit);
/* run instruct */
pika_assert(NULL != vm->try_info);
return_arg = VM_instruct_handler_table[instruct](self, vm, data, &ret_reg);
if (vm->error_code != PIKA_RES_OK) {
/* raise jmp */
if (vm->try_info->try_state == TRY_STATE_INNER) {
vm->jmp = VM_JMP_RAISE;
};
}
if (NULL != return_arg) {
stack_pushArg(&(vm->stack), return_arg);
}
goto nextLine;
nextLine:
/* exit */
if (VM_JMP_EXIT == vm->jmp) {
pc_next = VM_PC_EXIT;
goto exit;
}
/* break */
if (VM_JMP_BREAK == vm->jmp) {
pc_next = vm->pc + VMState_getAddrOffsetOfBreak(vm);
goto exit;
}
/* continue */
if (VM_JMP_CONTINUE == vm->jmp) {
pc_next = vm->pc + VMState_getAddrOffsetOfContinue(vm);
goto exit;
}
/* raise */
if (VM_JMP_RAISE == vm->jmp) {
int offset = VMState_getAddrOffsetOfRaise(vm);
if (0 == offset) {
/* can not found end of try, return */
pc_next = VM_PC_EXIT;
vm->try_info->try_result = TRY_RESULT_RAISE;
goto exit;
}
pc_next = vm->pc + offset;
goto exit;
}
/* static jmp */
if (vm->jmp != 0) {
pc_next = vm->pc + VMState_getAddrOffsetFromJmp(vm);
goto exit;
}
/* not jmp */
pc_next = vm->pc + instructUnit_getSize();
/* jump to next line */
if (vm->error_code != 0) {
while (1) {
if (pc_next >= (int)VMState_getInstructArraySize(vm)) {
pc_next = VM_PC_EXIT;
goto exit;
}
InstructUnit* ins_next = instructArray_getByOffset(
&vm->bytecode_frame->instruct_array, pc_next);
if (instructUnit_getIsNewLine(ins_next)) {
goto exit;
}
pc_next = pc_next + instructUnit_getSize();
}
}
goto exit;
exit:
vm->jmp = 0;
/* reach the end */
if (pc_next >= (int)VMState_getInstructArraySize(vm)) {
return VM_PC_EXIT;
}
return pc_next;
}
VMParameters* pikaVM_runAsm(PikaObj* self, char* pikaAsm) {
ByteCodeFrame bytecode_frame;
byteCodeFrame_init(&bytecode_frame);
byteCodeFrame_appendFromAsm(&bytecode_frame, pikaAsm);
VMParameters* res = pikaVM_runByteCodeFrame(self, &bytecode_frame);
byteCodeFrame_deinit(&bytecode_frame);
return res;
}
static VMParameters* __pikaVM_runPyLines_or_byteCode(PikaObj* self,
char* py_lines,
uint8_t* bytecode) {
uint8_t is_run_py;
if (NULL != py_lines) {
is_run_py = 1;
} else if (NULL != bytecode) {
is_run_py = 0;
} else {
return NULL;
}
Args buffs = {0};
VMParameters* globals = NULL;
ByteCodeFrame bytecode_frame_stack = {0};
ByteCodeFrame* bytecode_frame_p = NULL;
uint8_t is_use_heap_bytecode = 0;
/*
* the first obj_run, cache bytecode to heap, to support 'def' and 'class'
*/
if (!args_isArgExist(self->list, "__first_bytecode")) {
is_use_heap_bytecode = 1;
/* load bytecode to heap */
args_setHeapStruct(self->list, "__first_bytecode", bytecode_frame_stack,
byteCodeFrame_deinit);
/* get bytecode_ptr from heap */
bytecode_frame_p = args_getHeapStruct(self->list, "__first_bytecode");
} else {
/* not the first obj_run */
/* save 'def' and 'class' to heap */
if ((strIsStartWith(py_lines, "def ")) ||
(strIsStartWith(py_lines, "class "))) {
char* declear_name = strsGetFirstToken(&buffs, py_lines, ':');
/* load bytecode to heap */
args_setHeapStruct(self->list, declear_name, bytecode_frame_stack,
byteCodeFrame_deinit);
/* get bytecode_ptr from heap */
bytecode_frame_p = args_getHeapStruct(self->list, declear_name);
} else {
/* get bytecode_ptr from stack */
bytecode_frame_p = &bytecode_frame_stack;
}
}
/* load or generate byte code frame */
if (is_run_py) {
/* generate byte code */
byteCodeFrame_init(bytecode_frame_p);
if (1 == bytecodeFrame_fromLines(bytecode_frame_p, py_lines)) {
__platform_printf("Error: Syntax error.\r\n");
globals = NULL;
goto exit;
}
} else {
/* load bytecode */
byteCodeFrame_loadByteCode(bytecode_frame_p, bytecode);
}
/* run byteCode */
globals = pikaVM_runByteCodeFrame(self, bytecode_frame_p);
goto exit;
exit:
if (!is_use_heap_bytecode) {
byteCodeFrame_deinit(&bytecode_frame_stack);
}
strsDeinit(&buffs);
return globals;
}
VMParameters* pikaVM_runSingleFile(PikaObj* self, char* filename) {
Args buffs = {0};
Arg* file_arg = arg_loadFile(NULL, filename);
pika_assert(NULL != file_arg);
if (NULL == file_arg) {
return NULL;
}
char* lines = (char*)arg_getBytes(file_arg);
/* clear the void line */
VMParameters* res = pikaVM_run(self, lines);
arg_deinit(file_arg);
strsDeinit(&buffs);
return res;
}
VMParameters* pikaVM_run(PikaObj* self, char* py_lines) {
return __pikaVM_runPyLines_or_byteCode(self, py_lines, NULL);
}
VMParameters* pikaVM_runByteCode(PikaObj* self, uint8_t* bytecode) {
return __pikaVM_runPyLines_or_byteCode(self, NULL, bytecode);
}
void constPool_update(ConstPool* self) {
self->content_start = (void*)arg_getContent(self->arg_buff);
}
void constPool_init(ConstPool* self) {
self->arg_buff = arg_newStr("");
constPool_update(self);
self->content_offset_now = 0;
self->size = strGetSize(constPool_getStart(self)) + 1;
self->output_redirect_fun = NULL;
self->output_f = NULL;
}
void constPool_deinit(ConstPool* self) {
if (NULL != self->arg_buff) {
arg_deinit(self->arg_buff);
}
}
void constPool_append(ConstPool* self, char* content) {
uint16_t size = strGetSize(content) + 1;
if (NULL == self->output_redirect_fun) {
self->arg_buff = arg_append(self->arg_buff, content, size);
} else {
self->output_redirect_fun(self, content);
};
constPool_update(self);
self->size += size;
}
char* constPool_getNow(ConstPool* self) {
if (self->content_offset_now >= self->size) {
/* is the end */
return NULL;
}
return (char*)((uintptr_t)constPool_getStart(self) +
(uintptr_t)(self->content_offset_now));
}
uint16_t constPool_getOffsetByData(ConstPool* self, char* data) {
uint16_t ptr_befor = self->content_offset_now;
/* set ptr_now to begin */
self->content_offset_now = 0;
uint16_t offset_out = 65535;
while (1) {
if (NULL == constPool_getNext(self)) {
goto exit;
}
if (strEqu(data, constPool_getNow(self))) {
offset_out = self->content_offset_now;
goto exit;
}
}
exit:
/* retore ptr_now */
self->content_offset_now = ptr_befor;
return offset_out;
}
char* constPool_getNext(ConstPool* self) {
self->content_offset_now += strGetSize(constPool_getNow(self)) + 1;
return constPool_getNow(self);
}
char* constPool_getByIndex(ConstPool* self, uint16_t index) {
uint16_t ptr_befor = self->content_offset_now;
/* set ptr_now to begin */
self->content_offset_now = 0;
for (uint16_t i = 0; i < index; i++) {
constPool_getNext(self);
}
char* res = constPool_getNow(self);
/* retore ptr_now */
self->content_offset_now = ptr_befor;
return res;
}
void constPool_print(ConstPool* self) {
uint16_t ptr_befor = self->content_offset_now;
/* set ptr_now to begin */
self->content_offset_now = 0;
while (1) {
if (NULL == constPool_getNext(self)) {
goto exit;
}
uint16_t offset = self->content_offset_now;
__platform_printf("%d: %s\r\n", offset, constPool_getNow(self));
}
exit:
/* retore ptr_now */
self->content_offset_now = ptr_befor;
return;
}
void byteCodeFrame_init(ByteCodeFrame* self) {
/* init to support append,
if only load static bytecode,
can not init */
constPool_init(&(self->const_pool));
instructArray_init(&(self->instruct_array));
}
void byteCodeFrame_loadByteCode(ByteCodeFrame* self, uint8_t* bytes) {
uint16_t* ins_size_p = (uint16_t*)bytes;
void* ins_start_p = (uint16_t*)(bytes + 2);
uint16_t* const_size_p =
(uint16_t*)((uintptr_t)ins_start_p + (uintptr_t)(*ins_size_p));
self->instruct_array.size = *ins_size_p;
self->instruct_array.content_start = ins_start_p;
self->const_pool.size = *const_size_p;
self->const_pool.content_start = (char*)((uintptr_t)const_size_p + 2);
}
void byteCodeFrame_deinit(ByteCodeFrame* self) {
constPool_deinit(&(self->const_pool));
instructArray_deinit(&(self->instruct_array));
}
void instructArray_init(InstructArray* self) {
self->arg_buff = arg_newNull();
instructArray_update(self);
self->size = 0;
self->content_offset_now = 0;
self->output_redirect_fun = NULL;
self->output_f = NULL;
}
void instructArray_deinit(InstructArray* self) {
if (NULL != self->arg_buff) {
arg_deinit(self->arg_buff);
}
}
void instructArray_append(InstructArray* self, InstructUnit* ins_unit) {
if (NULL == self->output_redirect_fun) {
self->arg_buff =
arg_append(self->arg_buff, ins_unit, instructUnit_getSize());
} else {
self->output_redirect_fun(self, ins_unit);
};
instructArray_update(self);
self->size += instructUnit_getSize();
}
void instructUnit_init(InstructUnit* ins_unit) {
ins_unit->deepth = 0;
ins_unit->const_pool_index = 0;
ins_unit->isNewLine_instruct = 0;
}
void instructArray_update(InstructArray* self) {
self->content_start = (void*)arg_getContent(self->arg_buff);
}
InstructUnit* instructArray_getNow(InstructArray* self) {
if (self->content_offset_now >= self->size) {
/* is the end */
return NULL;
}
return (InstructUnit*)((uintptr_t)instructArray_getStart(self) +
(uintptr_t)(self->content_offset_now));
}
InstructUnit* instructArray_getNext(InstructArray* self) {
self->content_offset_now += instructUnit_getSize();
return instructArray_getNow(self);
}
static char* instructUnit_getInstructStr(InstructUnit* self) {
#define __INS_GET_INS_STR
#include "__instruction_table.cfg"
return "NON";
}
void instructUnit_print(InstructUnit* self) {
if (instructUnit_getIsNewLine(self)) {
__platform_printf("B%d\r\n", instructUnit_getBlockDeepth(self));
}
__platform_printf("%d %s #%d\r\n", instructUnit_getInvokeDeepth(self),
instructUnit_getInstructStr(self),
self->const_pool_index);
}
static void instructUnit_printWithConst(InstructUnit* self,
ConstPool* const_pool) {
// if (instructUnit_getIsNewLine(self)) {
// __platform_printf("B%d\r\n", instructUnit_getBlockDeepth(self));
// }
__platform_printf("%s %s \t\t(#%d)\r\n", instructUnit_getInstructStr(self),
constPool_getByOffset(const_pool, self->const_pool_index),
self->const_pool_index);
}
void instructArray_printWithConst(InstructArray* self, ConstPool* const_pool) {
uint16_t offset_befor = self->content_offset_now;
self->content_offset_now = 0;
while (1) {
InstructUnit* ins_unit = instructArray_getNow(self);
if (NULL == ins_unit) {
goto exit;
}
instructUnit_printWithConst(ins_unit, const_pool);
instructArray_getNext(self);
}
exit:
self->content_offset_now = offset_befor;
return;
}
void instructArray_print(InstructArray* self) {
uint16_t offset_befor = self->content_offset_now;
self->content_offset_now = 0;
while (1) {
InstructUnit* ins_unit = instructArray_getNow(self);
if (NULL == ins_unit) {
goto exit;
}
instructUnit_print(ins_unit);
instructArray_getNext(self);
}
exit:
self->content_offset_now = offset_befor;
return;
}
void instructArray_printAsArray(InstructArray* self) {
uint16_t offset_befor = self->content_offset_now;
self->content_offset_now = 0;
uint8_t line_num = 12;
uint16_t g_i = 0;
uint8_t* ins_size_p = (uint8_t*)&self->size;
__platform_printf("0x%02x, ", *(ins_size_p));
__platform_printf("0x%02x, ", *(ins_size_p + (uintptr_t)1));
__platform_printf("/* instruct array size */\n");
while (1) {
InstructUnit* ins_unit = instructArray_getNow(self);
if (NULL == ins_unit) {
goto exit;
}
for (int i = 0; i < (int)instructUnit_getSize(ins_unit); i++) {
g_i++;
__platform_printf("0x%02x, ", *((uint8_t*)ins_unit + (uintptr_t)i));
if (g_i % line_num == 0) {
__platform_printf("\n");
}
}
instructArray_getNext(self);
}
exit:
__platform_printf("/* instruct array */\n");
self->content_offset_now = offset_befor;
return;
}
size_t byteCodeFrame_getSize(ByteCodeFrame* bf) {
return bf->const_pool.size + bf->instruct_array.size;
}
void byteCodeFrame_print(ByteCodeFrame* self) {
constPool_print(&(self->const_pool));
instructArray_printWithConst(&(self->instruct_array), &(self->const_pool));
__platform_printf("---------------\r\n");
__platform_printf("byte code size: %d\r\n",
self->const_pool.size + self->instruct_array.size);
}
void VMState_solveUnusedStack(VMState* vm) {
uint8_t top = stack_getTop(&(vm->stack));
for (int i = 0; i < top; i++) {
Arg* arg = stack_popArg_alloc(&(vm->stack));
ArgType type = arg_getType(arg);
if (type == ARG_TYPE_NONE) {
arg_deinit(arg);
continue;
}
if (vm->line_error_code != 0) {
arg_deinit(arg);
continue;
}
if (argType_isObject(type)) {
char* res = obj_toStr(arg_getPtr(arg));
__platform_printf("%s\r\n", res);
} else if (type == ARG_TYPE_INT) {
__platform_printf("%d\r\n", (int)arg_getInt(arg));
} else if (type == ARG_TYPE_FLOAT) {
__platform_printf("%f\r\n", arg_getFloat(arg));
} else if (type == ARG_TYPE_STRING) {
__platform_printf("'%s'\r\n", arg_getStr(arg));
} else if (type == ARG_TYPE_BYTES) {
arg_printBytes(arg);
} else if (ARG_TYPE_POINTER == type ||
ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) {
__platform_printf("%p\r\n", arg_getPtr(arg));
}
arg_deinit(arg);
}
}
static VMParameters* __pikaVM_runByteCodeFrameWithState(
PikaObj* self,
VMParameters* locals,
VMParameters* globals,
ByteCodeFrame* bytecode_frame,
uint16_t pc,
TryInfo* try_info) {
pika_assert(NULL != try_info);
int size = bytecode_frame->instruct_array.size;
/* locals is the local scope */
VMState vm = {
.bytecode_frame = bytecode_frame,
.locals = locals,
.globals = globals,
.jmp = 0,
.pc = pc,
.loop_deepth = 0,
.error_code = PIKA_RES_OK,
.line_error_code = PIKA_RES_OK,
.try_error_code = PIKA_RES_OK,
.try_info = try_info,
.ins_cnt = 0,
};
stack_init(&(vm.stack));
VMState_initReg(&vm);
while (vm.pc < size) {
if (vm.pc == VM_PC_EXIT) {
break;
}
InstructUnit* this_ins_unit = VMState_getInstructNow(&vm);
if (instructUnit_getIsNewLine(this_ins_unit)) {
VMState_solveUnusedStack(&vm);
stack_reset(&(vm.stack));
vm.error_code = 0;
vm.line_error_code = 0;
}
vm.pc = pikaVM_runInstructUnit(self, &vm, this_ins_unit);
vm.ins_cnt++;
#if PIKA_INSTRUCT_HOOK_ENABLE
if (vm.ins_cnt % PIKA_INSTRUCT_HOOK_PERIOD == 0) {
__pks_hook_instruct();
}
#endif
if (0 != vm.error_code) {
vm.line_error_code = vm.error_code;
InstructUnit* head_ins_unit = this_ins_unit;
/* get first ins of a line */
while (1) {
if (instructUnit_getIsNewLine(head_ins_unit)) {
break;
}
head_ins_unit--;
}
if (vm.try_info->try_state) {
vm.try_error_code = vm.error_code;
}
/* print inses of a line */
if (!vm.try_info->try_state) {
while (1) {
if (head_ins_unit != this_ins_unit) {
__platform_printf(" ");
} else {
__platform_printf(" -> ");
}
instructUnit_printWithConst(head_ins_unit,
&(bytecode_frame->const_pool));
head_ins_unit++;
if (head_ins_unit > this_ins_unit) {
break;
}
}
}
__platform_error_handle();
vm.error_code = 0;
}
}
VMState_solveUnusedStack(&vm);
stack_deinit(&(vm.stack));
return locals;
}
VMParameters* pikaVM_runByteCodeFrame(PikaObj* self,
ByteCodeFrame* byteCode_frame) {
TryInfo try_info = {.try_state = TRY_STATE_NONE,
.try_result = TRY_RESULT_NONE};
try_info.try_state = TRY_STATE_NONE;
return __pikaVM_runByteCodeFrameWithState(self, self, self, byteCode_frame,
0, &try_info);
}
InstructUnit* instructArray_getByOffset(InstructArray* self, int32_t offset) {
return (InstructUnit*)((uintptr_t)instructArray_getStart(self) +
(uintptr_t)offset);
}
void constPool_printAsArray(ConstPool* self) {
uint8_t* const_size_str = (uint8_t*)&(self->size);
__platform_printf("0x%02x, ", *(const_size_str));
__platform_printf("0x%02x, ", *(const_size_str + (uintptr_t)1));
__platform_printf("/* const pool size */\n");
uint16_t ptr_befor = self->content_offset_now;
uint8_t line_num = 12;
uint16_t g_i = 0;
/* set ptr_now to begin */
self->content_offset_now = 0;
__platform_printf("0x00, ");
while (1) {
if (NULL == constPool_getNext(self)) {
goto exit;
}
char* data_each = constPool_getNow(self);
/* todo start */
for (uint32_t i = 0; i < strGetSize(data_each) + 1; i++) {
__platform_printf("0x%02x, ", *(data_each + (uintptr_t)i));
g_i++;
if (g_i % line_num == 0) {
__platform_printf("\n");
}
}
/* todo end */
}
exit:
/* retore ptr_now */
__platform_printf("/* const pool */\n");
self->content_offset_now = ptr_befor;
return;
}
void byteCodeFrame_printAsArray(ByteCodeFrame* self) {
__platform_printf("const uint8_t bytes[] = {\n");
instructArray_printAsArray(&(self->instruct_array));
constPool_printAsArray(&(self->const_pool));
__platform_printf("};\n");
__platform_printf("pikaVM_runByteCode(self, (uint8_t*)bytes);\n");
}
PikaObj* pikaVM_runFile(PikaObj* self, char* file_name) {
Args buffs = {0};
char* module_name = strsCopy(&buffs, file_name);
strPopLastToken(module_name, '.');
__platform_printf("(pikascript) pika compiler:\r\n");
PikaMaker* maker = New_PikaMaker();
pikaMaker_compileModuleWithDepends(maker, module_name);
pikaMaker_linkCompiledModules(maker, "pikaModules_cache.py.a");
obj_deinit(maker);
__platform_printf("(pikascript) all succeed.\r\n\r\n");
pikaMemMaxReset();
Obj_linkLibraryFile(self, "pikascript-api/pikaModules_cache.py.a");
self = pikaVM_runSingleFile(self, file_name);
strsDeinit(&buffs);
return self;
}