mirror of
https://github.com/janet-lang/janet
synced 2025-02-22 03:00:02 +00:00
Add some test code and fix sqlite3 native example.
This commit is contained in:
parent
ed9037e603
commit
c0e373f420
@ -1,7 +1,5 @@
|
||||
# Dst Bytecode Reference
|
||||
|
||||
### Dst alpha 0.0.0
|
||||
|
||||
This document outlines the Dst bytecode format, and core ideas in the runtime
|
||||
that are closely related to the bytecode. It should enable the reader
|
||||
to write dst assembly code and hopefully understand the dst internals better.
|
||||
@ -62,8 +60,9 @@ Fibers also have an incomplete stack frame for the next function call on top
|
||||
of their stacks. Making a function call involves pushing arguments to this
|
||||
temporary stack, and then invoking either the CALL or TCALL instructions.
|
||||
Arguments for the next function call are pushed via the PUSH, PUSH2, PUSH3, and
|
||||
PUSHA instructions. The stack of a fiber will grow as large as needed, so
|
||||
recursive algorithms can be used without fear of stack overflow.
|
||||
PUSHA instructions. The stack of a fiber will grow as large as needed, although by
|
||||
default dst will limit the maximum size of a fiber's stack.
|
||||
The maximum stack size can be modified on a per fiber basis.
|
||||
|
||||
The slots in the stack are exposed as virtual registers to instructions. They
|
||||
can hold any Dst value.
|
||||
@ -72,7 +71,7 @@ can hold any Dst value.
|
||||
|
||||
All functions in dst are closures; they combine some bytecode instructions
|
||||
with 0 or more environments. In the C source, a closure (hereby the same as
|
||||
a function) is represented by the type `DstFunc *`. The bytecode instruction
|
||||
a function) is represented by the type `DstFunction *`. The bytecode instruction
|
||||
part of the function is represented by `DstFuncDef *`, and a function environment
|
||||
is represented with `DstFuncEnv *`.
|
||||
|
||||
@ -95,10 +94,12 @@ have a destination register, and 1 or 2 source register. Registers are simply
|
||||
named with positive integers.
|
||||
|
||||
Each instruction is a 32 bit integer, meaning that the instruction set is a constant
|
||||
width instruction set like MIPS. The opcode of each instruction is the least significant
|
||||
width RISC instruction set like MIPS. The opcode of each instruction is the least significant
|
||||
byte of the instruction. The highest bit of
|
||||
this leading byte is reserved for debugging purpose, so there are 128 possible opcodes encodable
|
||||
with this scheme. The current implementation uses about half of these possible opcodes.
|
||||
with this scheme. Not all of these possible opcode are defined, and will trap the interpreter
|
||||
and emit a debug signal. Note that this mean an unknown opcode is still valid bytecode, it will
|
||||
just put the interpreter into a debug state when executed.
|
||||
|
||||
```
|
||||
X - Payload bits
|
||||
@ -117,13 +118,13 @@ There are a few instruction variants that divide these payload bits.
|
||||
arguments. The payload is essentially ignored.
|
||||
* 1 arg - All payload bits correspond to a single value, usually a signed or unsigned integer.
|
||||
Used for instructions of 1 argument, like returning a value, yielding a value to the parent fiber,
|
||||
or doing a jump.
|
||||
or doing a (relative) jump.
|
||||
* 2 arg - Payload is split into byte 2 and bytes 3 and 4.
|
||||
The first argument is the 8 bit value from byte 2, and the second argument is the 16 bit value
|
||||
from bytes 3 and 4 (`instruction >> 16`). Used for instructions of two arguments, like move, normal
|
||||
function calls, conditionals, etc.
|
||||
* 3 arg - Bytes 2, 3, and 4 each correspond to an 8 bit argument.
|
||||
Used for arithmetic operations.
|
||||
Used for arithmetic operations, emitting a signal, etc.
|
||||
|
||||
These instruction variants can be further refined based on the semantics of the arguments.
|
||||
Some instructions may treat an argument as a slot index, while other instructions
|
||||
@ -222,6 +223,7 @@ failure to return or error.
|
||||
| `ret` | `(ret val)` | Return $val |
|
||||
| `retn` | `(retn)` | Return nil |
|
||||
| `setu` | `(setu env index val)` | envs[env][index] = $val |
|
||||
| `sig` | `(sig dest value sigtype)` | $dest = emit $value as sigtype |
|
||||
| `sl` | `(sl dest lhs rhs)` | $dest = $lhs << $rhs |
|
||||
| `slim` | `(slim dest lhs shamt)` | $dest = $lhs << shamt |
|
||||
| `sr` | `(sr dest lhs rhs)` | $dest = $lhs >> $rhs |
|
||||
@ -231,5 +233,4 @@ failure to return or error.
|
||||
| `sub` | `(sub dest lhs rhs)` | $dest = $lhs - $rhs |
|
||||
| `tcall` | `(tcall callee)` | Return call($callee) |
|
||||
| `tchck` | `(tcheck slot types)` | Assert $slot does matches types |
|
||||
| `yield` | `(yield dest value)` | $dest = yield $value to parent |
|
||||
|
||||
|
@ -88,10 +88,10 @@ static int sql_sql(DstArgs args) {
|
||||
const uint8_t *str;
|
||||
DstArray *rows;
|
||||
sqlite3 **conn;
|
||||
dst_fixarity(args, 2);
|
||||
dst_checkabstract(args, 0, &sql_conn_type);
|
||||
DST_FIXARITY(args, 2);
|
||||
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||
conn = (sqlite3 **)dst_unwrap_abstract(args.v[0]);
|
||||
dst_arg_string(str, args, 1);
|
||||
DST_ARG_STRING(str, args, 1);
|
||||
rows = dst_array(10);
|
||||
status = sqlite3_exec(
|
||||
*conn,
|
||||
|
@ -206,6 +206,7 @@ recur:
|
||||
i = frame->prevframe;
|
||||
}
|
||||
|
||||
/* Explicit tail recursion */
|
||||
if (fiber->child) {
|
||||
fiber = fiber->child;
|
||||
goto recur;
|
||||
|
@ -715,8 +715,8 @@ static void *op_lookup[255] = {
|
||||
retreg = dst_wrap_nil();
|
||||
args.v = fiber->data + fiber->frame;
|
||||
args.ret = &retreg;
|
||||
if (dst_unwrap_cfunction(callee)(args)) {
|
||||
goto vm_error;
|
||||
if ((signal = dst_unwrap_cfunction(callee)(args))) {
|
||||
goto vm_exit;
|
||||
}
|
||||
goto vm_return_cfunc;
|
||||
}
|
||||
@ -739,8 +739,8 @@ static void *op_lookup[255] = {
|
||||
retreg = dst_wrap_nil();
|
||||
args.v = fiber->data + fiber->frame;
|
||||
args.ret = &retreg;
|
||||
if (dst_unwrap_cfunction(callee)(args)) {
|
||||
goto vm_error;
|
||||
if ((signal = dst_unwrap_cfunction(callee)(args))) {
|
||||
goto vm_exit;
|
||||
}
|
||||
goto vm_return_cfunc_tail;
|
||||
}
|
||||
|
@ -93,5 +93,31 @@
|
||||
(assert (= myvar 4) "fiber resumes properly from debug state")
|
||||
(assert (= (fiber.status myfiber) :dead) "fiber properly dies from debug state")
|
||||
|
||||
# Test max triangle program
|
||||
|
||||
# Find the maximum path from the top (root)
|
||||
# of the triangle to the leaves of the triangle.
|
||||
|
||||
(defn myfold [xs ys]
|
||||
(let [xs1 (tuple.prepend xs 0)
|
||||
xs2 (tuple.append xs 0)
|
||||
m1 (map + xs1 ys)
|
||||
m2 (map + xs2 ys)]
|
||||
(map max m1 m2)))
|
||||
|
||||
(defn maxpath [t]
|
||||
(extreme > (reduce myfold () t)))
|
||||
|
||||
# Test it
|
||||
# Maximum path is 3 -> 10 -> 3 -> 9 for a total of 25
|
||||
|
||||
(def triangle '[
|
||||
[3]
|
||||
[7 10]
|
||||
[4 3 7]
|
||||
[8 9 1 3]
|
||||
])
|
||||
|
||||
(assert (= (maxpath triangle) 25) `max triangle`)
|
||||
|
||||
(end-suite)
|
||||
|
Loading…
x
Reference in New Issue
Block a user