summaryrefslogtreecommitdiffhomepage
path: root/lib.h
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-12-23 20:54:05 +0100
committerJo-Philipp Wich <jo@mein.io>2021-02-17 14:10:51 +0100
commit3756806674da909ec6dc10ad25862b592792604e (patch)
treef2af7e47f8444caaff0a5a33599f381889db24e3 /lib.h
parent77580a893283f2bde7ab46496bd3a3d7b2fc6784 (diff)
treewide: rewrite ucode interpreter
Replace the former AST walking interpreter implementation with a single pass bytecode compiler and a corresponding virtual machine. The rewrite lays the groundwork for a couple of improvements with will be subsequently implemented: - Ability to precompile ucode sources into binary byte code - Strippable debug information - Reduced runtime memory usage Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'lib.h')
-rw-r--r--lib.h184
1 files changed, 177 insertions, 7 deletions
diff --git a/lib.h b/lib.h
index 409cfc4..c14d11d 100644
--- a/lib.h
+++ b/lib.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Jo-Philipp Wich <jo@mein.io>
+ * 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
@@ -17,17 +17,187 @@
#ifndef __LIB_H_
#define __LIB_H_
-#include "ast.h"
+#include "vm.h"
#include "lexer.h"
+#include "object.h"
-typedef struct json_object *(uc_c_fn)(struct uc_state *, uint32_t, struct json_object *);
+typedef struct {
+ const char *name;
+ uc_cfn_ptr func;
+} uc_cfunction_list;
-void uc_lib_init(struct uc_state *state, struct json_object *scope);
+typedef struct {
+ /* value operations */
+ struct {
+ uc_prototype *(*proto)(uc_prototype *);
+ uc_cfunction *(*cfunc)(const char *, uc_cfn_ptr);
+ json_object *(*dbl)(double);
+ uc_regexp *(*regexp)(const char *, bool, bool, bool, char **);
+ uc_ressource *(*ressource)(json_object *, uc_ressource_type *, void *);
+ enum json_type (*tonumber)(json_object *, int64_t *, double *);
+ } value;
-struct json_object *uc_execute_source(struct uc_state *s, struct uc_source *src, struct uc_scope *scope);
+ /* ressource operations */
+ struct {
+ uc_ressource_type *(*define)(const char *, uc_prototype *, void (*)(void *));
+ uc_ressource *(*create)(json_object *, uc_ressource_type *, void *);
+ void **(*data)(json_object *, const char *);
+ uc_prototype *(*proto)(json_object *);
+ } ressource;
-struct json_object *uc_parse_error(struct uc_state *s, uint32_t off, uint64_t *tokens, int max_token);
+ /* VM operations */
+ struct {
+ uc_exception_type_t (*call)(uc_vm *, bool, size_t);
+ json_object *(*peek)(uc_vm *, size_t);
+ json_object *(*pop)(uc_vm *);
+ void (*push)(uc_vm *, json_object *);
+ void (*raise)(uc_vm *, uc_exception_type_t, const char *, ...);
+ } vm;
+} uc_ops;
-char *uc_format_error(struct uc_state *state, FILE *fp);
+extern const uc_ops uc;
+
+void uc_lib_init(uc_prototype *scope);
+
+void format_source_context(char **msg, size_t *msglen, uc_source *src, size_t off, bool compact);
+void format_error_context(char **msg, size_t *msglen, uc_source *src, json_object *stacktrace, size_t off);
+
+
+/* vm helper */
+
+static inline void *
+_uc_get_self(const uc_ops *ops, uc_vm *vm, const char *expected_type)
+{
+ return ops->ressource.data(vm->callframes.entries[vm->callframes.count - 1].ctx, expected_type);
+}
+
+#define uc_get_self(...) _uc_get_self(ops, vm, __VA_ARGS__)
+
+static inline json_object *
+_uc_get_arg(const uc_ops *ops, uc_vm *vm, size_t nargs, size_t n)
+{
+ if (n >= nargs)
+ return NULL;
+
+ return ops->vm.peek(vm, nargs - n - 1);
+}
+
+#define uc_get_arg(...) _uc_get_arg(ops, vm, nargs, __VA_ARGS__)
+
+#define uc_call(nargs) ops->vm.call(vm, false, nargs)
+#define uc_push_val(val) ops->vm.push(vm, val)
+#define uc_pop_val() ops->vm.pop(vm)
+
+
+/* value helper */
+
+static inline json_object *
+_uc_alloc_proto(const uc_ops *ops, uc_prototype *parent)
+{
+ return ops->value.proto(parent)->header.jso;
+}
+
+static inline json_object *
+_uc_alloc_cfunc(const uc_ops *ops, const char *name, uc_cfn_ptr fptr)
+{
+ return ops->value.cfunc(name, fptr)->header.jso;
+}
+
+static inline json_object *
+_uc_alloc_double(const uc_ops *ops, double dbl)
+{
+ return ops->value.dbl(dbl);
+}
+
+static inline json_object *
+_uc_alloc_regexp(const uc_ops *ops, const char *pattern, bool global, bool icase, bool newline, char **errp)
+{
+ uc_regexp *re = ops->value.regexp(pattern, global, icase, newline, errp);
+
+ return re ? re->header.jso : NULL;
+}
+
+static inline json_object *
+_uc_alloc_ressource(const uc_ops *ops, uc_ressource_type *type, void *data)
+{
+ uc_ressource *res = ops->value.ressource(xjs_new_object(), type, data);
+
+ return res ? res->header.jso : NULL;
+}
+
+#define uc_alloc_proto(...) _uc_alloc_proto(ops, __VA_ARGS__)
+#define uc_alloc_cfunc(...) _uc_alloc_cfunc(ops, __VA_ARGS__)
+#define uc_alloc_double(...) _uc_alloc_double(ops, __VA_ARGS__)
+#define uc_alloc_regexp(...) _uc_alloc_regexp(ops, __VA_ARGS__)
+#define uc_alloc_ressource(...) _uc_alloc_ressource(ops, __VA_ARGS__)
+
+static inline json_type
+_uc_to_number(const uc_ops *ops, json_object *v, int64_t *n, double *d)
+{
+ return ops->value.tonumber(v, n, d);
+}
+
+static inline double
+_uc_to_double(const uc_ops *ops, json_object *v)
+{
+ int64_t n;
+ double d;
+
+ return (ops->value.tonumber(v, &n, &d) == json_type_double) ? d : (double)n;
+}
+
+static inline int64_t
+_uc_to_int64(const uc_ops *ops, json_object *v)
+{
+ int64_t n;
+ double d;
+
+ return (ops->value.tonumber(v, &n, &d) == json_type_double) ? (int64_t)d : n;
+}
+
+#define uc_to_number(...) _uc_to_number(ops, __VA_ARGS__)
+#define uc_to_double(...) _uc_to_double(ops, __VA_ARGS__)
+#define uc_to_int64(...) _uc_to_int64(ops, __VA_ARGS__)
+
+
+/* ressource type helper */
+
+static inline uc_ressource_type *
+_uc_declare_type(const uc_ops *ops, const char *name, const uc_cfunction_list *list, size_t len, void (*freefn)(void *))
+{
+ uc_prototype *proto = ops->value.proto(NULL);
+
+ while (len-- > 0)
+ json_object_object_add(proto->header.jso, list[len].name,
+ _uc_alloc_cfunc(ops, list[len].name, list[len].func));
+
+ return ops->ressource.define(name, proto, freefn);
+}
+
+#define uc_declare_type(name, functions, freefn) \
+ _uc_declare_type(ops, name, functions, ARRAY_SIZE(functions), freefn)
+
+
+/* prototype helper */
+
+static inline bool
+uc_add_proto_val(uc_prototype *proto, const char *key, json_object *value)
+{
+ if (!proto)
+ return false;
+
+ return json_object_object_add(proto->header.jso, key, value);
+}
+
+static inline void
+_uc_add_proto_functions(const uc_ops *ops, uc_prototype *proto, const uc_cfunction_list *list, size_t len)
+{
+ while (len-- > 0)
+ json_object_object_add(proto->header.jso, list[len].name,
+ _uc_alloc_cfunc(ops, list[len].name, list[len].func));
+}
+
+#define uc_add_proto_functions(proto, functions) \
+ _uc_add_proto_functions(ops, proto, functions, ARRAY_SIZE(functions))
#endif /* __LIB_H_ */