aboutsummaryrefslogtreecommitdiff
path: root/src/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/execute.c')
-rw-r--r--src/execute.c367
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);
+}