#ifndef __GACK
#define __GACK
ANN void gack(const VM_Shred, const Instr);
+
+#define INTERP_PRINTF(fmt, ...) { \
+ m_str ret = *(m_str*)(VALUE - SZ_INT);\
+ gw_asprintf(shred->info->vm->gwion->mp, &ret, fmt, ##__VA_ARGS__); \
+ *(m_str*)(VALUE - SZ_INT) = ret;\
+}
+
+ANN2(2) int gw_asprintf(MemPool mp, char **str, const char *fmt, ...);
#endif
eGcAdd,
eGcEnd,
eGack,
- eGack3,
+ eGackEnd,
eNoOp,
eDotTmplVal,
eOP_MAX,
#define GcAdd (f_instr)eGcAdd
#define GcEnd (f_instr)eGcEnd
#define Gack (f_instr)eGack
-#define Gack3 (f_instr)eGack3
+#define GackEnd (f_instr)eGackEnd
#define NoOp (f_instr)eNoOp
#define DotTmplVal (f_instr)eDotTmplVal
#define OP_MAX (f_instr)eOP_MAX
GcAdd
GcEnd
Gack
-Gack3
+GackEnd
NoOp
DotTmplVal
OP_MAX
return instr; \
}
regxxx(pop, Pop)
+regxxx(push, Push)
regxxx(pushi, PushImm)
regxxx(seti, SetImm)
}
ANN static m_bool emit_prim_hack(const Emitter emit, const Exp *exp) {
+ regpushi(emit, 0);
Exp e = *exp, next = NULL;
do {
next = e->next;
instr->m_val2 = emit_code_offset(emit);
} while((e = e->next = next));
if(!(emit->env->func && emit->env->func->def->base->xid == insert_symbol("@gack")))
- emit_add_instr(emit, Gack3);
+ emit_add_instr(emit, GackEnd);
return GW_OK;
}
return size;
}
-ANN static m_uint pop_exp_size(const Emitter emit, Exp e) {
+ANN static m_uint pop_exp_size(Exp e) {
m_uint size = 0;
do {
- if(e->exp_type == ae_exp_primary &&
- e->d.prim.prim_type == ae_prim_hack) {
- size += pop_exp_size(emit, e->d.prim.d.exp);
- continue;
- }
size += (e->exp_type == ae_exp_decl ?
get_decl_size(e->d.exp_decl.list) : e->type->size);
} while((e = e->next));
}
ANN static inline void pop_exp(const Emitter emit, Exp e) {
- const m_uint size = pop_exp_size(emit, e);
+ const m_uint size = pop_exp_size(e);
if(size)
regpop(emit, size);
}
ADD_REF(f->code)
return f->code;
} else if(f->def->base->xid == insert_symbol("@gack")) {
+ regpush(emit, SZ_INT);
f->code = finalyze(emit, FuncReturn);
return emit->env->class_def->e->gack = f->code;
}
#include "import.h"
#include "gwi.h"
+#include "gack.h"
#define describe(name, op) \
static INSTR(Complex##name) {\
polar_def2_r(Div, /, -)
static GACK(gack_complex) {
- gw_out("#(%.4f, %.4f)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT));
+ INTERP_PRINTF("#(%.4f, %.4f)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT));
}
static GACK(gack_polar) {
- gw_out("%%(%.4f, %.4f*pi)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT) / M_PI);
+ INTERP_PRINTF("%%(%4f, %.4f*pi)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT) / M_PI);
}
EQUALITY_OPER(complex, SZ_COMPLEX)
#include "parser.h"
#include "lang_private.h"
#include "specialid.h"
+#include "gack.h"
static GACK(gack_class) {
const Type type = actual_type(shred->info->vm->gwion, t) ?: t;
- gw_out("class(%s)", type->name);
+ INTERP_PRINTF("class(%s)", type->name)
}
static GACK(gack_function) {
- gw_out("%s", t->name);
+ INTERP_PRINTF("%s", t->name)
}
static GACK(gack_fptr) {
const VM_Code code = *(VM_Code*)VALUE;
if(code)
- gw_out("%s", code->name);
+ INTERP_PRINTF("%s", code->name)
else
- gw_out("%s", t->name);
+ INTERP_PRINTF("%s", t->name)
}
static GACK(gack_void) {
- gw_out("(void)");
+ INTERP_PRINTF("void");
}
static GACK(gack_int) {
- gw_out("%"INT_F, *(m_uint*)VALUE);
+ INTERP_PRINTF("%"INT_F, *(m_uint*)VALUE);
}
static GACK(gack_char) {
- gw_out("%c", *(char*)VALUE);
+ INTERP_PRINTF("%c", *(char*)VALUE);
}
static GACK(gack_float) {
- gw_out("%.4f", *(m_float*)VALUE);
+ INTERP_PRINTF("%.4f", *(m_float*)VALUE);
}
#define mk_class_instr(op, arg0, arg1, ...) \
#include <stdlib.h>
#include <string.h>
-#include <complex.h>
+#include <stdarg.h>
#include "gwion_util.h"
#include "gwion_ast.h"
#include "gwion_env.h"
#include "import.h"
#include "gack.h"
+ANN2(1) static int fmtlen(const char *fmt, va_list args) {
+ va_list tmpa;
+ va_copy(tmpa, args);
+ const int size = vsnprintf(NULL, 0, fmt, tmpa);
+ va_end(tmpa);
+ return size;
+}
+
+ANN2(2) static int gw_vasprintf(MemPool mp, char **str, const char *fmt, va_list args) {
+ char *base = *str;
+ const size_t base_len = base ? strlen(base) : 0;
+ DECL_BB(const int, size, = fmtlen(fmt, args))
+ char *ret = mp_malloc2(mp, base_len + size + 1);
+ if(base)
+ strcpy(ret, base);
+ DECL_BB(const int, final_len, = vsprintf(ret + base_len, fmt, args))
+ if(base)
+ mp_free2(mp, strlen(base), base);
+ *str = ret;
+ return final_len;
+}
+
+ANN2(2) int gw_asprintf(MemPool mp, char **str, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ const int ret = gw_vasprintf(mp, str, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+__attribute__((returns_nonnull))
+ANN static inline VM_Code get_gack(Type t) {
+ do if(t->e->gack)
+ return t->e->gack;
+ while((t = t->e->parent));
+ return NULL; // unreachable
+}
+
+ANN static void prepare_call(const VM_Shred shred, m_uint offset) {
+ shred->mem += offset;
+ *(m_uint*)(shred->mem+ SZ_INT) = offset + SZ_INT;
+ *(VM_Code*)(shred->mem+ SZ_INT*2) = shred->code;
+ *(m_uint*)(shred->mem+ SZ_INT*3) = shred->pc;
+ *(m_uint*)(shred->mem+ SZ_INT*4) = SZ_INT;
+ shred->mem += SZ_INT*5;
+ *(M_Object*)(shred->mem)= *(M_Object*)(shred->reg - SZ_INT);
+ shred->pc = 0;
+}
+
ANN void gack(const VM_Shred shred, const Instr instr) {
- Type base = (Type)instr->m_val, t = base;
- do {
- if(t->e->gack) {
- if(GET_FLAG(t->e->gack, builtin))
- ((f_gack)t->e->gack->native_func)(base, (shred->reg - t->size), shred);
- else {
- shred->mem += instr->m_val2;
- *(m_uint*)(shred->mem+ SZ_INT) = instr->m_val2 + SZ_INT;
- *(VM_Code*)(shred->mem+ SZ_INT*2) = shred->code;
- *(m_uint*)(shred->mem+ SZ_INT*3) = shred->pc;
- *(m_uint*)(shred->mem+ SZ_INT*4) = SZ_INT;
- shred->mem += SZ_INT*5;
- *(M_Object*)(shred->mem)= *(M_Object*)(shred->reg - SZ_INT);
- shred->code = t->e->gack;
- shred->pc = 0;
- }
- return;
- }
- } while((t = t->e->parent));
+ Type t = (Type)instr->m_val;
+ const VM_Code code = get_gack(t);
+ if(GET_FLAG(code, builtin)) {
+ ((f_gack)code->native_func)(t, (shred->reg - t->size), shred);
+ POP_REG(shred, t->size);
+ } else {
+ prepare_call(shred, instr->m_val2);
+ shred->code = code;
+ }
+ return;
}
#include "specialid.h"
#include "gwi.h"
+#include "gack.h"
#undef insert_symbol
ANN void exception(const VM_Shred shred, const m_str c) {
}
static GACK(gack_object) {
- gw_out("%p", *(M_Object*)VALUE);
+ INTERP_PRINTF("%p", *(M_Object*)VALUE);
}
GWION_IMPORT(object) {
#include "parse.h"
#include "specialid.h"
#include "array.h"
+#include "gack.h"
#define CHECK_OP(op, check, func) _CHECK_OP(op, check, int_##func)
return GW_OK;
}
static GACK(gack_bool) {
- gw_out("%s", *(m_uint*)VALUE ? "true" : "false");
+// gw_out("%s", *(m_uint*)VALUE ? "true" : "false");
+ INTERP_PRINTF("%s", *(m_uint*)VALUE ? "true" : "false");
}
static GWION_IMPORT(int_values) {
#include "emit.h"
#include "specialid.h"
#include "gwi.h"
+#include "gack.h"
ANN static void push_string(const VM_Shred shred, const M_Object obj, const m_str c) {
STRING(obj) = s_name(insert_symbol(shred->info->vm->gwion->st, c));
static GACK(gack_string) {
const M_Object obj = *(M_Object*)VALUE;
- gw_out("%s", obj ? STRING(obj) : "(null string)");
+ INTERP_PRINTF("%s", obj ? STRING(obj) : "(null string)");
}
static inline m_bool bounds(const m_str str, const m_int i) {
#include "import.h"
#include "driver.h"
#include "gwi.h"
+#include "gack.h"
INSTR(VecCpy) {
POP_REG(shred, instr->m_val2);
}
static GACK(gack_vec3) {
- gw_out("%%(%.4f, %.4f, %.4f)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT), *(m_float*)(VALUE + SZ_FLOAT*2));
+ INTERP_PRINTF("%%(%.4f, %.4f, %.4f)", *(m_float*)VALUE, *(m_float*)(VALUE + SZ_FLOAT), *(m_float*)(VALUE + SZ_FLOAT*2));
}
EQUALITY_OPER(vec3, SZ_VEC3);
}
static GACK(gack_vec4) {
- gw_out("%%(%.4f, %.4f, %.4f, %.4f)",
+ INTERP_PRINTF("%%(%.4f, %.4f, %.4f, %.4f)",
*(m_float*)VALUE,
*(m_float*)(VALUE + SZ_FLOAT),
*(m_float*)(VALUE + SZ_FLOAT*2),
&&staticint, &&staticfloat, &&staticother,
&&dotfunc, &&dotstaticfunc, &&pushstaticcode,
&&gcini, &&gcadd, &&gcend,
- &&gack, &&gack3, &&noop, &®pushimm, &&other, &&eoc
+ &&gack, &&gackend, &&noop, &®pushimm, &&other, &&eoc
};
const Shreduler s = vm->shreduler;
register VM_Shred shred;
VM_OUT
gack(shred, (Instr)VAL);
goto in;
-gack3:
- gw_out("\n");
+gackend:
+{
+ m_str str = *(m_str*)(reg - SZ_INT);
+ gw_out("%s\n", str);
+ mp_free2(vm->gwion->mp, strlen(str), str);
+}
noop:
DISPATCH();
other: