#pragma once
#include "gdjn.h"
#include "type.h"

Janet
gdjn_janetize_typed
(	GDExtensionTypePtr     const v,
	GDExtensionVariantType const t
);

static inline Janet
gdjn_janetize(gd_variant* const v) {
	return gdjn_janetize_typed(v, _t(variant).getType(v));
}

void
gdjn_dejanetize_typed
(	GDExtensionTypePtr v, /* out */
	GDExtensionVariantType const t,
	Janet val /* in */
);

// typedef struct gdjn_vm_class {
//
// } gdjn_vm_class;

JanetTable* gdjn_vm_api_build_compTime(void);
JanetTable* gdjn_vm_api_build_core(void);

JanetTable*
gdjn_vm_compile
(	pstr const  body,
	JanetTable* api,
	const char* ctx
);

pstr
gdjn_vm_image
(	JanetTable* env,
	JanetTable* binds
);

typedef struct gdjn_vm_bind {
	enum gdjn_vm_bind_kind {
		gdjn_vm_bind_flag_static = 1 << 5,
		gdjn_vm_bind_flag_doc    = 1 << 6,
		gdjn_vm_bind_flag_umask = ~(
			gdjn_vm_bind_flag_static |
			gdjn_vm_bind_flag_doc
		),

		gdjn_vm_bind_none = 0,
		gdjn_vm_bind_const,
		gdjn_vm_bind_prop,
		gdjn_vm_bind_method,
		gdjn_vm_bind_class,
		gdjn_vm_bind_mac, /* always static unfortunately */

		gdjn_vm_bind_prop_static = gdjn_vm_bind_prop
			| gdjn_vm_bind_flag_static,
		gdjn_vm_bind_method_static = gdjn_vm_bind_method
			| gdjn_vm_bind_flag_static,
	} kind;
	Janet val, meta;
} gdjn_vm_bind;

static inline bool
gdjn_vm_metaKey
(	JanetTable* const bind,
	char const* const kw,
	Janet     *       valSlot
) {
	Janet jv;
	if (valSlot == nullptr) valSlot = &jv;
	*valSlot = janet_table_get(bind, janet_ckeywordv(kw));
	return (janet_type(*valSlot) != JANET_NIL);
}

static inline bool
gdjn_vm_metaFlag
(	JanetTable* const bind,
	char const* const kw
) {
	Janet v = janet_table_get(bind, janet_ckeywordv(kw));
	return janet_truthy(v);
}

gdjn_vm_bind
gdjn_vm_meta
(	JanetTable* bind
);

gdjn_vm_bind
gdjn_vm_resv
(	JanetTable* env,
	Janet       key
);
