diff options
Diffstat (limited to 'src/execute.c')
-rw-r--r-- | src/execute.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/execute.c b/src/execute.c new file mode 100644 index 0000000..0d321d7 --- /dev/null +++ b/src/execute.c @@ -0,0 +1,367 @@ +#include <math.h> + +#include <posthaste/execute.h> +#include <posthaste/lower.h> +#include <posthaste/date.h> +#include <posthaste/vec.h> + +#define UNUSED(x) (void)x + +#define DEF(x) \ +static void exec_##x(struct insn i, size_t sp, struct vec *stack, struct vec *globals) + +static int64_t load(struct loc l, size_t sp, struct vec *stack, struct vec *globals) +{ + if (l.l) + return vect_at(int64_t, *stack, l.o + sp); + + return vect_at(int64_t, *globals, l.o); +} + +static void store(struct loc l, int64_t v, size_t sp, struct vec *stack, struct vec *globals) +{ + if (l.l) { + vect_at(int64_t, *stack, l.o + sp) = v; + return; + } + + vect_at(int64_t, *globals, l.o) = v; +} + +#define get(l) \ + load(l, sp, stack, globals) + +#define put(l, v) \ + store(l, v, sp, stack, globals) + +DEF(MOVE) { + int64_t i0 = get(i.i0); + put(i.o, i0); +} + +DEF(ADD) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t o = i0 + i1; + put(i.o, o); +} + +DEF(SUB) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t o = i0 - i1; + put(i.o, o); +} + +DEF(MUL) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t o = i0 * i1; + put(i.o, o); +} + +DEF(DIV) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t o = i0 / i1; + put(i.o, o); +} + +DEF(PRINT_DATE) { + int64_t i0 = get(i.i0); + char str[11] = {0}; + date_to_string(str, i0); + printf("%s", str); +} + +DEF(PRINT_INT) { + int64_t i0 = get(i.i0); + printf("%lli", (long long)i0); +} + +DEF(PRINT_STRING) { + int64_t i0 = get(i.i0); + printf("%s", (const char *)i0); +} + +DEF(PRINT_BOOL) { + int64_t i0 = get(i.i0); + printf("%s", i0 ? "true" : "false"); +} + +DEF(PRINT_NEWLINE) { + UNUSED(i); + UNUSED(sp); + UNUSED(stack); + UNUSED(globals); + printf("\n"); +} + +DEF(PRINT_SPACE) { + UNUSED(i); + UNUSED(sp); + UNUSED(stack); + UNUSED(globals); + printf(" "); +} + +DEF(CONST) { + put(i.o, i.v); +} + +DEF(EQ) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t b = i0 == i1; + put(i.o, b); +} + +DEF(LT) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + int64_t b = i0 < i1; + put(i.o, b); +} + +DEF(NEG) { + int64_t i0 = get(i.i0); + put(i.o, -i0); +} + +DEF(LOAD_DAY) { + int64_t i0 = get(i.i0); + unsigned day = 0; + date_split((ph_date_t)i0, NULL, NULL, &day); + put(i.o, (int64_t)day); +} + +DEF(LOAD_MONTH) { + int64_t i0 = get(i.i0); + unsigned month = 0; + date_split((ph_date_t)i0, NULL, &month, NULL); + put(i.o, (int64_t)month); +} + +DEF(LOAD_YEAR) { + int64_t i0 = get(i.i0); + unsigned year = 0; + date_split((ph_date_t)i0, &year, NULL, NULL); + put(i.o, (int64_t)year); +} + +DEF(LOAD_WEEKDAY) { + int64_t i0 = get(i.i0); + struct tm time = tm_from_date((ph_date_t)i0); + + const char *day = "Sunday"; + switch (time.tm_wday) { + case 0: day = "Sunday"; break; + case 1: day = "Monday"; break; + case 2: day = "Tuesday"; break; + case 3: day = "Wednesday"; break; + case 4: day = "Thursday"; break; + case 5: day = "Friday"; break; + case 6: day = "Saturday"; break; + } + + put(i.o, (int64_t)day); +} + +DEF(LOAD_WEEKNUM) { + int64_t i0 = get(i.i0); + struct tm time = tm_from_date((ph_date_t)i0); + put(i.o, time.tm_yday / 7); +} + +DEF(STORE_DAY) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + unsigned year = 0; + unsigned month = 0; + date_split((ph_date_t)i0, &year, &month, NULL); + ph_date_t date = date_from_numbers(year, month, i1); + put(i.o, (int64_t)date); +} + +DEF(STORE_MONTH) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + unsigned year = 0; + unsigned day = 0; + date_split((ph_date_t)i0, &year, NULL, &day); + ph_date_t date = date_from_numbers(year, i1, day); + put(i.o, (int64_t)date); +} + +DEF(STORE_YEAR) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + unsigned month = 0; + unsigned day = 0; + date_split((ph_date_t)i0, NULL, &month, &day); + ph_date_t date = date_from_numbers(i1, month, day); + put(i.o, (int64_t)date); +} + +DEF(TODAY) { + ph_date_t date = current_date(); + put(i.o, (int64_t)date); +} + +DEF(DATE_ADD) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + struct tm time = tm_from_date((ph_date_t)i0); + time.tm_mday += i1; + mktime(&time); + + ph_date_t date = date_from_tm(time); + put(i.o, (int64_t)date); +} + +DEF(DATE_SUB) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + struct tm time = tm_from_date((ph_date_t)i0); + time.tm_mday -= i1; + mktime(&time); + + ph_date_t date = date_from_tm(time); + put(i.o, (int64_t)date); +} + +DEF(DATE_DIFF) { + int64_t i0 = get(i.i0); + int64_t i1 = get(i.i1); + + struct tm time0 = tm_from_date((ph_date_t)i0); + struct tm time1 = tm_from_date((ph_date_t)i1); + + /* close enough at least */ + time_t t0 = mktime(&time0); + time_t t1 = mktime(&time1); + double seconds = difftime(t0, t1); + int64_t days = round(seconds / 86400); + put(i.o, days); +} + +static int64_t exec_func(struct fn *f, struct vec *args, size_t sp, struct vec *stack, struct vec *globals) +{ + /* move args to formal locations */ + size_t i = 0; + foreach_vec(ai, *args) { + int64_t a = vect_at(int64_t, *args, ai); + vect_at(int64_t, *stack, sp + i) = a; + i += 1; + } + + vec_reset(args); + + size_t pc = 0; + int64_t retval = 0; + struct vec insns = f->insns; + while (1) { + struct insn i = vect_at(struct insn, insns, pc); + +#define DO(x) case x: exec_##x(i, sp, stack, globals); break; + switch (i.k) { + /* special cases first */ + case LABEL: break; + case STOP: return 0; + case RET: return get(i.i0); + case RETVAL: put(i.o, retval); break; + case J: pc = i.v; continue; + case B: { + int64_t i0 = get(i.i0); + if (i0) { + pc = i.v; + continue; + } + + break; + } + + case BZ: { + int64_t i0 = get(i.i0); + if (!i0) { + pc = i.v; + continue; + } + + break; + } + + case ARG: { + int64_t a = get(i.i0); + vect_append(int64_t, *args, &a); + break; + } + + case CALL: { + struct fn *cf = find_fn(i.v); + assert(cf); + + retval = exec_func(cf, args, sp + f->max_sp, stack, globals); + break; + } + + DO(MOVE); + DO(ADD); + DO(SUB); + DO(MUL); + DO(DIV); + DO(CONST); + DO(PRINT_DATE); + DO(PRINT_INT); + DO(PRINT_BOOL); + DO(PRINT_STRING); + DO(PRINT_NEWLINE); + DO(PRINT_SPACE); + DO(LOAD_DAY); + DO(LOAD_MONTH); + DO(LOAD_YEAR); + DO(LOAD_WEEKDAY); + DO(LOAD_WEEKNUM); + DO(STORE_DAY); + DO(STORE_MONTH); + DO(STORE_YEAR); + DO(DATE_ADD); + DO(DATE_SUB); + DO(DATE_DIFF); + DO(TODAY); + DO(EQ); + DO(LT); + DO(NEG); + } +#undef DO + + pc += 1; + } +} + +void execute() +{ + struct fn *main = find_fn(0); + assert(main); + + struct vec stack = vec_create(sizeof(int64_t)); + /* arbitrary amount */ + vec_reserve(&stack, 65535); + + struct vec globals = vec_create(sizeof(int64_t)); + /* should really take the value calculated during lowering */ + vec_reserve(&globals, 65535); + + struct vec args = vec_create(sizeof(int64_t)); + + exec_func(main, &args, 0, &stack, &globals); + + vec_destroy(&args); + vec_destroy(&stack); + vec_destroy(&globals); +} |