sl_value sl_string_concat(struct sl_interpreter_state *state, sl_value s1, sl_value s2) { char *str; sl_value s; int size; if (sl_type(s1) != state->tString) { s1 = sl_inspect(state, s1); } if (sl_type(s2) != state->tString) { s2 = sl_inspect(state, s2); } size = NUM2INT(sl_string_size(state, s1)) + NUM2INT(sl_string_size(state, s2)) + 1; str = sl_native_malloc(size * sizeof(char)); sprintf(str, "%s%s", sl_string_cstring(state, s1), sl_string_cstring(state, s2)); s = sl_string_new(state, str); free(str); return s; }
static void run_repl(sl_vm_t* vm) { printf("Interactive Slash\n"); cli_setup_readline(); while(true) { char* line = cli_readline(">> "); if(!line) { printf("\n"); shutdown_vm(vm, 0); } sl_vm_frame_t frame; SLVAL exception; SL_TRY(frame, SL_UNWIND_EXCEPTION, { SLVAL result = sl_do_string(vm, (uint8_t*)line, strlen(line), "(repl)", 1); result = sl_inspect(vm, result); printf("=> "); sl_string_t* str = (sl_string_t*)sl_get_ptr(result); fwrite(str->buff, str->buff_len, 1, stdout); printf("\n"); }, exception, { SLVAL exception_str = sl_to_s_no_throw(vm, exception); sl_string_t* str = (sl_string_t*)sl_get_ptr(exception_str); fwrite(str->buff, str->buff_len, 1, stdout); printf("\n"); });
sl_value sl_eval(struct sl_interpreter_state *state, sl_value expression, sl_value environment) { if (sl_type(expression) == state->tSymbol) { if (sl_env_has_key(state, environment, expression)) { return sl_env_get(state, environment, expression); } else { fprintf(stderr, "Error: `%s' is undefined\n", sl_string_cstring(state, sl_inspect(state, expression))); abort(); } } else if (sl_type(expression) != state->tList) { return expression; } else if (sl_empty(state, expression) == state->sl_true) { return expression; } else if (sl_type(sl_first(state, expression)) == state->tSymbol) { sl_value first = sl_first(state, expression); if (state->s_def == first) { assert(NUM2INT(sl_list_size(state, expression)) == 3); sl_value second = sl_second(state, expression); sl_value third = sl_third(state, expression); return sl_def(state, second, sl_eval(state, third, environment)); } else if (state->s_quote == first) { assert(NUM2INT(sl_list_size(state, expression)) == 2); return sl_second(state, expression); } else if (state->s_if == first) { assert(NUM2INT(sl_list_size(state, expression)) == 4); sl_value rest = sl_rest(state, expression); sl_value result = sl_eval(state, sl_first(state, rest), environment); if (result == state->sl_false) { return sl_eval(state, sl_third(state, rest), environment); } else { return sl_eval(state, sl_second(state, rest), environment); } } else if (state->s_annotate == first) { assert(NUM2INT(sl_list_size(state, expression)) == 3); sl_value val = sl_eval(state, sl_second(state, expression), environment); sl_value type = sl_eval(state, sl_third(state, expression), environment); assert(sl_type(val) == type); return val; } else { sl_value f = sl_eval(state, first, environment); sl_value new_expression = sl_list_new(state, f, sl_rest(state, expression)); return sl_eval(state, new_expression, environment); } } else if (sl_type(sl_first(state, expression)) == state->tFunction) { sl_value f = sl_first(state, expression); sl_value args = sl_rest(state, expression); /* TODO: make eval_each a map and eval */ return sl_apply(state, f, eval_each(state, args, environment)); } else { fprintf(stderr, "Error: %s is not implemented yet\n", sl_string_cstring(state, sl_inspect(state, expression))); abort(); } }
// somewhat similar to sprintf // // Valid formats: // // %V - Slash value, converted to string first with #to_s // %I - Slash ID // %s - C string // %d - integer // %% - literal '%' sign // // You may add the 'Q' modifier to a format specifier to quote it in double // quotes. For example "%QV" would quote the value when interpolating it into // the string SLVAL sl_make_formatted_string_va(struct sl_vm* vm, const char* format, va_list va) { SLVAL strings = sl_make_array(vm, 0, NULL); const char *current_ptr = format, *next_ptr; SLVAL quote = vm->lib.nil; while((next_ptr = strchr(current_ptr, '%'))) { if(next_ptr != current_ptr) { SLVAL literal = sl_make_string(vm, (uint8_t*)current_ptr, (size_t)(next_ptr - current_ptr)); sl_array_push(vm, strings, 1, &literal); } SLVAL element = vm->lib.nil; bool quoted = false; again: switch(next_ptr[1]) { case 'Q': { if(sl_get_primitive_type(quote) == SL_T_NIL) { quote = sl_make_cstring(vm, "\""); } sl_array_push(vm, strings, 1, "e); next_ptr++; quoted = true; goto again; } case 'V': { element = va_arg(va, SLVAL); break; } case 'X': { element = va_arg(va, SLVAL); element = sl_inspect(vm, element); break; } case 'I': { SLID id = va_arg(va, SLID); element = sl_id_to_string(vm, id); break; } case 's': { char* cstr = va_arg(va, char*); element = sl_make_cstring(vm, cstr); break; } case 'd': { char buff[32]; int num = va_arg(va, int); sprintf(buff, "%d", num); element = sl_make_cstring(vm, buff); break; } case 'p': { char buff[32]; void* ptr = va_arg(va, void*); sprintf(buff, "%p", ptr); element = sl_make_cstring(vm, buff); break; } case 0: { return vm->lib.nil; } default: { element = sl_make_string(vm, (uint8_t*)(next_ptr + 1), 1); break; } } sl_array_push(vm, strings, 1, &element); if(quoted) { sl_array_push(vm, strings, 1, "e); quoted = false; } current_ptr = next_ptr + 2; } if(current_ptr[0]) { SLVAL element = sl_make_cstring(vm, current_ptr); sl_array_push(vm, strings, 1, &element); } return sl_array_join(vm, strings, 0, NULL); }