static void push_var(struct context *context, struct byte_array *program) { struct byte_array* name = serial_decode_string(program); VM_DEBUGPRINT("VAR %s\n", byte_array_to_string(name)); struct variable *v = find_var(context, name); if (!v) DEBUGPRINT("variable %s not found\n", byte_array_to_string(name)); vm_assert(context, v, "variable %s not found", byte_array_to_string(name)); variable_push(context, v); }
static void push_str(struct context *context, struct byte_array *program) { struct byte_array* str = serial_decode_string(program); VM_DEBUGPRINT("STR '%s'\n", byte_array_to_string(str)); struct variable* v = variable_new_str(context, str); variable_push(context, v); }
static void set(struct context *context, enum Opcode op, struct program_state *state, struct byte_array *program) { struct byte_array *name = serial_decode_string(program); // destination variable name if (!context->runtime) VM_DEBUGPRINT("%s %s\n", op==VM_SET?"SET":"STX", byte_array_to_string(name)); struct variable *value = get_value(context, op); DEBUGPRINT("%s %s to %s\n", op==VM_SET ? "SET" : "STX", byte_array_to_string(name), variable_value_str(context, value)); set_named_variable(context, state, name, value); // set the variable to the value }
// run a file, using the same context struct context *interpret_file_with(struct context *context, struct byte_array *path) { if (NULL == context) { context = context_new(NULL, true, true); } struct byte_array *script = read_file(path, 0, 0); assert_message(NULL != script, "file not found: %s\n", byte_array_to_string(path)); interpret_string(context, script); return context; }
// FOR who IN what WHERE where DO how static bool iterate(struct context *context, enum Opcode op, struct program_state *state, struct byte_array *program) { struct byte_array *who = serial_decode_string(program); struct byte_array *where = serial_decode_string(program); struct byte_array *how = serial_decode_string(program); #ifdef DEBUG DEBUGPRINT("%s %s\n", NUM_TO_STRING(opcodes, op), byte_array_to_string(who)); if (!context->runtime) { if (where && where->length) { DEBUGPRINT("%s\tWHERE\n", indentation(context)); display_code(context, where); } DEBUGPRINT("%s\tDO\n", indentation(context)); display_code(context, how); return false; } #endif bool comprehending = (op == VM_COM); struct variable *result = comprehending ? variable_new_list(context, NULL) : NULL; struct variable *what = variable_pop(context); uint32_t len = variable_length(context, what); for (int i=0; i<len; i++) { struct variable *that = list_get_int(context, what, i); set_named_variable(context, state, who, that); byte_array_reset(where); byte_array_reset(how); if (where && where->length) run(context, where, NULL, true); if (!where || !where->length || test_operand(context)) { if (run(context, how, NULL, true)) // true if run hit VM_RET return true; if (comprehending) { struct variable *item = (struct variable*)stack_pop(context->operand_stack); array_add(result->list, item); } } } if (comprehending) stack_push(context->operand_stack, result); return false; }
// creates directory struct variable *sys_mkdir(struct context *context) { struct variable *value = (struct variable*)stack_pop(context->operand_stack); struct variable *path = (struct variable*)array_get(value->list.ordered, 1); char *path2 = byte_array_to_string(path->str); file_mkdir(path2); free(path2); return NULL; }
struct variable *sys_open(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); char *path2 = byte_array_to_string(path->str); bool result = hal_open(path2); struct variable *result2 = variable_new_bool(context, result); variable_push(context, result2); free(path2); return NULL; }
char *param_str(const struct variable *value, uint32_t index) { if (index >= value->list.ordered->length) return NULL; const struct variable *strv = (struct variable*)array_get(value->list.ordered, index); char *str = NULL; switch (strv->type) { case VAR_NIL: break; case VAR_STR: str = byte_array_to_string(strv->str); break; default: exit_message("wrong param type"); break; } return str; }
// deletes file or folder struct variable *sys_rm(struct context *context) { struct variable *value = (struct variable*)stack_pop(context->operand_stack); struct variable *path = (struct variable*)array_get(value->list.ordered, 1); char *path2 = byte_array_to_string(path->str); assert_message(strlen(path2)>1, "oops"); char rmcmd[100]; sprintf(rmcmd, "rm -rf %s", path2); if (system(rmcmd)) printf("\n\nCould not rm %s\n\n", path2); free(path2); return NULL; }
struct variable *sys_print(struct context *context) { null_check(context); struct variable *args = (struct variable*)stack_pop(context->operand_stack); assert_message(args && args->type==VAR_SRC && args->list.ordered, "bad print arg"); for (int i=1; i<args->list.ordered->length; i++) { struct variable *arg = (struct variable*)array_get(args->list.ordered, i); struct byte_array *str = variable_value(context, arg); if (arg->type == VAR_STR) str = byte_array_part(str, 1, str->length-2); printf("%s\n", byte_array_to_string(str)); } return NULL; }
struct variable *sys_fileattr(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); const char *path2 = byte_array_to_string(path->str); long siz = file_size(path2); long mod = file_timestamp(path2); struct variable *siz2 = variable_new_int(context, (int32_t)siz); struct variable *mod2 = variable_new_int(context, (int32_t)mod); variable_push(context, siz2); variable_push(context, mod2 ); struct variable *result = variable_new_src(context, 2); return result; }
struct byte_array *read_file(const struct byte_array *filename_ba, uint32_t offset, long size) { FILE * file; char *str; const char *filename_str = byte_array_to_string(filename_ba); if (!(file = fopen(filename_str, "rb"))) goto no_file; long available; if ((available = fsize(file)) < 0) goto no_file; available -= offset; //printf("read_file %s @%d size=%ld available=%ld\n", filename_str, offset, size, available); size = size ? MIN(size, available) : available; if (size <= 0) goto no_file; if (size > INPUT_MAX_LEN) goto no_file; if (!(str = (char*)malloc((size_t)size + 1))) goto no_file; if (fseek(file, offset, SEEK_SET)) goto no_file; if (fread(str, 1, (size_t)size, file) == EOF) goto no_file; if (ferror(file)) goto no_file; if (fclose(file)) goto no_file; struct byte_array* ba = byte_array_new_size((uint32_t)size); ba->length = (uint32_t)size; memcpy(ba->data, str, size); //free(filename_str); free(str); return ba; no_file: //free(filename_str); DEBUGPRINT("\nCould not read file %s\n", filename_str); return NULL; }
static inline bool vm_trycatch(struct context *context, struct byte_array *program) { struct byte_array *trial = serial_decode_string(program); DEBUGPRINT("TRY %d\n", trial->length); display_code(context, trial); struct byte_array *name = serial_decode_string(program); struct byte_array *catcher = serial_decode_string(program); DEBUGPRINT("%sCATCH %s %d\n", indentation(context), byte_array_to_string(name), catcher->length); display_code(context, catcher); if (!context->runtime) return false; run(context, trial, NULL, true); if (context->vm_exception) { set_named_variable(context, NULL, name, context->vm_exception); context->vm_exception = NULL; return run(context, catcher, NULL, true); } return false; }
int write_file(const struct byte_array* path, struct byte_array* bytes, uint32_t from, int32_t timestamp) { int result = -1; const char *path2 = byte_array_to_string(path); FILE *file = fopen2(path2); if (NULL == file) goto done; if (fseek(file, from, SEEK_SET)) { perror("fseek"); goto done; } // write bytes if (NULL != bytes) { int r = (int)fwrite(bytes->data, 1, bytes->length, file); int s = fclose(file); result = (r<0) || s; } done: return result; }
struct variable *builtin_method(struct context *context, struct variable *indexable, const struct variable *index) { enum VarType it = indexable->type; char *idxstr = byte_array_to_string(index->str); struct variable *result = NULL; if (!strcmp(idxstr, FNC_LENGTH)) { int n; switch (indexable->type) { case VAR_LST: n = indexable->list.ordered->length; break; case VAR_STR: n = indexable->str->length; break; case VAR_NIL: n = 0; break; default: free(idxstr); exit_message("no length for non-indexable"); return NULL; } result = variable_new_int(context, n); } else if (!strcmp(idxstr, FNC_TYPE)) { const char *typestr = var_type_str(it); result = variable_new_str_chars(context, typestr); } else if (!strcmp(idxstr, FNC_STRING)) { switch (indexable->type) { case VAR_STR: case VAR_BYT: case VAR_FNC: result = variable_copy(context, indexable); break; default: { struct byte_array *vv = variable_value(context, indexable); result = variable_new_str(context, vv); byte_array_del(vv); break; } } } else if (!strcmp(idxstr, FNC_LIST)) result = variable_new_list(context, indexable->list.ordered); else if (!strcmp(idxstr, FNC_KEY)) { if (indexable->type == VAR_KVP) result = indexable->kvp.key; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_VAL)) { if (indexable->type == VAR_KVP) result = indexable->kvp.val; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_KEYS)) result = variable_map_list(context, indexable, &map_keys); else if (!strcmp(idxstr, FNC_VALS)) result = variable_map_list(context, indexable, &map_vals); else if (!strcmp(idxstr, FNC_PACK)) result = variable_new_cfnc(context, &cfnc_pack); else if (!strcmp(idxstr, FNC_SERIALIZE)) result = variable_new_cfnc(context, &cfnc_serialize); else if (!strcmp(idxstr, FNC_DESERIALIZE)) result = variable_new_cfnc(context, &cfnc_deserialize); else if (!strcmp(idxstr, FNC_SORT)) { assert_message(indexable->type == VAR_LST, "sorting non-list"); result = variable_new_cfnc(context, &cfnc_sort); } else if (!strcmp(idxstr, FNC_CHAR)) result = variable_new_cfnc(context, &cfnc_char); else if (!strcmp(idxstr, FNC_HAS)) result = variable_new_cfnc(context, &cfnc_has); else if (!strcmp(idxstr, FNC_FIND)) result = variable_new_cfnc(context, &cfnc_find); else if (!strcmp(idxstr, FNC_PART)) result = variable_new_cfnc(context, &cfnc_part); else if (!strcmp(idxstr, FNC_REMOVE)) result = variable_new_cfnc(context, &cfnc_remove); else if (!strcmp(idxstr, FNC_INSERT)) result = variable_new_cfnc(context, &cfnc_insert); else if (!strcmp(idxstr, FNC_REPLACE)) result = variable_new_cfnc(context, &cfnc_replace); free(idxstr); return result; }