diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-12-23 20:54:05 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-02-17 14:10:51 +0100 |
commit | 3756806674da909ec6dc10ad25862b592792604e (patch) | |
tree | f2af7e47f8444caaff0a5a33599f381889db24e3 /lib.h | |
parent | 77580a893283f2bde7ab46496bd3a3d7b2fc6784 (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.h | 184 |
1 files changed, 177 insertions, 7 deletions
@@ -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_ */ |