mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-02-05 17:28:23 +08:00
1533 lines
51 KiB
C
1533 lines
51 KiB
C
/*
|
|
* This file is part of the PikaPython project.
|
|
* http://github.com/pikastech/pikapython
|
|
*
|
|
* 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 "PikaCompiler.h"
|
|
#include "BaseObj.h"
|
|
#include "PikaObj.h"
|
|
#include "PikaParser.h"
|
|
#include "dataQueue.h"
|
|
#include "dataQueueObj.h"
|
|
#include "dataStack.h"
|
|
#include "dataStrs.h"
|
|
|
|
const char magic_code_pyo[] = {0x0f, 'p', 'y', 'o'};
|
|
|
|
/*
|
|
* @brief check magic code of pyo file
|
|
* @param bytecode
|
|
* @return pika_true or pika_false
|
|
*/
|
|
static pika_bool _check_magic_code_pyo(uint8_t* bytecode) {
|
|
char* data = (char*)bytecode;
|
|
if (data[0] == magic_code_pyo[0] && data[1] == magic_code_pyo[1] &&
|
|
data[2] == magic_code_pyo[2] && data[3] == magic_code_pyo[3]) {
|
|
return pika_true;
|
|
}
|
|
return pika_false;
|
|
}
|
|
|
|
/*
|
|
* @brief get bytecode from bytes arg
|
|
* @param self bytes arg
|
|
* @return bytecode
|
|
*/
|
|
static uint8_t* arg_getBytecode(Arg* self) {
|
|
uint8_t* bytecode_file = arg_getBytes(self);
|
|
if (_check_magic_code_pyo(bytecode_file)) {
|
|
return bytecode_file + sizeof(magic_code_pyo) + sizeof(uint32_t);
|
|
}
|
|
return bytecode_file;
|
|
}
|
|
|
|
/*
|
|
* @brief get bytecode size from bytes arg
|
|
* @param self bytes arg
|
|
* @return bytecode size
|
|
*/
|
|
static size_t arg_getBytecodeSize(Arg* self) {
|
|
size_t size_all = arg_getBytesSize(self);
|
|
uint8_t* bytecode_file = arg_getBytes(self);
|
|
if (_check_magic_code_pyo(bytecode_file)) {
|
|
return size_all - sizeof(magic_code_pyo) - sizeof(uint32_t);
|
|
}
|
|
return size_all;
|
|
}
|
|
|
|
/* const Pool output redirect */
|
|
static void __handler_constPool_output_file(ConstPool* self, char* content) {
|
|
/* to ram */
|
|
uint16_t size = strGetSize(content) + 1;
|
|
self->arg_buff = arg_append(self->arg_buff, content, size);
|
|
/* to flash */
|
|
pika_platform_fwrite(content, 1, size, self->output_f);
|
|
}
|
|
|
|
/* instruct array output redirect */
|
|
static void __handler_instructArray_output_none(InstructArray* self,
|
|
InstructUnit* ins_unit) {
|
|
/* none */
|
|
}
|
|
|
|
static void __handler_instructArray_output_file(InstructArray* self,
|
|
InstructUnit* ins_unit) {
|
|
/* to flash */
|
|
pika_platform_fwrite(ins_unit, 1, instructUnit_getSize(), self->output_f);
|
|
}
|
|
|
|
/*
|
|
need implament :
|
|
pika_platform_fopen()
|
|
pika_platform_fwrite()
|
|
pika_platform_fclose()
|
|
*/
|
|
|
|
PIKA_RES pikaCompile(char* output_file_name, char* py_lines) {
|
|
PIKA_RES res = PIKA_RES_OK;
|
|
ByteCodeFrame bytecode_frame = {0};
|
|
uint32_t const_pool_size = 0;
|
|
uint32_t instruct_array_size = 0;
|
|
uint32_t bytecode_size = 0;
|
|
char void_ = 0;
|
|
FILE* bytecode_f = pika_platform_fopen(output_file_name, "wb+");
|
|
if (NULL == bytecode_f) {
|
|
pika_platform_printf("Error: open file %s failed.\r\n",
|
|
output_file_name);
|
|
res = PIKA_RES_ERR_IO_ERROR;
|
|
goto __exit;
|
|
}
|
|
/* main process */
|
|
|
|
/* step 1, get size of const pool and instruct array */
|
|
byteCodeFrame_init(&bytecode_frame);
|
|
bytecode_frame.const_pool.output_f = bytecode_f;
|
|
bytecode_frame.instruct_array.output_f = bytecode_f;
|
|
bytecode_frame.instruct_array.output_redirect_fun =
|
|
__handler_instructArray_output_none;
|
|
res = pika_lines2Bytes(&bytecode_frame, py_lines);
|
|
if (PIKA_RES_OK != res) {
|
|
pika_platform_printf(" Error: Syntax error.\r\n");
|
|
goto __exit;
|
|
}
|
|
const_pool_size = bytecode_frame.const_pool.size;
|
|
instruct_array_size = bytecode_frame.instruct_array.size;
|
|
bytecode_size = const_pool_size + instruct_array_size +
|
|
sizeof(const_pool_size) + sizeof(instruct_array_size);
|
|
byteCodeFrame_deinit(&bytecode_frame);
|
|
|
|
/* step 2, write instruct array to file */
|
|
/* write magic code */
|
|
pika_platform_fwrite(magic_code_pyo, 1, sizeof(magic_code_pyo), bytecode_f);
|
|
/* write bytecode size */
|
|
pika_platform_fwrite(&bytecode_size, 1, sizeof(bytecode_size), bytecode_f);
|
|
/* write ins array size */
|
|
pika_platform_fwrite(&instruct_array_size, 1, sizeof(instruct_array_size),
|
|
bytecode_f);
|
|
byteCodeFrame_init(&bytecode_frame);
|
|
bytecode_frame.const_pool.output_f = bytecode_f;
|
|
bytecode_frame.instruct_array.output_f = bytecode_f;
|
|
/* instruct array to file */
|
|
bytecode_frame.instruct_array.output_redirect_fun =
|
|
__handler_instructArray_output_file;
|
|
pika_lines2Bytes(&bytecode_frame, py_lines);
|
|
byteCodeFrame_deinit(&bytecode_frame);
|
|
|
|
/* step 3, write const pool to file */
|
|
pika_platform_fwrite(&const_pool_size, 1, sizeof(const_pool_size),
|
|
bytecode_f);
|
|
void_ = 0;
|
|
/* add \0 at the start */
|
|
pika_platform_fwrite(&void_, 1, 1, bytecode_f);
|
|
byteCodeFrame_init(&bytecode_frame);
|
|
bytecode_frame.const_pool.output_f = bytecode_f;
|
|
bytecode_frame.instruct_array.output_f = bytecode_f;
|
|
/* const pool to file */
|
|
bytecode_frame.const_pool.output_redirect_fun =
|
|
__handler_constPool_output_file;
|
|
/* instruct array to none */
|
|
bytecode_frame.instruct_array.output_redirect_fun =
|
|
__handler_instructArray_output_none;
|
|
pika_lines2Bytes(&bytecode_frame, py_lines);
|
|
|
|
/* deinit */
|
|
__exit:
|
|
byteCodeFrame_deinit(&bytecode_frame);
|
|
if (NULL != bytecode_f) {
|
|
pika_platform_fclose(bytecode_f);
|
|
}
|
|
/* succeed */
|
|
return res;
|
|
};
|
|
|
|
/*
|
|
need implament :
|
|
pika_platform_fopen()
|
|
pika_platform_fread()
|
|
pika_platform_fwrite()
|
|
pika_platform_fclose()
|
|
*/
|
|
PIKA_RES pikaCompileFileWithOutputName(char* output_file_name,
|
|
char* input_file_name) {
|
|
Args buffs = {0};
|
|
Arg* input_file_arg = arg_loadFile(NULL, input_file_name);
|
|
if (NULL == input_file_arg) {
|
|
pika_platform_printf("Error: Could not load file '%s'\n",
|
|
input_file_name);
|
|
return PIKA_RES_ERR_IO_ERROR;
|
|
}
|
|
char* lines = (char*)arg_getBytes(input_file_arg);
|
|
lines = strsFilePreProcess(&buffs, lines);
|
|
PIKA_RES res = pikaCompile(output_file_name, lines);
|
|
arg_deinit(input_file_arg);
|
|
strsDeinit(&buffs);
|
|
return res;
|
|
}
|
|
|
|
PIKA_RES pikaCompileFile(char* input_file_name) {
|
|
Args buffs = {0};
|
|
char* output_file_name = strsGetFirstToken(&buffs, input_file_name, '.');
|
|
output_file_name = strsAppend(&buffs, input_file_name, ".o");
|
|
PIKA_RES res =
|
|
pikaCompileFileWithOutputName(output_file_name, input_file_name);
|
|
strsDeinit(&buffs);
|
|
return res;
|
|
}
|
|
|
|
LibObj* New_LibObj(Args* args) {
|
|
LibObj* self = New_PikaObj();
|
|
return self;
|
|
}
|
|
|
|
void LibObj_deinit(LibObj* self) {
|
|
obj_deinit(self);
|
|
}
|
|
|
|
/* add bytecode to lib, not copy the bytecode */
|
|
void LibObj_dynamicLink(LibObj* self, char* module_name, uint8_t* bytecode) {
|
|
Args buffs = {0};
|
|
char* module_obj_name = strsReplace(&buffs, module_name, ".", "|");
|
|
if (!obj_isArgExist(self, module_obj_name)) {
|
|
obj_newObj(self, module_obj_name, "", New_TinyObj);
|
|
}
|
|
PikaObj* module_obj = obj_getObj(self, module_obj_name);
|
|
obj_setStr(module_obj, "name", module_name);
|
|
obj_setPtr(module_obj, "bytecode", bytecode);
|
|
strsDeinit(&buffs);
|
|
}
|
|
|
|
/*
|
|
* @brief add bytecode to lib, and copy the bytecode to the buff in the lib
|
|
* @param self the lib obj
|
|
* @param module_name the module name
|
|
* @param bytecode the bytecode
|
|
* @param size the size of the bytecode
|
|
* @return error code
|
|
*/
|
|
int LibObj_staticLink(LibObj* self,
|
|
char* module_name,
|
|
uint8_t* bytecode,
|
|
size_t size) {
|
|
Args buffs = {0};
|
|
char* module_obj_name = strsReplace(&buffs, module_name, ".", "|");
|
|
if (!obj_isArgExist(self, module_obj_name)) {
|
|
obj_newObj(self, module_obj_name, "", New_TinyObj);
|
|
}
|
|
PikaObj* module_obj = obj_getObj(self, module_obj_name);
|
|
uint16_t name_len = strGetSize(module_name);
|
|
|
|
/* copy bytecode to buff */
|
|
obj_setBytes(module_obj, "buff", bytecode, size);
|
|
obj_setInt(module_obj, "namelen", name_len);
|
|
obj_setInt(module_obj, "bytesize", size);
|
|
|
|
/* link to buff */
|
|
LibObj_dynamicLink(self, module_name, obj_getBytes(module_obj, "buff"));
|
|
strsDeinit(&buffs);
|
|
return 0;
|
|
}
|
|
|
|
int LibObj_staticLinkFileWithPath(LibObj* self,
|
|
char* input_file_name,
|
|
char* path) {
|
|
Args buffs = {0};
|
|
/* read file */
|
|
Arg* input_file_arg = arg_loadFile(NULL, input_file_name);
|
|
if (NULL == input_file_arg) {
|
|
pika_platform_printf("Error: can't open file %s\r\n", input_file_name);
|
|
return -1;
|
|
}
|
|
char* module_name = strsGetLastToken(&buffs, input_file_name, '/');
|
|
|
|
size_t module_name_len = strlen(module_name);
|
|
|
|
/* cut off '.py.o' */
|
|
if (module_name[module_name_len - 1] == 'o' &&
|
|
module_name[module_name_len - 2] == '.' &&
|
|
module_name[module_name_len - 3] == 'y' &&
|
|
module_name[module_name_len - 4] == 'p' &&
|
|
module_name[module_name_len - 5] == '.') {
|
|
module_name[module_name_len - 5] = 0;
|
|
} else {
|
|
// pika_platform_printf("linking raw %s:%s:%ld\r\n", input_file_name,
|
|
// module_name, arg_getBytecodeSize(input_file_arg));
|
|
/* replace . to | */
|
|
module_name = strsReplace(&buffs, module_name, ".", "|");
|
|
}
|
|
char* module_name_new = strsPathJoin(&buffs, path, module_name);
|
|
|
|
/* push bytecode */
|
|
uint8_t* byte_code = arg_getBytecode(input_file_arg);
|
|
size_t code_size = arg_getBytecodeSize(input_file_arg);
|
|
LibObj_staticLink(self, module_name_new, byte_code, code_size);
|
|
|
|
/* deinit */
|
|
strsDeinit(&buffs);
|
|
arg_deinit(input_file_arg);
|
|
return 0;
|
|
}
|
|
|
|
int LibObj_staticLinkFile(LibObj* self, char* input_file_name) {
|
|
return LibObj_staticLinkFileWithPath(self, input_file_name, "");
|
|
}
|
|
|
|
static int32_t __foreach_handler_listModules(Arg* argEach, void* context) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
pika_platform_printf("%s\r\n", obj_getStr(module_obj, "name"));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void LibObj_listModules(LibObj* self) {
|
|
args_foreach(self->list, __foreach_handler_listModules, NULL);
|
|
}
|
|
|
|
typedef struct {
|
|
FILE* out_file;
|
|
uint32_t module_num;
|
|
uint32_t sum_size;
|
|
uint32_t block_size;
|
|
size_t written_size;
|
|
} PikaLinker;
|
|
|
|
static void linker_fwrite(PikaLinker* context, uint8_t* bytes, size_t size) {
|
|
size_t write_size = pika_platform_fwrite(bytes, 1, size, context->out_file);
|
|
context->written_size += write_size;
|
|
}
|
|
|
|
static int32_t __foreach_handler_libWriteBytecode(Arg* argEach,
|
|
PikaLinker* context) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
pika_assert_obj_alive(module_obj);
|
|
uint8_t* bytecode = obj_getPtr(module_obj, "bytecode");
|
|
size_t bytecode_size = obj_getBytesSize(module_obj, "buff");
|
|
/* align by 4 bytes */
|
|
size_t align_size =
|
|
align_by(bytecode_size, sizeof(uint32_t)) - bytecode_size;
|
|
uint8_t aline_buff[sizeof(uint32_t)] = {0};
|
|
// pika_platform_printf(" linking %s:%ld\r\n", obj_getStr(module_obj,
|
|
// "name"),
|
|
// bytecode_size);
|
|
linker_fwrite(context, bytecode, bytecode_size);
|
|
linker_fwrite(context, aline_buff, align_size);
|
|
// printf("link success:%s\r\n", obj_getStr(module_obj, "name"));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// #define NAME_BUFF_SIZE LIB_INFO_BLOCK_SIZE - sizeof(uint32_t)
|
|
static int32_t __foreach_handler_libWriteIndex(Arg* argEach,
|
|
PikaLinker* linker) {
|
|
Args buffs = {0};
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
uint32_t bytecode_size = obj_getInt(module_obj, "bytesize");
|
|
uint32_t bytecode_size_align = align_by(bytecode_size, 4);
|
|
char* module_name = obj_getStr(module_obj, "name");
|
|
module_name = strsReplace(&buffs, module_name, "|", ".");
|
|
uint32_t name_size = strGetSize(module_name);
|
|
char* block_buff = (char*)pikaMalloc(linker->block_size);
|
|
pika_platform_memset(block_buff, 0x00, linker->block_size);
|
|
|
|
/*
|
|
*create the block as [name][bytecode_size]
|
|
* the space of name is LIB_INFO_BLOCK_SIZE - sizeof(bytecode_size)
|
|
*/
|
|
|
|
pika_platform_memcpy(block_buff, module_name,
|
|
name_size + 1); /* add '\0' after name */
|
|
/* should write the size without align */
|
|
pika_platform_memcpy(
|
|
block_buff + linker->block_size - sizeof(bytecode_size_align),
|
|
&bytecode_size, sizeof(bytecode_size_align));
|
|
|
|
/* write the block to file */
|
|
linker_fwrite(linker, (uint8_t*)block_buff, linker->block_size);
|
|
pikaFree(block_buff, linker->block_size);
|
|
}
|
|
strsDeinit(&buffs);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t __foreach_handler_selectBlockSize(Arg* argEach,
|
|
PikaLinker* linker) {
|
|
uint32_t block_size = 0; /* block_size is the size of file info */
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
/* namelen(aligned by 4bytes) and bytecode_size(uint32_t) */
|
|
block_size =
|
|
align_by(obj_getInt(module_obj, "namelen"), 4) + sizeof(uint32_t);
|
|
if (block_size > linker->block_size) {
|
|
// block_size should support the langest module name
|
|
linker->block_size = block_size;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int32_t __foreach_handler_libSumSize(Arg* argEach, PikaLinker* linker) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
/* namelen(aligned by 4bytes) and bytecode_size(uint32_t) */
|
|
uint32_t bytecode_size =
|
|
obj_getInt(module_obj, "bytesize"); /* size of every module obj */
|
|
/* align the bytecode_size by 4 bytes */
|
|
linker->sum_size += align_by(bytecode_size, 4);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int32_t __foreach_handler_getModuleNum(Arg* argEach,
|
|
PikaLinker* linker) {
|
|
if (arg_isObject(argEach)) {
|
|
linker->module_num++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int LibObj_linkFile(LibObj* self, char* output_file_name) {
|
|
FILE* out_file = pika_platform_fopen(output_file_name, "wb+");
|
|
|
|
PikaLinker linker = {0};
|
|
linker.block_size = 64; /* 64 is the default block size */
|
|
linker.out_file = out_file;
|
|
|
|
/* write meta information */
|
|
args_foreach(self->list, (fn_args_foreach)__foreach_handler_getModuleNum,
|
|
&linker);
|
|
|
|
/* select block size of pya */
|
|
args_foreach(self->list, (fn_args_foreach)__foreach_handler_selectBlockSize,
|
|
&linker);
|
|
|
|
/* get sum size of pya */
|
|
args_foreach(self->list, (fn_args_foreach)__foreach_handler_libSumSize,
|
|
&linker);
|
|
|
|
/* meta info */
|
|
char magic_code[] = {0x0f, 'p', 'y', 'a'};
|
|
uint32_t version_num = LIB_VERSION_NUMBER;
|
|
uint32_t module_num = linker.module_num;
|
|
uint32_t modules_size = linker.sum_size;
|
|
uint32_t block_size = linker.block_size;
|
|
uint32_t totle_size = block_size * (module_num + 1) + modules_size;
|
|
uint8_t* meta_block_buff = pikaMalloc(block_size);
|
|
pika_platform_memset(meta_block_buff, 0, block_size);
|
|
|
|
/* write meta info */
|
|
const uint32_t magic_code_offset =
|
|
sizeof(uint32_t) * PIKA_APP_MAGIC_CODE_OFFSET;
|
|
const uint32_t totle_size_offset =
|
|
sizeof(uint32_t) * PIKA_APP_MODULE_SIZE_OFFSET;
|
|
const uint32_t version_offset = sizeof(uint32_t) * PIKA_APP_VERSION_OFFSET;
|
|
const uint32_t module_num_offset =
|
|
sizeof(uint32_t) * PIKA_APP_MODULE_NUM_OFFSET;
|
|
const uint32_t info_block_size_offset =
|
|
sizeof(uint32_t) * PIKA_APP_INFO_BLOCK_SIZE_OFFSET;
|
|
|
|
// the meta info is the first block
|
|
pika_platform_memcpy(meta_block_buff + magic_code_offset, &magic_code,
|
|
sizeof(uint32_t));
|
|
pika_platform_memcpy(meta_block_buff + version_offset, &version_num,
|
|
sizeof(uint32_t));
|
|
/* write module_num to the file */
|
|
pika_platform_memcpy(meta_block_buff + module_num_offset, &module_num,
|
|
sizeof(uint32_t));
|
|
/* write modules_size to the file */
|
|
pika_platform_memcpy(meta_block_buff + totle_size_offset, &totle_size,
|
|
sizeof(uint32_t));
|
|
/* write block_size to the file */
|
|
pika_platform_memcpy(meta_block_buff + info_block_size_offset, &block_size,
|
|
sizeof(uint32_t));
|
|
linker_fwrite(&linker, meta_block_buff, block_size);
|
|
/* write module index to file */
|
|
args_foreach(self->list, (fn_args_foreach)__foreach_handler_libWriteIndex,
|
|
&linker);
|
|
/* write module bytecode to file */
|
|
args_foreach(self->list,
|
|
(fn_args_foreach)__foreach_handler_libWriteBytecode, &linker);
|
|
/* main process */
|
|
/* deinit */
|
|
pika_platform_fclose(out_file);
|
|
pikaFree(meta_block_buff, block_size);
|
|
pika_assert(totle_size == linker.written_size);
|
|
return 0;
|
|
}
|
|
|
|
static int _getModuleNum(uint8_t* library_bytes) {
|
|
if (0 != ((intptr_t)library_bytes & 0x03)) {
|
|
return PIKA_RES_ERR_UNALIGNED_PTR;
|
|
}
|
|
|
|
char* magic_code = (char*)library_bytes;
|
|
|
|
uint32_t* library_info = (uint32_t*)library_bytes;
|
|
uint32_t version_num = library_info[PIKA_APP_VERSION_OFFSET];
|
|
uint32_t module_num = library_info[PIKA_APP_MODULE_NUM_OFFSET];
|
|
|
|
/* check magic_code */
|
|
if (!((magic_code[0] == 0x0f) && (magic_code[1] == 'p') &&
|
|
(magic_code[2] == 'y') && (magic_code[3] == 'a'))) {
|
|
pika_platform_printf("Error: invalid magic code.\r\n");
|
|
return PIKA_RES_ERR_ILLEGAL_MAGIC_CODE;
|
|
}
|
|
/* check version num */
|
|
if (version_num != LIB_VERSION_NUMBER) {
|
|
pika_platform_printf(
|
|
"Error: invalid version number. Expected %d, got %d\r\n",
|
|
LIB_VERSION_NUMBER, version_num);
|
|
pika_platform_printf(
|
|
"Please run the 'rus-msc-latest-win10.exe' again to update the "
|
|
"version of compiled library.\r\n");
|
|
return PIKA_RES_ERR_INVALID_VERSION_NUMBER;
|
|
}
|
|
return module_num;
|
|
}
|
|
|
|
#define MOD_NAMELEN_OFFSET 0
|
|
#define MOD_NAME_OFFSET 4
|
|
#define MOD_SIZE_OFFSET (name_len + 5) /* 5 = 4 + 1*/
|
|
|
|
static PIKA_RES _loadModuleDataWithIndex(uint8_t* library_bytes,
|
|
int module_num,
|
|
int module_index,
|
|
char** name_p,
|
|
uint8_t** addr_p,
|
|
size_t* size) {
|
|
uint32_t block_size = *(uint32_t*)(library_bytes + 4 * sizeof(uint32_t));
|
|
uint8_t* file_info_block_start = library_bytes + block_size;
|
|
uint8_t* bytecode_ptr = file_info_block_start + block_size * module_num;
|
|
uint8_t* bytecode_ptr_next = bytecode_ptr;
|
|
uint32_t module_size = 0;
|
|
char* module_name = NULL;
|
|
uintptr_t offset = 0;
|
|
for (uint32_t i = 0; i < module_index + 1; i++) {
|
|
uint8_t* file_info_block = file_info_block_start + offset;
|
|
module_name = (char*)(file_info_block);
|
|
module_size =
|
|
*(uint32_t*)(file_info_block + block_size - sizeof(uint32_t));
|
|
bytecode_ptr = bytecode_ptr_next;
|
|
offset += block_size;
|
|
/* next module ptr, align by 4 bytes */
|
|
bytecode_ptr_next += align_by(module_size, 4);
|
|
}
|
|
*name_p = module_name;
|
|
*addr_p = bytecode_ptr;
|
|
*size = module_size;
|
|
/* fix size for string */
|
|
PIKA_BOOL bIsString = PIKA_TRUE;
|
|
for (size_t i = 0; i < module_size - 1; ++i) {
|
|
if (bytecode_ptr[i] == 0) {
|
|
bIsString = PIKA_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (bIsString) {
|
|
/* remove the last '\0' for stirng */
|
|
if (bytecode_ptr[module_size - 1] == 0) {
|
|
*size -= 1;
|
|
}
|
|
}
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
PIKA_RES _loadModuleDataWithName(uint8_t* library_bytes,
|
|
char* module_name,
|
|
uint8_t** addr_p,
|
|
size_t* size_p) {
|
|
int module_num = _getModuleNum(library_bytes);
|
|
if (module_num < 0) {
|
|
return (PIKA_RES)module_num;
|
|
}
|
|
|
|
Args buffs = {0};
|
|
|
|
for (int i = 0; i < module_num; i++) {
|
|
char* name = NULL;
|
|
uint8_t* addr = NULL;
|
|
size_t size = 0;
|
|
_loadModuleDataWithIndex(library_bytes, module_num, i, &name, &addr,
|
|
&size);
|
|
name = strsGetLastToken(&buffs, name, '/');
|
|
|
|
if (strEqu(module_name, name)) {
|
|
*addr_p = addr;
|
|
*size_p = size;
|
|
strsDeinit(&buffs);
|
|
return PIKA_RES_OK;
|
|
}
|
|
}
|
|
strsDeinit(&buffs);
|
|
return PIKA_RES_ERR_ARG_NO_FOUND;
|
|
}
|
|
|
|
Arg* _getPack_libraryBytes(char* pack_name) {
|
|
if (NULL == pack_name) {
|
|
pika_platform_printf(
|
|
"[%s - %d]What I freakin' need is a damn pack file name! Why the "
|
|
"hell did you give me a goddamn NULL?!\r\n",
|
|
__FILE__, __LINE__);
|
|
return NULL;
|
|
}
|
|
|
|
Arg* f_arg = NULL;
|
|
f_arg = arg_loadFile(NULL, pack_name);
|
|
if (NULL == f_arg) {
|
|
pika_platform_printf("Error: Could not load file \'%s\'\r\n",
|
|
pack_name);
|
|
// pikaFree(*fp, sizeof(pikafs_FILE));
|
|
// arg_deinit(f_arg);
|
|
return NULL;
|
|
}
|
|
return f_arg;
|
|
}
|
|
|
|
typedef struct {
|
|
char* module_name;
|
|
PikaObj* module;
|
|
} Context_LibObj_getModule;
|
|
|
|
int32_t _handler_LibObj_getModule(Arg* argEach, void* context) {
|
|
Context_LibObj_getModule* ctx = context;
|
|
if (NULL != ctx->module) {
|
|
return 0;
|
|
}
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
if (strEqu(obj_getStr(module_obj, "name"), ctx->module_name)) {
|
|
ctx->module = module_obj;
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PikaObj* LibObj_getModule(LibObj* self, char* module_name) {
|
|
Context_LibObj_getModule context = {0};
|
|
context.module_name = module_name;
|
|
args_foreach(self->list, _handler_LibObj_getModule, &context);
|
|
return context.module;
|
|
}
|
|
|
|
/*
|
|
redirect import to module
|
|
example:
|
|
when IMP XXX.YYY.ZZZ and ZZZ is a calss
|
|
then redirect to IMP XXX.YYY
|
|
*/
|
|
char* LibObj_redirectModule(LibObj* self, Args* buffs_out, char* module_name) {
|
|
if (NULL == self) {
|
|
return NULL;
|
|
}
|
|
char* module_name_new = NULL;
|
|
PikaObj* module_obj = NULL;
|
|
Args buffs = {0};
|
|
size_t token_num = strCountSign(module_name, '.');
|
|
if (0 == token_num) {
|
|
goto __exit;
|
|
}
|
|
module_obj = LibObj_getModule(self, module_name);
|
|
if (NULL != module_obj) {
|
|
module_name_new = module_name;
|
|
goto __exit;
|
|
}
|
|
module_name_new = strsCopy(&buffs, module_name);
|
|
for (int i = 0; i < token_num + 1; i++) {
|
|
PikaObj* module_obj = LibObj_getModule(self, module_name_new);
|
|
if (NULL != module_obj) {
|
|
goto __exit;
|
|
}
|
|
strPopLastToken(module_name_new, '.');
|
|
}
|
|
__exit:
|
|
if (NULL != module_name_new) {
|
|
module_name_new = strsCopy(buffs_out, module_name_new);
|
|
}
|
|
strsDeinit(&buffs);
|
|
return module_name_new;
|
|
}
|
|
|
|
int LibObj_loadLibrary(LibObj* self, uint8_t* library_bytes) {
|
|
int module_num = _getModuleNum(library_bytes);
|
|
if (module_num < 0) {
|
|
/* load error */
|
|
return module_num;
|
|
}
|
|
for (uint32_t i = 0; i < module_num; i++) {
|
|
char* module_name = NULL;
|
|
uint8_t* bytecode_addr = NULL;
|
|
size_t bytecode_size = 0;
|
|
_loadModuleDataWithIndex(library_bytes, module_num, i, &module_name,
|
|
&bytecode_addr, &bytecode_size);
|
|
LibObj_dynamicLink(self, module_name, bytecode_addr);
|
|
}
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
int32_t __foreach_handler_printModule(Arg* argEach, void* context) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
char* module_name = obj_getStr(module_obj, "name");
|
|
if (NULL != module_name) {
|
|
pika_platform_printf(module_name);
|
|
pika_platform_printf("\r\n");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void LibObj_printModules(LibObj* self) {
|
|
args_foreach(self->list, __foreach_handler_printModule, NULL);
|
|
}
|
|
|
|
int LibObj_loadLibraryFile(LibObj* self, char* lib_file_name) {
|
|
Arg* aFile = arg_loadFile(NULL, lib_file_name);
|
|
if (NULL == aFile) {
|
|
pika_platform_printf("Error: Could not load library file '%s'\n",
|
|
lib_file_name);
|
|
return PIKA_RES_ERR_IO_ERROR;
|
|
}
|
|
/* save file_arg as @lib_buf to libObj */
|
|
obj_setArg_noCopy(self, "@lib_buf", aFile);
|
|
if (0 != LibObj_loadLibrary(self, arg_getBytes(aFile))) {
|
|
pika_platform_printf("Error: Could not load library from '%s'\n",
|
|
lib_file_name);
|
|
return PIKA_RES_ERR_OPERATION_FAILED;
|
|
}
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief unpack *.pack file to Specified path
|
|
*
|
|
* @param pack_name the name of *.pack file
|
|
* @param out_path output path
|
|
* @return
|
|
*/
|
|
PIKA_RES pikafs_unpack_files(char* pack_name, char* out_path) {
|
|
PIKA_RES stat = PIKA_RES_OK;
|
|
Arg* file_arg = NULL;
|
|
uint8_t* library_bytes = NULL;
|
|
pikafs_FILE* fptr = NULL;
|
|
if (NULL == out_path) {
|
|
out_path = "./packout/";
|
|
}
|
|
|
|
file_arg = _getPack_libraryBytes(pack_name);
|
|
if (NULL != file_arg) {
|
|
library_bytes = arg_getBytes(file_arg);
|
|
} else {
|
|
return PIKA_RES_ERR_IO_ERROR;
|
|
}
|
|
|
|
int module_num = _getModuleNum(library_bytes);
|
|
if (module_num < 0) {
|
|
return (PIKA_RES)module_num;
|
|
}
|
|
|
|
Args buffs = {0};
|
|
char* output_file_path = NULL;
|
|
FILE* new_fp = NULL;
|
|
char* name = NULL;
|
|
uint8_t* addr = NULL;
|
|
size_t size = 0;
|
|
|
|
for (int i = 0; i < module_num; ++i) {
|
|
size = 0;
|
|
stat = _loadModuleDataWithIndex(library_bytes, module_num, i, &name,
|
|
&addr, &size);
|
|
name = strsGetLastToken(&buffs, name, '/');
|
|
output_file_path = strsPathJoin(&buffs, out_path, name);
|
|
pika_platform_printf("output_file_path: %s\r\n", output_file_path);
|
|
new_fp = pika_platform_fopen(output_file_path, "wb+");
|
|
|
|
if (NULL != new_fp) {
|
|
pika_platform_fwrite(addr, size, 1, new_fp);
|
|
pika_platform_fclose(new_fp);
|
|
pika_platform_printf("unpack %s to %s\r\n", name, output_file_path);
|
|
} else {
|
|
pika_platform_printf("can't open %s\r\n", output_file_path);
|
|
stat = PIKA_RES_ERR_IO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
arg_deinit(file_arg);
|
|
strsDeinit(&buffs);
|
|
pikaFree(fptr, sizeof(pikafs_FILE));
|
|
return stat;
|
|
}
|
|
|
|
size_t pika_fputs(char* str, FILE* fp) {
|
|
size_t size = strGetSize(str);
|
|
return pika_platform_fwrite(str, 1, size, fp);
|
|
}
|
|
|
|
int Lib_loadLibraryFileToArray(char* origin_file_name, char* out_folder) {
|
|
Args buffs = {0};
|
|
Arg* file_arg = arg_loadFile(NULL, origin_file_name);
|
|
int res = 0;
|
|
if (NULL == file_arg) {
|
|
pika_platform_printf("Error: Could not load file '%s'\n",
|
|
origin_file_name);
|
|
return 1;
|
|
}
|
|
char* output_file_name = NULL;
|
|
output_file_name = strsGetLastToken(&buffs, origin_file_name, '/');
|
|
output_file_name = strsAppend(&buffs, "__asset_", output_file_name);
|
|
output_file_name = strsReplace(&buffs, output_file_name, ".", "_");
|
|
output_file_name = strsAppend(&buffs, output_file_name, ".c");
|
|
|
|
char* output_file_path = strsPathJoin(&buffs, out_folder, output_file_name);
|
|
|
|
FILE* fp = pika_platform_fopen(output_file_path, "wb+");
|
|
char* array_name = strsGetLastToken(&buffs, origin_file_name, '/');
|
|
array_name = strsReplace(&buffs, array_name, ".", "_");
|
|
pika_platform_printf(" loading %s[]...\n", array_name);
|
|
pika_fputs("#include \"PikaPlatform.h\"\n", fp);
|
|
pika_fputs("/* warning: auto generated file, please do not modify */\n",
|
|
fp);
|
|
pika_fputs("PIKA_BYTECODE_ALIGN const unsigned char ", fp);
|
|
pika_fputs(array_name, fp);
|
|
pika_fputs("[] = {", fp);
|
|
char byte_buff[32] = {0};
|
|
uint8_t* array = arg_getBytes(file_arg);
|
|
for (size_t i = 0; i < arg_getBytesSize(file_arg); i++) {
|
|
if (i % 12 == 0) {
|
|
pika_fputs("\n ", fp);
|
|
}
|
|
pika_sprintf(byte_buff, "0x%02x, ", array[i]);
|
|
pika_fputs(byte_buff, fp);
|
|
}
|
|
|
|
pika_fputs("\n};\n", fp);
|
|
res = 0;
|
|
goto __exit;
|
|
|
|
__exit:
|
|
pika_platform_fclose(fp);
|
|
strsDeinit(&buffs);
|
|
arg_deinit(file_arg);
|
|
return res;
|
|
}
|
|
|
|
static PIKA_RES __Maker_compileModuleWithInfo(PikaMaker* self,
|
|
char* module_name) {
|
|
Args buffs = {0};
|
|
char* input_file_name = strsReplace(&buffs, module_name, ".", "/");
|
|
input_file_name = strsAppend(&buffs, input_file_name, ".py");
|
|
char* input_file_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), input_file_name);
|
|
pika_platform_printf(" compiling %s...\r\n", input_file_name);
|
|
char* output_file_name = strsAppend(&buffs, module_name, ".py.o");
|
|
char* output_file_path = NULL;
|
|
output_file_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api");
|
|
output_file_path = strsPathJoin(&buffs, output_file_path, output_file_name);
|
|
PIKA_RES res =
|
|
pikaCompileFileWithOutputName(output_file_path, input_file_path);
|
|
strsDeinit(&buffs);
|
|
return res;
|
|
}
|
|
|
|
PikaMaker* New_PikaMaker(void) {
|
|
PikaMaker* self = New_PikaObj();
|
|
obj_setStr(self, "pwd", "");
|
|
obj_setInt(self, "err", 0);
|
|
LibObj* lib = New_LibObj(NULL);
|
|
obj_setPtr(self, "lib", lib);
|
|
return self;
|
|
}
|
|
|
|
/*
|
|
* @brief: deinit PikaMaker
|
|
* @param: self PikaMaker
|
|
* @return: void
|
|
*/
|
|
void pikaMaker_deinit(PikaMaker* self) {
|
|
LibObj* lib = obj_getPtr(self, "lib");
|
|
LibObj_deinit(lib);
|
|
obj_deinit(self);
|
|
}
|
|
|
|
/*
|
|
* @brief: set pwd
|
|
* @param: self PikaMaker
|
|
* @param: pwd
|
|
* @return: void
|
|
*/
|
|
void pikaMaker_setPWD(PikaMaker* self, char* pwd) {
|
|
obj_setStr(self, "pwd", pwd);
|
|
}
|
|
|
|
/*
|
|
* @brief: set state
|
|
* @param: self PikaMaker
|
|
* @param: module_name
|
|
* @param: state
|
|
* @return: void
|
|
*/
|
|
void pikaMaker_setState(PikaMaker* self, char* module_name, char* state) {
|
|
Args buffs = {0};
|
|
char* module_obj_name = strsReplace(&buffs, module_name, ".", "|");
|
|
obj_newMetaObj(self, module_obj_name, New_TinyObj);
|
|
PikaObj* module_obj = obj_getObj(self, module_obj_name);
|
|
obj_setStr(module_obj, "name", module_name);
|
|
obj_setStr(module_obj, "state", state);
|
|
strsDeinit(&buffs);
|
|
}
|
|
|
|
char* pikaMaker_getState(PikaMaker* self, char* module_name) {
|
|
PikaObj* module_obj = obj_getObj(self, module_name);
|
|
if (NULL == module_obj) {
|
|
return "nocompiled";
|
|
}
|
|
return obj_getStr(module_obj, "state");
|
|
}
|
|
|
|
/*
|
|
* @brief: compile module
|
|
* @param: self PikaMaker
|
|
* @param: module_name
|
|
* @return: PIKA_RES
|
|
*/
|
|
PIKA_RES pikaMaker_compileModule(PikaMaker* self, char* module_name) {
|
|
PIKA_RES res = __Maker_compileModuleWithInfo(self, module_name);
|
|
/* update compile info */
|
|
if (PIKA_RES_OK == res) {
|
|
pikaMaker_setState(self, module_name, "compiled");
|
|
} else {
|
|
pikaMaker_setState(self, module_name, "failed");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
enum PIKA_MODULE_TYPE {
|
|
PIKA_MODULE_TYPE_UNKNOWN,
|
|
PIKA_MODULE_TYPE_PY,
|
|
PIKA_MODULE_TYPE_PYI,
|
|
PIKA_MODULE_TYPE_PYO
|
|
};
|
|
|
|
static enum PIKA_MODULE_TYPE _checkModuleType(char* module_path) {
|
|
Args buffs = {0};
|
|
enum PIKA_MODULE_TYPE module_type = PIKA_MODULE_TYPE_UNKNOWN;
|
|
/* module info is not exist */
|
|
/* set module to be compile */
|
|
FILE* imp_file_py =
|
|
pika_platform_fopen(strsAppend(&buffs, module_path, ".py"), "rb");
|
|
FILE* imp_file_pyi =
|
|
pika_platform_fopen(strsAppend(&buffs, module_path, ".pyi"), "rb");
|
|
FILE* imp_file_pyo =
|
|
pika_platform_fopen(strsAppend(&buffs, module_path, ".py.o"), "rb");
|
|
if (NULL != imp_file_pyo) {
|
|
module_type = PIKA_MODULE_TYPE_PYO;
|
|
goto __exit;
|
|
}
|
|
if (NULL != imp_file_py) {
|
|
module_type = PIKA_MODULE_TYPE_PY;
|
|
goto __exit;
|
|
}
|
|
if (NULL != imp_file_pyi) {
|
|
module_type = PIKA_MODULE_TYPE_PYI;
|
|
goto __exit;
|
|
}
|
|
__exit:
|
|
if (NULL != imp_file_pyo) {
|
|
pika_platform_fclose(imp_file_pyo);
|
|
}
|
|
if (NULL != imp_file_pyi) {
|
|
pika_platform_fclose(imp_file_pyi);
|
|
}
|
|
if (NULL != imp_file_py) {
|
|
pika_platform_fclose(imp_file_py);
|
|
}
|
|
strsDeinit(&buffs);
|
|
return module_type;
|
|
}
|
|
|
|
static char* _redirectModuleFromFs(Args* buffs_out,
|
|
char* module_path,
|
|
char* module_name) {
|
|
Args buffs = {0};
|
|
size_t token_num = strCountSign(module_name, '.');
|
|
char* module_name_new = NULL;
|
|
char* module_try = NULL;
|
|
if (0 == token_num) {
|
|
goto __exit;
|
|
}
|
|
module_try = strsCopy(&buffs, module_path);
|
|
module_name_new = strsCopy(&buffs, module_name);
|
|
for (int i = 0; i < token_num + 1; i++) {
|
|
enum PIKA_MODULE_TYPE module_type = _checkModuleType(module_try);
|
|
if (module_type != PIKA_MODULE_TYPE_UNKNOWN) {
|
|
char* module_name = module_try;
|
|
if (NULL != module_name) {
|
|
goto __exit;
|
|
}
|
|
}
|
|
strPopLastToken(module_try, '/');
|
|
strPopLastToken(module_name_new, '.');
|
|
}
|
|
module_path = NULL;
|
|
__exit:
|
|
if (NULL != module_name_new) {
|
|
module_name_new = strsCopy(buffs_out, module_name_new);
|
|
}
|
|
strsDeinit(&buffs);
|
|
return module_name_new;
|
|
}
|
|
|
|
FILE* _openModuleFile(char* module_path, enum PIKA_MODULE_TYPE module_type) {
|
|
Args buffs = {0};
|
|
FILE* fp = NULL;
|
|
switch (module_type) {
|
|
case PIKA_MODULE_TYPE_PY:
|
|
fp = pika_platform_fopen(strsAppend(&buffs, module_path, ".py"),
|
|
"rb");
|
|
break;
|
|
case PIKA_MODULE_TYPE_PYI:
|
|
fp = pika_platform_fopen(strsAppend(&buffs, module_path, ".pyi"),
|
|
"rb");
|
|
break;
|
|
case PIKA_MODULE_TYPE_PYO:
|
|
fp = pika_platform_fopen(strsAppend(&buffs, module_path, ".py.o"),
|
|
"rb");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
strsDeinit(&buffs);
|
|
return fp;
|
|
}
|
|
|
|
int pikaMaker_linkByteocdeFile(PikaMaker* self, char* imp_module_name) {
|
|
Args buffs = {0};
|
|
char* imp_module_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), imp_module_name);
|
|
FILE* imp_file = _openModuleFile(imp_module_path, PIKA_MODULE_TYPE_PYO);
|
|
pika_platform_printf(" loading %s.py.o...\r\n", imp_module_path);
|
|
/* found *.py.o, push to compiled list */
|
|
pikaMaker_setState(self, imp_module_name, "compiled");
|
|
char* imp_api_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api/");
|
|
imp_api_path = strsPathJoin(&buffs, imp_api_path, imp_module_name);
|
|
FILE* imp_file_pyo_api =
|
|
pika_platform_fopen(strsAppend(&buffs, imp_api_path, ".py.o"), "wb+");
|
|
pika_assert(imp_file_pyo_api != NULL);
|
|
/* copy imp_file_pyo to imp_api_path */
|
|
uint8_t* buff = (uint8_t*)pika_platform_malloc(128);
|
|
size_t read_size = 0;
|
|
while (1) {
|
|
read_size = pika_platform_fread(buff, 1, 128, imp_file);
|
|
if (read_size > 0) {
|
|
pika_platform_fwrite(buff, 1, read_size, imp_file_pyo_api);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
pika_platform_free(buff);
|
|
pika_platform_fclose(imp_file_pyo_api);
|
|
pika_platform_fclose(imp_file);
|
|
strsDeinit(&buffs);
|
|
return 0;
|
|
}
|
|
|
|
int pikaMaker_getDependencies(PikaMaker* self, char* module_name) {
|
|
int res = 0;
|
|
ByteCodeFrame bf = {0};
|
|
Args buffs = {0};
|
|
byteCodeFrame_init(&bf);
|
|
ConstPool* const_pool = NULL;
|
|
InstructArray* ins_array = NULL;
|
|
char* module_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api/");
|
|
module_path = strsPathJoin(&buffs, module_path, module_name);
|
|
char* file_path = strsAppend(&buffs, module_path, ".py.o");
|
|
Arg* file_arg = arg_loadFile(NULL, file_path);
|
|
uint8_t offset_befor = 0;
|
|
if (NULL == file_arg) {
|
|
pika_platform_printf("Error: Could not load file '%s'\n", file_path);
|
|
res = 1;
|
|
goto __exit;
|
|
}
|
|
byteCodeFrame_loadByteCode(&bf, arg_getBytes(file_arg));
|
|
const_pool = &bf.const_pool;
|
|
ins_array = &bf.instruct_array;
|
|
|
|
offset_befor = ins_array->content_offset_now;
|
|
ins_array->content_offset_now = 0;
|
|
while (1) {
|
|
InstructUnit* ins_unit = instructArray_getNow(ins_array);
|
|
if (NULL == ins_unit) {
|
|
goto __exit;
|
|
}
|
|
if (instructUnit_getInstructIndex(ins_unit) == PIKA_INS(IMP) ||
|
|
instructUnit_getInstructIndex(ins_unit) == PIKA_INS(INH)) {
|
|
char* imp_module_name =
|
|
constPool_getByOffset(const_pool, ins_unit->const_pool_index);
|
|
char* imp_module_name_fs =
|
|
strsReplace(&buffs, imp_module_name, ".", "/");
|
|
char* imp_module_path = strsPathJoin(
|
|
&buffs, obj_getStr(self, "pwd"), imp_module_name_fs);
|
|
char* imp_module_name_redirect =
|
|
_redirectModuleFromFs(&buffs, imp_module_path, imp_module_name);
|
|
if (NULL != imp_module_name_redirect) {
|
|
/* redirect to real module */
|
|
imp_module_name = imp_module_name_redirect;
|
|
imp_module_name_fs =
|
|
strsReplace(&buffs, imp_module_name, ".", "/");
|
|
imp_module_path = strsPathJoin(&buffs, obj_getStr(self, "pwd"),
|
|
imp_module_name_fs);
|
|
}
|
|
/* check if compiled the module */
|
|
if (args_isArgExist(self->list, imp_module_name)) {
|
|
/* module info is exist, do nothing */
|
|
} else {
|
|
/* module info is not exist */
|
|
/* set module to be compile */
|
|
enum PIKA_MODULE_TYPE module_type =
|
|
_checkModuleType(imp_module_path);
|
|
if (module_type == PIKA_MODULE_TYPE_PYO) {
|
|
pikaMaker_linkByteocdeFile(self, imp_module_path);
|
|
} else if (module_type == PIKA_MODULE_TYPE_PY) {
|
|
/* found *.py, push to nocompiled list */
|
|
pikaMaker_setState(self, imp_module_name, "nocompiled");
|
|
} else if (module_type == PIKA_MODULE_TYPE_PYI) {
|
|
/* found *.py, push to nocompiled list */
|
|
pikaMaker_setState(self, imp_module_name, "cmodule");
|
|
} else {
|
|
pika_platform_printf(
|
|
" [warning]: file: '%s.pyi', '%s.py' or '%s.py.o' "
|
|
"no found\n",
|
|
imp_module_name_fs, imp_module_name_fs,
|
|
imp_module_name_fs);
|
|
}
|
|
}
|
|
}
|
|
instructArray_getNext(ins_array);
|
|
}
|
|
|
|
__exit:
|
|
if (NULL != ins_array) {
|
|
ins_array->content_offset_now = offset_befor;
|
|
}
|
|
if (NULL != file_arg) {
|
|
arg_deinit(file_arg);
|
|
}
|
|
strsDeinit(&buffs);
|
|
byteCodeFrame_deinit(&bf);
|
|
return res;
|
|
}
|
|
|
|
int32_t __foreach_handler_printStates(Arg* argEach, void* context) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
pika_platform_printf("%s: %s\r\n", obj_getStr(module_obj, "name"),
|
|
obj_getStr(module_obj, "state"));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void pikaMaker_printStates(PikaMaker* self) {
|
|
args_foreach(self->list, __foreach_handler_printStates, NULL);
|
|
}
|
|
|
|
int32_t __foreach_handler_getFirstNocompiled(Arg* argEach, void* context) {
|
|
if (arg_isObject(argEach)) {
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
char* state = obj_getStr(module_obj, "state");
|
|
if (args_isArgExist((Args*)context, "res")) {
|
|
/* already get method */
|
|
return 0;
|
|
}
|
|
if (strEqu("nocompiled", state)) {
|
|
/* push module */
|
|
args_setStr((Args*)context, "res", obj_getStr(module_obj, "name"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char* pikaMaker_getFirstNocompiled(PikaMaker* self) {
|
|
Args context = {0};
|
|
args_foreach(self->list, __foreach_handler_getFirstNocompiled, &context);
|
|
char* res = args_getStr(&context, "res");
|
|
if (NULL == res) {
|
|
/* remove res in maker */
|
|
obj_removeArg(self, "res");
|
|
} else {
|
|
obj_setStr(self, "res", res);
|
|
}
|
|
args_deinit_stack(&context);
|
|
return obj_getStr(self, "res");
|
|
}
|
|
|
|
/*
|
|
* @brief compile module with depends
|
|
* @param self PikaMaker
|
|
* @param module_name
|
|
* @return PIKA_RES
|
|
*/
|
|
PIKA_RES pikaMaker_compileModuleWithDepends(PikaMaker* self,
|
|
char* module_name) {
|
|
PIKA_RES res = PIKA_RES_OK;
|
|
if (!strEqu("nocompiled", pikaMaker_getState(self, module_name))) {
|
|
return PIKA_RES_OK;
|
|
}
|
|
res = pikaMaker_compileModule(self, module_name);
|
|
if (PIKA_RES_OK != res) {
|
|
obj_setInt(self, "err", res);
|
|
return res;
|
|
}
|
|
pikaMaker_getDependencies(self, module_name);
|
|
while (1) {
|
|
char* uncompiled = pikaMaker_getFirstNocompiled(self);
|
|
/* compiled all modules */
|
|
if (NULL == uncompiled) {
|
|
break;
|
|
}
|
|
res = pikaMaker_compileModule(self, uncompiled);
|
|
if (PIKA_RES_OK != res) {
|
|
obj_setInt(self, "err", res);
|
|
return res;
|
|
}
|
|
pikaMaker_getDependencies(self, uncompiled);
|
|
}
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
PIKA_RES pikaMaker_compileModuleWithList(PikaMaker* self, char* list_content) {
|
|
PIKA_RES res = PIKA_RES_OK;
|
|
Args buffs = {0};
|
|
char* module_name = NULL;
|
|
char* module_name_start = list_content;
|
|
char* module_name_end = NULL;
|
|
pika_platform_printf(" <module list>\r\n");
|
|
while (1) {
|
|
module_name_end = strFind(module_name_start, '\n');
|
|
if (NULL == module_name_end) {
|
|
break;
|
|
}
|
|
module_name = strsSubStr(&buffs, module_name_start, module_name_end);
|
|
if (!strIsBlank(module_name)) {
|
|
pika_platform_printf(" - %s\r\n", module_name);
|
|
}
|
|
module_name_start = module_name_end + 1;
|
|
}
|
|
module_name_start = list_content;
|
|
while (1) {
|
|
module_name_end = strFind(module_name_start, '\n');
|
|
if (NULL == module_name_end) {
|
|
break;
|
|
}
|
|
module_name = strsSubStr(&buffs, module_name_start, module_name_end);
|
|
if (!strIsBlank(module_name)) {
|
|
char* module_name_fs = strsReplace(&buffs, module_name, ".", "/");
|
|
enum PIKA_MODULE_TYPE module_type =
|
|
_checkModuleType(module_name_fs);
|
|
if (module_type == PIKA_MODULE_TYPE_PY) {
|
|
res = pikaMaker_compileModuleWithDepends(self, module_name);
|
|
if (PIKA_RES_OK != res) {
|
|
obj_setInt(self, "err", res);
|
|
goto __exit;
|
|
}
|
|
}
|
|
if (module_type == PIKA_MODULE_TYPE_PYO) {
|
|
pikaMaker_linkByteocdeFile(self, module_name);
|
|
}
|
|
if (module_type == PIKA_MODULE_TYPE_UNKNOWN) {
|
|
pika_platform_printf(
|
|
" [warning]: file: '%s.pyi', '%s.py' or '%s.py.o' "
|
|
"no found\n",
|
|
module_name, module_name, module_name);
|
|
}
|
|
}
|
|
module_name_start = module_name_end + 1;
|
|
}
|
|
__exit:
|
|
strsDeinit(&buffs);
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
PIKA_RES pikaMaker_compileModuleWithListFile(PikaMaker* self,
|
|
char* list_file_name) {
|
|
Args buffs = {0};
|
|
PIKA_RES res = PIKA_RES_OK;
|
|
char* folder_path =
|
|
strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api/");
|
|
char* list_file_path = strsPathJoin(&buffs, folder_path, list_file_name);
|
|
char* list_file_content = NULL;
|
|
pika_platform_printf(" loading %s...\r\n", list_file_name);
|
|
Arg* list_file_arg = arg_loadFile(NULL, list_file_path);
|
|
if (NULL == list_file_arg) {
|
|
pika_platform_printf("Error: Could not load file '%s'\n",
|
|
list_file_path);
|
|
res = PIKA_RES_ERR_IO_ERROR;
|
|
goto __exit;
|
|
}
|
|
list_file_content = (char*)arg_getBytes(list_file_arg);
|
|
list_file_content = strsFilePreProcess_ex(&buffs, list_file_content, "\n");
|
|
res = pikaMaker_compileModuleWithList(self, list_file_content);
|
|
goto __exit;
|
|
__exit:
|
|
strsDeinit(&buffs);
|
|
return res;
|
|
}
|
|
|
|
int32_t __foreach_handler_linkCompiledModules(Arg* argEach, void* context) {
|
|
Args buffs = {0};
|
|
if (arg_isObject(argEach)) {
|
|
LibObj* lib = args_getPtr((Args*)context, "@lib");
|
|
PikaMaker* maker = args_getPtr((Args*)context, "__maker");
|
|
PikaObj* module_obj = arg_getPtr(argEach);
|
|
char* module_name = obj_getStr(module_obj, "name");
|
|
char* state = obj_getStr(module_obj, "state");
|
|
if (strEqu(state, "compiled")) {
|
|
char* pwd = obj_getStr(maker, "pwd");
|
|
char* folder_path = strsPathJoin(&buffs, pwd, "pikascript-api/");
|
|
char* module_file_name = strsAppend(&buffs, module_name, ".py.o");
|
|
char* module_file_path =
|
|
strsPathJoin(&buffs, folder_path, module_file_name);
|
|
LibObj_staticLinkFile(lib, module_file_path);
|
|
}
|
|
}
|
|
strsDeinit(&buffs);
|
|
return 0;
|
|
}
|
|
|
|
PIKA_RES _do_pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
|
|
char* lib_path,
|
|
pika_bool gen_c_array) {
|
|
PIKA_RES compile_err = (PIKA_RES)obj_getInt(self, "err");
|
|
if (PIKA_RES_OK != compile_err) {
|
|
pika_platform_printf(" Error: compile failed, link aborted.\r\n");
|
|
return compile_err;
|
|
}
|
|
Args context = {0};
|
|
Args buffs = {0};
|
|
pika_platform_printf(" linking %s...\n", lib_path);
|
|
LibObj* lib = obj_getPtr(self, "lib");
|
|
args_setPtr(&context, "@lib", lib);
|
|
args_setPtr(&context, "__maker", self);
|
|
args_foreach(self->list, __foreach_handler_linkCompiledModules, &context);
|
|
args_deinit_stack(&context);
|
|
char* pwd = obj_getStr(self, "pwd");
|
|
char* lib_path_folder = strsPathGetFolder(&buffs, lib_path);
|
|
char* folder_path = strsPathJoin(&buffs, pwd, lib_path_folder);
|
|
char* lib_file_path = strsPathJoin(&buffs, pwd, lib_path);
|
|
LibObj_linkFile(lib, lib_file_path);
|
|
if (gen_c_array) {
|
|
Lib_loadLibraryFileToArray(lib_file_path, folder_path);
|
|
}
|
|
strsDeinit(&buffs);
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
|
|
char* lib_path) {
|
|
return _do_pikaMaker_linkCompiledModulesFullPath(self, lib_path, pika_true);
|
|
}
|
|
|
|
PIKA_RES _do_pikaMaker_linkCompiledModules(PikaMaker* self,
|
|
char* lib_name,
|
|
pika_bool gen_c_array) {
|
|
Args buffs = {0};
|
|
char* lib_file_path = strsPathJoin(&buffs, "pikascript-api/", lib_name);
|
|
PIKA_RES res = _do_pikaMaker_linkCompiledModulesFullPath(
|
|
self, lib_file_path, gen_c_array);
|
|
strsDeinit(&buffs);
|
|
return res;
|
|
}
|
|
|
|
PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name) {
|
|
return _do_pikaMaker_linkCompiledModules(self, lib_name, pika_true);
|
|
}
|
|
|
|
/*
|
|
* @brief link raw file to library
|
|
* @param self PikaMaker
|
|
* @param file_path
|
|
* @return PIKA_RES
|
|
*/
|
|
PIKA_RES pikaMaker_linkRaw(PikaMaker* self, char* file_path) {
|
|
LibObj* lib = obj_getPtr(self, "lib");
|
|
LibObj_staticLinkFile(lib, file_path);
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
/*
|
|
* @brief link raw file to library
|
|
* @param self PikaMaker
|
|
* @param path of the file to be packed
|
|
* @param path of the file in pikafs
|
|
* @return PIKA_RES
|
|
*/
|
|
PIKA_RES pikaMaker_linkRawWithPath(PikaMaker* self,
|
|
char* file_path,
|
|
char* pack_path) {
|
|
LibObj* lib = obj_getPtr(self, "lib");
|
|
PIKA_RES ret =
|
|
(PIKA_RES)LibObj_staticLinkFileWithPath(lib, file_path, pack_path);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @brief open file from library
|
|
* @param file_name
|
|
* @param mode "r" or "rb"
|
|
* @return pikafs_FILE* or NULL if failed
|
|
*/
|
|
pikafs_FILE* pikafs_fopen(char* file_name, char* mode) {
|
|
pikafs_FILE* f = (pikafs_FILE*)pikaMalloc(sizeof(pikafs_FILE));
|
|
if (NULL == f) {
|
|
return NULL;
|
|
}
|
|
memset(f, 0, sizeof(pikafs_FILE));
|
|
extern volatile PikaObj* __pikaMain;
|
|
uint8_t* library_bytes = obj_getPtr((PikaObj*)__pikaMain, "@libraw");
|
|
if (NULL == library_bytes) {
|
|
goto __error;
|
|
}
|
|
if (PIKA_RES_OK !=
|
|
_loadModuleDataWithName(library_bytes, file_name, &f->addr, &f->size)) {
|
|
goto __error;
|
|
}
|
|
return f;
|
|
|
|
__error:
|
|
pikaFree(f, sizeof(pikafs_FILE));
|
|
return NULL;
|
|
}
|
|
|
|
pikafs_FILE* pikafs_fopen_pack(char* pack_name, char* file_name) {
|
|
pikafs_FILE* f = NULL;
|
|
Arg* file_arg = NULL;
|
|
uint8_t* library_bytes = NULL;
|
|
|
|
f = (pikafs_FILE*)pikaMalloc(sizeof(pikafs_FILE));
|
|
if (NULL == f) {
|
|
pika_platform_printf("Error: malloc failed \r\n");
|
|
goto __malloc_err;
|
|
// return PIKA_RES_ERR_OUT_OF_RANGE;
|
|
}
|
|
memset(f, 0, sizeof(pikafs_FILE));
|
|
|
|
file_arg = _getPack_libraryBytes(pack_name);
|
|
if (NULL != file_arg) {
|
|
library_bytes = arg_getBytes(file_arg);
|
|
} else {
|
|
goto __getpack_err;
|
|
}
|
|
|
|
if (PIKA_RES_OK !=
|
|
_loadModuleDataWithName(library_bytes, file_name, &f->addr, &f->size)) {
|
|
goto __exit;
|
|
}
|
|
|
|
f->farg = file_arg;
|
|
return f;
|
|
|
|
__exit:
|
|
if (NULL != f->farg) {
|
|
arg_deinit(f->farg);
|
|
}
|
|
__getpack_err:
|
|
pikaFree(f, sizeof(pikafs_FILE));
|
|
__malloc_err:
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* @brief read file
|
|
* @param buf the buffer to read
|
|
* @param size size of each item
|
|
* @param count count of items
|
|
* @param f file
|
|
* @return read count
|
|
*/
|
|
int pikafs_fread(void* buf, size_t size, size_t count, pikafs_FILE* f) {
|
|
size_t read_len = size * count;
|
|
if (f->pos >= f->size) {
|
|
return 0;
|
|
}
|
|
if (f->pos + read_len > f->size) {
|
|
read_len = f->size;
|
|
}
|
|
__platform_memcpy(buf, f->addr + f->pos, read_len);
|
|
f->pos += read_len;
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* @brief write file
|
|
* @param buf the buffer to write
|
|
* @param size size of each item
|
|
* @param count count of items
|
|
* @param f file
|
|
* @return write count or -1 if failed
|
|
*/
|
|
int pikafs_fwrite(void* buf, size_t size, size_t count, pikafs_FILE* file) {
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* @brief close file
|
|
* @param f file
|
|
* @return 0 if success
|
|
*/
|
|
int pikafs_fclose(pikafs_FILE* file) {
|
|
if (file->need_free) {
|
|
pikaFree(file->addr, file->size);
|
|
}
|
|
if (NULL != file->farg) {
|
|
arg_deinit(file->farg);
|
|
}
|
|
pikaFree(file, sizeof(pikafs_FILE));
|
|
return 0;
|
|
}
|