1
0
mirror of https://github.com/janet-lang/janet synced 2024-09-29 23:40:40 +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" "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

View File

@ -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

View File

@ -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

View File

@ -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}
}; };

View File

@ -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)

View File

@ -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));

View File

@ -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},

View File

@ -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},

View File

@ -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) {

View File

@ -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;
} }

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)); 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},

View File

@ -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:

View File

@ -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;
} }

View File

@ -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);

View File

@ -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. */

View File

@ -48,4 +48,6 @@
(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))))))
)

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) { 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) {
default:
p->error = "unexpected character in long string delimiter";
return 1;
case '\\':
state->flags |= PFLAG_INSTRING;
return 1;
case '=':
state->argn++; state->argn++;
return 1; 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 '"': 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},

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 (>= 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

View File

@ -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)