1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-13 17:06:49 +00:00

More work on renaming functions. Change long string syntax to use

backticks. Allow custom masks in fibers for custom error and debug
handling.
This commit is contained in:
Calvin Rose 2018-05-09 17:01:58 -04:00
parent f47323c915
commit 932a0324ee
19 changed files with 171 additions and 117 deletions

View File

@ -148,19 +148,14 @@ Literal text can be entered inside quotes, as we have seen above.
"Hello\nThis is on line two\n\tThis is indented\n"
# For long strings where you don't want to type a lot of escape characters,
# you can use two backslashes with 0 or more equal signs inside them.
# To close this string, simply repeat the opening sequence (with a matching number of = characters).
\====\
# you can use 1 or more backticks (`\``) to delimit a string.
# To close this string, simply repeat the opening sequence of backticks
``
This is a string.
Line 2
Indented
"We can just type quotes here", no problem.
\====\
# You don't need any = charcters in the delimiters
\\
This works if two backslashes don't appear in your string.
\\
"We can just type quotes here", and backslashes \ no problem.
``
```
# Functions

View File

@ -1,7 +1,7 @@
# Example of dst bytecode assembly
# Fibonacci sequence, implemented with naive recursion.
(def fibasm (asm/asm '{
(def fibasm (asm.asm '{
arity 1
bytecode [
(ldi 1 0x2) # $1 = 2

View File

@ -2,7 +2,7 @@
# sequences, as in clojure. The lazy seq is essentially
# A lazy linked list, where the next value is a function
# that must be called (realizing it), and the memoized.
# Use with (import "./path/to/this/file" :prefix "seq/")
# Use with (import "./path/to/this/file" :prefix "seq.")
(defmacro delay [& forms]
"Lazily evaluate a series of expressions. Returns a function that

View File

@ -908,8 +908,8 @@ int dst_disasm_cfun(DstArgs args) {
}
static const DstReg cfuns[] = {
{"asm/asm", dst_asm_cfun},
{"asm/disasm", dst_disasm_cfun},
{"asm.asm", dst_asm_cfun},
{"asm.disasm", dst_disasm_cfun},
{NULL, NULL}
};

View File

@ -257,7 +257,7 @@ evaluates to true."
(defmacro coro
"A wrapper for making fibers. Same as (fiber (fn [] ...body))."
[& body]
(tuple fiber (apply tuple 'fn [] body)))
(tuple fiber.new (apply tuple 'fn [] body)))
(defmacro if-let
"Takes the first one or two forms in a vector and if both are true binds
@ -868,7 +868,7 @@ onvalue."
(var going true)
# The parser object
(def p (parser.make 1))
(def p (parser.new 1))
# Fiber stream of characters
(def chars (coro
@ -879,18 +879,18 @@ onvalue."
(chunks buf p)
(:= len (length buf))
(for [i 0 len]
(yield (get buf i))))
(fiber.yield (get buf i))))
0))
# Fiber stream of values
(def vals (coro
(while going
(switch (parser.status p)
:full (yield (parser.produce p))
:full (fiber.yield (parser.produce p))
:error (onerr "parse" (parser.error p))
(switch (fiber.status chars)
:new (parser.byte p (resume chars))
:pending (parser.byte p (resume chars))
:new (parser.byte p (fiber.resume chars))
:pending (parser.byte p (fiber.resume chars))
(:= going false))))
(when (not= :root (parser.status p))
(onerr "parse" "unexpected end of source"))))
@ -898,23 +898,24 @@ onvalue."
# Evaluate 1 source form
(defn eval1 [source]
(var good true)
(def f (coro
(def f (fiber.new (fn []
(def res (compile source env))
(if (= (type res) :function)
(res)
(do
(:= good false)
(onerr "compile" (get res :error))))))
(def res (resume f))
(onerr "compile" (get res :error))))) :de))
(def res (fiber.resume f))
(if good
(if (= (fiber.status f) :error)
(onerr "runtime" res f)
(if going (onvalue res)))))
(cond
(= (fiber.status f) :error) (onerr "runtime" res f)
(= (fiber.status f) :debug) (onerr "debug" res f)
going (onvalue res))))
# Run loop
(def oldenv *env*)
(:= *env* env)
(while going (eval1 (resume vals)))
(while going (eval1 (fiber.resume vals)))
(:= *env* oldenv)
env)

View File

@ -45,7 +45,6 @@ static const DstReg cfuns[] = {
{"scan-real", dst_core_scanreal},
{"tuple", dst_core_tuple},
{"struct", dst_core_struct},
{"fiber", dst_core_fiber},
{"buffer", dst_core_buffer},
{"gensym", dst_core_gensym},
{"get", dst_core_get},
@ -65,32 +64,23 @@ DstTable *dst_stl_env() {
static uint32_t error_asm[] = {
DOP_ERROR
};
static uint32_t apply_asm[] = {
DOP_PUSH_ARRAY | (1 << 8),
DOP_TAILCALL
};
static uint32_t yield_asm[] = {
DOP_YIELD,
DOP_RETURN
static uint32_t debug_asm[] = {
DOP_DEBUG,
DOP_RETURN_NIL
};
static uint32_t resume_asm[] = {
DOP_RESUME | (1 << 24),
DOP_RETURN
};
DstTable *env = dst_table(0);
Dst ret = dst_wrap_table(env);
/* Load main functions */
dst_env_cfuns(env, cfuns);
dst_env_def(env, "debug", dst_wrap_function(dst_quick_asm(0, 0, 0, debug_asm, sizeof(debug_asm))));
dst_env_def(env, "error", dst_wrap_function(dst_quick_asm(1, 0, 1, error_asm, sizeof(error_asm))));
dst_env_def(env, "apply1", dst_wrap_function(dst_quick_asm(2, 0, 2, apply_asm, sizeof(apply_asm))));
dst_env_def(env, "yield", dst_wrap_function(dst_quick_asm(1, 0, 2, yield_asm, sizeof(yield_asm))));
dst_env_def(env, "resume", dst_wrap_function(dst_quick_asm(2, 0, 2, resume_asm, sizeof(resume_asm))));
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));

View File

@ -105,6 +105,15 @@ Dst dst_array_peek(DstArray *array) {
/* C Functions */
static int cfun_new(DstArgs args) {
int32_t cap;
DstArray *array;
dst_fixarity(args, 1);
dst_arg_integer(cap, args, 0);
array = dst_array(cap);
return dst_return(args, dst_wrap_array(array));
}
static int cfun_pop(DstArgs args) {
dst_fixarity(args, 1);
dst_check(args, 0, DST_ARRAY);
@ -219,6 +228,7 @@ static int cfun_concat(DstArgs args) {
}
static const DstReg cfuns[] = {
{"array.new", cfun_new},
{"array.pop", cfun_pop},
{"array.peek", cfun_peek},
{"array.push", cfun_push},

View File

@ -157,6 +157,16 @@ int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x) {
}
/* C functions */
static int cfun_new(DstArgs args) {
int32_t cap;
DstBuffer *buffer;
dst_fixarity(args, 1);
dst_arg_integer(cap, args, 0);
buffer = dst_buffer(cap);
return dst_return(args, dst_wrap_buffer(buffer));
}
static int cfun_u8(DstArgs args) {
int32_t i;
DstBuffer *buffer;
@ -258,6 +268,7 @@ static int cfun_slice(DstArgs args) {
}
static const DstReg cfuns[] = {
{"buffer.new", cfun_new},
{"buffer.push-byte", cfun_u8},
{"buffer.push-integer", cfun_int},
{"buffer.push-string", cfun_chars},

View File

@ -202,14 +202,6 @@ int dst_core_struct(DstArgs args) {
return dst_return(args, dst_wrap_struct(dst_struct_end(st)));
}
int dst_core_fiber(DstArgs args) {
DstFiber *fiber;
dst_fixarity(args, 1);
dst_check(args, 0, DST_FUNCTION);
fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64);
return dst_return(args, dst_wrap_fiber(fiber));
}
int dst_core_gensym(DstArgs args) {
dst_maxarity(args, 1);
if (args.n == 0) {

View File

@ -21,6 +21,7 @@
*/
#include <dst/dst.h>
#include <dst/dstopcodes.h>
#include "fiber.h"
#include "gc.h"
@ -257,6 +258,35 @@ void dst_fiber_popframe(DstFiber *fiber) {
/* CFuns */
static int cfun_new(DstArgs args) {
DstFiber *fiber;
dst_minarity(args, 1);
dst_maxarity(args, 2);
dst_check(args, 0, DST_FUNCTION);
fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64);
if (args.n == 2) {
const uint8_t *flags;
int32_t len, i;
dst_arg_bytes(flags, len, args, 1);
fiber->flags |= DST_FIBER_MASK_ERROR;
for (i = 0; i < len; i++) {
switch (flags[i]) {
default:
return dst_throw(args, "invalid flag, expected d or e");
case ':':
break;
case 'd':
fiber->flags &= ~DST_FIBER_MASK_DEBUG;
break;
case 'e':
fiber->flags &= ~DST_FIBER_MASK_ERROR;
break;
}
}
}
return dst_return(args, dst_wrap_fiber(fiber));
}
static int cfun_status(DstArgs args) {
const char *status = "";
dst_fixarity(args, 1);
@ -338,6 +368,7 @@ static int cfun_stack(DstArgs args) {
}
static const DstReg cfuns[] = {
{"fiber.new", cfun_new},
{"fiber.status", cfun_status},
{"fiber.stack", cfun_stack},
{NULL, NULL}
@ -345,7 +376,21 @@ static const DstReg cfuns[] = {
/* Module entry point */
int dst_lib_fiber(DstArgs args) {
static uint32_t yield_asm[] = {
DOP_YIELD,
DOP_RETURN
};
static uint32_t resume_asm[] = {
DOP_RESUME | (1 << 24),
DOP_RETURN
};
DstTable *env = dst_env_arg(args);
dst_env_cfuns(env, cfuns);
dst_env_def(env, "fiber.yield",
dst_wrap_function(dst_quick_asm(1, 0, 2,
yield_asm, sizeof(yield_asm))));
dst_env_def(env, "fiber.resume",
dst_wrap_function(dst_quick_asm(2, 0, 2,
resume_asm, sizeof(resume_asm))));
return 0;
}

View File

@ -235,6 +235,17 @@ void dst_table_merge_struct(DstTable *table, const DstKV *other) {
dst_table_mergekv(table, other, dst_struct_capacity(other));
}
/* C Functions */
static int cfun_new(DstArgs args) {
DstTable *t;
int32_t cap;
dst_fixarity(args, 1);
dst_arg_integer(cap, args, 0);
t = dst_table(cap);
return dst_return(args, dst_wrap_table(t));
}
static int cfun_getproto(DstArgs args) {
DstTable *t;
dst_fixarity(args, 1);
@ -269,6 +280,7 @@ static int cfun_rawget(DstArgs args) {
}
static const DstReg cfuns[] = {
{"table.new", cfun_new},
{"table.to-struct", cfun_tostruct},
{"table.getproto", cfun_getproto},
{"table.setproto", cfun_setproto},

View File

@ -255,6 +255,7 @@ int32_t dst_length(Dst x) {
default:
return 0;
case DST_STRING:
case DST_SYMBOL:
return dst_string_length(dst_unwrap_string(x));
case DST_ARRAY:
return dst_unwrap_array(x)->count;
@ -275,6 +276,7 @@ Dst dst_getindex(Dst ds, int32_t index) {
default:
return dst_wrap_nil();
case DST_STRING:
case DST_SYMBOL:
if (index >= dst_string_length(dst_unwrap_string(ds))) return dst_wrap_nil();
return dst_wrap_integer(dst_unwrap_string(ds)[index]);
case DST_ARRAY:

View File

@ -750,7 +750,6 @@ static void *op_lookup[255] = {
break;
default:
fiber->child = NULL;
if (nextfiber->flags & DST_FIBER_MASK_RETURN) goto vm_return_root;
break;
}
stack[oparg(1, 0xFF)] = retreg;
@ -844,6 +843,7 @@ static void *op_lookup[255] = {
vm_debug:
{
fiber->status = DST_FIBER_DEBUG;
retreg = dst_wrap_nil();
goto vm_exit;
}

View File

@ -92,7 +92,6 @@ int dst_core_tuple(DstArgs args);
int dst_core_array(DstArgs args);
int dst_core_table(DstArgs args);
int dst_core_struct(DstArgs args);
int dst_core_fiber(DstArgs args);
int dst_core_buffer(DstArgs args);
int dst_core_gensym(DstArgs args);
int dst_core_length(DstArgs args);

View File

@ -338,12 +338,12 @@ struct DstArgs {
Dst *ret;
};
/* Fiber signal masks */
#define DST_FIBER_MASK_RETURN 1
#define DST_FIBER_MASK_ERROR 2
#define DST_FIBER_MASK_DEBUG 4
/* Fiber flags */
#define DST_FIBER_FLAG_NEW (1 << 31)
#define DST_FIBER_FLAG_NEW 8
/* Fiber signal masks. Should not overlap any fiber flags. */
#define DST_FIBER_MASK_ERROR 1
#define DST_FIBER_MASK_DEBUG 2
/* A lightweight green thread in dst. Does not correspond to
* operating system threads. */

View File

@ -6,24 +6,24 @@
# Flag handlers
(def handlers :private {
"h" (fn []
(print "usage: " (get args 0) " [options] scripts...")
(print "Options are:")
(print " -h Show this help")
(print " -v Print the version string")
(print " -s Use raw stdin instead of getline like functionality")
(print " -e Execute a string of dst")
(print " -r Enter the repl after running all scripts")
(os.exit 0)
1)
"v" (fn [] (print VERSION) (os.exit 0) 1)
"s" (fn [] (:= *raw-stdin* true) (:= *should-repl* true) 1)
"r" (fn [] (:= *should-repl* true) 1)
"e" (fn [i]
(:= *no-file* false)
(eval (get args (+ i 1)))
2)
})
"h" (fn []
(print "usage: " (get args 0) " [options] scripts...")
(print "Options are:")
(print " -h Show this help")
(print " -v Print the version string")
(print " -s Use raw stdin instead of getline like functionality")
(print " -e Execute a string of dst")
(print " -r Enter the repl after running all scripts")
(os.exit 0)
1)
"v" (fn [] (print VERSION) (os.exit 0) 1)
"s" (fn [] (:= *raw-stdin* true) (:= *should-repl* true) 1)
"r" (fn [] (:= *should-repl* true) 1)
"e" (fn [i]
(:= *no-file* false)
(eval (get args (+ i 1)))
2)
})
(defn- dohandler [n i]
(def h (get handlers n))
@ -33,13 +33,13 @@
(var i 1)
(def lenargs (length args))
(while (< i lenargs)
(def arg (get args i))
(if (= "-" (string.slice arg 0 1))
(+= i (dohandler (string.slice arg 1 2) i))
(do
(:= *no-file* false)
(import arg)
(++ i))))
(def arg (get args i))
(if (= "-" (string.slice arg 0 1))
(+= i (dohandler (string.slice arg 1 2) i))
(do
(:= *no-file* false)
(import arg)
(++ i))))
(when (or *should-repl* *no-file*)
(if *raw-stdin*
@ -47,5 +47,7 @@
(do
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
(repl (fn [buf p]
(def prompt (string (parser.state p) "> "))
(getline prompt buf)))))))
(def prompt (string (parser.state p) "> "))
(getline prompt buf))))))
)

View File

@ -381,10 +381,10 @@ static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
if (state->flags & PFLAG_INSTRING) {
/* We are inside the long string */
if (c == '\\') {
if (c == '`') {
state->flags |= PFLAG_END_CANDIDATE;
state->flags &= ~PFLAG_INSTRING;
state->qcount = 0; /* Use qcount to keep track of number of '=' seen */
state->qcount = 1; /* Use qcount to keep track of number of '=' seen */
return 1;
}
dst_v_push(p->buf, c);
@ -392,17 +392,17 @@ static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
} else if (state->flags & PFLAG_END_CANDIDATE) {
int i;
/* We are checking a potential end of the string */
if (c == '\\' && state->qcount == state->argn) {
return stringend(p, state);
if (c != '`' && state->qcount == state->argn) {
stringend(p, state);
return 0;
}
if (c == '=' && state->qcount < state->argn) {
if (c == '`' && state->qcount < state->argn) {
state->qcount++;
return 1;
}
/* Failed end candidate */
dst_v_push(p->buf, '\\');
for (i = 0; i < state->qcount; i++) {
dst_v_push(p->buf, '=');
dst_v_push(p->buf, '`');
}
dst_v_push(p->buf, c);
state->qcount = 0;
@ -411,17 +411,12 @@ static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
return 1;
} else {
/* We are at beginning of string */
switch (c) {
default:
p->error = "unexpected character in long string delimiter";
return 1;
case '\\':
state->flags |= PFLAG_INSTRING;
return 1;
case '=':
state->argn++;
return 1;
state->argn++;
if (c != '`') {
state->flags |= PFLAG_INSTRING;
dst_v_push(p->buf, c);
}
return 1;
}
}
@ -435,7 +430,7 @@ static int ampersand(DstParser *p, DstParseState *state, uint8_t c) {
case '"':
pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
return 1;
case '\\':
case '`':
pushstate(p, longstring, PFLAG_BUFFER | PFLAG_LONGSTRING);
return 1;
case '[':
@ -474,7 +469,7 @@ static int root(DstParser *p, DstParseState *state, uint8_t c) {
case '@':
pushstate(p, ampersand, 0);
return 1;
case '\\':
case '`':
pushstate(p, longstring, PFLAG_LONGSTRING);
return 1;
case ')':
@ -769,7 +764,7 @@ static int cfun_node(DstArgs args) {
}
static const DstReg cfuns[] = {
{"parser.make", cfun_parser},
{"parser.new", cfun_parser},
{"parser.produce", cfun_produce},
{"parser.consume", cfun_consume},
{"parser.byte", cfun_byte},

View File

@ -36,7 +36,7 @@
(assert (>= 6.0 5.0 4.0 4.0 3.0 2.0 1.0) "greater than or equal to reals")
(assert (order< nil false true
(fiber (fn [x] x))
(fiber.new (fn [x] x))
1 1.0 "hi"
(quote hello)
(array 1 2 3)
@ -145,21 +145,21 @@
# Fiber tests
(def afiber (fiber (fn [x]
(def afiber (fiber.new (fn [x]
(error (string "hello, " x)))))
(def afiber-result (resume afiber "world!"))
(def afiber-result (fiber.resume afiber "world!"))
(assert (= afiber-result "hello, world!") "fiber error result")
(assert (= (fiber.status afiber) :error) "fiber error status")
# yield tests
(def t (fiber (fn [] (yield 1) (yield 2) 3)))
(def t (fiber.new (fn [] (fiber.yield 1) (fiber.yield 2) 3)))
(assert (= 1 (resume t)) "initial transfer to new fiber")
(assert (= 2 (resume t)) "second transfer to fiber")
(assert (= 3 (resume t)) "return from fiber")
(assert (= 1 (fiber.resume t)) "initial transfer to new fiber")
(assert (= 2 (fiber.resume t)) "second transfer to fiber")
(assert (= 3 (fiber.resume t)) "return from fiber")
(assert (= (fiber.status t) :dead) "finished fiber is dead")
# Var arg tests

View File

@ -62,15 +62,15 @@
(table.setproto childtab roottab)
(assert (= 123 (get roottab :parentprop)), "table get 1")
(assert (= 123 (get childtab :parentprop)), "table get proto")
(assert (= nil (get roottab :childprop)), "table get 2")
(assert (= 456 (get childtab :childprop)), "proto no effect")
(assert (= 123 (get roottab :parentprop)) "table get 1")
(assert (= 123 (get childtab :parentprop)) "table get proto")
(assert (= nil (get roottab :childprop)) "table get 2")
(assert (= 456 (get childtab :childprop)) "proto no effect")
# Long strings
(assert (= "hello, world" \==\hello, world\==\), "simple long string")
(assert (= "hello, \"world\"" \\hello, "world"\\), "long string with embedded quotes")
(assert (= "hello, \\\\\\ \"world\"" \=\hello, \\\ "world"\=\), "long string with embedded quotes and backslashes")
(assert (= "hello, world" `hello, world`) "simple long string")
(assert (= "hello, \"world\"" `hello, "world"`) "long string with embedded quotes")
(assert (= "hello, \\\\\\ \"world\"" `hello, \\\ "world"`), "long string with embedded quotes and backslashes")
(end-suite)