mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Add proto field to tables to allow prototypal inheritance.
This commit is contained in:
parent
0c3b0673ff
commit
0b6ac1698c
@ -114,14 +114,17 @@
|
||||
ret)
|
||||
})
|
||||
|
||||
(defn onerr [t e]
|
||||
(print (string t " error: " e)))
|
||||
# Compile time
|
||||
|
||||
(var *read* nil)
|
||||
(var *onvalue* identity)
|
||||
(var *env* _env)
|
||||
|
||||
(def require-loading @{})
|
||||
|
||||
(defn onerr [t e]
|
||||
(print (string t " error: " e)))
|
||||
|
||||
(defn char-stream [getchunk ondone]
|
||||
(fiber (fn [parent]
|
||||
(def buf @"")
|
||||
@ -197,7 +200,7 @@
|
||||
(def wrapper (fiber (fn []
|
||||
(while *read*
|
||||
(def source (*read*))
|
||||
(def res (compile source _env))
|
||||
(def res (compile source *env*))
|
||||
(if (= (type res) :function)
|
||||
(*onvalue* (res))
|
||||
(onerr "compile" (get res :error)))))))
|
||||
|
@ -47,6 +47,9 @@ static const DstReg cfuns[] = {
|
||||
{"buffer", dst_core_buffer},
|
||||
{"gensym", dst_core_gensym},
|
||||
{"get", dst_core_get},
|
||||
{"rawget", dst_core_rawget},
|
||||
{"getproto", dst_core_getproto},
|
||||
{"setproto", dst_core_setproto},
|
||||
{"put", dst_core_put},
|
||||
{"length", dst_core_length},
|
||||
{"gccollect", dst_core_gccollect},
|
||||
|
@ -172,6 +172,33 @@ int dst_core_get(DstArgs args) {
|
||||
return dst_return(args, ds);
|
||||
}
|
||||
|
||||
int dst_core_rawget(DstArgs args) {
|
||||
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
|
||||
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
|
||||
return dst_return(args, dst_table_rawget(dst_unwrap_table(args.v[0]), args.v[1]));
|
||||
}
|
||||
|
||||
int dst_core_getproto(DstArgs args) {
|
||||
DstTable *t;
|
||||
if (args.n != 1) return dst_throw(args, "expected 1 argument");
|
||||
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
|
||||
t = dst_unwrap_table(args.v[0]);
|
||||
return dst_return(args, t->proto
|
||||
? dst_wrap_table(t->proto)
|
||||
: dst_wrap_nil());
|
||||
}
|
||||
|
||||
int dst_core_setproto(DstArgs args) {
|
||||
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
|
||||
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
|
||||
if (!dst_checktype(args.v[1], DST_TABLE) && !dst_checktype(args.v[1], DST_NIL))
|
||||
return dst_throw(args, "expected table");
|
||||
dst_unwrap_table(args.v[0])->proto = dst_checktype(args.v[1], DST_TABLE)
|
||||
? dst_unwrap_table(args.v[1])
|
||||
: NULL;
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
int dst_core_fiber_status(DstArgs args) {
|
||||
const char *status = "";
|
||||
if (args.n != 1) return dst_throw(args, "expected 1 argument");
|
||||
|
@ -109,10 +109,15 @@ static void dst_mark_array(DstArray *array) {
|
||||
}
|
||||
|
||||
static void dst_mark_table(DstTable *table) {
|
||||
recur: /* Manual tail recursion */
|
||||
if (dst_gc_reachable(table))
|
||||
return;
|
||||
dst_gc_mark(table);
|
||||
dst_mark_kvs(table->data, table->capacity);
|
||||
if (table->proto) {
|
||||
table = table->proto;
|
||||
goto recur;
|
||||
}
|
||||
}
|
||||
|
||||
static void dst_mark_struct(const DstKV *st) {
|
||||
|
@ -43,6 +43,7 @@ DstTable *dst_table_init(DstTable *table, int32_t capacity) {
|
||||
}
|
||||
table->count = 0;
|
||||
table->deleted = 0;
|
||||
table->proto = NULL;
|
||||
return table;
|
||||
}
|
||||
|
||||
@ -114,8 +115,25 @@ static void dst_table_rehash(DstTable *t, int32_t size) {
|
||||
free(olddata);
|
||||
}
|
||||
|
||||
/* Get a value out of the object */
|
||||
/* Get a value out of the table */
|
||||
Dst dst_table_get(DstTable *t, Dst key) {
|
||||
DstKV *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL))
|
||||
return bucket->value;
|
||||
/* Check prototypes */
|
||||
{
|
||||
int i;
|
||||
for (i = DST_MAX_PROTO_DEPTH, t = t->proto; t && i; t = t->proto, --i) {
|
||||
bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL))
|
||||
return bucket->value;
|
||||
}
|
||||
}
|
||||
return dst_wrap_nil();
|
||||
}
|
||||
|
||||
/* Get a value out of the table. Don't check prototype tables. */
|
||||
Dst dst_table_rawget(DstTable *t, Dst key) {
|
||||
DstKV *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL))
|
||||
return bucket->value;
|
||||
|
@ -120,6 +120,7 @@ DstTable *dst_table(int32_t capacity);
|
||||
DstTable *dst_table_init(DstTable *table, int32_t capacity);
|
||||
void dst_table_deinit(DstTable *table);
|
||||
Dst dst_table_get(DstTable *t, Dst key);
|
||||
Dst dst_table_rawget(DstTable *t, Dst key);
|
||||
Dst dst_table_remove(DstTable *t, Dst key);
|
||||
void dst_table_put(DstTable *t, Dst key, Dst value);
|
||||
const DstKV *dst_table_next(DstTable *t, const DstKV *kv);
|
||||
|
@ -120,6 +120,9 @@ extern "C" {
|
||||
* ands crashing (the parser). Instead, error out. */
|
||||
#define DST_RECURSION_GUARD 1024
|
||||
|
||||
/* Maximum depth to follow table prototypes before giving up and returning nil. */
|
||||
#define DST_MAX_PROTO_DEPTH 200
|
||||
|
||||
/* Define max stack size for stacks before raising a stack overflow error.
|
||||
* If this is not defined, fiber stacks can grow without limit (until memory
|
||||
* runs out) */
|
||||
|
@ -90,6 +90,9 @@ int dst_core_buffer(DstArgs args);
|
||||
int dst_core_gensym(DstArgs args);
|
||||
int dst_core_length(DstArgs args);
|
||||
int dst_core_get(DstArgs args);
|
||||
int dst_core_rawget(DstArgs args);
|
||||
int dst_core_getproto(DstArgs args);
|
||||
int dst_core_setproto(DstArgs args);
|
||||
int dst_core_fiber_status(DstArgs args);
|
||||
int dst_core_fiber_current(DstArgs args);
|
||||
int dst_core_put(DstArgs args);
|
||||
|
@ -359,6 +359,7 @@ struct DstBuffer {
|
||||
/* A mutable associative data type. Backed by a hashtable. */
|
||||
struct DstTable {
|
||||
DstKV *data;
|
||||
DstTable *proto;
|
||||
int32_t count;
|
||||
int32_t capacity;
|
||||
int32_t deleted;
|
||||
|
38
thoughts.md
38
thoughts.md
@ -2,38 +2,6 @@
|
||||
|
||||
A collection of thoughts and todo tasks for the project.
|
||||
|
||||
- Allow entrances into the VM to track the size of the stack when they entered, and return
|
||||
when the stack is less that. This would make calling dst functions from C feasible (
|
||||
The programmer would still have to ensure no GC violations).
|
||||
|
||||
Instead, we can just keep allocating new Fibers when we call a dst function from C. A pool
|
||||
of fibers would mostly mitigate the overhead of allocation. (going with this).
|
||||
|
||||
We can now call into dst from C without suspending the entire garbage collector. A separate
|
||||
function does exactly that.
|
||||
|
||||
- Make unknown instruction in vm trap and put current fiber in a new state, 'debug'.
|
||||
This could allow implementation of a debugger. Since opcodes are encoded in one byte,
|
||||
we can use the most significant bit (0x80) to set breakpoints in code, assuming all valid
|
||||
opcodes are in the range [0, 127]. The debugger could simply set the MSB of the opcode for each
|
||||
instruction that was marked. This would allow debugging with 0 overhead.
|
||||
|
||||
We could also add a debugger instruction, much like JavaScripts debugger; statement very easily.
|
||||
|
||||
Lastly, to make continuation after a breakpoint easier, stopping on the first instruction
|
||||
could be optional. This could be as simple as selecting the first 7 bits of the instructions
|
||||
instead of the usual 8 for the very instruction executed after entering the vm loop.
|
||||
|
||||
What exactly should happen on a trapped instruction is another issue. It would be preferable
|
||||
for the runtime to be able to handle a trap in dst, but allow nested fibers to not capture
|
||||
debugging signals unless needed.
|
||||
|
||||
Fiber's currently propagate all states to their direct parent, but perhaps each fiber
|
||||
could have a mask for different signals - error, debug, return. So a single fiber could
|
||||
say capture returns, error, but not debug. Possibly like try - catch in other languages, where
|
||||
we only catch certain kinds of errors. The default fiber would be to only mask debug, so a single fiber
|
||||
could wrap an entire running application for debugging.
|
||||
|
||||
- Remove the concept of 'Ast node'. While providing fine-grained source mapping is
|
||||
is reasonably useful, it complicates the implementation of macros and other source
|
||||
transforming operations. Instead, we can key collection types (which have the unique
|
||||
@ -53,7 +21,7 @@ A collection of thoughts and todo tasks for the project.
|
||||
definitions generated with this one form.
|
||||
|
||||
- Serialization and deserialization of all datatypes. This would allow loading of bytecode
|
||||
without needing the compiler present. However, loading C functions is currently problamatic.
|
||||
without needing the compiler present. However, loading C functions is currently problematic.
|
||||
C functions could perhaps be wrapped in data structures that contain some meta information
|
||||
about them, say home module and types. This could also allow some automated type checking for
|
||||
C functions rather than writing it manually. Some slight overhead could perhaps be compensated
|
||||
@ -65,7 +33,7 @@ A collection of thoughts and todo tasks for the project.
|
||||
values and data structure style values. For example, simply adding special keys as fields
|
||||
would make plain a table or struct possibly become object-like if the write keys are added.
|
||||
|
||||
A Lua like solution would be a metatables. It would perhaps make sense to only allow
|
||||
A Lua like solution would be metatables. It would perhaps make sense to only allow
|
||||
metatables on tables, as object like behavior seems to makes most sense on mutable data (?).
|
||||
For example, metatables on a struct could allow non-pure behavior unless they were extremely
|
||||
limited, or purity was enforced somehow. This could break expectations of a struct to behave
|
||||
@ -73,7 +41,7 @@ A collection of thoughts and todo tasks for the project.
|
||||
|
||||
Also, it might make sense that the metatable of a value would actually be a struct, so
|
||||
a metastruct. Implementations of Lua (LuaJIT) do not allow (or do not acknowledge)
|
||||
changing certain values of a metatables after it is set, such as __gc, for performance
|
||||
changing certain values of a metatables after it is set, such as gc, for performance
|
||||
reasons.
|
||||
|
||||
- Actually make a debugger. While the VM changes to enable debugging are relatively
|
||||
|
Loading…
Reference in New Issue
Block a user