+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+
+#include "oberon.h"
+#include "generator.h"
+
+#include <libgccjit.h>
+
+/*
+ * oberon_var_t -> gvar == gcc_jit_lvalue;
+ * oberon_type_t -> gtype == gcc_jit_type;
+ * oberon_context_t -> gctx == gen_context_t;
+ */
+
+typedef struct
+{
+ gcc_jit_context * gcc_context;
+ gcc_jit_block * gcc_block;
+ gcc_jit_result * gcc_result;
+} gen_context_t;
+
+static void printcontext(oberon_context_t * ctx, char * s)
+{
+/*
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+ gcc_jit_block * gcc_block = gen_context -> gcc_block;
+
+ printf("%s:\n", s);
+ printf(" ctx = %p:\n", ctx);
+ printf(" gctx = %p:\n", gctx);
+ printf(" context = %p:\n", context);
+ printf(" block = %p:\n", block);
+*/
+}
+
+// =======================================================================
+// ALLOC
+// =======================================================================
+
+void
+oberon_generator_init_context(oberon_context_t * ctx)
+{
+ gen_context_t * gen_context = malloc(sizeof *gen_context);
+ memset(gen_context, 0, sizeof *gen_context);
+
+ gcc_jit_context * gcc_context;
+ gcc_context = gcc_jit_context_acquire();
+
+ ctx -> gen_context = gen_context;
+ gen_context -> gcc_context = gcc_context;
+
+ printcontext(ctx, "oberon_generator_init_context");
+}
+
+void
+oberon_generator_destroy_context(oberon_context_t * ctx)
+{
+ printcontext(ctx, "oberon_generator_destroy_context");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+
+ gcc_jit_context_release(gcc_context);
+}
+
+void
+oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type)
+{
+ printcontext(ctx, "oberon_generator_init_type");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+
+ gcc_jit_type * gen_type;
+ if(type -> class == OBERON_TYPE_INTEGER)
+ {
+ gen_type = gcc_jit_context_get_int_type(gcc_context, type -> size, 1);
+ }
+ else if(type -> class == OBERON_TYPE_BOOLEAN)
+ {
+ gen_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL);
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_generator_init_type: invalid type class %i", type -> class);
+ }
+
+ type -> gen_type = gen_type;
+}
+
+void
+oberon_generator_init_var(oberon_context_t * ctx, oberon_var_t * var)
+{
+ printcontext(ctx, "oberon_generator_init_var");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+ gcc_jit_type * gen_type = var -> type -> gen_type;
+ const char * name = var -> name;
+
+ gcc_jit_lvalue * gen_var;
+ gen_var = gcc_jit_context_new_global(gcc_context, NULL, GCC_JIT_GLOBAL_INTERNAL, gen_type, name);
+
+ var -> gen_var = gen_var;
+}
+
+// =======================================================================
+// GENERATOR
+// =======================================================================
+
+static gcc_jit_rvalue *
+oberon_generate_rvalue_from_item(oberon_context_t * ctx, oberon_item_t * item)
+{
+ printcontext(ctx, "oberon_generate_rvalue_from_item");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+
+ gcc_jit_rvalue * right;
+ if(item -> mode == MODE_VAR)
+ {
+ gcc_jit_lvalue * gen_var = item -> var -> gen_var;
+ right = gcc_jit_lvalue_as_rvalue(gen_var);
+ printf("PUSH (var) %s\n", item -> var -> name);
+ }
+ else if(item -> mode == MODE_INTEGER)
+ {
+ gcc_jit_type * int_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_INT);
+ right = gcc_jit_context_new_rvalue_from_int(gcc_context, int_type, item -> integer);
+ printf("PUSH (int) %i\n", item -> integer);
+ }
+ else if(item -> mode == MODE_BOOLEAN)
+ {
+ gcc_jit_type * bool_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL);
+ if(item -> boolean)
+ {
+ right = gcc_jit_context_one(gcc_context, bool_type);
+ }
+ else
+ {
+ right = gcc_jit_context_zero(gcc_context, bool_type);
+ }
+ printf("PUSH (bool) %i\n", item -> boolean);
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_generate_push: invalid mode %i", item -> mode);
+ }
+
+ return right;
+}
+
+void
+oberon_generate_begin_module(oberon_context_t * ctx)
+{
+ printcontext(ctx, "oberon_generate_begin_module");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+
+ gcc_jit_type * void_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_VOID);
+ gcc_jit_function * func = gcc_jit_context_new_function(
+ gcc_context, NULL, GCC_JIT_FUNCTION_EXPORTED, void_type, "BEGIN", 0, NULL, 0
+ );
+ gcc_jit_block * gcc_block = gcc_jit_function_new_block(func, NULL);
+
+ gen_context -> gcc_block = gcc_block;
+}
+
+void
+oberon_generate_end_module(oberon_context_t * ctx)
+{
+ printcontext(ctx, "oberon_generate_end_module");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_block * gcc_block = gen_context -> gcc_block;
+
+ gcc_jit_block_end_with_void_return(gcc_block, NULL);
+
+ gen_context -> gcc_block = NULL;
+}
+
+void
+oberon_generate_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst)
+{
+ printcontext(ctx, "oberon_generate_assign");
+
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_block * gcc_block = gen_context -> gcc_block;
+
+ gcc_jit_lvalue * left;
+ gcc_jit_rvalue * right;
+
+ right = oberon_generate_rvalue_from_item(ctx, src);
+
+ if(dst -> mode == MODE_VAR)
+ {
+ printf("STORE %s\n", dst -> var -> name);
+ left = dst -> var -> gen_var;
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_generate_assign: invalid assignment");
+ }
+
+ gcc_jit_block_add_assignment(gcc_block, NULL, left, right);
+}
+
+void
+oberon_generate_code(oberon_context_t * ctx)
+{
+ gen_context_t * gen_context = ctx -> gen_context;
+ gcc_jit_context * gcc_context = gen_context -> gcc_context;
+
+ gcc_jit_result * gcc_result;
+ gcc_result = gcc_jit_context_compile(gcc_context);
+
+ gen_context -> gcc_result = gcc_result;
+ ctx -> mod -> begin = gcc_jit_result_get_code(gcc_result, "BEGIN");
+}