mirror of
https://github.com/janet-lang/janet
synced 2024-11-17 14:14: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:
parent
f47323c915
commit
932a0324ee
15
doc/intro.md
15
doc/intro.md
@ -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"
|
"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,
|
# 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.
|
# you can use 1 or more backticks (`\``) to delimit a string.
|
||||||
# To close this string, simply repeat the opening sequence (with a matching number of = characters).
|
# To close this string, simply repeat the opening sequence of backticks
|
||||||
\====\
|
``
|
||||||
This is a string.
|
This is a string.
|
||||||
Line 2
|
Line 2
|
||||||
Indented
|
Indented
|
||||||
"We can just type quotes here", no problem.
|
"We can just type quotes here", and backslashes \ no problem.
|
||||||
\====\
|
``
|
||||||
|
|
||||||
# You don't need any = charcters in the delimiters
|
|
||||||
\\
|
|
||||||
This works if two backslashes don't appear in your string.
|
|
||||||
\\
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# Functions
|
# Functions
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Example of dst bytecode assembly
|
# Example of dst bytecode assembly
|
||||||
|
|
||||||
# Fibonacci sequence, implemented with naive recursion.
|
# Fibonacci sequence, implemented with naive recursion.
|
||||||
(def fibasm (asm/asm '{
|
(def fibasm (asm.asm '{
|
||||||
arity 1
|
arity 1
|
||||||
bytecode [
|
bytecode [
|
||||||
(ldi 1 0x2) # $1 = 2
|
(ldi 1 0x2) # $1 = 2
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# sequences, as in clojure. The lazy seq is essentially
|
# sequences, as in clojure. The lazy seq is essentially
|
||||||
# A lazy linked list, where the next value is a function
|
# A lazy linked list, where the next value is a function
|
||||||
# that must be called (realizing it), and the memoized.
|
# 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]
|
(defmacro delay [& forms]
|
||||||
"Lazily evaluate a series of expressions. Returns a function that
|
"Lazily evaluate a series of expressions. Returns a function that
|
||||||
|
@ -908,8 +908,8 @@ int dst_disasm_cfun(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
{"asm/asm", dst_asm_cfun},
|
{"asm.asm", dst_asm_cfun},
|
||||||
{"asm/disasm", dst_disasm_cfun},
|
{"asm.disasm", dst_disasm_cfun},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ evaluates to true."
|
|||||||
(defmacro coro
|
(defmacro coro
|
||||||
"A wrapper for making fibers. Same as (fiber (fn [] ...body))."
|
"A wrapper for making fibers. Same as (fiber (fn [] ...body))."
|
||||||
[& body]
|
[& body]
|
||||||
(tuple fiber (apply tuple 'fn [] body)))
|
(tuple fiber.new (apply tuple 'fn [] body)))
|
||||||
|
|
||||||
(defmacro if-let
|
(defmacro if-let
|
||||||
"Takes the first one or two forms in a vector and if both are true binds
|
"Takes the first one or two forms in a vector and if both are true binds
|
||||||
@ -868,7 +868,7 @@ onvalue."
|
|||||||
(var going true)
|
(var going true)
|
||||||
|
|
||||||
# The parser object
|
# The parser object
|
||||||
(def p (parser.make 1))
|
(def p (parser.new 1))
|
||||||
|
|
||||||
# Fiber stream of characters
|
# Fiber stream of characters
|
||||||
(def chars (coro
|
(def chars (coro
|
||||||
@ -879,18 +879,18 @@ onvalue."
|
|||||||
(chunks buf p)
|
(chunks buf p)
|
||||||
(:= len (length buf))
|
(:= len (length buf))
|
||||||
(for [i 0 len]
|
(for [i 0 len]
|
||||||
(yield (get buf i))))
|
(fiber.yield (get buf i))))
|
||||||
0))
|
0))
|
||||||
|
|
||||||
# Fiber stream of values
|
# Fiber stream of values
|
||||||
(def vals (coro
|
(def vals (coro
|
||||||
(while going
|
(while going
|
||||||
(switch (parser.status p)
|
(switch (parser.status p)
|
||||||
:full (yield (parser.produce p))
|
:full (fiber.yield (parser.produce p))
|
||||||
:error (onerr "parse" (parser.error p))
|
:error (onerr "parse" (parser.error p))
|
||||||
(switch (fiber.status chars)
|
(switch (fiber.status chars)
|
||||||
:new (parser.byte p (resume chars))
|
:new (parser.byte p (fiber.resume chars))
|
||||||
:pending (parser.byte p (resume chars))
|
:pending (parser.byte p (fiber.resume chars))
|
||||||
(:= going false))))
|
(:= going false))))
|
||||||
(when (not= :root (parser.status p))
|
(when (not= :root (parser.status p))
|
||||||
(onerr "parse" "unexpected end of source"))))
|
(onerr "parse" "unexpected end of source"))))
|
||||||
@ -898,23 +898,24 @@ onvalue."
|
|||||||
# Evaluate 1 source form
|
# Evaluate 1 source form
|
||||||
(defn eval1 [source]
|
(defn eval1 [source]
|
||||||
(var good true)
|
(var good true)
|
||||||
(def f (coro
|
(def f (fiber.new (fn []
|
||||||
(def res (compile source env))
|
(def res (compile source env))
|
||||||
(if (= (type res) :function)
|
(if (= (type res) :function)
|
||||||
(res)
|
(res)
|
||||||
(do
|
(do
|
||||||
(:= good false)
|
(:= good false)
|
||||||
(onerr "compile" (get res :error))))))
|
(onerr "compile" (get res :error))))) :de))
|
||||||
(def res (resume f))
|
(def res (fiber.resume f))
|
||||||
(if good
|
(if good
|
||||||
(if (= (fiber.status f) :error)
|
(cond
|
||||||
(onerr "runtime" res f)
|
(= (fiber.status f) :error) (onerr "runtime" res f)
|
||||||
(if going (onvalue res)))))
|
(= (fiber.status f) :debug) (onerr "debug" res f)
|
||||||
|
going (onvalue res))))
|
||||||
|
|
||||||
# Run loop
|
# Run loop
|
||||||
(def oldenv *env*)
|
(def oldenv *env*)
|
||||||
(:= *env* env)
|
(:= *env* env)
|
||||||
(while going (eval1 (resume vals)))
|
(while going (eval1 (fiber.resume vals)))
|
||||||
(:= *env* oldenv)
|
(:= *env* oldenv)
|
||||||
|
|
||||||
env)
|
env)
|
||||||
|
@ -45,7 +45,6 @@ static const DstReg cfuns[] = {
|
|||||||
{"scan-real", dst_core_scanreal},
|
{"scan-real", dst_core_scanreal},
|
||||||
{"tuple", dst_core_tuple},
|
{"tuple", dst_core_tuple},
|
||||||
{"struct", dst_core_struct},
|
{"struct", dst_core_struct},
|
||||||
{"fiber", dst_core_fiber},
|
|
||||||
{"buffer", dst_core_buffer},
|
{"buffer", dst_core_buffer},
|
||||||
{"gensym", dst_core_gensym},
|
{"gensym", dst_core_gensym},
|
||||||
{"get", dst_core_get},
|
{"get", dst_core_get},
|
||||||
@ -65,32 +64,23 @@ DstTable *dst_stl_env() {
|
|||||||
static uint32_t error_asm[] = {
|
static uint32_t error_asm[] = {
|
||||||
DOP_ERROR
|
DOP_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t apply_asm[] = {
|
static uint32_t apply_asm[] = {
|
||||||
DOP_PUSH_ARRAY | (1 << 8),
|
DOP_PUSH_ARRAY | (1 << 8),
|
||||||
DOP_TAILCALL
|
DOP_TAILCALL
|
||||||
};
|
};
|
||||||
|
static uint32_t debug_asm[] = {
|
||||||
static uint32_t yield_asm[] = {
|
DOP_DEBUG,
|
||||||
DOP_YIELD,
|
DOP_RETURN_NIL
|
||||||
DOP_RETURN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t resume_asm[] = {
|
|
||||||
DOP_RESUME | (1 << 24),
|
|
||||||
DOP_RETURN
|
|
||||||
};
|
|
||||||
|
|
||||||
DstTable *env = dst_table(0);
|
DstTable *env = dst_table(0);
|
||||||
Dst ret = dst_wrap_table(env);
|
Dst ret = dst_wrap_table(env);
|
||||||
|
|
||||||
/* Load main functions */
|
/* Load main functions */
|
||||||
dst_env_cfuns(env, cfuns);
|
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, "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, "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));
|
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
|
||||||
|
|
||||||
|
@ -105,6 +105,15 @@ Dst dst_array_peek(DstArray *array) {
|
|||||||
|
|
||||||
/* C Functions */
|
/* 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) {
|
static int cfun_pop(DstArgs args) {
|
||||||
dst_fixarity(args, 1);
|
dst_fixarity(args, 1);
|
||||||
dst_check(args, 0, DST_ARRAY);
|
dst_check(args, 0, DST_ARRAY);
|
||||||
@ -219,6 +228,7 @@ static int cfun_concat(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
|
{"array.new", cfun_new},
|
||||||
{"array.pop", cfun_pop},
|
{"array.pop", cfun_pop},
|
||||||
{"array.peek", cfun_peek},
|
{"array.peek", cfun_peek},
|
||||||
{"array.push", cfun_push},
|
{"array.push", cfun_push},
|
||||||
|
@ -157,6 +157,16 @@ int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* C functions */
|
/* 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) {
|
static int cfun_u8(DstArgs args) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
DstBuffer *buffer;
|
DstBuffer *buffer;
|
||||||
@ -258,6 +268,7 @@ static int cfun_slice(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
|
{"buffer.new", cfun_new},
|
||||||
{"buffer.push-byte", cfun_u8},
|
{"buffer.push-byte", cfun_u8},
|
||||||
{"buffer.push-integer", cfun_int},
|
{"buffer.push-integer", cfun_int},
|
||||||
{"buffer.push-string", cfun_chars},
|
{"buffer.push-string", cfun_chars},
|
||||||
|
@ -202,14 +202,6 @@ int dst_core_struct(DstArgs args) {
|
|||||||
return dst_return(args, dst_wrap_struct(dst_struct_end(st)));
|
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) {
|
int dst_core_gensym(DstArgs args) {
|
||||||
dst_maxarity(args, 1);
|
dst_maxarity(args, 1);
|
||||||
if (args.n == 0) {
|
if (args.n == 0) {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dst/dst.h>
|
#include <dst/dst.h>
|
||||||
|
#include <dst/dstopcodes.h>
|
||||||
#include "fiber.h"
|
#include "fiber.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
|
||||||
@ -257,6 +258,35 @@ void dst_fiber_popframe(DstFiber *fiber) {
|
|||||||
|
|
||||||
/* CFuns */
|
/* 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) {
|
static int cfun_status(DstArgs args) {
|
||||||
const char *status = "";
|
const char *status = "";
|
||||||
dst_fixarity(args, 1);
|
dst_fixarity(args, 1);
|
||||||
@ -338,6 +368,7 @@ static int cfun_stack(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
|
{"fiber.new", cfun_new},
|
||||||
{"fiber.status", cfun_status},
|
{"fiber.status", cfun_status},
|
||||||
{"fiber.stack", cfun_stack},
|
{"fiber.stack", cfun_stack},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
@ -345,7 +376,21 @@ static const DstReg cfuns[] = {
|
|||||||
|
|
||||||
/* Module entry point */
|
/* Module entry point */
|
||||||
int dst_lib_fiber(DstArgs args) {
|
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);
|
DstTable *env = dst_env_arg(args);
|
||||||
dst_env_cfuns(env, cfuns);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +235,17 @@ void dst_table_merge_struct(DstTable *table, const DstKV *other) {
|
|||||||
dst_table_mergekv(table, other, dst_struct_capacity(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) {
|
static int cfun_getproto(DstArgs args) {
|
||||||
DstTable *t;
|
DstTable *t;
|
||||||
dst_fixarity(args, 1);
|
dst_fixarity(args, 1);
|
||||||
@ -269,6 +280,7 @@ static int cfun_rawget(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
|
{"table.new", cfun_new},
|
||||||
{"table.to-struct", cfun_tostruct},
|
{"table.to-struct", cfun_tostruct},
|
||||||
{"table.getproto", cfun_getproto},
|
{"table.getproto", cfun_getproto},
|
||||||
{"table.setproto", cfun_setproto},
|
{"table.setproto", cfun_setproto},
|
||||||
|
@ -255,6 +255,7 @@ int32_t dst_length(Dst x) {
|
|||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
case DST_STRING:
|
case DST_STRING:
|
||||||
|
case DST_SYMBOL:
|
||||||
return dst_string_length(dst_unwrap_string(x));
|
return dst_string_length(dst_unwrap_string(x));
|
||||||
case DST_ARRAY:
|
case DST_ARRAY:
|
||||||
return dst_unwrap_array(x)->count;
|
return dst_unwrap_array(x)->count;
|
||||||
@ -275,6 +276,7 @@ Dst dst_getindex(Dst ds, int32_t index) {
|
|||||||
default:
|
default:
|
||||||
return dst_wrap_nil();
|
return dst_wrap_nil();
|
||||||
case DST_STRING:
|
case DST_STRING:
|
||||||
|
case DST_SYMBOL:
|
||||||
if (index >= dst_string_length(dst_unwrap_string(ds))) return dst_wrap_nil();
|
if (index >= dst_string_length(dst_unwrap_string(ds))) return dst_wrap_nil();
|
||||||
return dst_wrap_integer(dst_unwrap_string(ds)[index]);
|
return dst_wrap_integer(dst_unwrap_string(ds)[index]);
|
||||||
case DST_ARRAY:
|
case DST_ARRAY:
|
||||||
|
@ -750,7 +750,6 @@ static void *op_lookup[255] = {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fiber->child = NULL;
|
fiber->child = NULL;
|
||||||
if (nextfiber->flags & DST_FIBER_MASK_RETURN) goto vm_return_root;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stack[oparg(1, 0xFF)] = retreg;
|
stack[oparg(1, 0xFF)] = retreg;
|
||||||
@ -844,6 +843,7 @@ static void *op_lookup[255] = {
|
|||||||
vm_debug:
|
vm_debug:
|
||||||
{
|
{
|
||||||
fiber->status = DST_FIBER_DEBUG;
|
fiber->status = DST_FIBER_DEBUG;
|
||||||
|
retreg = dst_wrap_nil();
|
||||||
goto vm_exit;
|
goto vm_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,6 @@ int dst_core_tuple(DstArgs args);
|
|||||||
int dst_core_array(DstArgs args);
|
int dst_core_array(DstArgs args);
|
||||||
int dst_core_table(DstArgs args);
|
int dst_core_table(DstArgs args);
|
||||||
int dst_core_struct(DstArgs args);
|
int dst_core_struct(DstArgs args);
|
||||||
int dst_core_fiber(DstArgs args);
|
|
||||||
int dst_core_buffer(DstArgs args);
|
int dst_core_buffer(DstArgs args);
|
||||||
int dst_core_gensym(DstArgs args);
|
int dst_core_gensym(DstArgs args);
|
||||||
int dst_core_length(DstArgs args);
|
int dst_core_length(DstArgs args);
|
||||||
|
@ -338,12 +338,12 @@ struct DstArgs {
|
|||||||
Dst *ret;
|
Dst *ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Fiber signal masks */
|
/* Fiber flags */
|
||||||
#define DST_FIBER_MASK_RETURN 1
|
#define DST_FIBER_FLAG_NEW (1 << 31)
|
||||||
#define DST_FIBER_MASK_ERROR 2
|
|
||||||
#define DST_FIBER_MASK_DEBUG 4
|
|
||||||
|
|
||||||
#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
|
/* A lightweight green thread in dst. Does not correspond to
|
||||||
* operating system threads. */
|
* operating system threads. */
|
||||||
|
@ -6,24 +6,24 @@
|
|||||||
|
|
||||||
# Flag handlers
|
# Flag handlers
|
||||||
(def handlers :private {
|
(def handlers :private {
|
||||||
"h" (fn []
|
"h" (fn []
|
||||||
(print "usage: " (get args 0) " [options] scripts...")
|
(print "usage: " (get args 0) " [options] scripts...")
|
||||||
(print "Options are:")
|
(print "Options are:")
|
||||||
(print " -h Show this help")
|
(print " -h Show this help")
|
||||||
(print " -v Print the version string")
|
(print " -v Print the version string")
|
||||||
(print " -s Use raw stdin instead of getline like functionality")
|
(print " -s Use raw stdin instead of getline like functionality")
|
||||||
(print " -e Execute a string of dst")
|
(print " -e Execute a string of dst")
|
||||||
(print " -r Enter the repl after running all scripts")
|
(print " -r Enter the repl after running all scripts")
|
||||||
(os.exit 0)
|
(os.exit 0)
|
||||||
1)
|
1)
|
||||||
"v" (fn [] (print VERSION) (os.exit 0) 1)
|
"v" (fn [] (print VERSION) (os.exit 0) 1)
|
||||||
"s" (fn [] (:= *raw-stdin* true) (:= *should-repl* true) 1)
|
"s" (fn [] (:= *raw-stdin* true) (:= *should-repl* true) 1)
|
||||||
"r" (fn [] (:= *should-repl* true) 1)
|
"r" (fn [] (:= *should-repl* true) 1)
|
||||||
"e" (fn [i]
|
"e" (fn [i]
|
||||||
(:= *no-file* false)
|
(:= *no-file* false)
|
||||||
(eval (get args (+ i 1)))
|
(eval (get args (+ i 1)))
|
||||||
2)
|
2)
|
||||||
})
|
})
|
||||||
|
|
||||||
(defn- dohandler [n i]
|
(defn- dohandler [n i]
|
||||||
(def h (get handlers n))
|
(def h (get handlers n))
|
||||||
@ -33,13 +33,13 @@
|
|||||||
(var i 1)
|
(var i 1)
|
||||||
(def lenargs (length args))
|
(def lenargs (length args))
|
||||||
(while (< i lenargs)
|
(while (< i lenargs)
|
||||||
(def arg (get args i))
|
(def arg (get args i))
|
||||||
(if (= "-" (string.slice arg 0 1))
|
(if (= "-" (string.slice arg 0 1))
|
||||||
(+= i (dohandler (string.slice arg 1 2) i))
|
(+= i (dohandler (string.slice arg 1 2) i))
|
||||||
(do
|
(do
|
||||||
(:= *no-file* false)
|
(:= *no-file* false)
|
||||||
(import arg)
|
(import arg)
|
||||||
(++ i))))
|
(++ i))))
|
||||||
|
|
||||||
(when (or *should-repl* *no-file*)
|
(when (or *should-repl* *no-file*)
|
||||||
(if *raw-stdin*
|
(if *raw-stdin*
|
||||||
@ -47,5 +47,7 @@
|
|||||||
(do
|
(do
|
||||||
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
|
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
|
||||||
(repl (fn [buf p]
|
(repl (fn [buf p]
|
||||||
(def prompt (string (parser.state p) "> "))
|
(def prompt (string (parser.state p) "> "))
|
||||||
(getline prompt buf)))))))
|
(getline prompt buf))))))
|
||||||
|
|
||||||
|
)
|
||||||
|
@ -381,10 +381,10 @@ static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
|
|||||||
static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
|
static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
|
||||||
if (state->flags & PFLAG_INSTRING) {
|
if (state->flags & PFLAG_INSTRING) {
|
||||||
/* We are inside the long string */
|
/* We are inside the long string */
|
||||||
if (c == '\\') {
|
if (c == '`') {
|
||||||
state->flags |= PFLAG_END_CANDIDATE;
|
state->flags |= PFLAG_END_CANDIDATE;
|
||||||
state->flags &= ~PFLAG_INSTRING;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
dst_v_push(p->buf, c);
|
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) {
|
} else if (state->flags & PFLAG_END_CANDIDATE) {
|
||||||
int i;
|
int i;
|
||||||
/* We are checking a potential end of the string */
|
/* We are checking a potential end of the string */
|
||||||
if (c == '\\' && state->qcount == state->argn) {
|
if (c != '`' && state->qcount == state->argn) {
|
||||||
return stringend(p, state);
|
stringend(p, state);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (c == '=' && state->qcount < state->argn) {
|
if (c == '`' && state->qcount < state->argn) {
|
||||||
state->qcount++;
|
state->qcount++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Failed end candidate */
|
/* Failed end candidate */
|
||||||
dst_v_push(p->buf, '\\');
|
|
||||||
for (i = 0; i < state->qcount; i++) {
|
for (i = 0; i < state->qcount; i++) {
|
||||||
dst_v_push(p->buf, '=');
|
dst_v_push(p->buf, '`');
|
||||||
}
|
}
|
||||||
dst_v_push(p->buf, c);
|
dst_v_push(p->buf, c);
|
||||||
state->qcount = 0;
|
state->qcount = 0;
|
||||||
@ -411,17 +411,12 @@ static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
|
|||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
/* We are at beginning of string */
|
/* We are at beginning of string */
|
||||||
switch (c) {
|
state->argn++;
|
||||||
default:
|
if (c != '`') {
|
||||||
p->error = "unexpected character in long string delimiter";
|
state->flags |= PFLAG_INSTRING;
|
||||||
return 1;
|
dst_v_push(p->buf, c);
|
||||||
case '\\':
|
|
||||||
state->flags |= PFLAG_INSTRING;
|
|
||||||
return 1;
|
|
||||||
case '=':
|
|
||||||
state->argn++;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +430,7 @@ static int ampersand(DstParser *p, DstParseState *state, uint8_t c) {
|
|||||||
case '"':
|
case '"':
|
||||||
pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
|
pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
|
||||||
return 1;
|
return 1;
|
||||||
case '\\':
|
case '`':
|
||||||
pushstate(p, longstring, PFLAG_BUFFER | PFLAG_LONGSTRING);
|
pushstate(p, longstring, PFLAG_BUFFER | PFLAG_LONGSTRING);
|
||||||
return 1;
|
return 1;
|
||||||
case '[':
|
case '[':
|
||||||
@ -474,7 +469,7 @@ static int root(DstParser *p, DstParseState *state, uint8_t c) {
|
|||||||
case '@':
|
case '@':
|
||||||
pushstate(p, ampersand, 0);
|
pushstate(p, ampersand, 0);
|
||||||
return 1;
|
return 1;
|
||||||
case '\\':
|
case '`':
|
||||||
pushstate(p, longstring, PFLAG_LONGSTRING);
|
pushstate(p, longstring, PFLAG_LONGSTRING);
|
||||||
return 1;
|
return 1;
|
||||||
case ')':
|
case ')':
|
||||||
@ -769,7 +764,7 @@ static int cfun_node(DstArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
{"parser.make", cfun_parser},
|
{"parser.new", cfun_parser},
|
||||||
{"parser.produce", cfun_produce},
|
{"parser.produce", cfun_produce},
|
||||||
{"parser.consume", cfun_consume},
|
{"parser.consume", cfun_consume},
|
||||||
{"parser.byte", cfun_byte},
|
{"parser.byte", cfun_byte},
|
||||||
|
@ -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 (>= 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
|
(assert (order< nil false true
|
||||||
(fiber (fn [x] x))
|
(fiber.new (fn [x] x))
|
||||||
1 1.0 "hi"
|
1 1.0 "hi"
|
||||||
(quote hello)
|
(quote hello)
|
||||||
(array 1 2 3)
|
(array 1 2 3)
|
||||||
@ -145,21 +145,21 @@
|
|||||||
|
|
||||||
# Fiber tests
|
# Fiber tests
|
||||||
|
|
||||||
(def afiber (fiber (fn [x]
|
(def afiber (fiber.new (fn [x]
|
||||||
(error (string "hello, " 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 (= afiber-result "hello, world!") "fiber error result")
|
||||||
(assert (= (fiber.status afiber) :error) "fiber error status")
|
(assert (= (fiber.status afiber) :error) "fiber error status")
|
||||||
|
|
||||||
# yield tests
|
# 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 (= 1 (fiber.resume t)) "initial transfer to new fiber")
|
||||||
(assert (= 2 (resume t)) "second transfer to fiber")
|
(assert (= 2 (fiber.resume t)) "second transfer to fiber")
|
||||||
(assert (= 3 (resume t)) "return from fiber")
|
(assert (= 3 (fiber.resume t)) "return from fiber")
|
||||||
(assert (= (fiber.status t) :dead) "finished fiber is dead")
|
(assert (= (fiber.status t) :dead) "finished fiber is dead")
|
||||||
|
|
||||||
# Var arg tests
|
# Var arg tests
|
||||||
|
@ -62,15 +62,15 @@
|
|||||||
|
|
||||||
(table.setproto childtab roottab)
|
(table.setproto childtab roottab)
|
||||||
|
|
||||||
(assert (= 123 (get roottab :parentprop)), "table get 1")
|
(assert (= 123 (get roottab :parentprop)) "table get 1")
|
||||||
(assert (= 123 (get childtab :parentprop)), "table get proto")
|
(assert (= 123 (get childtab :parentprop)) "table get proto")
|
||||||
(assert (= nil (get roottab :childprop)), "table get 2")
|
(assert (= nil (get roottab :childprop)) "table get 2")
|
||||||
(assert (= 456 (get childtab :childprop)), "proto no effect")
|
(assert (= 456 (get childtab :childprop)) "proto no effect")
|
||||||
|
|
||||||
# Long strings
|
# Long strings
|
||||||
|
|
||||||
(assert (= "hello, world" \==\hello, world\==\), "simple long string")
|
(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")
|
||||||
(assert (= "hello, \\\\\\ \"world\"" \=\hello, \\\ "world"\=\), "long string with embedded quotes and backslashes")
|
(assert (= "hello, \\\\\\ \"world\"" `hello, \\\ "world"`), "long string with embedded quotes and backslashes")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
Loading…
Reference in New Issue
Block a user