summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/ucode/chunk.h39
-rw-r--r--include/ucode/compiler.h117
-rw-r--r--include/ucode/lexer.h175
-rw-r--r--include/ucode/lib.h132
-rw-r--r--include/ucode/module.h53
-rw-r--r--include/ucode/source.h36
-rw-r--r--include/ucode/types.h439
-rw-r--r--include/ucode/util.h158
-rw-r--r--include/ucode/value.h60
-rw-r--r--include/ucode/vm.h137
10 files changed, 1346 insertions, 0 deletions
diff --git a/include/ucode/chunk.h b/include/ucode/chunk.h
new file mode 100644
index 0000000..458af1f
--- /dev/null
+++ b/include/ucode/chunk.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __CHUNK_H_
+#define __CHUNK_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "value.h"
+#include "util.h"
+#include "types.h"
+
+void uc_chunk_init(uc_chunk_t *chunk);
+void uc_chunk_free(uc_chunk_t *chunk);
+size_t uc_chunk_add(uc_chunk_t *chunk, uint8_t byte, size_t line);
+
+ssize_t uc_chunk_add_constant(uc_chunk_t *chunk, uc_value_t *value);
+uc_value_t *uc_chunk_get_constant(uc_chunk_t *chunk, size_t idx);
+void uc_chunk_pop(uc_chunk_t *chunk);
+
+size_t uc_chunk_debug_get_srcpos(uc_chunk_t *chunk, size_t off);
+void uc_chunk_debug_add_variable(uc_chunk_t *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name);
+uc_value_t *uc_chunk_debug_get_variable(uc_chunk_t *chunk, size_t off, size_t slot, bool upval);
+
+#endif /* __CHUNK_H_ */
diff --git a/include/ucode/compiler.h b/include/ucode/compiler.h
new file mode 100644
index 0000000..19fcf37
--- /dev/null
+++ b/include/ucode/compiler.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __COMPILER_H_
+#define __COMPILER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef JSONC
+ #include <json.h>
+#else
+ #include <json-c/json.h>
+#endif
+
+#include "source.h"
+#include "lexer.h"
+#include "types.h"
+#include "util.h"
+
+typedef enum {
+ P_NONE,
+
+ P_COMMA, /* , */
+
+ P_ASSIGN, /* = += -= *= /= %= <<= >>= &= ^= |= */
+
+ P_TERNARY, /* ?: */
+
+ P_OR, /* || */
+ P_AND, /* && */
+ P_BOR, /* | */
+ P_BXOR, /* ^ */
+ P_BAND, /* & */
+
+ P_EQUAL, /* === !== == != */
+ P_COMPARE, /* < <= > >= in */
+
+ P_SHIFT, /* << >> */
+
+ P_ADD, /* + - */
+ P_MUL, /* * / % */
+
+ P_UNARY, /* ! ~ +… -… ++… --… */
+
+ P_INC, /* …++ …-- */
+
+ P_CALL, /* ….…, …[…], …(…) */
+
+ P_PRIMARY /* (…) */
+} uc_precedence_t;
+
+typedef struct uc_patchlist {
+ struct uc_patchlist *parent;
+ size_t depth, count, *entries;
+} uc_patchlist_t;
+
+typedef struct {
+ uc_value_t *name;
+ ssize_t depth;
+ size_t from;
+ bool captured;
+ bool constant;
+} uc_local_t;
+
+typedef struct {
+ uc_value_t *name;
+ size_t index;
+ bool local;
+ bool constant;
+} uc_upval_t;
+
+uc_declare_vector(uc_locals_t, uc_local_t);
+uc_declare_vector(uc_upvals_t, uc_upval_t);
+uc_declare_vector(uc_jmplist_t, size_t);
+
+typedef struct {
+ uc_parse_config_t *config;
+ uc_lexer_t lex;
+ uc_token_t prev, curr;
+ bool synchronizing;
+ uc_stringbuf_t *error;
+} uc_parser_t;
+
+typedef struct uc_compiler {
+ struct uc_compiler *parent;
+ uc_locals_t locals;
+ uc_upvals_t upvals;
+ uc_patchlist_t *patchlist;
+ uc_value_t *function;
+ uc_parser_t *parser;
+ size_t scope_depth, current_srcpos, last_insn;
+} uc_compiler_t;
+
+typedef struct {
+ void (*prefix)(uc_compiler_t *, bool);
+ void (*infix)(uc_compiler_t *, bool);
+ uc_precedence_t precedence;
+} uc_parse_rule_t;
+
+uc_function_t *uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp);
+
+#endif /* __COMPILER_H_ */
diff --git a/include/ucode/lexer.h b/include/ucode/lexer.h
new file mode 100644
index 0000000..1b19b60
--- /dev/null
+++ b/include/ucode/lexer.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __LEXER_H_
+#define __LEXER_H_
+
+#include "source.h"
+#include "types.h"
+
+
+typedef enum {
+ TK_LEXP = 1,
+ TK_REXP,
+ TK_LSTM,
+ TK_RSTM,
+ TK_IF,
+ TK_ELSE,
+ TK_COMMA,
+ TK_ASSIGN,
+ TK_ASADD,
+ TK_ASSUB,
+ TK_ASMUL,
+ TK_ASDIV,
+ TK_ASMOD,
+ TK_ASLEFT,
+ TK_ASRIGHT,
+ TK_ASBAND,
+ TK_ASBXOR,
+ TK_ASBOR,
+ TK_QMARK,
+ TK_COLON,
+ TK_OR,
+ TK_AND,
+ TK_BOR,
+ TK_BXOR,
+ TK_BAND,
+ TK_EQS,
+ TK_NES,
+ TK_EQ,
+ TK_NE,
+ TK_LT,
+ TK_LE,
+ TK_GT,
+ TK_GE,
+ TK_IN,
+ TK_LSHIFT,
+ TK_RSHIFT,
+ TK_ADD,
+ TK_SUB,
+ TK_MUL,
+ TK_DIV,
+ TK_MOD,
+ TK_NOT,
+ TK_COMPL,
+ TK_INC,
+ TK_DEC,
+ TK_DOT,
+ TK_LBRACK,
+ TK_RBRACK,
+ TK_LPAREN,
+ TK_RPAREN,
+ TK_TEXT,
+ TK_LBRACE,
+ TK_RBRACE,
+ TK_SCOL,
+ TK_ENDIF,
+ TK_ELIF,
+ TK_WHILE,
+ TK_ENDWHILE,
+ TK_FOR,
+ TK_ENDFOR,
+ TK_FUNC,
+ TK_LABEL,
+ TK_ENDFUNC,
+ TK_TRY,
+ TK_CATCH,
+ TK_SWITCH,
+ TK_CASE,
+ TK_DEFAULT,
+ TK_ELLIP,
+ TK_RETURN,
+ TK_BREAK,
+ TK_CONTINUE,
+ TK_LOCAL,
+ TK_ARROW,
+ TK_TRUE,
+ TK_FALSE,
+ TK_NUMBER,
+ TK_DOUBLE,
+ TK_STRING,
+ TK_REGEXP,
+ TK_NULL,
+ TK_THIS,
+ TK_DELETE,
+ TK_CONST,
+
+ TK_EOF,
+ TK_ERROR
+} uc_tokentype_t;
+
+typedef enum {
+ UC_LEX_IDENTIFY_BLOCK,
+ UC_LEX_BLOCK_COMMENT_START,
+ UC_LEX_BLOCK_EXPRESSION_START,
+ UC_LEX_BLOCK_EXPRESSION_EMIT_TAG,
+ UC_LEX_BLOCK_STATEMENT_START,
+ UC_LEX_BLOCK_COMMENT,
+ UC_LEX_IDENTIFY_TOKEN,
+ UC_LEX_PARSE_TOKEN,
+ UC_LEX_EOF
+} uc_lex_state_t;
+
+typedef struct {
+ uc_tokentype_t type;
+ uc_value_t *uv;
+ size_t pos;
+} uc_token_t;
+
+typedef struct {
+ uc_lex_state_t state;
+ uc_parse_config_t *config;
+ uc_source_t *source;
+ uint8_t eof:1;
+ uint8_t is_escape:1;
+ uint8_t no_regexp:1;
+ uint8_t no_keyword:1;
+ size_t buflen;
+ char *buf, *bufstart, *bufend;
+ size_t lookbehindlen;
+ char *lookbehind;
+ const void *tok;
+ uc_token_t curr;
+ char esc[5];
+ uint8_t esclen;
+ int lead_surrogate;
+ size_t lastoff;
+ enum {
+ UNSPEC,
+ PLUS,
+ MINUS,
+ NEWLINE
+ } modifier;
+ enum {
+ NONE,
+ EXPRESSION = '{',
+ STATEMENTS = '%',
+ COMMENT = '#'
+ } block;
+} uc_lexer_t;
+
+
+void uc_lexer_init(uc_lexer_t *lex, uc_parse_config_t *config, uc_source_t *source);
+void uc_lexer_free(uc_lexer_t *lex);
+
+uc_token_t *uc_lexer_next_token(uc_lexer_t *lex);
+
+bool utf8enc(char **out, int *rem, int code);
+
+const char *
+uc_get_tokenname(unsigned type);
+
+#endif /* __LEXER_H_ */
diff --git a/include/ucode/lib.h b/include/ucode/lib.h
new file mode 100644
index 0000000..7eeae9f
--- /dev/null
+++ b/include/ucode/lib.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __LIB_H_
+#define __LIB_H_
+
+#include "vm.h"
+#include "lexer.h"
+
+typedef struct {
+ const char *name;
+ uc_cfn_ptr_t func;
+} uc_cfunction_list_t;
+
+extern const uc_cfunction_list_t uc_stdlib_functions[];
+
+void uc_load_stdlib(uc_value_t *scope);
+
+bool format_source_context(uc_stringbuf_t *buf, uc_source_t *src, size_t off, bool compact);
+bool format_error_context(uc_stringbuf_t *buf, uc_source_t *src, uc_value_t *stacktrace, size_t off);
+
+
+/* vm helper */
+
+static inline void *
+_uc_get_self(uc_vm_t *vm, const char *expected_type)
+{
+ return ucv_ressource_dataptr(vm->callframes.entries[vm->callframes.count - 1].ctx, expected_type);
+}
+
+#define uc_get_self(...) _uc_get_self(vm, __VA_ARGS__)
+
+static inline uc_value_t *
+_uc_get_arg(uc_vm_t *vm, size_t nargs, size_t n)
+{
+ if (n >= nargs)
+ return NULL;
+
+ return uc_vm_stack_peek(vm, nargs - n - 1);
+}
+
+#define uc_get_arg(...) _uc_get_arg(vm, nargs, __VA_ARGS__)
+
+#define uc_call(nargs) uc_vm_call(vm, false, nargs)
+#define uc_push_val(val) uc_vm_stack_push(vm, val)
+#define uc_pop_val() uc_vm_stack_pop(vm)
+
+
+/* value helper */
+
+static inline uc_value_t *
+uc_alloc_ressource(uc_ressource_type_t *type, void *data)
+{
+ return ucv_ressource_new(type, data);
+}
+
+static inline uc_type_t
+uc_to_number(uc_value_t *v, int64_t *n, double *d)
+{
+ return uc_cast_number(v, n, d);
+}
+
+static inline double
+uc_to_double(uc_value_t *v)
+{
+ int64_t n;
+ double d;
+
+ return (uc_cast_number(v, &n, &d) == UC_DOUBLE) ? d : (double)n;
+}
+
+static inline int64_t
+uc_to_int64(uc_value_t *v)
+{
+ int64_t n;
+ double d;
+
+ return (uc_cast_number(v, &n, &d) == UC_DOUBLE) ? (int64_t)d : n;
+}
+
+
+/* ressource type helper */
+
+static inline uc_ressource_type_t *
+_uc_declare_type(uc_vm_t *vm, const char *name, const uc_cfunction_list_t *list, size_t len, void (*freefn)(void *))
+{
+ uc_value_t *proto = ucv_object_new(NULL);
+
+ while (len-- > 0)
+ ucv_object_add(proto, list[len].name,
+ ucv_cfunction_new(list[len].name, list[len].func));
+
+ return ucv_ressource_type_add(vm, name, proto, freefn);
+}
+
+#define uc_declare_type(vm, name, functions, freefn) \
+ _uc_declare_type(vm, name, functions, ARRAY_SIZE(functions), freefn)
+
+
+/* function helper */
+
+#define uc_add_function(object, name, function) \
+ ucv_object_add(object, name, ucv_cfunction_new(name, function))
+
+static inline bool
+_uc_add_functions(uc_value_t *object, const uc_cfunction_list_t *list, size_t len)
+{
+ bool rv = true;
+
+ while (len-- > 0)
+ rv &= uc_add_function(object, list[len].name, list[len].func);
+
+ return rv;
+}
+
+#define uc_add_functions(object, functions) \
+ _uc_add_functions(object, functions, ARRAY_SIZE(functions))
+
+#endif /* __LIB_H_ */
diff --git a/include/ucode/module.h b/include/ucode/module.h
new file mode 100644
index 0000000..43d9d51
--- /dev/null
+++ b/include/ucode/module.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MODULE_H_
+#define __MODULE_H_
+
+#include "lib.h"
+#include "vm.h"
+
+#define register_functions(scope, functions) \
+ if (scope) \
+ for (int i = 0; i < ARRAY_SIZE(functions); i++) \
+ json_object_object_add(scope->header.jso, functions[i].name, \
+ ops->value.cfunc(functions[i].name, functions[i].func))
+
+#define alloc_prototype(functions) ({ \
+ uc_prototype *__proto = uc_object_as_prototype(ops->value.proto(NULL)); \
+ register_functions(__proto, functions); \
+ __proto; \
+})
+
+#define declare_type(name, proto, freefn) \
+ ucv_ressource_type_add(name, proto, freefn)
+
+#define alloc_ressource(data, type) \
+ ucv_ressource_new(ucv_object_new(NULL), type, data)
+
+#define register_ressource(scope, key, res) \
+ json_object_object_add((scope)->header.jso, key, (res)->header.jso)
+
+void uc_module_init(uc_vm_t *vm, uc_value_t *scope) __attribute__((weak));
+
+void uc_module_entry(uc_vm_t *vm, uc_value_t *scope);
+void uc_module_entry(uc_vm_t *vm, uc_value_t *scope)
+{
+ if (uc_module_init)
+ uc_module_init(vm, scope);
+}
+
+#endif /* __MODULE_H_ */
diff --git a/include/ucode/source.h b/include/ucode/source.h
new file mode 100644
index 0000000..3de7c93
--- /dev/null
+++ b/include/ucode/source.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __SOURCE_H_
+#define __SOURCE_H_
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "types.h"
+
+
+uc_source_t *uc_source_new_file(const char *path);
+uc_source_t *uc_source_new_buffer(const char *name, char *buf, size_t len);
+
+size_t uc_source_get_line(uc_source_t *source, size_t *offset);
+
+uc_source_t *uc_source_get(uc_source_t *source);
+void uc_source_put(uc_source_t *source);
+
+#endif /* __SOURCE_H_ */
diff --git a/include/ucode/types.h b/include/ucode/types.h
new file mode 100644
index 0000000..e2cb15d
--- /dev/null
+++ b/include/ucode/types.h
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __TYPES_H_
+#define __TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <regex.h>
+#include <json-c/json.h>
+
+#include "util.h"
+
+
+/* Value types and generic value header */
+
+typedef enum uc_type {
+ UC_NULL,
+ UC_INTEGER,
+ UC_BOOLEAN,
+ UC_STRING,
+ UC_DOUBLE,
+ UC_ARRAY,
+ UC_OBJECT,
+ UC_REGEXP,
+ UC_FUNCTION,
+ UC_CFUNCTION,
+ UC_CLOSURE,
+ UC_UPVALUE,
+ UC_RESSOURCE
+} uc_type_t;
+
+typedef struct uc_value {
+ uint32_t type:4;
+ uint32_t mark:1;
+ uint32_t u64:1;
+ uint32_t refcount:26;
+} uc_value_t;
+
+
+/* Constant list defintions */
+
+typedef struct {
+ size_t isize;
+ size_t dsize;
+ uint64_t *index;
+ char *data;
+} uc_value_list_t;
+
+
+/* Source buffer defintions */
+
+uc_declare_vector(uc_lineinfo_t, uint8_t);
+
+typedef struct {
+ char *filename, *buffer;
+ FILE *fp;
+ size_t usecount, off;
+ uc_lineinfo_t lineinfo;
+} uc_source_t;
+
+
+/* Bytecode chunk defintions */
+
+typedef struct {
+ size_t from, to, target, slot;
+} uc_ehrange_t;
+
+typedef struct {
+ size_t from, to, slot, nameidx;
+} uc_varrange_t;
+
+uc_declare_vector(uc_ehranges_t, uc_ehrange_t);
+uc_declare_vector(uc_variables_t, uc_varrange_t);
+uc_declare_vector(uc_offsetinfo_t, uint8_t);
+
+typedef struct {
+ size_t count;
+ uint8_t *entries;
+ uc_value_list_t constants;
+ uc_ehranges_t ehranges;
+ struct {
+ uc_variables_t variables;
+ uc_value_list_t varnames;
+ uc_offsetinfo_t offsets;
+ } debuginfo;
+} uc_chunk_t;
+
+
+/* Value type structures */
+
+typedef struct uc_weakref {
+ struct uc_weakref *prev;
+ struct uc_weakref *next;
+} uc_weakref_t;
+
+typedef struct {
+ uc_value_t header;
+ double dbl;
+} uc_double_t;
+
+typedef struct {
+ uc_value_t header;
+ union {
+ int64_t s64;
+ uint64_t u64;
+ } i;
+} uc_integer_t;
+
+typedef struct {
+ uc_value_t header;
+ size_t length;
+ char str[];
+} uc_string_t;
+
+typedef struct {
+ uc_value_t header;
+ uc_weakref_t ref;
+ size_t count;
+ uc_value_t *proto;
+ uc_value_t **entries;
+} uc_array_t;
+
+typedef struct {
+ uc_value_t header;
+ uc_weakref_t ref;
+ uc_value_t *proto;
+ struct lh_table *table;
+} uc_object_t;
+
+typedef struct {
+ uc_value_t header;
+ regex_t regexp;
+ bool icase, newline, global;
+ char source[];
+} uc_regexp_t;
+
+typedef struct {
+ uc_value_t header;
+ bool arrow, vararg, strict;
+ size_t nargs;
+ size_t nupvals;
+ size_t srcpos;
+ uc_chunk_t chunk;
+ uc_source_t *source;
+ char name[];
+} uc_function_t;
+
+typedef struct uc_upval_tref {
+ uc_value_t header;
+ size_t slot;
+ bool closed;
+ uc_value_t *value;
+ struct uc_upval_tref *next;
+} uc_upval_tref_t;
+
+typedef struct {
+ uc_value_t header;
+ uc_weakref_t ref;
+ bool is_arrow;
+ uc_function_t *function;
+ uc_upval_tref_t **upvals;
+} uc_closure_t;
+
+typedef struct uc_vm uc_vm_t;
+typedef uc_value_t *(*uc_cfn_ptr_t)(uc_vm_t *, size_t);
+
+typedef struct {
+ uc_value_t header;
+ uc_cfn_ptr_t cfn;
+ char name[];
+} uc_cfunction_t;
+
+typedef struct {
+ const char *name;
+ uc_value_t *proto;
+ void (*free)(void *);
+} uc_ressource_type_t;
+
+typedef struct {
+ uc_value_t header;
+ uc_ressource_type_t *type;
+ void *data;
+} uc_ressource_t;
+
+uc_declare_vector(uc_ressource_types_t, uc_ressource_type_t *);
+
+
+/* Parser definitions */
+
+typedef struct {
+ bool lstrip_blocks;
+ bool trim_blocks;
+ bool strict_declarations;
+ bool raw_mode;
+} uc_parse_config_t;
+
+
+/* VM definitions */
+
+typedef enum {
+ EXCEPTION_NONE,
+ EXCEPTION_SYNTAX,
+ EXCEPTION_RUNTIME,
+ EXCEPTION_TYPE,
+ EXCEPTION_REFERENCE,
+ EXCEPTION_USER,
+ EXCEPTION_EXIT
+} uc_exception_type_t;
+
+typedef struct {
+ uc_exception_type_t type;
+ uc_value_t *stacktrace;
+ char *message;
+} uc_exception_t;
+
+typedef struct {
+ uint8_t *ip;
+ uc_closure_t *closure;
+ uc_cfunction_t *cfunction;
+ size_t stackframe;
+ uc_value_t *ctx;
+ bool mcall, strict;
+} uc_callframe_t;
+
+uc_declare_vector(uc_callframes_t, uc_callframe_t);
+uc_declare_vector(uc_stack_t, uc_value_t *);
+
+typedef struct printbuf uc_stringbuf_t;
+
+typedef void (uc_exception_handler_t)(uc_vm_t *, uc_exception_t *);
+
+struct uc_vm {
+ uc_stack_t stack;
+ uc_exception_t exception;
+ uc_callframes_t callframes;
+ uc_upval_tref_t *open_upvals;
+ uc_parse_config_t *config;
+ uc_value_t *globals;
+ uc_source_t *sources;
+ uc_weakref_t values;
+ uc_ressource_types_t restypes;
+ union {
+ uint32_t u32;
+ int32_t s32;
+ uint16_t u16;
+ int16_t s16;
+ uint8_t u8;
+ int8_t s8;
+ } arg;
+ size_t spread_values;
+ uint8_t trace;
+ uc_stringbuf_t *strbuf;
+ uc_exception_handler_t *exhandler;
+ FILE *output;
+};
+
+
+/* Value API */
+
+void ucv_free(uc_value_t *, bool);
+void ucv_put(uc_value_t *);
+
+uc_value_t *ucv_get(uc_value_t *uv);
+
+uc_type_t ucv_type(uc_value_t *);
+const char *ucv_typename(uc_value_t *);
+
+uc_value_t *ucv_boolean_new(bool);
+bool ucv_boolean_get(uc_value_t *);
+
+uc_value_t *ucv_string_new(const char *);
+uc_value_t *ucv_string_new_length(const char *, size_t);
+size_t ucv_string_length(uc_value_t *);
+
+char *_ucv_string_get(uc_value_t **);
+#define ucv_string_get(uv) _ucv_string_get((uc_value_t **)&uv)
+
+uc_stringbuf_t *ucv_stringbuf_new(void);
+uc_value_t *ucv_stringbuf_finish(uc_stringbuf_t *);
+
+void _ucv_stringbuf_append(uc_stringbuf_t *, const char *, size_t);
+
+#define _ucv_is_literal(str) ("" str)
+#define ucv_stringbuf_append(buf, str) _ucv_stringbuf_append(buf, _ucv_is_literal(str), sizeof(str) - 1)
+#define ucv_stringbuf_addstr(buf, str, len) _ucv_stringbuf_append(buf, str, len)
+#define ucv_stringbuf_printf(buf, fmt, ...) sprintbuf(buf, fmt, __VA_ARGS__)
+
+uc_value_t *ucv_int64_new(int64_t);
+uc_value_t *ucv_uint64_new(uint64_t);
+int64_t ucv_int64_get(uc_value_t *);
+uint64_t ucv_uint64_get(uc_value_t *);
+
+uc_value_t *ucv_double_new(double);
+double ucv_double_get(uc_value_t *);
+
+uc_value_t *ucv_array_new(uc_vm_t *);
+uc_value_t *ucv_array_new_length(uc_vm_t *, size_t);
+uc_value_t *ucv_array_get(uc_value_t *, size_t);
+uc_value_t *ucv_array_pop(uc_value_t *);
+uc_value_t *ucv_array_push(uc_value_t *, uc_value_t *);
+uc_value_t *ucv_array_shift(uc_value_t *);
+uc_value_t *ucv_array_unshift(uc_value_t *, uc_value_t *);
+void ucv_array_sort(uc_value_t *, int (*)(const void *, const void *));
+bool ucv_array_delete(uc_value_t *, size_t, size_t);
+bool ucv_array_set(uc_value_t *, size_t, uc_value_t *);
+size_t ucv_array_length(uc_value_t *);
+
+uc_value_t *ucv_object_new(uc_vm_t *);
+uc_value_t *ucv_object_get(uc_value_t *, const char *, bool *);
+bool ucv_object_add(uc_value_t *, const char *, uc_value_t *);
+bool ucv_object_delete(uc_value_t *, const char *);
+size_t ucv_object_length(uc_value_t *);
+
+#define ucv_object_foreach(obj, key, val) \
+ char *key = NULL; \
+ uc_value_t *val = NULL; \
+ struct lh_entry *entry##key; \
+ struct lh_entry *entry_next##key = NULL; \
+ for (entry##key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL; \
+ (entry##key ? (key = (char *)lh_entry_k(entry##key), \
+ val = (uc_value_t *)lh_entry_v(entry##key), \
+ entry_next##key = entry##key->next, entry##key) \
+ : 0); \
+ entry##key = entry_next##key)
+
+uc_value_t *ucv_function_new(const char *, size_t, uc_source_t *);
+size_t ucv_function_srcpos(uc_value_t *, size_t);
+
+uc_value_t *ucv_cfunction_new(const char *, uc_cfn_ptr_t);
+
+uc_value_t *ucv_closure_new(uc_vm_t *, uc_function_t *, bool);
+
+uc_ressource_type_t *ucv_ressource_type_add(uc_vm_t *, const char *, uc_value_t *, void (*)(void *));
+uc_ressource_type_t *ucv_ressource_type_lookup(uc_vm_t *, const char *);
+
+uc_value_t *ucv_ressource_new(uc_ressource_type_t *, void *);
+void **ucv_ressource_dataptr(uc_value_t *, const char *);
+
+uc_value_t *ucv_regexp_new(const char *, bool, bool, bool, char **);
+
+uc_value_t *ucv_upvalref_new(size_t);
+
+uc_value_t *ucv_prototype_get(uc_value_t *);
+bool ucv_prototype_set(uc_value_t *, uc_value_t *);
+
+uc_value_t *ucv_property_get(uc_value_t *, const char *);
+
+uc_value_t *ucv_from_json(uc_vm_t *, json_object *);
+json_object *ucv_to_json(uc_value_t *);
+
+char *ucv_to_string(uc_vm_t *, uc_value_t *);
+char *ucv_to_jsonstring_formatted(uc_vm_t *, uc_value_t *, char, size_t);
+void ucv_to_stringbuf_formatted(uc_vm_t *, uc_stringbuf_t *, uc_value_t *, size_t, char, size_t);
+
+#define ucv_to_jsonstring(vm, val) ucv_to_jsonstring_formatted(vm, val, '\1', 0)
+#define ucv_to_stringbuf(vm, buf, val, json) ucv_to_stringbuf_formatted(vm, buf, val, 0, json ? '\1' : '\0', 0)
+
+static inline bool
+ucv_is_callable(uc_value_t *uv)
+{
+ switch (ucv_type(uv)) {
+ case UC_CLOSURE:
+ case UC_CFUNCTION:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static inline bool
+ucv_is_arrowfn(uc_value_t *uv)
+{
+ uc_closure_t *closure = (uc_closure_t *)uv;
+
+ return (ucv_type(uv) == UC_CLOSURE && closure->is_arrow);
+}
+
+static inline bool
+ucv_is_u64(uc_value_t *uv)
+{
+ return (((uintptr_t)uv & 3) == 0 && uv != NULL && uv->u64 == true);
+}
+
+static inline bool
+ucv_is_scalar(uc_value_t *uv)
+{
+ switch (ucv_type(uv)) {
+ case UC_NULL:
+ case UC_BOOLEAN:
+ case UC_DOUBLE:
+ case UC_INTEGER:
+ case UC_STRING:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static inline bool
+ucv_is_marked(uc_value_t *uv)
+{
+ return (((uintptr_t)uv & 3) == 0 && uv != NULL && uv->mark == true);
+}
+
+static inline void
+ucv_set_mark(uc_value_t *uv)
+{
+ if (((uintptr_t)uv & 3) == 0 && uv != NULL)
+ uv->mark = true;
+}
+
+static inline void
+ucv_clear_mark(uc_value_t *uv)
+{
+ if (((uintptr_t)uv & 3) == 0 && uv != NULL)
+ uv->mark = false;
+}
+
+bool ucv_equal(uc_value_t *, uc_value_t *);
+
+void ucv_gc(uc_vm_t *, bool);
+
+#endif /* __TYPES_H_ */
diff --git a/include/ucode/util.h b/include/ucode/util.h
new file mode 100644
index 0000000..858a3fd
--- /dev/null
+++ b/include/ucode/util.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __UTIL_H_
+#define __UTIL_H_
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h> /* va_start(), va_end(), va_list */
+#include <string.h> /* strdup() */
+#include <json-c/json.h>
+
+
+/* alignment & array size */
+
+#ifndef ALIGN
+#define ALIGN(x) (((x) + sizeof(size_t) - 1) & -sizeof(size_t))
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+
+/* vector macros */
+
+#define UC_VECTOR_CHUNK_SIZE 8
+
+#define uc_declare_vector(name, type) \
+ typedef struct { \
+ size_t count; \
+ type *entries; \
+ } name
+
+#define uc_vector_grow(vec) \
+ do { \
+ if (((vec)->count % UC_VECTOR_CHUNK_SIZE) == 0) { \
+ (vec)->entries = xrealloc((vec)->entries, sizeof((vec)->entries[0]) * ((vec)->count + UC_VECTOR_CHUNK_SIZE)); \
+ memset(&(vec)->entries[(vec)->count], 0, sizeof((vec)->entries[0]) * UC_VECTOR_CHUNK_SIZE); \
+ } \
+ } while(0)
+
+#define uc_vector_clear(vec) \
+ do { \
+ free((vec)->entries); \
+ (vec)->entries = NULL; \
+ (vec)->count = 0; \
+ } while(0)
+
+#define uc_vector_first(vec) \
+ (&((vec)->entries[0]))
+
+#define uc_vector_last(vec) \
+ (&((vec)->entries[(vec)->count - 1]))
+
+
+/* "failsafe" utility functions */
+
+static inline void *xalloc(size_t size) {
+ void *ptr = calloc(1, size);
+
+ if (!ptr) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return ptr;
+}
+
+static inline void *xrealloc(void *ptr, size_t size) {
+ ptr = realloc(ptr, size);
+
+ if (!ptr) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return ptr;
+}
+
+static inline char *xstrdup(const char *s) {
+ char *ptr = strdup(s);
+
+ if (!ptr) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return ptr;
+}
+
+static inline struct json_tokener *xjs_new_tokener(void) {
+ struct json_tokener *tok = json_tokener_new();
+
+ if (!tok) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return tok;
+}
+
+__attribute__((format(printf, 2, 0)))
+static inline int xasprintf(char **strp, const char *fmt, ...) {
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vasprintf(strp, fmt, ap);
+ va_end(ap);
+
+ if (len == -1) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return len;
+}
+
+__attribute__((format(printf, 2, 0)))
+static inline int xvasprintf(char **strp, const char *fmt, va_list ap) {
+ int len = vasprintf(strp, fmt, ap);
+
+ if (len == -1) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return len;
+}
+
+static inline struct printbuf *xprintbuf_new(void) {
+ struct printbuf *pb = printbuf_new();
+
+ if (!pb) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ return pb;
+}
+
+#endif /* __UTIL_H_ */
diff --git a/include/ucode/value.h b/include/ucode/value.h
new file mode 100644
index 0000000..04d37a9
--- /dev/null
+++ b/include/ucode/value.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __VALUE_H_
+#define __VALUE_H_
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifdef JSONC
+ #include <json.h>
+#else
+ #include <json-c/json.h>
+#endif
+
+#include <stdio.h>
+
+#include "types.h"
+
+typedef enum {
+ TAG_INVAL = 0,
+ TAG_NUM = 1,
+ TAG_LNUM = 2,
+ TAG_DBL = 3,
+ TAG_STR = 4,
+ TAG_LSTR = 5,
+ TAG_PTR = 6
+} uc_value_type_t;
+
+bool uc_cmp(int how, uc_value_t *v1, uc_value_t *v2);
+bool uc_val_is_truish(uc_value_t *val);
+
+uc_type_t uc_cast_number(uc_value_t *v, int64_t *n, double *d);
+
+uc_value_t *uc_getval(uc_vm_t *, uc_value_t *scope, uc_value_t *key);
+uc_value_t *uc_setval(uc_vm_t *, uc_value_t *scope, uc_value_t *key, uc_value_t *val);
+bool uc_delval(uc_vm_t *, uc_value_t *scope, uc_value_t *key);
+
+void uc_vallist_init(uc_value_list_t *list);
+void uc_vallist_free(uc_value_list_t *list);
+
+ssize_t uc_vallist_add(uc_value_list_t *list, uc_value_t *value);
+uc_value_type_t uc_vallist_type(uc_value_list_t *list, size_t idx);
+uc_value_t *uc_vallist_get(uc_value_list_t *list, size_t idx);
+
+#endif /* __VALUE_H_ */
diff --git a/include/ucode/vm.h b/include/ucode/vm.h
new file mode 100644
index 0000000..553cf61
--- /dev/null
+++ b/include/ucode/vm.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __VM_H_
+#define __VM_H_
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include "chunk.h"
+#include "util.h"
+#include "lexer.h"
+#include "types.h"
+
+#define __insns \
+__insn(NOOP) \
+__insn(LOAD) \
+__insn(LOAD8) \
+__insn(LOAD16) \
+__insn(LOAD32) \
+__insn(LTHIS) \
+__insn(LREXP) \
+__insn(LNULL) \
+__insn(LTRUE) \
+__insn(LFALSE) \
+__insn(LLOC) \
+__insn(LUPV) \
+__insn(LVAR) \
+__insn(LVAL) \
+__insn(CLFN) \
+__insn(ARFN) \
+__insn(SLOC) \
+__insn(SUPV) \
+__insn(SVAR) \
+__insn(SVAL) \
+__insn(ULOC) \
+__insn(UUPV) \
+__insn(UVAR) \
+__insn(UVAL) \
+__insn(NARR) \
+__insn(PARR) \
+__insn(MARR) \
+__insn(NOBJ) \
+__insn(SOBJ) \
+__insn(MOBJ) \
+__insn(BOR) \
+__insn(BXOR) \
+__insn(BAND) \
+__insn(EQS) \
+__insn(NES) \
+__insn(EQ) \
+__insn(NE) \
+__insn(LT) \
+__insn(LE) \
+__insn(GT) \
+__insn(GE) \
+__insn(IN) \
+__insn(LSHIFT) \
+__insn(RSHIFT) \
+__insn(ADD) \
+__insn(SUB) \
+__insn(MUL) \
+__insn(DIV) \
+__insn(MOD) \
+__insn(NOT) \
+__insn(COMPL) \
+__insn(PLUS) \
+__insn(MINUS) \
+__insn(JMP) \
+__insn(JMPZ) \
+__insn(COPY) \
+__insn(POP) \
+__insn(CUPV) \
+__insn(RETURN) \
+__insn(CALL) \
+__insn(MCALL) \
+__insn(PRINT) \
+__insn(NEXTK) \
+__insn(NEXTKV) \
+__insn(DELETE)
+
+
+#undef __insn
+#define __insn(_name) I_##_name,
+
+typedef enum {
+ __insns
+ __I_MAX
+} uc_vm_insn_t;
+
+typedef enum {
+ STATUS_OK,
+ STATUS_EXIT,
+ ERROR_COMPILE,
+ ERROR_RUNTIME
+} uc_vm_status_t;
+
+extern uint32_t insns[__I_MAX];
+
+void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config);
+void uc_vm_free(uc_vm_t *vm);
+
+uc_value_t *uc_vm_scope_get(uc_vm_t *vm);
+void uc_vm_scope_set(uc_vm_t *vm, uc_value_t *ctx);
+
+void uc_vm_stack_push(uc_vm_t *vm, uc_value_t *value);
+uc_value_t *uc_vm_stack_pop(uc_vm_t *vm);
+uc_value_t *uc_vm_stack_peek(uc_vm_t *vm, size_t offset);
+
+uc_exception_handler_t *uc_vm_exception_handler_get(uc_vm_t *vm);
+void uc_vm_exception_handler_set(uc_vm_t *vm, uc_exception_handler_t *exhandler);
+
+uint32_t uc_vm_trace_get(uc_vm_t *vm);
+void uc_vm_trace_set(uc_vm_t *vm, uint32_t level);
+
+uc_exception_type_t uc_vm_call(uc_vm_t *vm, bool mcall, size_t nargs);
+
+void __attribute__((format(printf, 3, 0)))
+uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...);
+
+uc_vm_status_t uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval);
+uc_value_t *uc_vm_invoke(uc_vm_t *vm, const char *fname, size_t nargs, ...);
+
+#endif /* __VM_H_ */