void repl() { char str[FG_MAX_INPUT]; struct context *context = context_new(NULL, true, true); for (;;) { fflush(stdin); str[0] = 0; printf("f> "); if (!fgets(str, FG_MAX_INPUT, stdin)) { if (feof(stdin)) return; if (ferror(stdin)) { printf("unknown error reading stdin\n"); return; } } struct byte_array *input = byte_array_from_string(str); struct byte_array *program = build_string(input, NULL); if (!setjmp(trying)) { run(context, program, NULL, true); } byte_array_del(input); byte_array_del(program); } }
void interpret_file(struct byte_array *path, struct byte_array *args) { struct byte_array *program; if (NULL != args) { struct byte_array *source = read_file(path, 0, 0); if (NULL == source) return; byte_array_append(args, source); program = build_string(args, path); } else { program = build_file(path); } #ifdef DEBUG //display_program(program); #endif execute(program); byte_array_del(program); }
static inline struct variable *cfnc_serialize(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *indexable = (struct variable*)array_get(args->list.ordered, 0); struct byte_array *bits = variable_serialize(context, NULL, indexable); byte_array_reset(bits); struct variable *result = variable_new_str(context, bits); byte_array_del(bits); return result; }
struct variable *sys_load(struct context *context) { struct variable *value = (struct variable*)stack_pop(context->operand_stack); struct variable *path = (struct variable*)array_get(value->list.ordered, 1); struct byte_array *file_bytes = read_file(path->str, 0, 0); if (NULL == file_bytes) return variable_new_nil(context); struct variable *v = variable_deserialize(context, file_bytes); byte_array_del(file_bytes); return v; }
struct variable *sys_save(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *v = param_var(args, 1); struct variable *path = param_var(args, 2); struct byte_array *bytes = byte_array_new(); variable_serialize(context, bytes, v); int w = write_file(path->str, bytes, 0, -1); byte_array_del(bytes); return variable_new_int(context, w); }
int main (int argc, char** argv) { struct sigaction act, oact; // for handling ctrl-c act.sa_handler = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, &oact); if (1 == argc) { repl(); } else { struct byte_array *args = arg2ba(argc, argv); struct byte_array *path = byte_array_from_string(argv[1]); interpret_file(path, args); if (NULL != args) { byte_array_del(args); } byte_array_del(path); } }
// a b c // <sought> <replacement> [<start>] // <start> <length> <replacement> static inline struct variable *cfnc_replace(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *self = (struct variable*)array_get(args->list.ordered, 0); struct variable *a = (struct variable*)array_get(args->list.ordered, 1); struct variable *b = (struct variable*)array_get(args->list.ordered, 2); struct variable *c = args->list.ordered->length > 3 ? (struct variable*)array_get(args->list.ordered, 3) : NULL; null_check(self); null_check(b); assert_message(self->type == VAR_STR, "searching in a non-string"); struct byte_array *replaced = NULL; if (a->type == VAR_STR) { // find a, replace with b assert_message(b->type == VAR_STR, "non-string replacement"); int32_t where = 0; if (c) { // replace first match after index c assert_message(c->type == VAR_INT, "non-integer index"); if (((where = byte_array_find(self->str, a->str, c->integer)) >= 0)) replaced = byte_array_replace(self->str, b->str, where, b->str->length); } else { replaced = byte_array_replace_all(self->str, a->str, b->str); } } else if (a->type == VAR_INT ) { // replace at index a, length b, insert c assert_message(a || a->type == VAR_INT, "non-integer count"); assert_message(b || b->type == VAR_INT, "non-integer start"); replaced = byte_array_replace(self->str, c->str, a->integer, b->integer); } else exit_message("replacement is not a string"); null_check(replaced); struct variable *result = variable_new_str(context, replaced); byte_array_del(replaced); return result; }
struct byte_array *byte_array_replace_all(struct byte_array *original, struct byte_array *a, struct byte_array *b) { /*DEBUGPRINT("replace in %s: %s -> %s\n", byte_array_to_string(original), byte_array_to_string(a), byte_array_to_string(b));*/ struct byte_array *replaced = byte_array_copy(original); int32_t where = 0; for(;;) { // replace all if ((where = byte_array_find(replaced, a, where)) < 0) break; struct byte_array *replaced2 = byte_array_replace(replaced, b, where++, a->length); byte_array_del(replaced); replaced = replaced2; } return replaced; }
static inline struct variable *cfnc_insert(struct context *context) // todo: test { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *self = (struct variable*)array_get(args->list.ordered, 0); struct variable *insertion = (struct variable*)array_get(args->list.ordered, 1); struct variable *start = args->list.ordered->length > 2 ? (struct variable*)array_get(args->list.ordered, 2) : NULL; null_check(self); null_check(insertion); assert_message(!start || start->type == VAR_INT, "non-integer index"); int32_t position = 0; switch (self->type) { case VAR_LST: { struct array *list = array_new_size(1); array_set(list, 0, insertion); insertion = variable_new_list(context, list); position = self->list.ordered->length; array_del(list); } break; case VAR_STR: assert_message(insertion->type == VAR_STR, "insertion doesn't match destination"); position = self->str->length; break; default: exit_message("bad insertion destination"); break; } struct variable *first = variable_part(context, variable_copy(context, self), 0, position); struct variable *second = variable_part(context, variable_copy(context, self), position, -1); struct variable *joined = variable_concatenate(context, 3, first, insertion, second); if (self->type == VAR_LST) { array_del(self->list.ordered); self->list.ordered = array_copy(joined->list.ordered); } else { byte_array_del(self->str); self->str = byte_array_copy(joined->str); } return joined; }
// returns contents and modification time of file struct variable *sys_read(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); uint32_t offset = param_int(args, 2); uint32_t length = param_int(args, 3); struct byte_array *bytes = read_file(path->str, offset, length); DEBUGPRINT("read %d bytes\n", bytes ? bytes->length : 0); struct variable *content = NULL; if (NULL != bytes) { content = variable_new_str(context, bytes); byte_array_del(bytes); } else { context->error = variable_new_str_chars(context, "could not load file"); content = variable_new_nil(context); } return content; }
void interpret_string(struct context *context, struct byte_array *script) { struct byte_array *program = build_string(script, NULL); execute_with(context, program, true); byte_array_del(program); }
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; }