2022-06-24 00:21:00 +08:00

1630 lines
52 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"
/* head declear start */
static uint8_t VMState_getInputArgNum(VMState* vs);
static VMParameters* __pikaVM_runByteCodeFrameWithState(
PikaObj* self,
VMParameters* locals,
VMParameters* globals,
ByteCodeFrame* bytecode_frame,
uint16_t pc);
/* head declear end */
static InstructUnit* VMState_getInstructNow(VMState* vs) {
return instructArray_getByOffset(&(vs->bytecode_frame->instruct_array),
vs->pc);
}
static void VMState_setErrorCode(VMState* vs, uint8_t error_code) {
vs->error_code = error_code;
}
static InstructUnit* VMState_getInstructWithOffset(VMState* vs,
int32_t offset) {
return instructArray_getByOffset(&(vs->bytecode_frame->instruct_array),
vs->pc + offset);
}
static int VMState_getBlockDeepthNow(VMState* vs) {
/* support run byteCode */
InstructUnit* ins_unit = VMState_getInstructNow(vs);
return instructUnit_getBlockDeepth(ins_unit);
}
static char* VMState_getConstWithInstructUnit(VMState* vs,
InstructUnit* ins_unit) {
return constPool_getByOffset(&(vs->bytecode_frame->const_pool),
instructUnit_getConstPoolIndex(ins_unit));
}
static int32_t VMState_getAddrOffsetOfJUM(VMState* vs) {
int offset = 0;
InstructUnit* ins_unit_now = VMState_getInstructNow(vs);
while (1) {
offset += instructUnit_getSize(ins_unit_now);
ins_unit_now = VMState_getInstructWithOffset(vs, offset);
uint16_t invoke_deepth = instructUnit_getInvokeDeepth(ins_unit_now);
enum Instruct ins = instructUnit_getInstruct(ins_unit_now);
char* data = VMState_getConstWithInstructUnit(vs, ins_unit_now);
if ((0 == invoke_deepth) && (JMP == ins) && strEqu(data, "-1")) {
return offset;
}
}
}
static size_t VMState_getInstructArraySize(VMState* vs) {
return instructArray_getSize(&(vs->bytecode_frame->instruct_array));
}
static int32_t VMState_getAddrOffsetFromJmp(VMState* vs) {
int offset = 0;
/* run byte Code */
InstructUnit* this_ins_unit = VMState_getInstructNow(vs);
int thisBlockDeepth = instructUnit_getBlockDeepth(this_ins_unit);
int8_t blockNum = 0;
if (vs->jmp > 0) {
offset = 0;
while (1) {
offset += instructUnit_getSize();
/* reach the end */
if (vs->pc + offset >= (int)VMState_getInstructArraySize(vs)) {
break;
}
this_ins_unit = VMState_getInstructWithOffset(vs, offset);
if (instructUnit_getIsNewLine(this_ins_unit)) {
uint8_t blockDeepth =
instructUnit_getBlockDeepth(this_ins_unit);
if (blockDeepth <= thisBlockDeepth) {
blockNum++;
}
}
if (blockNum >= vs->jmp) {
break;
}
}
}
if (vs->jmp < 0) {
while (1) {
offset -= instructUnit_getSize();
this_ins_unit = VMState_getInstructWithOffset(vs, offset);
if (instructUnit_getIsNewLine(this_ins_unit)) {
uint8_t blockDeepth =
instructUnit_getBlockDeepth(this_ins_unit);
if (blockDeepth == thisBlockDeepth) {
blockNum--;
}
}
if (blockNum <= vs->jmp) {
break;
}
}
}
return offset;
}
static int32_t VMState_getAddrOffsetOfBreak(VMState* vs) {
int32_t offset = VMState_getAddrOffsetOfJUM(vs);
/* byteCode */
offset += instructUnit_getSize();
return offset;
}
static int32_t VMState_getAddrOffsetOfContinue(VMState* vs) {
int32_t offset = VMState_getAddrOffsetOfJUM(vs);
/* byteCode */
return offset;
}
typedef Arg* (*VM_instruct_handler)(PikaObj* self, VMState* vs, char* data);
static Arg* VM_instruction_handler_NON(PikaObj* self, VMState* vs, char* data) {
return NULL;
}
static Arg* VM_instruction_handler_NEW(PikaObj* self, VMState* vs, char* data) {
Arg* origin_arg = obj_getArg(vs->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* vs, char* data) {
if (strEqu(data, (char*)"True")) {
return arg_setInt(NULL, "", 1);
}
if (strEqu(data, (char*)"False")) {
return arg_setInt(NULL, "", 0);
}
/* find in local list first */
Arg* arg = arg_copy(obj_getArg(vs->locals, data));
if (NULL == arg) {
/* find in global list second */
arg = arg_copy(obj_getArg(vs->globals, data));
}
if (NULL == arg) {
VMState_setErrorCode(vs, 1);
__platform_printf("NameError: name '%s' is not defined\r\n", data);
}
return 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;
}
static Arg* VMState_runMethodArg(VMState* vs,
PikaObj* method_host_obj,
PikaObj* method_args_obj,
Arg* method_arg) {
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_VOID == method_type) {
return NULL;
}
ByteCodeFrame* method_bytecodeFrame =
methodArg_getBytecodeFrame(method_arg);
obj_setErrorCode(method_host_obj, 0);
/* run method */
if (method_type == ARG_TYPE_METHOD_NATIVE) {
/* native method */
method_ptr(method_host_obj, method_args_obj->list);
/* get method return */
return_arg =
arg_copy(args_getArg(method_args_obj->list, (char*)"return"));
} else if (method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) {
/* native method */
method_ptr(method_host_obj, method_args_obj->list);
/* get method return */
return_arg =
arg_copy(args_getArg(method_args_obj->list, (char*)"return"));
} 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(
method_host_obj, method_args_obj, vs->globals, method_bytecodeFrame,
pc);
/* get method return */
return_arg =
arg_copy(args_getArg(method_args_obj->list, (char*)"return"));
}
args_foreach(method_args_obj->list, __foreach_handler_deinitTuple, NULL);
return return_arg;
}
static int VMState_loadArgsFromMethodArg(VMState* vs,
PikaObj* method_host_obj,
Args* args,
Arg* method_arg,
char* method_name,
int arg_num_used) {
Args buffs = {0};
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;
/* get method type list */
char* type_list = methodArg_getTypeList(method_arg, &buffs);
if (NULL == type_list) {
goto exit;
}
ArgType 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--;
}
uint8_t arg_num_input = VMState_getInputArgNum(vs);
/* 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(vs, 3);
__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;
}
PikaTuple* tuple = NULL;
char* variable_tuple_name = NULL;
/* get variable tuple name */
char* type_list_buff = strsCopy(&buffs, type_list);
int 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 = strsCopy(&buffs, "");
}
Arg* call_arg = stack_popArg(&(vs->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) {
/* resort the tuple */
PikaTuple* tuple_sorted = New_tuple();
if (NULL != tuple) {
int tuple_size = tuple_getSize(tuple);
for (int i = 0; i < tuple_size; i++) {
Arg* arg = tuple_getArg(tuple, tuple_size - 1 - i);
list_append(&(tuple_sorted->super), arg);
}
tuple_deinit(tuple);
}
/* load variable tuple */
args_setPtrWithType(args, variable_tuple_name, ARG_TYPE_TUPLE,
tuple_sorted);
}
/* 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:
strsDeinit(&buffs);
return arg_num;
}
#if PIKA_BUILTIN_LIST_ENABLE
void PikaStdData_List_append(PikaObj* self, Arg* arg);
void PikaStdData_List___init__(PikaObj* self);
PikaObj* New_PikaStdData_List(Args* args);
#endif
static Arg* VM_instruction_handler_LST(PikaObj* self, VMState* vs, char* data) {
#if PIKA_BUILTIN_LIST_ENABLE
uint8_t arg_num = VMState_getInputArgNum(vs);
PikaObj* list = newNormalObj(New_PikaStdData_List);
PikaStdData_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(&(vs->stack));
stack_pushArg(&stack, arg);
}
for (int i = 0; i < arg_num; i++) {
Arg* arg = stack_popArg(&stack);
PikaStdData_List_append(list, arg);
arg_deinit(arg);
}
stack_deinit(&stack);
return arg_setPtr(NULL, "", ARG_TYPE_OBJECT, list);
#else
return VM_instruction_handler_NON(self, vs, data);
#endif
}
static Arg* VM_instruction_handler_RUN(PikaObj* self, VMState* vs, char* data) {
Args buffs = {0};
Arg* return_arg = NULL;
VMParameters* sub_locals = NULL;
char* methodPath = data;
PikaObj* method_host_obj;
Arg* method_arg = NULL;
char* sys_out;
int arg_num_used = 0;
/* return arg directly */
if (strEqu(data, "")) {
return_arg = stack_popArg(&(vs->stack));
goto exit;
}
/* return tiny obj */
if (strEqu(data, "TinyObj")) {
return_arg = arg_newMetaObj(New_TinyObj);
goto exit;
}
/* get method host obj from self */
method_host_obj = obj_getHostObj(self, methodPath);
/* get method host obj from local scope */
if (NULL == method_host_obj) {
method_host_obj = obj_getHostObj(vs->locals, methodPath);
}
if (NULL == method_host_obj) {
/* error, not found object */
VMState_setErrorCode(vs, 1);
__platform_printf("Error: method '%s' no found.\r\n", data);
goto exit;
}
/* get method in local */
method_arg = obj_getMethodArg(method_host_obj, methodPath);
if (NULL == method_arg) {
/* get method in global */
method_arg = obj_getMethodArg(vs->globals, methodPath);
}
/* assert method*/
if (NULL == method_arg || ARG_TYPE_VOID == arg_getType(method_arg)) {
/* error, method no found */
VMState_setErrorCode(vs, 2);
__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(
vs, method_host_obj, sub_locals->list, method_arg, data, 0);
/* load args faild */
if (vs->error_code != 0) {
goto exit;
}
/* run method arg */
return_arg =
VMState_runMethodArg(vs, method_host_obj, sub_locals, method_arg);
/* __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(new_obj, "__init__");
PikaObj* sub_locals = New_PikaObj();
Arg* return_arg_init = NULL;
if (NULL == method_arg) {
goto init_exit;
}
VMState_loadArgsFromMethodArg(vs, new_obj, sub_locals->list, method_arg,
"__init__", arg_num_used);
/* load args faild */
if (vs->error_code != 0) {
goto init_exit;
}
return_arg_init =
VMState_runMethodArg(vs, new_obj, sub_locals, method_arg);
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(vs->locals->list, sys_out);
}
/* transfer errCode */
if (0 != obj_getErrorCode(method_host_obj)) {
/* method error */
VMState_setErrorCode(vs, 6);
}
goto exit;
exit:
if (NULL != method_arg) {
arg_deinit(method_arg);
}
if (NULL != sub_locals) {
obj_deinit(sub_locals);
}
strsDeinit(&buffs);
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");
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* vs, char* data) {
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_setStr(return_arg, "", transfered_str);
strsDeinit(&buffs);
return return_arg;
}
return arg_setStr(NULL, "", data);
}
static Arg* VM_instruction_handler_BYT(PikaObj* self, VMState* vs, char* data) {
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_setBytes(NULL, "", (uint8_t*)data, strGetSize(data));
}
static Arg* VM_instruction_handler_OUT(PikaObj* self, VMState* vs, char* data) {
Arg* outArg = stack_popArg(&(vs->stack));
ArgType outArg_type = arg_getType(outArg);
PikaObj* hostObj = vs->locals;
/* match global_list */
if (args_isArgExist(vs->locals->list, "__gl")) {
char* global_list = args_getStr(vs->locals->list, "__gl");
/* use a arg as buff */
Arg* global_list_arg = arg_setStr(NULL, "", 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 = vs->globals;
}
}
arg_deinit(global_list_arg);
}
/* use RunAs object */
if (args_isArgExist(vs->locals->list, "__runAs")) {
hostObj = args_getPtr(vs->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* vs, char* data) {
if (strEqu(data, "$origin")) {
/* use origin object to run */
obj_removeArg(vs->locals, "__runAs");
return NULL;
}
/* use "data" object to run */
PikaObj* runAs = obj_getObj(vs->locals, data);
args_setRef(vs->locals->list, "__runAs", runAs);
return NULL;
}
static Arg* VM_instruction_handler_NUM(PikaObj* self, VMState* vs, char* data) {
Arg* numArg = New_arg(NULL);
/* 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));
}
/* float */
if (strIsContain(data, '.')) {
return arg_setFloat(numArg, "", atof(data));
}
/* int */
return arg_setInt(numArg, "", fast_atoi(data));
}
static Arg* VM_instruction_handler_JMP(PikaObj* self, VMState* vs, char* data) {
vs->jmp = fast_atoi(data);
return NULL;
}
static Arg* VM_instruction_handler_JEZ(PikaObj* self, VMState* vs, char* data) {
int thisBlockDeepth;
thisBlockDeepth = VMState_getBlockDeepthNow(vs);
Arg* assertArg = stack_popArg(&(vs->stack));
int assert = arg_getInt(assertArg);
arg_deinit(assertArg);
char __else[] = "__else0";
__else[6] = '0' + thisBlockDeepth;
args_setInt(self->list, __else, !assert);
if (0 == assert) {
/* set __else flag */
vs->jmp = fast_atoi(data);
}
return NULL;
}
static uint8_t VMState_getInputArgNum(VMState* vs) {
InstructUnit* ins_unit_now = VMState_getInstructNow(vs);
uint8_t invode_deepth_this = instructUnit_getInvokeDeepth(ins_unit_now);
int32_t pc_this = vs->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 == invode_deepth_this + 1) {
num++;
}
if (instructUnit_getIsNewLine(ins_unit_now)) {
break;
}
if (invode_deepth <= invode_deepth_this) {
break;
}
}
return num;
}
static Arg* VM_instruction_handler_OPT(PikaObj* self, VMState* vs, char* data) {
Arg* outArg = NULL;
uint8_t input_arg_num = VMState_getInputArgNum(vs);
Arg* arg2 = NULL;
Arg* arg1 = NULL;
if (input_arg_num == 2) {
/* tow input */
arg2 = stack_popArg(&(vs->stack));
arg1 = stack_popArg(&(vs->stack));
} else if (input_arg_num == 1) {
/* only one input */
arg2 = stack_popArg(&(vs->stack));
arg1 = arg_setNull(NULL);
}
ArgType type_arg1 = arg_getType(arg1);
ArgType type_arg2 = arg_getType(arg2);
int num1_i = 0;
int num2_i = 0;
float num1_f = 0.0;
float num2_f = 0.0;
/* get int and float num */
if (type_arg1 == ARG_TYPE_INT) {
num1_i = arg_getInt(arg1);
num1_f = (float)num1_i;
} else if (type_arg1 == ARG_TYPE_FLOAT) {
num1_f = arg_getFloat(arg1);
num1_i = (int)num1_f;
}
if (type_arg2 == ARG_TYPE_INT) {
num2_i = arg_getInt(arg2);
num2_f = (float)num2_i;
} else if (type_arg2 == ARG_TYPE_FLOAT) {
num2_f = arg_getFloat(arg2);
num2_i = (int)num2_f;
}
if (strEqu("+", data)) {
if ((type_arg1 == ARG_TYPE_STRING) && (type_arg2 == ARG_TYPE_STRING)) {
char* num1_s = NULL;
char* num2_s = NULL;
Args str_opt_buffs = {0};
num1_s = arg_getStr(arg1);
num2_s = arg_getStr(arg2);
char* opt_str_out = strsAppend(&str_opt_buffs, num1_s, num2_s);
outArg = arg_setStr(outArg, "", opt_str_out);
strsDeinit(&str_opt_buffs);
goto OPT_exit;
}
/* match float */
if ((type_arg1 == ARG_TYPE_FLOAT) || type_arg2 == ARG_TYPE_FLOAT) {
outArg = arg_setFloat(outArg, "", num1_f + num2_f);
goto OPT_exit;
}
/* int is default */
outArg = arg_setInt(outArg, "", num1_i + num2_i);
goto OPT_exit;
}
if (strEqu("-", data)) {
if (type_arg2 == ARG_TYPE_NONE) {
if (type_arg1 == ARG_TYPE_INT) {
outArg = arg_setInt(outArg, "", -num1_i);
goto OPT_exit;
}
if (type_arg1 == ARG_TYPE_FLOAT) {
outArg = arg_setFloat(outArg, "", -num1_f);
goto OPT_exit;
}
}
if ((type_arg1 == ARG_TYPE_FLOAT) || type_arg2 == ARG_TYPE_FLOAT) {
outArg = arg_setFloat(outArg, "", num1_f - num2_f);
goto OPT_exit;
}
outArg = arg_setInt(outArg, "", num1_i - num2_i);
goto OPT_exit;
}
if (strEqu("*", data)) {
if ((type_arg1 == ARG_TYPE_FLOAT) || type_arg2 == ARG_TYPE_FLOAT) {
outArg = arg_setFloat(outArg, "", num1_f * num2_f);
goto OPT_exit;
}
outArg = arg_setInt(outArg, "", num1_i * num2_i);
goto OPT_exit;
}
if (strEqu("/", data)) {
if (0 == num2_f) {
VMState_setErrorCode(vs, 1);
args_setSysOut(vs->locals->list,
"ZeroDivisionError: division by zero");
outArg = NULL;
goto OPT_exit;
}
outArg = arg_setFloat(outArg, "", num1_f / num2_f);
goto OPT_exit;
}
if (strEqu("<", data)) {
outArg = arg_setInt(outArg, "", num1_f < num2_f);
goto OPT_exit;
}
if (strEqu(">", data)) {
outArg = arg_setInt(outArg, "", num1_f > num2_f);
goto OPT_exit;
}
if (strEqu("%", data)) {
outArg = arg_setInt(outArg, "", num1_i % num2_i);
goto OPT_exit;
}
if (strEqu("**", data)) {
float res = 1;
for (int i = 0; i < num2_i; i++) {
res = res * num1_f;
}
outArg = arg_setFloat(outArg, "", res);
goto OPT_exit;
}
if (strEqu("//", data)) {
outArg = arg_setInt(outArg, "", num1_i / num2_i);
goto OPT_exit;
}
if (strEqu("==", data) || strEqu("!=", data)) {
int8_t is_equ = -1;
/* type not equl, and type is not int or float */
if (type_arg1 != type_arg2) {
if ((type_arg1 != ARG_TYPE_FLOAT) && (type_arg1 != ARG_TYPE_INT)) {
is_equ = 0;
goto EQU_exit;
}
if ((type_arg2 != ARG_TYPE_FLOAT) && (type_arg2 != ARG_TYPE_INT)) {
is_equ = 0;
goto EQU_exit;
}
}
/* string compire */
if (type_arg1 == ARG_TYPE_STRING) {
is_equ = strEqu(arg_getStr(arg1), arg_getStr(arg2));
goto EQU_exit;
}
/* bytes compire */
if (type_arg1 == ARG_TYPE_BYTES) {
if (arg_getBytesSize(arg1) != arg_getBytesSize(arg2)) {
is_equ = 0;
goto EQU_exit;
}
is_equ = 1;
for (size_t i = 0; i < arg_getBytesSize(arg1); i++) {
if (arg_getBytes(arg1)[i] != arg_getBytes(arg2)[i]) {
is_equ = 0;
goto EQU_exit;
}
}
goto EQU_exit;
}
/* default: int and float */
is_equ = ((num1_f - num2_f) * (num1_f - num2_f) < (float)0.000001);
goto EQU_exit;
EQU_exit:
if (strEqu("==", data)) {
outArg = arg_setInt(outArg, "", is_equ);
} else {
outArg = arg_setInt(outArg, "", !is_equ);
}
goto OPT_exit;
}
if (strEqu(">=", data)) {
outArg = arg_setInt(
outArg, "",
(num1_f > num2_f) ||
((num1_f - num2_f) * (num1_f - num2_f) < (float)0.000001));
goto OPT_exit;
}
if (strEqu("<=", data)) {
outArg = arg_setInt(
outArg, "",
(num1_f < num2_f) ||
((num1_f - num2_f) * (num1_f - num2_f) < (float)0.000001));
goto OPT_exit;
}
if (strEqu("&", data)) {
outArg = arg_setInt(outArg, "", num1_i & num2_i);
goto OPT_exit;
}
if (strEqu("|", data)) {
outArg = arg_setInt(outArg, "", num1_i | num2_i);
goto OPT_exit;
}
if (strEqu("~", data)) {
outArg = arg_setInt(outArg, "", ~num2_i);
goto OPT_exit;
}
if (strEqu(">>", data)) {
outArg = arg_setInt(outArg, "", num1_i >> num2_i);
goto OPT_exit;
}
if (strEqu("<<", data)) {
outArg = arg_setInt(outArg, "", num1_i << num2_i);
goto OPT_exit;
}
if (strEqu(" and ", data)) {
outArg = arg_setInt(outArg, "", num1_i && num2_i);
goto OPT_exit;
}
if (strEqu(" or ", data)) {
outArg = arg_setInt(outArg, "", num1_i || num2_i);
goto OPT_exit;
}
if (strEqu(" not ", data)) {
outArg = arg_setInt(outArg, "", !num2_i);
goto OPT_exit;
}
if (strEqu(" import ", data)) {
outArg = NULL;
goto OPT_exit;
}
OPT_exit:
arg_deinit(arg1);
arg_deinit(arg2);
if (NULL != outArg) {
return outArg;
}
return NULL;
}
static Arg* __VM_instruction_handler_DEF(PikaObj* self,
VMState* vs,
char* data,
uint8_t is_class) {
int thisBlockDeepth = VMState_getBlockDeepthNow(vs);
PikaObj* hostObj = vs->locals;
uint8_t is_in_class = 0;
/* use RunAs object */
if (args_isArgExist(vs->locals->list, "__runAs")) {
hostObj = args_getPtr(vs->locals->list, "__runAs");
is_in_class = 1;
}
int offset = 0;
/* byteCode */
while (1) {
InstructUnit* ins_unit_now = VMState_getInstructWithOffset(vs, 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,
vs->bytecode_frame);
} else {
if (is_class) {
class_defineRunTimeConstructor(hostObj, data,
(Method)ins_unit_now,
vs->bytecode_frame);
} else {
class_defineStaticMethod(hostObj, data,
(Method)ins_unit_now,
vs->bytecode_frame);
}
}
break;
}
offset += instructUnit_getSize();
}
return NULL;
}
static Arg* VM_instruction_handler_DEF(PikaObj* self, VMState* vs, char* data) {
return __VM_instruction_handler_DEF(self, vs, data, 0);
}
static Arg* VM_instruction_handler_CLS(PikaObj* self, VMState* vs, char* data) {
return __VM_instruction_handler_DEF(self, vs, data, 1);
}
static Arg* VM_instruction_handler_RET(PikaObj* self, VMState* vs, char* data) {
/* exit jmp signal */
vs->jmp = -999;
Arg* return_arg = stack_popArg(&(vs->stack));
method_returnArg(vs->locals->list, return_arg);
return NULL;
}
static Arg* VM_instruction_handler_NEL(PikaObj* self, VMState* vs, char* data) {
int thisBlockDeepth = VMState_getBlockDeepthNow(vs);
char __else[] = "__else0";
__else[6] = '0' + thisBlockDeepth;
if (0 == args_getInt(self->list, __else)) {
/* set __else flag */
vs->jmp = fast_atoi(data);
}
return NULL;
}
static Arg* VM_instruction_handler_DEL(PikaObj* self, VMState* vs, char* data) {
obj_removeArg(vs->locals, data);
return NULL;
}
static Arg* VM_instruction_handler_EST(PikaObj* self, VMState* vs, char* data) {
Arg* arg = obj_getArg(vs->locals, data);
if (arg == NULL) {
return arg_setInt(NULL, "", 0);
}
if (ARG_TYPE_NULL == arg_getType(arg)) {
return arg_setInt(NULL, "", 0);
}
return arg_setInt(NULL, "", 1);
}
static Arg* VM_instruction_handler_BRK(PikaObj* self, VMState* vs, char* data) {
/* break jmp signal */
vs->jmp = -998;
return NULL;
}
static Arg* VM_instruction_handler_CTN(PikaObj* self, VMState* vs, char* data) {
/* continue jmp signal */
vs->jmp = -997;
return NULL;
}
static Arg* VM_instruction_handler_GLB(PikaObj* self, VMState* vs, char* data) {
Arg* global_list_buff = NULL;
char* global_list = args_getStr(vs->locals->list, "__gl");
/* create new global_list */
if (NULL == global_list) {
args_setStr(vs->locals->list, "__gl", data);
goto exit;
}
/* append to exist global_list */
global_list_buff = arg_setStr(NULL, "", global_list);
global_list_buff = arg_strAppend(global_list_buff, ",");
global_list_buff = arg_strAppend(global_list_buff, data);
args_setStr(vs->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* vs, char* data) {
/* 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(vs, 3);
__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* line) {
#define __INS_COMPIRE
#include "__instruction_table.cfg"
return NON;
}
static int pikaVM_runInstructUnit(PikaObj* self,
VMState* vs,
InstructUnit* ins_unit) {
enum Instruct instruct = instructUnit_getInstruct(ins_unit);
Arg* return_arg;
// char invode_deepth1_str[2] = {0};
int32_t pc_next = vs->pc + instructUnit_getSize();
char* data = VMState_getConstWithInstructUnit(vs, ins_unit);
/* run instruct */
return_arg = VM_instruct_handler_table[instruct](self, vs, data);
if (NULL != return_arg) {
stack_pushArg(&(vs->stack), return_arg);
}
goto nextLine;
nextLine:
/* exit */
if (-999 == vs->jmp) {
pc_next = -99999;
goto exit;
}
/* break */
if (-998 == vs->jmp) {
pc_next = vs->pc + VMState_getAddrOffsetOfBreak(vs);
goto exit;
}
/* continue */
if (-997 == vs->jmp) {
pc_next = vs->pc + VMState_getAddrOffsetOfContinue(vs);
goto exit;
}
/* static jmp */
if (vs->jmp != 0) {
pc_next = vs->pc + VMState_getAddrOffsetFromJmp(vs);
goto exit;
}
/* not jmp */
pc_next = vs->pc + instructUnit_getSize();
goto exit;
exit:
vs->jmp = 0;
/* reach the end */
if (pc_next >= (int)VMState_getInstructArraySize(vs)) {
return -99999;
}
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_fromMultiLine(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_runFile(PikaObj* self, char* filename) {
Arg* file_arg = arg_loadFile(NULL, filename);
char* lines = (char*)arg_getBytes(file_arg);
Args buffs = {0};
/* replace the "\r\n" to "\n" */
lines = strsReplace(&buffs, lines, "\r\n", "\n");
/* clear the void line */
lines = strsReplace(&buffs, lines, "\n\n", "\n");
/* add '\n' at the end */
lines = strsAppend(&buffs, lines, "\n\n");
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);
}
static void* constPool_getStart(ConstPool* self) {
return self->content_start;
}
void constPool_update(ConstPool* self) {
self->content_start = (void*)arg_getContent(self->arg_buff);
}
void constPool_init(ConstPool* self) {
self->arg_buff = arg_setStr(NULL, "", "");
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_getLastOffset(ConstPool* self) {
return self->size;
}
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_setNull(NULL);
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;
}
static void* instructArray_getStart(InstructArray* self) {
return self->content_start;
}
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* vs) {
uint8_t top = stack_getTop(&(vs->stack));
for (int i = 0; i < top; i++) {
Arg* arg = stack_popArg(&(vs->stack));
ArgType type = arg_getType(arg);
if (type == ARG_TYPE_VOID) {
arg_deinit(arg);
continue;
}
if (vs->line_error_code != 0) {
arg_deinit(arg);
continue;
}
if (argType_isObject(type)) {
__platform_printf("<object at 0x%02x>\r\n",
(uintptr_t)arg_getPtr(arg));
}
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);
}
arg_deinit(arg);
}
}
static VMParameters* __pikaVM_runByteCodeFrameWithState(
PikaObj* self,
VMParameters* locals,
VMParameters* globals,
ByteCodeFrame* bytecode_frame,
uint16_t pc) {
int size = bytecode_frame->instruct_array.size;
/* locals is the local scope */
VMState vs = {
.bytecode_frame = bytecode_frame,
.locals = locals,
.globals = globals,
.jmp = 0,
.pc = pc,
.error_code = 0,
.line_error_code = 0,
};
stack_init(&(vs.stack));
while (vs.pc < size) {
if (vs.pc == -99999) {
break;
}
InstructUnit* this_ins_unit = VMState_getInstructNow(&vs);
if (instructUnit_getIsNewLine(this_ins_unit)) {
VMState_solveUnusedStack(&vs);
stack_reset(&(vs.stack));
vs.error_code = 0;
vs.line_error_code = 0;
}
vs.pc = pikaVM_runInstructUnit(self, &vs, this_ins_unit);
if (0 != vs.error_code) {
vs.line_error_code = vs.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--;
}
/* print inses of a line */
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();
vs.error_code = 0;
}
}
VMState_solveUnusedStack(&vs);
stack_deinit(&(vs.stack));
return locals;
}
VMParameters* pikaVM_runByteCodeFrame(PikaObj* self,
ByteCodeFrame* byteCode_frame) {
return __pikaVM_runByteCodeFrameWithState(self, self, self, byteCode_frame,
0);
}
char* constPool_getByOffset(ConstPool* self, uint16_t offset) {
return (char*)((uintptr_t)constPool_getStart(self) + (uintptr_t)offset);
}
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");
}