├── ATTIC ├── 0.c-almost-good ├── 0.c-before-desymbolizer ├── 0.c-first └── chkpt1.tgz ├── LICENSE ├── README.md ├── accessors.h ├── accessors.js ├── c ├── cast.h ├── cast.js ├── common.js ├── d ├── def.h ├── doc ├── groceries.xxl ├── implementation.md ├── jsonencode.png ├── lang.xxl ├── logo.png ├── sect_files.xxl ├── sect_logic.xxl ├── sect_mbox.xxl └── sect_posts.xxl ├── examples ├── ackermann.xxl ├── charclass.xxl ├── docs │ ├── README.md │ ├── hdr.png │ ├── layout.xxl │ └── server.xxl ├── factorial.xxl ├── ffi.xxl ├── fibonacci.xxl ├── groceries-0.xxl ├── json.xxl ├── to-c.xxl ├── trees.xxl ├── web-ctr.xxl └── web-static-files.xxl ├── net.c ├── proto.h ├── repl.c ├── repr.h ├── repr.js ├── rootctx.h ├── stdlib.c ├── test-match.h ├── tests ├── lambda-in-comment.xxl ├── returns-of-loads.xxl ├── sharedlib-test.c ├── sharedlib-test.sh ├── simple-func.xxl ├── string-brace.xxl ├── test-basics.h ├── test-ctx.h ├── test-eval.h ├── test-logic.h ├── test-nest.h ├── test-semantics.h ├── test-y-in-lambda.xxl └── undefined-x.xxl ├── tools └── syntax │ ├── vim-build.xxl │ ├── vim-syntax.vim │ └── vim-template.vim ├── txpost ├── CONFIG-default.xxl ├── app.xxl ├── start.sh └── test.sh ├── types.h ├── types.js ├── util ├── memusg ├── ribosome.js └── vg ├── vary.h ├── vary.js ├── verbs.c ├── workbench ├── app.xxl ├── css.xxl ├── pub │ ├── app.js │ ├── bg.jpg │ ├── bgxxl.jpg │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ └── logo.png └── ui.xxl ├── x └── xxl.c /ATTIC/chkpt1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/ATTIC/chkpt1.tgz -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Thomas Lackner 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the organization nor the names of its contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | -------------------------------------------------------------------------------- /accessors.js: -------------------------------------------------------------------------------- 1 | // TODO rename accessor functions to something pretty 2 | var max=0; 3 | var lib=require('./common.js'); 4 | console.log(lib.prelude); 5 | lib.each(lib.types, function(t) { 6 | if(t[8]==false) { 7 | var tmpls = [ 8 | '', 9 | '/* accessors for simple type #{{0}} or {{1}} ({{2}}) implemented as {{3}} */', 10 | '#define MAX_{{1}} {{7}}', 11 | '#define CTYPE_{{1}} {{3}}', 12 | '#define T_{{1}} {{0}}', 13 | '#define IS_{{1}}(v) ( (v)->t=={{0}} )', 14 | '#define AS_{{1}}(v,n) ({ \\\n\tASSERT(IS_{{1}}(v)==1, "AS_{{1}}: type not {{1}}");\\\n\t{{3}} __x=EL(v,{{3}},n); __x; })', 15 | '/* create a single-item {{2}} containing C value x (a {{3}}) */', 16 | 'static inline VP x{{1}}({{3}} x) { VP a; a=xalloc({{0}},1); EL(a,{{3}},0)=x; a->n=1; return a; }', 17 | '/* create an empty {{2}} */', 18 | 'static inline VP x{{1}}0() { VP a=xalloc({{0}},1); return a; }', 19 | '/* return an empty {{2}} of size sz */', 20 | 'static inline VP x{{1}}sz(int sz) { VP a=xalloc({{0}},sz); return a; }', 21 | '/* append C value y (a {{3}}) to x */', 22 | 'static inline VP x{{1}}a(VP x, {{3}} y) { x=xrealloc(x,x->n++); EL(x,{{3}},x->n-1)=y; return x; }', 23 | '/* create a {{2}} using C variable arguments - VP r = x{{1}}n(2, {{3}}_a, {{3}}_b) */', 24 | 'static inline VP x{{1}}n(int nargs,...) { ', 25 | '\tVP a; va_list args; int i; {{4}} x;', 26 | '\ta=xalloc(T_{{1}},nargs); a->n=nargs;', 27 | '\tva_start(args,nargs);', 28 | '\tfor(i=0;in+nargs); va_start(args,nargs);', 35 | '\tfor(i=0;in)+i)=x;', 38 | '\t}', 39 | '\ta->n+=nargs;', 40 | '\treturn a;', 41 | '}' 42 | ]; 43 | lib.each(tmpls,function(tmpl) { 44 | console.log(lib.exhaust(lib.projr(lib.repl,t),tmpl)); 45 | }); 46 | if(t[0]>max) max=t[0]; 47 | } 48 | }); 49 | console.log("\n"); 50 | lib.each(lib.types, function(t) { 51 | if(t[8]==true) { 52 | var tmpls = [ 53 | '', 54 | '/* accessors for container type #{{0}} or {{1}} ({{2}}) implemented as {{3}} */', 55 | '#define MAX_{{1}} {{7}}', 56 | '#define CTYPE_{{1}} {{3}}', 57 | '#define T_{{1}} {{0}}', 58 | '#define IS_{{1}}(v) ( (v)->t=={{0}} )', 59 | '#define AS_{{1}}(v,n) ({ \\\n\tASSERT(IS_{{1}}(v)==1, "AS_{{1}}: type not {{1}}");\\\n\t{{3}} __x=EL(v,{{3}},n); __x; })', 60 | '/* create a {{2}} containing a {{3}} */', 61 | 'static inline VP x{{1}}({{3}} x) { VP a; a=xalloc({{0}},1); EL(a,{{3}},0)=xref(x); a->n=1; return a; }', 62 | '/* create an empty {{2}} */', 63 | 'static inline VP x{{1}}0() { VP a=xalloc({{0}},1); return a; }', 64 | '/* create an empty but presized {{2}} of length sz */', 65 | 'static inline VP x{{1}}sz(int sz) { VP a=xalloc({{0}},sz); return a; }', 66 | '/* append {{3}} x to {{2}} a */', 67 | 'static inline VP x{{1}}a(VP a, {{3}} x) { a=xrealloc(a,a->n++); EL(a,{{3}},a->n-1)=xref(x); return a; }', 68 | '/* create a {{2}} from var args */', 69 | 'static inline VP x{{1}}n(int nargs,...) {', 70 | '\tVP a; va_list args; int i; {{4}} x;', 71 | '\ta=xalloc({{0}},nargs); a->n=nargs; va_start(args,nargs);', 72 | '\tfor(i=0;in+nargs); va_start(args,nargs);', 79 | '\tfor(i=0;in)+i)=xref(x);', 82 | '\t}', 83 | '\ta->n+=nargs;', 84 | '\treturn a;', 85 | '}' 86 | ]; 87 | lib.each(tmpls,function(tmpl) { 88 | console.log(lib.exhaust(lib.projr(lib.repl,t),tmpl)); 89 | }); 90 | if(t[0]>max) max=t[0]; 91 | } 92 | }); 93 | console.log('\n\nstatic int MAX_TYPE = '+max+';\n\n'); 94 | -------------------------------------------------------------------------------- /c: -------------------------------------------------------------------------------- 1 | BUILDH="yes" 2 | CC="gcc" 3 | NODE="node" # often 'nodejs' 4 | ARCH="-m64" 5 | LIBS="-pthread -ldl " 6 | DEBUG="-pg" 7 | DEBUG="-DDEBUG -g -pg -ggdb3" # comment out for silence 8 | OPT="" 9 | # OPT="-O3" 10 | DEFS="-DTHREAD $DEBUG $OPT" 11 | WARN="-Wall -Wno-format-extra-args -Wno-unused-function -Wno-unused-value -Wno-char-subscripts" 12 | WARN="$WARN -Wno-unused-variable -Wno-unused-but-set-variable -Wno-format" 13 | 14 | # decide what libraries go into your XXL build. 15 | # uncomment lines for things you want, or comment out things you don't. 16 | LIBRARIES="" 17 | LIBRARIES="OCTA ${LIBRARIES}" # 128bit type support (octaword) 18 | LIBRARIES="STDLIBFILE ${LIBRARIES}" # simple posixish file operations 19 | LIBRARIES="STDLIBGLOB ${LIBRARIES}" # files matching a pattern 20 | LIBRARIES="STDLIBMBOX ${LIBRARIES}" # mailboxes 21 | LIBRARIES="STDLIBNET ${LIBRARIES}" # networking 22 | LIBRARIES="STDLIBSHAREDLIB ${LIBRARIES}" # shared libraries 23 | LIBRARIES="STDLIBSHELL ${LIBRARIES}" # shell command execution 24 | LIBRARIES="STDLIBXD ${LIBRARIES}" # binary file representation 25 | 26 | echo including libraries: $LIBRARIES 27 | 28 | # command to use to run it - put testing args to binary for execution here 29 | RUN="./xxl $*" 30 | 31 | errcho() { echo "$@" 1>&2; } 32 | 33 | if [ -x /usr/bin/clang ]; then 34 | errcho using clang 35 | CC="/usr/bin/clang" 36 | ARCH="" 37 | DEFS="$DEFS -fsanitize=address -fno-omit-frame-pointer -DTHREAD_NO_TIMEDLOCK " 38 | # add Mac-specific definitions here 39 | fi 40 | 41 | if [ -x /bin/x86_64-w64-mingw32-gcc-4.9.2.exe ]; then 42 | errcho using mingw64 43 | CC="/bin/x86_64-w64-mingw32-gcc-4.9.2.exe" 44 | fi 45 | 46 | if [ -x /bin/x86_64-pc-cygwin-gcc.exe ]; then 47 | errcho using cygwin 48 | CC="/bin/x86_64-pc-cygwin-gcc.exe" 49 | DEFS="$DEFS -DTHREAD_NO_TIMEDLOCK" 50 | fi 51 | 52 | if (uname -a | grep "edison" >/dev/null) then 53 | errcho using intel edison 32bit mode 54 | ARCH="" 55 | DEBUG="" 56 | DEFS="-DTHREAD -O2 " # NB. DEFS is already defined by now, so we have to reset it 57 | LIBRARIES="STDLIBFILE STDLIBGLOB STDLIBMBOX STDLIBNET STDLIBSHAREDLIB STDLIBSHELL STDLIBXD" 58 | fi 59 | 60 | if [ -f /etc/os-release ]; then 61 | if grep "Ubuntu" /etc/os-release >/dev/null; then 62 | errcho using ubuntu -Wl,--no-as-needed 63 | LIBS="-Wl,--no-as-needed $LIBS" 64 | fi 65 | fi 66 | 67 | if which rlwrap >/dev/null; then 68 | errcho using rlwrap 69 | RUN="rlwrap $RUN" 70 | fi 71 | 72 | LIBDEFS=$(echo $LIBRARIES | sed -e 's/ / -D/g') 73 | LIBDEFS="-D${LIBDEFS}" 74 | SRC=`pwd` 75 | COMPILE="$CC $DEFS $WARN $LIBS $ARCH $LIBDEFS " 76 | COMPILEOBJ="$COMPILE -c " 77 | COMPILESHARED="$COMPILE -fPIC -shared " 78 | BUILDOBJ="$COMPILE -o " 79 | BUILDSHARED="$COMPILE -fPIC -shared -o " 80 | 81 | if [ "x$BUILDH" = "xyes" ]; then 82 | if hash $NODE 2>/dev/null; then 83 | errcho "rebuilding .h files" 84 | $NODE accessors.js $LIBDEFS > accessors.h && \ 85 | $NODE vary.js $LIBDEFS > vary.h && \ 86 | $NODE cast.js $LIBDEFS > cast.h && \ 87 | $NODE types.js $LIBDEFS > types.h && \ 88 | $NODE repr.js $LIBDEFS > repr.h 89 | else 90 | errcho "can't find node; skipping build" 91 | fi 92 | fi 93 | 94 | echo "" > compile.h 95 | echo "#define XXL_SRC \"$SRC/\"" >> compile.h 96 | echo "#define XXL_COMPILEOBJ \"$COMPILEOBJ\"" >> compile.h 97 | echo "#define XXL_COMPILESHARED \"$COMPILESHARED\"" >> compile.h 98 | echo "#define XXL_BUILDOBJ \"$BUILDOBJ\"" >> compile.h 99 | echo "#define XXL_BUILDSHARED \"$COMPILESHARED\"" >> compile.h 100 | 101 | $COMPILEOBJ \ 102 | xxl.c 2>&1 \ 103 | && \ 104 | $COMPILEOBJ \ 105 | repl.c 2>&1 \ 106 | && \ 107 | $COMPILEOBJ \ 108 | net.c 2>&1 \ 109 | && \ 110 | $COMPILEOBJ \ 111 | stdlib.c 2>&1 \ 112 | && \ 113 | $COMPILEOBJ \ 114 | verbs.c 2>&1 \ 115 | && \ 116 | $BUILDOBJ xxl \ 117 | xxl.o repl.o net.o stdlib.o verbs.o 2>&1 \ 118 | && \ 119 | $RUN 120 | 121 | 122 | -------------------------------------------------------------------------------- /cast.h: -------------------------------------------------------------------------------- 1 | // Autogenerated file; see corresponding .js 2 | 3 | int taglist=Ti(list); 4 | int tagtag=Ti(tag); 5 | int tagchar=Ti(char); 6 | int tagbyte=Ti(byte); 7 | int tagint=Ti(int); 8 | int taglong=Ti(long); 9 | int tagocta=Ti(octa); 10 | int tagfloat=Ti(float); 11 | int tagdict=Ti(dict); 12 | int tagtable=Ti(table); 13 | int tagf1=Ti(f1); 14 | int tagf2=Ti(f2); 15 | int tagproj=Ti(proj); 16 | int tagctx=Ti(ctx); 17 | if(x->t==1&&(typenum==1||typetag==tagtag)) { // tag -> tag 18 | tag_t from;tag_t to; res=xalloc(1,x->n); 19 | FOR(0,x->n,{from=AS_t(x,_i); 20 | to=from; 21 | appendbuf(res,(buf_t)&to,1); }); } 22 | 23 | if(x->t==1&&(typenum==2||typetag==tagchar)) { // tag -> char 24 | tag_t from;char to; res=xalloc(2,x->n); 25 | FOR(0,x->n,{from=AS_t(x,_i); 26 | to=from; 27 | appendbuf(res,(buf_t)&to,1); }); } 28 | 29 | if(x->t==1&&(typenum==3||typetag==tagbyte)) { // tag -> byte 30 | tag_t from;int8_t to; res=xalloc(3,x->n); 31 | FOR(0,x->n,{from=AS_t(x,_i); 32 | to=from; 33 | appendbuf(res,(buf_t)&to,1); }); } 34 | 35 | if(x->t==1&&(typenum==4||typetag==tagint)) { // tag -> int 36 | tag_t from;int to; res=xalloc(4,x->n); 37 | FOR(0,x->n,{from=AS_t(x,_i); 38 | to=from; 39 | appendbuf(res,(buf_t)&to,1); }); } 40 | 41 | if(x->t==1&&(typenum==5||typetag==taglong)) { // tag -> long 42 | tag_t from;__int64_t to; res=xalloc(5,x->n); 43 | FOR(0,x->n,{from=AS_t(x,_i); 44 | to=from; 45 | appendbuf(res,(buf_t)&to,1); }); } 46 | 47 | if(x->t==1&&(typenum==6||typetag==tagocta)) { // tag -> octa 48 | tag_t from;__int128_t to; res=xalloc(6,x->n); 49 | FOR(0,x->n,{from=AS_t(x,_i); 50 | to=from; 51 | appendbuf(res,(buf_t)&to,1); }); } 52 | 53 | if(x->t==1&&(typenum==7||typetag==tagfloat)) { // tag -> float 54 | tag_t from;double to; res=xalloc(7,x->n); 55 | FOR(0,x->n,{from=AS_t(x,_i); 56 | to=from; 57 | appendbuf(res,(buf_t)&to,1); }); } 58 | 59 | if(x->t==2&&(typenum==1||typetag==tagtag)) { // char -> tag 60 | char from;tag_t to; res=xalloc(1,x->n); 61 | FOR(0,x->n,{from=AS_c(x,_i); 62 | to=from; 63 | appendbuf(res,(buf_t)&to,1); }); } 64 | 65 | if(x->t==2&&(typenum==2||typetag==tagchar)) { // char -> char 66 | char from;char to; res=xalloc(2,x->n); 67 | FOR(0,x->n,{from=AS_c(x,_i); 68 | to=from; 69 | appendbuf(res,(buf_t)&to,1); }); } 70 | 71 | if(x->t==2&&(typenum==3||typetag==tagbyte)) { // char -> byte 72 | char from;int8_t to; res=xalloc(3,x->n); 73 | FOR(0,x->n,{from=AS_c(x,_i); 74 | to=from; 75 | appendbuf(res,(buf_t)&to,1); }); } 76 | 77 | if(x->t==2&&(typenum==4||typetag==tagint)) { // char -> int 78 | char from;int to; res=xalloc(4,x->n); 79 | FOR(0,x->n,{from=AS_c(x,_i); 80 | to=from; 81 | appendbuf(res,(buf_t)&to,1); }); } 82 | 83 | if(x->t==2&&(typenum==5||typetag==taglong)) { // char -> long 84 | char from;__int64_t to; res=xalloc(5,x->n); 85 | FOR(0,x->n,{from=AS_c(x,_i); 86 | to=from; 87 | appendbuf(res,(buf_t)&to,1); }); } 88 | 89 | if(x->t==2&&(typenum==6||typetag==tagocta)) { // char -> octa 90 | char from;__int128_t to; res=xalloc(6,x->n); 91 | FOR(0,x->n,{from=AS_c(x,_i); 92 | to=from; 93 | appendbuf(res,(buf_t)&to,1); }); } 94 | 95 | if(x->t==2&&(typenum==7||typetag==tagfloat)) { // char -> float 96 | char from;double to; res=xalloc(7,x->n); 97 | FOR(0,x->n,{from=AS_c(x,_i); 98 | to=from; 99 | appendbuf(res,(buf_t)&to,1); }); } 100 | 101 | if(x->t==3&&(typenum==1||typetag==tagtag)) { // byte -> tag 102 | int8_t from;tag_t to; res=xalloc(1,x->n); 103 | FOR(0,x->n,{from=AS_b(x,_i); 104 | to=from; 105 | appendbuf(res,(buf_t)&to,1); }); } 106 | 107 | if(x->t==3&&(typenum==2||typetag==tagchar)) { // byte -> char 108 | int8_t from;char to; res=xalloc(2,x->n); 109 | FOR(0,x->n,{from=AS_b(x,_i); 110 | to=from; 111 | appendbuf(res,(buf_t)&to,1); }); } 112 | 113 | if(x->t==3&&(typenum==3||typetag==tagbyte)) { // byte -> byte 114 | int8_t from;int8_t to; res=xalloc(3,x->n); 115 | FOR(0,x->n,{from=AS_b(x,_i); 116 | to=from; 117 | appendbuf(res,(buf_t)&to,1); }); } 118 | 119 | if(x->t==3&&(typenum==4||typetag==tagint)) { // byte -> int 120 | int8_t from;int to; res=xalloc(4,x->n); 121 | FOR(0,x->n,{from=AS_b(x,_i); 122 | to=from; 123 | appendbuf(res,(buf_t)&to,1); }); } 124 | 125 | if(x->t==3&&(typenum==5||typetag==taglong)) { // byte -> long 126 | int8_t from;__int64_t to; res=xalloc(5,x->n); 127 | FOR(0,x->n,{from=AS_b(x,_i); 128 | to=from; 129 | appendbuf(res,(buf_t)&to,1); }); } 130 | 131 | if(x->t==3&&(typenum==6||typetag==tagocta)) { // byte -> octa 132 | int8_t from;__int128_t to; res=xalloc(6,x->n); 133 | FOR(0,x->n,{from=AS_b(x,_i); 134 | to=from; 135 | appendbuf(res,(buf_t)&to,1); }); } 136 | 137 | if(x->t==3&&(typenum==7||typetag==tagfloat)) { // byte -> float 138 | int8_t from;double to; res=xalloc(7,x->n); 139 | FOR(0,x->n,{from=AS_b(x,_i); 140 | to=from; 141 | appendbuf(res,(buf_t)&to,1); }); } 142 | 143 | if(x->t==4&&(typenum==1||typetag==tagtag)) { // int -> tag 144 | int from;tag_t to; res=xalloc(1,x->n); 145 | FOR(0,x->n,{from=AS_i(x,_i); 146 | to=from; 147 | appendbuf(res,(buf_t)&to,1); }); } 148 | 149 | if(x->t==4&&(typenum==2||typetag==tagchar)) { // int -> char 150 | int from;char to; res=xalloc(2,x->n); 151 | FOR(0,x->n,{from=AS_i(x,_i); 152 | to=from; 153 | appendbuf(res,(buf_t)&to,1); }); } 154 | 155 | if(x->t==4&&(typenum==3||typetag==tagbyte)) { // int -> byte 156 | int from;int8_t to; res=xalloc(3,x->n); 157 | FOR(0,x->n,{from=AS_i(x,_i); 158 | to=from; 159 | appendbuf(res,(buf_t)&to,1); }); } 160 | 161 | if(x->t==4&&(typenum==4||typetag==tagint)) { // int -> int 162 | int from;int to; res=xalloc(4,x->n); 163 | FOR(0,x->n,{from=AS_i(x,_i); 164 | to=from; 165 | appendbuf(res,(buf_t)&to,1); }); } 166 | 167 | if(x->t==4&&(typenum==5||typetag==taglong)) { // int -> long 168 | int from;__int64_t to; res=xalloc(5,x->n); 169 | FOR(0,x->n,{from=AS_i(x,_i); 170 | to=from; 171 | appendbuf(res,(buf_t)&to,1); }); } 172 | 173 | if(x->t==4&&(typenum==6||typetag==tagocta)) { // int -> octa 174 | int from;__int128_t to; res=xalloc(6,x->n); 175 | FOR(0,x->n,{from=AS_i(x,_i); 176 | to=from; 177 | appendbuf(res,(buf_t)&to,1); }); } 178 | 179 | if(x->t==4&&(typenum==7||typetag==tagfloat)) { // int -> float 180 | int from;double to; res=xalloc(7,x->n); 181 | FOR(0,x->n,{from=AS_i(x,_i); 182 | to=from; 183 | appendbuf(res,(buf_t)&to,1); }); } 184 | 185 | if(x->t==5&&(typenum==1||typetag==tagtag)) { // long -> tag 186 | __int64_t from;tag_t to; res=xalloc(1,x->n); 187 | FOR(0,x->n,{from=AS_j(x,_i); 188 | to=from; 189 | appendbuf(res,(buf_t)&to,1); }); } 190 | 191 | if(x->t==5&&(typenum==2||typetag==tagchar)) { // long -> char 192 | __int64_t from;char to; res=xalloc(2,x->n); 193 | FOR(0,x->n,{from=AS_j(x,_i); 194 | to=from; 195 | appendbuf(res,(buf_t)&to,1); }); } 196 | 197 | if(x->t==5&&(typenum==3||typetag==tagbyte)) { // long -> byte 198 | __int64_t from;int8_t to; res=xalloc(3,x->n); 199 | FOR(0,x->n,{from=AS_j(x,_i); 200 | to=from; 201 | appendbuf(res,(buf_t)&to,1); }); } 202 | 203 | if(x->t==5&&(typenum==4||typetag==tagint)) { // long -> int 204 | __int64_t from;int to; res=xalloc(4,x->n); 205 | FOR(0,x->n,{from=AS_j(x,_i); 206 | to=from; 207 | appendbuf(res,(buf_t)&to,1); }); } 208 | 209 | if(x->t==5&&(typenum==5||typetag==taglong)) { // long -> long 210 | __int64_t from;__int64_t to; res=xalloc(5,x->n); 211 | FOR(0,x->n,{from=AS_j(x,_i); 212 | to=from; 213 | appendbuf(res,(buf_t)&to,1); }); } 214 | 215 | if(x->t==5&&(typenum==6||typetag==tagocta)) { // long -> octa 216 | __int64_t from;__int128_t to; res=xalloc(6,x->n); 217 | FOR(0,x->n,{from=AS_j(x,_i); 218 | to=from; 219 | appendbuf(res,(buf_t)&to,1); }); } 220 | 221 | if(x->t==5&&(typenum==7||typetag==tagfloat)) { // long -> float 222 | __int64_t from;double to; res=xalloc(7,x->n); 223 | FOR(0,x->n,{from=AS_j(x,_i); 224 | to=from; 225 | appendbuf(res,(buf_t)&to,1); }); } 226 | 227 | if(x->t==6&&(typenum==1||typetag==tagtag)) { // octa -> tag 228 | __int128_t from;tag_t to; res=xalloc(1,x->n); 229 | FOR(0,x->n,{from=AS_o(x,_i); 230 | to=from; 231 | appendbuf(res,(buf_t)&to,1); }); } 232 | 233 | if(x->t==6&&(typenum==2||typetag==tagchar)) { // octa -> char 234 | __int128_t from;char to; res=xalloc(2,x->n); 235 | FOR(0,x->n,{from=AS_o(x,_i); 236 | to=from; 237 | appendbuf(res,(buf_t)&to,1); }); } 238 | 239 | if(x->t==6&&(typenum==3||typetag==tagbyte)) { // octa -> byte 240 | __int128_t from;int8_t to; res=xalloc(3,x->n); 241 | FOR(0,x->n,{from=AS_o(x,_i); 242 | to=from; 243 | appendbuf(res,(buf_t)&to,1); }); } 244 | 245 | if(x->t==6&&(typenum==4||typetag==tagint)) { // octa -> int 246 | __int128_t from;int to; res=xalloc(4,x->n); 247 | FOR(0,x->n,{from=AS_o(x,_i); 248 | to=from; 249 | appendbuf(res,(buf_t)&to,1); }); } 250 | 251 | if(x->t==6&&(typenum==5||typetag==taglong)) { // octa -> long 252 | __int128_t from;__int64_t to; res=xalloc(5,x->n); 253 | FOR(0,x->n,{from=AS_o(x,_i); 254 | to=from; 255 | appendbuf(res,(buf_t)&to,1); }); } 256 | 257 | if(x->t==6&&(typenum==6||typetag==tagocta)) { // octa -> octa 258 | __int128_t from;__int128_t to; res=xalloc(6,x->n); 259 | FOR(0,x->n,{from=AS_o(x,_i); 260 | to=from; 261 | appendbuf(res,(buf_t)&to,1); }); } 262 | 263 | if(x->t==6&&(typenum==7||typetag==tagfloat)) { // octa -> float 264 | __int128_t from;double to; res=xalloc(7,x->n); 265 | FOR(0,x->n,{from=AS_o(x,_i); 266 | to=from; 267 | appendbuf(res,(buf_t)&to,1); }); } 268 | 269 | if(x->t==7&&(typenum==1||typetag==tagtag)) { // float -> tag 270 | double from;tag_t to; res=xalloc(1,x->n); 271 | FOR(0,x->n,{from=AS_f(x,_i); 272 | to=from; 273 | appendbuf(res,(buf_t)&to,1); }); } 274 | 275 | if(x->t==7&&(typenum==2||typetag==tagchar)) { // float -> char 276 | double from;char to; res=xalloc(2,x->n); 277 | FOR(0,x->n,{from=AS_f(x,_i); 278 | to=from; 279 | appendbuf(res,(buf_t)&to,1); }); } 280 | 281 | if(x->t==7&&(typenum==3||typetag==tagbyte)) { // float -> byte 282 | double from;int8_t to; res=xalloc(3,x->n); 283 | FOR(0,x->n,{from=AS_f(x,_i); 284 | to=from; 285 | appendbuf(res,(buf_t)&to,1); }); } 286 | 287 | if(x->t==7&&(typenum==4||typetag==tagint)) { // float -> int 288 | double from;int to; res=xalloc(4,x->n); 289 | FOR(0,x->n,{from=AS_f(x,_i); 290 | to=from; 291 | appendbuf(res,(buf_t)&to,1); }); } 292 | 293 | if(x->t==7&&(typenum==5||typetag==taglong)) { // float -> long 294 | double from;__int64_t to; res=xalloc(5,x->n); 295 | FOR(0,x->n,{from=AS_f(x,_i); 296 | to=from; 297 | appendbuf(res,(buf_t)&to,1); }); } 298 | 299 | if(x->t==7&&(typenum==6||typetag==tagocta)) { // float -> octa 300 | double from;__int128_t to; res=xalloc(6,x->n); 301 | FOR(0,x->n,{from=AS_f(x,_i); 302 | to=from; 303 | appendbuf(res,(buf_t)&to,1); }); } 304 | 305 | if(x->t==7&&(typenum==7||typetag==tagfloat)) { // float -> float 306 | double from;double to; res=xalloc(7,x->n); 307 | FOR(0,x->n,{from=AS_f(x,_i); 308 | to=from; 309 | appendbuf(res,(buf_t)&to,1); }); } 310 | 311 | -------------------------------------------------------------------------------- /cast.js: -------------------------------------------------------------------------------- 1 | var lib = require('./common.js'); 2 | var tmpls=[ 3 | "int tag{{2}}=Ti({{2}});", 4 | "if(x->t=={{x0}}&&(typenum=={{y0}}||typetag==tag{{y2}})) { // {{x2}} -> {{y2}} \n" + 5 | " {{x3}} from;{{y3}} to; res=xalloc({{y0}},x->n); \n"+ 6 | " FOR(0,x->n,{from=AS_{{x1}}(x,_i);\n" + 7 | " to=from; \n"+ 8 | " appendbuf(res,(buf_t)&to,1); }); }\n" 9 | ]; 10 | console.log(lib.prelude); 11 | lib.each(lib.types,function(tx) { 12 | console.log(lib.exhaust(lib.projr(lib.repl,tx),tmpls[0])); 13 | }); 14 | lib.each(lib.types,function(tx) { 15 | if(lib.dontcast.indexOf(tx[1])!=-1)return; 16 | lib.each(lib.types,function(ty) { 17 | if(lib.dontcast.indexOf(ty[1])!=-1)return; 18 | var a=[]; 19 | tmpl=tmpls[1]; 20 | for(var i in tx)a["x"+i]=tx[i]; 21 | for(var i in ty)a["y"+i]=ty[i]; 22 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 23 | }); 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /common.js: -------------------------------------------------------------------------------- 1 | var m = {}; 2 | // TODO common m.types should be a dict, array annoying 3 | var def={}; 4 | argv=process.argv.forEach(function(v) { 5 | var d=v.match(/-D(.+)/); 6 | if(d) { def[d[1]]=1; } 7 | }); 8 | m.types = [ 9 | // 0 type# 10 | // 1 type code 11 | // 2 english name 12 | // 3 c type 13 | // 4 var args type 14 | // 5 formatter 15 | // 6 has repr func in xxl.c 16 | // 7 max 17 | // 8 container? 18 | [0,"l","list","VP","VP","%p",true,"0",true], 19 | [1,"t","tag","tag_t","long long","%llld",true,"LONG_LONG_MAX",false], 20 | [2,"c","char","char","int","%c",true,"SCHAR_MAX",false], 21 | [3,"b","byte","int8_t","int","%d",false,"SCHAR_MAX",false], 22 | [4,"i","int","int","int","%d",false,"INT_MAX",false], 23 | [5,"j","long","__int64_t","int","%ld",false,"LONG_MAX",false], 24 | (('OCTA' in def) ? 25 | [6,"o","octa","__int128_t","int","%llld",true,"LONG_LONG_MAX",false] : 26 | [6,"o","octa","__int64_t","int","%ld",true,"LONG_MAX",false] 27 | ) 28 | , 29 | [7,"f","float","double","double","%0.5f",false,"DBL_MAX",false],/* TODO custom printf for octowords */ 30 | [8,"d","dict","VP","VP","%p",true,"0",true],// a dict is a general list with two items [keys,vals] 31 | [9,"a","table","VP","VP","%p",true,"0",true],// a table is a dict whose vectors happen to contain more than 1 value (usually) 32 | [10,"1","f1","unaryFunc*","unaryFunc*","%p",false,"0",false], 33 | [11,"2","f2","binaryFunc*","binaryFunc*","%p",false,"0",false], 34 | [12,"p","proj","Proj","Proj","%p",true,"0",false], 35 | [13,"x","ctx","VP","VP","%p",true,"0",true],// a context is a list [scope0,scope1,..scopen,[code]] 36 | ]; 37 | m.dontcast = ["l", "d", "a", "1", "2", "p", "x"]; // TODO should be flag on m.types 38 | m.each = function each(a,f) { 39 | var acc=[];for(var i in a) acc.push(f(a[i])); return acc; 40 | } 41 | m.eachr = function eachr(f,a) { 42 | return function(b) { 43 | var acc=[]; 44 | for(var i in a) { 45 | acc.push(f(b,a[i])); 46 | } 47 | return acc; 48 | } 49 | } 50 | m.exhaust = function exhaust(f,a) { 51 | var last=''; 52 | while(1) { 53 | a=f(a); if(a==last)return last; last=a; 54 | } 55 | } 56 | m.prelude = '// Autogenerated file; see corresponding .js\n'; 57 | m.projl = function projl(f,a) { 58 | return function(b) { return f(a,b); } 59 | } 60 | m.projr = function projr(f,a) { 61 | return function(b) { return f(b,a); } 62 | } 63 | m.repl = function repl(str,v) { 64 | //console.log('repl',str,v); 65 | for(var j in v) 66 | str=str.replace('{{'+j+'}}',v[j]); return str; 67 | } 68 | module.exports=m; 69 | -------------------------------------------------------------------------------- /d: -------------------------------------------------------------------------------- 1 | RUN="gdb -ex run --args ./xxl -xray " 2 | if which rlwrap >/dev/null; then 3 | echo using rlwrap 4 | RUN="rlwrap $RUN" 5 | fi 6 | $RUN $* 7 | 8 | 9 | -------------------------------------------------------------------------------- /def.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // dirname/basename 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef THREAD 19 | #include 20 | #endif 21 | 22 | #define XXL_VER "v0 spiral insana" 23 | #define TESTITERS 1 24 | #ifndef DEBUG 25 | #define DEBUG 0 26 | #endif 27 | 28 | /* Control structures of sorts: */ 29 | #define MAX(a,b) \ 30 | ({ __typeof__ (a) _a = (a); \ 31 | __typeof__ (b) _b = (b); \ 32 | _a > _b ? _a : _b; }) 33 | #define MIN(a,b) \ 34 | ({ __typeof__ (a) _a = (a); \ 35 | __typeof__ (b) _b = (b); \ 36 | _a < _b ? _a : _b; }) 37 | #define ABS(a) ( (a)<0 ? -1*(a) : (a) ) 38 | #define CASE(a,b) case (a): b; break 39 | #define FOR(st,en,stmt) ({ int _i;for(_i=(st);_i<(en);_i++)stmt; }) 40 | #define IF_RET(cond,thing) if((cond)) return thing 41 | #define ITER(thing,n,body) ({ int _i;for(_i=0;_in;_i++) { body; } }) 43 | #define ITER2(x,y,body) ({ \ 44 | int _i; int _j; \ 45 | if(x==NULL || y==NULL || x->n==0 || y->n==0) { \ 46 | } else if(x->n > 1) { \ 47 | for(_i=0;_in;_i++) { \ 48 | if(y->n > 1) { \ 49 | for (_j=0;_jn;_j++) { \ 50 | if(IS_i(x)&&IS_i(y)) { \ 51 | int _x = EL(x,int,_i); \ 52 | int _y = EL(y,int,_i); \ 53 | XRAY_log("_x %d,_y %d\n", _x, _y); \ 54 | body; \ 55 | } \ 56 | } \ 57 | } \ 58 | } \ 59 | } \ 60 | }) 61 | #define PERR(msg) {perror(msg);exit(1);} 62 | 63 | // DEBUGGING HELPER MACROS --------------------------------------------- 64 | 65 | #define FMT_into_s(sz,fmt,...) ({ int len=strlen(s); if(sz-len>5) { snprintf(s+len,sz-len,fmt,__VA_ARGS__); } s; }) 66 | #define ASSERT(cond,txt) ({ if (!(cond)) { printf("ASSERT: %s\n", txt); raise(SIGABRT); exit(1); } }) 67 | #define FMT_strA(fmt,x) ({ typeof(x) xx=x; char* s=malloc(1024);snprintf(fmt,1024,xx); xx; }) 68 | #define _XRAY_log(...) ({ FOR(0,XRAY_LVL,printf(" ")); printf(__VA_ARGS__);}) 69 | #define XRAY_log(...) (DEBUG && XRAY_LVL && _XRAY_log(__VA_ARGS__)) 70 | #define XRAY_in() (DEBUG && XRAY_LVL > 0 && XRAY_LVL++) 71 | #define XRAY_out() (DEBUG && XRAY_LVL > 0 && XRAY_LVL--) 72 | #define XRAY_toggle(stmt) ({ int opf=XRAY_LVL; XRAY_LVL++; XRAY_in(); stmt; XRAY_out(); XRAY_LVL=opf; }) 73 | #define XRAY_memlog(...) (MEM_WATCH && IN_OUTPUT_HANDLER==0 && _XRAY_log(__VA_ARGS__)) 74 | #if DEBUG 75 | #define XRAY_emit(x) ({ if (XRAY_LVL) { char* s = reprA(x); XRAY_log("%s\n", s); free(s); } x; }) 76 | #define XRAY_emitRAW(x,sz) ({ printf("%p ",x); FOR(0,sz,printf("%d ",x[_i])); printf("\n"); x; }) 77 | #else 78 | #define XRAY_emit(x) ({}) 79 | #define XRAY_emitRAW(x,sz) ({}) 80 | #endif 81 | #ifdef DEBUG 82 | #define TRACELBL(x,lbl) ( (x)->tag=lbl, x ) 83 | #else 84 | #define TRACELBL(x,lbl) (x) 85 | #endif 86 | #define REPR_MAX_ITEMS 500 87 | 88 | // ACCESSING THE DATA OF XXL VARIABLES (VP) ---------------------------- 89 | 90 | #define BUF(v) ((buf_t)( (v)->alloc ? (v->dyn) : (buf_t)&((v)->st) )) // data ptr 91 | #define EL(v,type,n) (((type*)BUF(v))[n]) // ..as type, for index n 92 | // TODO ELl() and friends should do more checking on arguments, or provide a safe wrapper to do it 93 | // for callers - perhaps simply delist(v,n) 94 | #define ELl(v,n) ((EL(v,VP,n))) // ..deref linked list item 95 | #define ELb(v,n) ELsz(v,1,n) // ..as a byte* for index n 96 | #define ELi(v,n) ((BUF(v))+((v->itemsz)*(n))) // ..for index n (no type assumed) 97 | #define ELsz(v,sz,n) ((BUF(v))+(sz*n)) // ..for index n, when casted to size = sz 98 | 99 | // HIGHER LEVEL VALUE ACCESSORS AND PREDICATES ------------------------- 100 | 101 | #define LEN(v) ((v)->n) 102 | #define SCALAR(v) ((v)->n==1) // is v a single value? 103 | #define NUM(v) (IS_c(v)||IS_b(v)||IS_i(v)||IS_j(v)||IS_o(v)||IS_f(v)) // works with math ops? 104 | #define NUMSTRICT(v) (IS_b(v)||IS_i(v)||IS_j(v)||IS_o(v)) // is v an int type? 105 | #define SIMPLE(v) (IS_t(v)||IS_c(v)||IS_b(v)||IS_i(v)||IS_j(v)||IS_o(v)||IS_f(v)) 106 | #define COMPARABLE(v) (NUM(v) || IS_c(v)) 107 | #define LIST(v) ((v)->t==0) // is v a general list type? 108 | #define LIST_of_lists(v) (LIST(v) && LEN(v) && LIST(ELl(v,0))) 109 | #define ENLISTED(v) (LIST(v)&&SCALAR(v)) // is v a single item inside a list? 110 | #define DISCLOSE(v) (ENLISTED(v) ? LIST_first(v) : v) 111 | #define EMPTYLIST(v) (LIST(v)&&v->n==0) // empty list 112 | #define LIST_first(v) (ELl(v,0)) 113 | #define LIST_item(v,n) (ELl(v,n)) 114 | #define KEYS(v) (ELl(v,0)) // keys for dict/table/ctx v 115 | #define VALS(v) (ELl(v,1)) // values for dict/table/ctx v 116 | #define DICT(v) (IS_d(v)) // is v a dictionary? 117 | #define LISTDICT(v) (IS_l(v)||IS_d(v)) // is v a list or dictionary? 118 | #define TABLE(v) (IS_a(v)) // is v a dictionary? 119 | // is v any kind of container? (i.e., non-vec but has children) 120 | #define CONTAINER(v) ((IS_l(v)||IS_d(v)||IS_a(v)||IS_x(v)) && !IS_EXC(v)) 121 | #define INDEXABLE(v) (CALLABLE(v) || !SCALAR(v)) 122 | #define CALLABLE(v) (IS_1(v)||IS_2(v)||IS_p(v)||IS_x(v)) // callable types - represent funcs or contexts 123 | 124 | #define NUM_item(x,n) ( IS_i(x)?AS_i(x,n) : (IS_b(x)?AS_b(x,n) : (IS_c(x)?AS_c(x,n) : (IS_j(x)?AS_j(x,n) : (IS_o(x)?AS_o(x,n) : -1)))) ) 125 | #define NUM_val(x) NUM_item(x,0) 126 | 127 | #define DICT_find(x,y) ({ int i = _find1(KEYS(x),y); VP result=(i==-1?((VP)NULL):ELl(VALS(x),i)); result; }) 128 | #define DICT_key_n(x,y) (ELl(KEYS(x),y)) // get key #y from x; doesnt allocate so dont xfree 129 | #define DICT_val_n(x,y) (ELl(VALS(x),y)) // get value #y from x; see above 130 | 131 | #define TABLE_col(x,n) (ELl(VALS(x),n)) 132 | #define TABLE_col_num_for_name(x,n) (_find1(KEYS(x),n)) 133 | #define TABLE_col_named(x,n) ({ int i = _find1(KEYS(x),n); i==-1 ? ((VP)NULL) : (TABLE_col(x,i)); }) 134 | #define TABLE_ncols(x) (LEN(KEYS(x))) 135 | #define TABLE_nrows(x) (LEN(VALS(x))==0 ? 0 : TABLE_col(x,0)->n) 136 | 137 | // is this member of a context (gen list) a body of code? 138 | #define LAMBDAISH(ctxmem) (LIST(ctxmem)&&(CALLABLE(ELl(ctxmem,0))||(ctxmem)->tag==Ti(lambda))) 139 | // is this member a dictionary of scope definitions (resolvable identifiers) 140 | #define LAMBDAARITY(x) (AS_i(ELl(x,1),0)) 141 | #define CTX_make_subctx(parentctx,newcode) \ 142 | ({ VP res=xxsz(2); res->n=2; \ 143 | EL(res,VP,0)=xd0(); \ 144 | EL(res,VP,0)=assign(KEYS(res),TTPARENT,parentctx); \ 145 | EL(res,VP,1)=xref(newcode); res; }) 146 | 147 | #define Ti(n) (_tagnums(#n)) // int value for tag n (literal not string) 148 | #define Tt(n) (xt(_tagnums(#n))) // tag n (literal not string) as a scalar of type tag 149 | 150 | #define TAGGED(x,t) (x->tag!=0 && x->tag==t) 151 | #define TAG_is_class(tag) (((char)tag>='A') && ((char)tag<='Z')) 152 | #define CLASSED(x) (x->tag!=0 && TAG_is_class(x->tag)) 153 | #define CLASS_dispatch(ctx,verb,x,y) \ 154 | if(x->tag!=0 && TAG_is_class(x->tag)) { \ 155 | VP verbtag=Tt(verb); \ 156 | VP tmp=classdispatch(ctx,verbtag,x,y); \ 157 | xfree(verbtag); \ 158 | if(tmp!=NULL) return tmp; \ 159 | } 160 | 161 | #define BEST_NUM_FIT(val) ({ int t; \ 162 | if(valt,y->t),MAX(x->n,y->n)); \ 166 | if(UNLIKELY(x->tag))new_->tag=x->tag; new_; }) 167 | #define ALLOC_LIKE(x) ({ VP new_ = xalloc(x->t,x->n); if(UNLIKELY(x->tag))new_->tag=x->tag; new_; }) 168 | #define ALLOC_LIKE_SZ(x,sz) ({ VP new_ = xalloc(x->t,sz); if(UNLIKELY(x->tag))new_->tag=x->tag; new_; }) 169 | #define ALLOC_BEST_FIT(val,sz) (xalloc(BEST_NUM_FIT(bval),sz)) 170 | #define XREALLOC(x,newn) ((newn) >= (x->cap) ? xrealloc(x,newn) : x) 171 | 172 | // does nothing for now, but as we ponder the switch to immutability, i thought it would be good 173 | // to mark parts of code that change their input arguments' values, so that we can have a good map 174 | // of the semantic and structural changes that immutability might require 175 | #define ARG_MUTATING(x) 176 | // at some point this will be intelligent about not cloning values for mapped types 177 | #define MUTATE_CLONE(x) (clone(x)) // (x->rc==1 ? x : clone(x)) 178 | 179 | #define EXC(type,lbl,x,y) ({ \ 180 | VP exc; exc = entag(xln(4,type,xfroms(lbl),x,y),Tt(exception)); \ 181 | if(0) printf("exception: %s\n", bfromx(repr(exc))); \ 182 | exc; }) 183 | #define IF_EXC(cond,type,msg,x,y) if((cond)) return EXC(type,msg,x,y) 184 | #define IS_EXC(x) (x==0 || (x)->tag==TIEXCEPTION) 185 | // TODO if_exc doesnt give us a chance to free memory :-/ 186 | #define RETURN_IF_EXC(x) if(IS_EXC(x)) return x; 187 | 188 | // MISC 189 | 190 | #define CH_SET_A "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 191 | #define CH_SET_a "abcdefghijklmnopqrstuvwxyz" 192 | #define CH_SET_n "0123456789" 193 | #define CH_SET_na CH_SET_n CH_SET_a 194 | #define CH_SET_nA CH_SET_n CH_SET_A 195 | 196 | #define IOBLOCKSZ 100*1024 197 | #define MAXSTACK 2048 198 | #define LIKELY(x) __builtin_expect((x),1) 199 | #define UNLIKELY(x) __builtin_expect((x),0) 200 | #define TIME(n,expr) ({ int i; clock_t st,en; \ 201 | st=clock(); for(i=0;i),{-" "}]``` 124 | 125 | Another version, using the lurid `aside` verb, might be: 126 | ```"hello world"aside{~" "rot(1neg)![0,1]~>as 'w}![w,{-" "}]``` 127 | 128 | For more information, see the following verbs: 129 | 130 | `{verbsincat:'logic}` 131 | 132 | " 133 | 134 | -------------------------------------------------------------------------------- /doc/sect_mbox.xxl: -------------------------------------------------------------------------------- 1 | // note for human readers: this doc is meant to be consumed by XXL itself to 2 | // produce the documentation website. the markdown tags below with triple 3 | // quotes are code samples. the part before the ||| is the XXL code 4 | // and the part after it is the result. 5 | 6 | " 7 | # Mailbox Soliloquy 8 | 9 | ## Overview 10 | 11 | XXL uses a system called mailboxes to allow multiple separate parts of running code 12 | to communicate. It also provides a way to use these mailboxes in a safe way between 13 | threads. 14 | 15 | It has been my observation that having a system-level message queue concept makes 16 | a whole lot of problems much simpler. I believe this has been observed in Go, 17 | Javascript (React's event bus approach), and in many other languages, where they 18 | tend to be implemented ad hoc as the need arises. 19 | 20 | Mailboxes are most similar to the concept of processes in Erlang but don't have to 21 | involve a running thread. XXL mailboxes are just a data structure which are 22 | convenient to use with threads, and some verbs to manipulate them. 23 | 24 | You might think of them as the underpinnings of a simple message queue. 25 | 26 | ## Creating a mailbox 27 | 28 | Create mailboxes with `Mbox.new`. It disregards its single argument, so by convention 29 | we use []. 30 | 31 | ```[]Mbox.new as 'me ||| 'mbox#[105827994227856j, 105827994227792j, []]``` 32 | 33 | Don't worry too much what `Mbox.new` returns. Consider it an opaque value or a handle. 34 | 35 | ## Reading 36 | 37 | Anyone can read from a mailbox if they have a reference to it so it acts as a name of sorts. 38 | There is no concept of an owner and anyone can read or write to a mailbox. Your code decides 39 | how the the mailbox is managed. 40 | 41 | You can use `mbox Mbox.recv` to get the first item out of a mailbox. If there is nothing in the 42 | mailbox, `Mbox.recv` returns null. Once the value has been returned from `recv`, it is gone, and 43 | has permanently removed from the mailbox. 44 | 45 | `Mbox.peek` is similar, but does not remove the message from the queue. It will also return 46 | null if nothing is in the queue. 47 | 48 | `Mbox.wait` saves you from calling `Mbox.recv` over and over again. It gracefully 49 | gives up processor cycles until a message is available using `sched_yield` and 50 | `usleep`. There is no ability to set a timeout yet. 51 | 52 | If more than one party read from a mailbox using `Mbox.recv` or `Mbox.wait`, it 53 | is undefined who will receive the message. 54 | 55 | Mailboxes have a read lock internally, so you can use read from them in multiple threads. 56 | 57 | ## Writing 58 | 59 | Anyone can write to a mailbox, if they have a reference to that mailbox. A mailbox has a 60 | write lock, so you need not worry about writing to a mailbox from different threads. 61 | 62 | `mbox Mbox.send msg` writes a message to a mailbox. 63 | 64 | ``` 65 | me Mbox.send "hi"; me Mbox.wait 66 | ||| 67 | "hi" 68 | ``` 69 | 70 | ## Watching (threads and callbacks) 71 | 72 | If you want to have a bit of code executed every time someone sends a message to a given 73 | mailbox, XXL provides a convenience function to do that. 74 | 75 | `mbox Mbox.watch {x as 'msg; y as 'state; code; newstate}` creates a thread 76 | that watches a mailbox and runs your code when a message is received. When a 77 | message is not available, it gracefully yields processor time slices to other 78 | programs. 79 | 80 | ``` 81 | me Mbox.watch {['incoming,x]show}; 82 | me Mbox.send "hi" 83 | ||| 84 | ['incoming,"hi"]``` 85 | 86 | Note: The output shown here comes from the `show` statement in the inner expression. We're 87 | joining it with the symbol `'incoming` for illustration purposes. In Erlang, this is an 88 | effective way to output debugging info. 89 | 90 | The code you supply to `Mbox.watch` is expected to be a binary function (one that takes two arguments). 91 | 92 | The `x` argument will be the message that was sent to the mailbox. The `y` argument will be a value (initially 93 | empty) that the function can use to maintain its own state. 94 | 95 | The first time the function is called, the state value will be the empty list `[]`. After your code is called, 96 | the last expression inside the code body will be returned as usual, and `Mbox.watch` will hold on to it for 97 | the next invocation of your code. It will then replace `[]`. 98 | 99 | You are advised to test `y` with `orelse` or a similar logical verb to inflict your own default value on `y`. 100 | 101 | An example: 102 | 103 | ``` 104 | [] Mbox.new as 'ctr 105 | Mbox.watch {y orelse 0+1 show}; 106 | 5 count each {ctr Mbox.send 'inc} 107 | ||| 108 | 1\n2\n3\n4\n5``` 109 | 110 | Note: The output shown here comes from the `show` statement in the inner expression. 111 | 112 | The `watch` verb also provides a ping function for convenience. This is done by the watch thread itself 113 | before your code is invoked. 114 | 115 | To use it, send a message like `['ping, mailboxid]`. mailboxid will be sent a message that looks like 116 | `['pong,mbox,nummsgsreceived,numemptypolls]`. 117 | 118 | A callback function used with `watch` function may return just `'exit` and the thread will exit cleanly. 119 | 120 | Otherwise there is no way to kill or interact with the thread. In other words, you can't shut down a watcher 121 | thread, except through the watcher callback code itself (by returning `'exit`). 122 | 123 | ## Querying a mailbox 124 | 125 | Let's say you had a service like the one we built above that provides monotonically increasing counter values. You 126 | could use these values across multiple threads, like to create a unique identifier. 127 | 128 | To use it from your code, you would have to send it a message, have it reply back to your mailbox, and then process it. 129 | 130 | This is somewhat inconvenient and can disturb the program flow for the code consuming the mailbox-based service. 131 | 132 | `Mbox.query` is a mashup of `Mbox.send` and `Mbox.recv` for convenience. 133 | 134 | `svc Mbox.query args` creates a temporary mailbox, sends `[args, tmpmbox]` to the mailbox `svc` (which you would 135 | have created elsewhere), and waits for a response, which it then returns. 136 | 137 | The receiving mailbox (the code that provides the service) should expect to unpack its argument. 138 | 139 | Here's an exciting multiplication example that communicates with a mailbox: 140 | 141 | ``` 142 | [] Mbox.new as 'mulsvc 143 | Mbox.watch {x@0 as 'req; x@1 as 'client; client Mbox.send (y|1*req)}; 144 | 1 range 5 :: {mulsvc Mbox.query x} 145 | ||| 146 | (1,2,6,24,120i) 147 | ``` 148 | 149 | The `watch` callback in this example utilizes the state (`y`) feature of `Mbox.watch` to preserve the last value 150 | you requested, and then multiplies it with the new value, which is sent back to the mailbox provided in the 151 | 152 | There is no timeout available right now with `Mbox.query`. 153 | 154 | ## About that mailbox handle.. 155 | 156 | A mailbox internally consists of a message queue, a read lock, and a write lock. Do not 157 | rely on the internals of a mailbox from XXL code, as the internals may change. 158 | 159 | ## March 2016 notes: 160 | 161 | - Classes: Having to type `Mbox` in front of these verbs is only a temporary annoyance. Eventually XXL will know from 162 | the x value's tag that you mean Mbox.send when you say send. See `Classes`. 163 | 164 | - Performance: On a $5/mo Digital Ocean server I get around 2500 `Mbox.send`s per second, or about 800 165 | `Mbox.query`/sec, when hitting a single mailbox and thread. This isn't ideal but seems usable to me. Of 166 | course, it used 800mb of RAM while doing so (grrr..), so be cautious. 167 | -------------------------------------------------------------------------------- /doc/sect_posts.xxl: -------------------------------------------------------------------------------- 1 | // This describes a feature that I am developing at this time 2 | """ 3 | # A Need to Post 4 | 5 | I'm in the weird position of really wanting a cut and paste feature for, like, 6 | everything in my life. 7 | 8 | I can't organize things if I can't make references to them, store them easily, 9 | find them again. 10 | 11 | On a simple level, the notion of the operating system's cut and paste buffer is 12 | an excellent one. It just works! 13 | 14 | But sadly, you can't cut and paste everything. To cut and paste some idea I'm 15 | building out, a mix of data and code, I have to "flatten" it into a .js source 16 | file, or put it together with some data into a .zip. That sucks! Now I have to 17 | redo it every time I change it. 18 | 19 | ## The dreaded "Export" step 20 | 21 | That last part, where you take your ideas and throw them into a text file and 22 | send them: that's wasted time. You should be able to share and consume freely, 23 | from inside the "creation environment" itself, such as a programming language, 24 | or from your code written in that language. 25 | 26 | Having to export, consume feedback, update the original, and export again 27 | really slows down collaboration. 28 | 29 | ## Enter the pastebin 30 | 31 | That's why I love pastebins. You can easily throw together some code and stuff, 32 | put it up, get a quasi-permanently sometimes-friendly URL and share that little 33 | blob of stuff. The good ones now let you collaborate, execute or interrogate 34 | the contents of the paste as well! This is awesome! 35 | 36 | I need that for everything. My bookmarks are no different than the code I'm 37 | working on or this really cute drawing of a cat I was trying to do. Grocery 38 | list. Reminders. Have you seen the (Palazzo 39 | Strozzi)[https://en.wikipedia.org/wiki/Palazzo_Strozzi]? Those are all just 40 | pastes. They simply do not yet have a common API. 41 | 42 | ## Products too high level and unprogrammable to communicate 43 | 44 | A common API of this sort is a challenge, of course. I needn't go into the variety of cross- 45 | domain issues that you get when you pass complex data from one system to another. 46 | 47 | The ability to paste from Evernote into Photoshop makes no sense on a level 48 | deeper than "static copy of the pixels that I saw at that moment." 49 | 50 | ## XXL posts 51 | 52 | XXL has the built-in concept of a `post`. Post transfers data from one place to 53 | another, and it's a general concept. You may post data from your script to a 54 | remote database, or perhaps post to a remote web service, or even to another 55 | part of your same program. Think of `post` as a thing you've been doing in 56 | every other language and never thought about it. 57 | 58 | The verb you use in XXL is `data post key`. A piece of that that you transfered 59 | using post is colloquially called \"a post\". 60 | 61 | ``` 62 | "Bob Willy Greg" split " " post "list of my best friends for the mini truck rally" 63 | ||| 64 | "http://txpo.st/-istfmybestfriendsfrteminitrckray" 65 | ``` 66 | 67 | Go to that URL in your web browser. You should see our list of friends. That URL 68 | is called a `post id`. It's a mangled form of what you typed in. 69 | 70 | The `post` verb knows what to do based on the thing on the right, which we call 71 | the key. Normally the thing on the right is some kind of unique identifier for 72 | that data, such as a name, or an identification number, or just a random bunch 73 | of letters. Usually we can use this name to get the data back again, when it is 74 | returned to us as the post id. 75 | 76 | ## Generic Post 77 | 78 | Let's talk about the simplest usage form first. We tend to call this "built-in 79 | post". 80 | 81 | Built-in `post` looks at a variable called `'remote` to decide what to do if you specify 82 | a plain old general string for the key. 83 | 84 | Normally XXL is compiled with `txpo.st:80` in `'remote`. This is the default 85 | setting that you can change in `def.h`. 86 | 87 | `txpost` is a convenience service that we run for the XXL user community for 88 | free. It acts kind of like a web server, but it speaks a very restricted 89 | dialect of HTTP. 90 | 91 | Here's how `txpost` is programmed to work. It's a convenient set of rules: 92 | 93 | `'remote` is the name of a remote server supporting a very simplistic version 94 | of HTTP. By default, it is set to the XXL public open pastebin server, 95 | `txpost`, which runs on `txpo.st` port 80. 96 | 97 | `txpost` will accept anything you give it and return a URL to you. The path 98 | part of that URL will be something like the key you supplied, with some 99 | exceptions: 100 | 101 | * Keys less than 16 characters in length will have random characters appended 102 | from the base 32 set (chosen to be easy to say over the phone and hard to mistake). 103 | 104 | * Keys longer than 255 characters in length will be trimmed to 255 characters. 105 | 106 | * Characters in your key that are not in the set A..Z, a..z, 0..9, `_` and `-` 107 | are stripped. Note: no punctuation or period. 108 | 109 | Therefore, if you want the key you specify to be exactly what you get back in 110 | the URL, please conform your key to these rules. Otherwise, if you don't care 111 | (which is what I recommend for casual use, such as inside the interactive 112 | command line), you may use any string as a key value, even "". 113 | 114 | Once a key has been transformed, if it is the same as an existing key, you'll 115 | get back an exception (HTTP 409 to be precise). Keys cannot be updated. Once a 116 | key is associated with some data, it should never change. This error will be 117 | returned to you as an exception which you can trap. 118 | 119 | If you're curious why we chose these rules they are explained later in this 120 | document. 121 | 122 | ### Usage of `txpo.st` 123 | 124 | Post anything! You can post data, or functions you are working on, or just 125 | strings. Use `txpost` as a garbage dump for all your work in progress. Save the 126 | URLs and you can always get the contents back. 127 | 128 | ### A word on uptime 129 | 130 | We run `txpost` as a service for the community. It's on some beefy hardware in a 131 | good data center, but we don't offer support guarantees that you might receive 132 | from a for-profit service. 133 | 134 | We intend to keep `txpost` online as much as possible, and make it very, very 135 | fast, but for uptime guarantees you should seek your own solution. 136 | 137 | ## A post server to call your own 138 | 139 | These are just the conventions that our public server supports. Your own servers 140 | (which are just one line of code) may do anything you want, or return any data 141 | you want, with or without HTTP. Later on in this document we'll explain why we chose these rules. 142 | 143 | You can customize any of this behavior. The format of `'remote` is simply 144 | `hostname:port`. You can use IP addresses as well of course. 145 | 146 | You don't have to store the results of things that are posted to your post 147 | server. Here's an example of a simple post server that simply returns a reversed version 148 | of what you supplied: 149 | 150 | ``` 151 | ("localhost",8000)Net.bind{x@0 reverse} 152 | ``` 153 | 154 | You could make a post server update an account balance, or serve as a counter, 155 | or provide a public view of some sensitive changing information. 156 | 157 | ## Posting and Classes 158 | 159 | We fibbed a little earlier when we said the contents of `'remote` had to be a string. 160 | It can be anything that your program assigns meaning to. 161 | 162 | `'remote` doesn't have to refer to a post server, either. The hostname could be 163 | a radio frequency, or an FTP resource to update, or a buffer on the GPU. In theory 164 | at least. I haven't written any of that. 165 | 166 | The key (right hand thing) that you supply to `post` can be what is known as a 167 | `Class`. Remember in XXL any regular value (such as a string, or a number, or a 168 | list) can have a tag supplied. If this tag has a capital first letter, XXL 169 | sometimes invokes special behavior, that lets us override how things like 170 | `post` (and `get`, `set`) might perform. 171 | 172 | It makes more sense in practice. Here's an example that submits a highly 173 | accurate movie review to some fantasy movie review service, perhaps called 174 | TomatoXXL. 175 | 176 | ``` 177 | 'summary is "Terrible"; 178 | {x@'year>2010} from movies @'id :: {summary post ('Tomato#x)} 179 | ``` 180 | 181 | When XXL performs the `post` verb, it will consider whether or not the key 182 | you provided has a class specified. If so, and `Class.post` exists, 183 | it will be invoked instead of the standard behavior (defined `Xp.post`). 184 | 185 | In this case, we could define our own `Tomato.post` function that will 186 | know how to post to the TomatoXXL reviews ingest server. In our case we're 187 | just slamming a movie id in there, but you'd probably want the data to be 188 | more structured, explaining what type of content it is, general rating, 189 | user who wrote the review, etc. 190 | 191 | TomatoXXL is just an example. A rotten one. (pause) You can define your class's 192 | post behavior to do anything, such as save to disk, perform a database 193 | operation, or connect to a remote service and send some data. 194 | 195 | Likewise, what your class decides to use as a key is entirely up to you. 196 | 197 | ## Authentication and permissions 198 | 199 | At this time, XXL does not give you any ability to control access to your 200 | services, whether or not they work within the `post` framework. You'll have to 201 | do it yourself. That said, consulting a user list represented as an in-memory 202 | table would be very easy. 203 | 204 | ## Netsplit 205 | 206 | Please dear godess when writing networked code consider and explain the 207 | different failure cases of your code, both for the consumer, and the server. If 208 | your system retries, say so, or be clear that it does not. Not considering the 209 | failure case is a huge problem in software. 210 | 211 | In XXL, you may consider the `orelse` verb to deal with failure cases with 212 | a callback, or simply `or` (`|`) to fill in default values. 213 | 214 | ## About `'remote` 215 | 216 | `'remote` is a global and that's highly annoying in practice. 217 | 218 | It's only useful for convenience when you have to do a lot of operations 219 | pointing to one source. 220 | 221 | As the user (programmer), the possibility that `'remote` has changed behind 222 | your back can be frustrating to worry about. 223 | 224 | When writing your class-driven `post` behaviors, XXL's behavior with `'remote` 225 | doesn't come into play unless you explicitly consider it in your callback 226 | function. 227 | 228 | Think about this before deciding whether or not your class-based behavior 229 | considers `'remote`. 230 | 231 | ## Using a post id after you have one 232 | 233 | Post IDs can be used on the left side of `get` to retrieve their contents. 234 | 235 | ``` 236 | "http://txpo.st/somereallylongurl" get 237 | ``` 238 | 239 | `get` also uses the class name of `x` to determine what it does. 240 | 241 | ## Ideas for things to post 242 | 243 | * Post your boss an idea for a new report 244 | * Post Youtube URLs to your media center 245 | * Post bookmarks and personal photos to your "personal cloud" server, a $5/mo 246 | Digital Ocean VM. Program it to reject posts that do not start with a 16 247 | character key that you choose. 248 | * Post music you make on your iPhone on the way to work, via Workflow (an 249 | excellent app). 250 | * Post your thoughts about politics to an anonymous obscure XXL server you 251 | heard about known only by a changing IP. Debate ensues. 252 | * Post updates to a separate, logged, firewalled database. 253 | * Post updates from your logged database to its logging server. 254 | * Post an alert to the logging server when the primary goes down. 255 | * Post your mama an email because she hasn't heard from you in a while. 256 | 257 | ## `txpo.st`'s odd rules 258 | 259 | Here's why the default `txpost` service works the way it does. Other services 260 | or your own creations may vary. 261 | 262 | * Encouraging longer post keys means less chance of unintentional collisions. 263 | It also allows the service consumer a convenient, logical time to think about 264 | issues of uniqueness and immutability. 265 | 266 | * 16 bytes (128 bits) is a lot of space for diffusion, though truthfully our 267 | current key filtering scheme greatly limits the actual size of this space. 268 | Similarly we'd have better input for a hash function if we were to hash the 269 | keys to their results. 270 | 271 | * GUIDs/UUIDs are often 128 bits, so there's a convenience aspect there. 272 | IPv6 too. 273 | 274 | * XXL supports vectors of 128bit integers, so you can quickly create and 275 | manipulate keys. (Though our public server removes characters from keys 276 | that do not fall into a very restrictive set) 277 | 278 | * Keys that are less than 16 bytes are known to be special, or not placed 279 | there by a public post. This means we can consider them to be a "restricted 280 | enclave" of the key space. They are trusted because the system rules 281 | allowed them to be created. 282 | 283 | * Having this secure enclave allows public clients to post requests (with 284 | long keys) that the server responds to with some pre-decided short key. For 285 | instance, the client might post something requesting an account balance update 286 | #142, and request the response be posted in a certain key it randomly selected, 287 | such as #82519. If that key is less than 16 characters it may seek out its 288 | contents later, and know that only the server could have placed them there. 289 | This allows for a secure message queue-type arrangement. 290 | 291 | * The contents of a key (URL) never change, so you can safely deploy software 292 | this way. If you've screened it once (and you should!) you don't need to 293 | consider that post id again. Consider the usefulness! 294 | 295 | ``` 296 | 'leftpad is {" "take(x len-y),x}; "hello" leftpad 7 297 | // whoa dude, we GOTTA ABSTRACT THAT! 298 | "http://txpo.st/leftpad-v0" get as 'leftpad; "hello" leftpad 7 299 | ``` 300 | 301 | I am doing everything I can to make this tutorial feel dated as soon as 302 | possible. 303 | 304 | * Because the contents of a key never change, it is incredibly easy to cache. 305 | This means lower performance overhead on an ongoing basis to support serving 306 | the contents of existing keys. CloudFront or CloudFlare could do a great job 307 | caching txpost. 308 | 309 | * Not allowing periods means fewer "is this a filename?" confusions on the 310 | client side. In particular, I am always afraid of web browsers trying to 311 | extension-guess with plugins and extensions, though I'm not aware of it really 312 | happening in practice. Furthermore, services implementing the txpost protocol 313 | have less to worry about from people planting semantically meaningful URLs, 314 | such as robots.txt. 315 | 316 | ## Abuse me not 317 | 318 | Right now we are operating `txpo.st` in a very permissive open way and not 319 | filtering or screening uploads. Let's keep it that way by you not being an ass. 320 | 321 | ## Searching public posts 322 | 323 | In the distant, highly theoretical future, `txpost` may support the ability to 324 | search for public posts, but *only* by specifying the first 32 characters of 325 | the key. We will then find all keys whose names begin with the 32 characters 326 | you supplied. 327 | 328 | This interesting feature implies that: 329 | 330 | 1. Anything posted by the server or public clients is private by default. Thus, 331 | responses to requests cannot be iterated, unless you iterate the entire key 332 | space (which at 256 bits can take some time). 333 | 334 | 2. Public key search could be used as a way for services to discover each other 335 | and communicate without as much centralized control. 336 | 337 | 3. Public key search can be used to provide mutability for data using a simple 338 | well-known protocol described below 339 | 340 | # Public key search to provide mutability 341 | 342 | I'm using abbreviated keys and values here, but I think the meaning is clear. 343 | 344 | ``` 345 | 'buddies is ["Timmy", "Rayray", "Chantel"]; 346 | 'keyy is "friends4now"; 347 | 'arb {"f"take 16 base 16 deal 1}; // dont have a MAX_OCTA const yet :) 348 | 'hash is {x % 7543 * x}; 349 | []arb as 'secret hash as 'hashedsecret; 350 | [buddies,hashedsecret] post keyy; 351 | // later on: 352 | [newbuddies,newhashval] post [keyy,secret]; 353 | ``` 354 | 355 | As human talk: 356 | 357 | 0. All clients decide on a hash function to use for authentication. You might use 358 | SHA, or whatever is popular this week, but these guys are real knuckleheads 359 | so they just use `'hash is {x % 7543 + x}`; 360 | 361 | 1. Client prepares data to publish and creates a 32 character long key. It 362 | doesn't matter what it is as long as all clients know how to find it. 363 | 364 | 2. Client also chooses a random value to act as a "next update key". In this example, 365 | 1826295696 was chosen. Cliet names this `'secret` and stores it away, along with 366 | the 32 character key. 367 | 368 | 2. The data is complex and will need to be amended, so the client also includes 369 | a "next update hash" of `secret hash`, or `7165, which will be publicly visible, but the meaning 370 | of which is difficult to reverse if you are using a good hash function. 371 | 372 | 3. Client discovers that it needs to publish an update, so it does so the same way, 373 | but the key it uses is a combination of the original key, and the original secret value. 374 | 375 | 4. Other clients are scanning for new items whose names begin with the 376 | original's key, and if one is found, they check if the second part of the new 377 | item's key, when hashed, returns the "next update hash" that was supplied in 378 | the first message. 379 | 380 | With a strong hash function, I believe this is safe because the attacker would 381 | not be able to guess what the secret value was that was used to derive the 382 | public next update hash. 383 | 384 | ## Encryption 385 | 386 | My opinion on this is still developing. 387 | 388 | A the risk of being very politically incorrect, I'm not sure I need to encrypt 389 | absolutely everything, especially if it impacts my runtime speed or ability to 390 | swap out hostnames and use IPs. I'd rather allow the user to decide when to 391 | employ encryption when using POST. 392 | 393 | I'd be more inclined to provide a very nice general crypto wrapper API or an 394 | operator-level cipher family with really simple and composable semantics. 395 | 396 | ## Inspiration 397 | 398 | I like some of the behavior that IPFS provides, but it's too complex and 399 | different for me. 400 | 401 | """ 402 | 403 | -------------------------------------------------------------------------------- /examples/ackermann.xxl: -------------------------------------------------------------------------------- 1 | // not yet working 2 | // {y as x} as 'is; 3 | { 4 | x as 'm -1 as 'mm; y as 'n -1 as 'nn; 5 | // ['ack,m,n] show; 6 | self as 'me; 7 | m=0 ifelse( (n+1),{ 8 | n=0 ifelse ( 9 | {mm me 1}, 10 | {m me nn as 'o; mm me o} 11 | )} ) 12 | } as 'ack 13 | 14 | -------------------------------------------------------------------------------- /examples/charclass.xxl: -------------------------------------------------------------------------------- 1 | 'lower is "abcdefghijklmnopqrstuvwxyz"; 2 | 'upper is "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 3 | 'alpha is (upper,lower); 4 | 'digit is "0123456789"; 5 | 'alnum is (alpha,digit); 6 | 'fnsafe is (alnum,"._-"); 7 | 'urlsafe is (alnum,".,-+!$*'()"); 8 | 'xdigit is (digit,"ABCDEFabcdef"); 9 | 'space is " \r\n\t"; 10 | 'blank is " \t"; 11 | 12 | ['lower:lower, 'upper:upper, 'alpha:alpha, 'digit:digit, 13 | 'xdigit: xdigit, 'alnum:alnum, 'fnsafe:fnsafe, 'urlsafe:urlsafe, 14 | 'space: space, 'blank:blank] 15 | 16 | -------------------------------------------------------------------------------- /examples/docs/README.md: -------------------------------------------------------------------------------- 1 | a simple website to read the XXL docs 2 | -------------------------------------------------------------------------------- /examples/docs/hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/examples/docs/hdr.png -------------------------------------------------------------------------------- /examples/docs/layout.xxl: -------------------------------------------------------------------------------- 1 | { 2 | _dir,"css.xxl" load as 'css; 3 | []sys@'ver as 'ver; 4 | " 5 | 6 | 7 | ",x," 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

XXL Workbench

17 | 23 | 24 |
25 |
26 | ",y," 27 |
28 |
29 |
30 | 31 |
32 |
33 | 54 |
55 |

Picture in Picture

56 |

57 | Enter an XXL expression below. Workbench will evaluate it every 5 seconds and show its result in the lower right 58 | of your web browser. 59 |

60 | 61 |
62 |
63 |

Save

64 | Use /save to share your session history up to now. 65 | You can see your previous sessions by typing /load. 66 |

67 | 68 |

Share

69 | Type /share [short dscription] to upload your session to the XXL pastebin. 70 | You'll get back a URL you can send to anyone you want. 71 |

72 | 73 |

74 | Don't worry. Your pastebin uploads aren't shown publicly to anyone unless you share the URL. 75 |

76 |
77 |
78 | * { color: white; font-family:'Open Sans',Arial,'Lucida Grande',sans-serif; } 79 |
80 |
81 | 82 | 83 | " 84 | } 85 | 86 | -------------------------------------------------------------------------------- /examples/docs/server.xxl: -------------------------------------------------------------------------------- 1 | // XXL documentation web site 2 | 3 | "localhost" as 'host; // CONFIG 4 | 8080 as 'port; 5 | 6 | _dir,"layout.xxl" load show as 'pagetmpl; 7 | []sys@'srcpath,"/doc/lang.xxl" load show as 'docs; 8 | 9 | 'safe is ('A is (26count as 'l+65$'char),('a is (l+97$'char)),".,-+!$*'()"); // rfc1738 10 | 'urldec is {;" ",x,"%" split "%" as 'p first behead,(p behead curtail :: 11 | { "0x",(x take 2)base16$'char,(x drop 2)}orelse"") flat}; 12 | 'urlenc is {;"z",x||[]![{in safe not},{"%",(x$'int base 16)}] drop 1 join ""}; 13 | 'wrapresp is {x show str as 'resp len str as 'szs; 14 | "HTTP/1.0 200 OK\r\nContent-Length: ",szs,"\r\n", 15 | "Connection: close\r\n","Server: xxl v0.0\r\n\r\n", 16 | resp}; 17 | 'mkhttp is {; 18 | x as 'handlecb; 19 | { 20 | ['innerhttp,x] noshow; 21 | x first split "\r\n" as 'lines; // HTTP requests are separated with CRLF 22 | lines first split" " as 'method; // separate request line.. GET /file HTTP/1.0 23 | method@1 behead as 'uri show // pull out uri for further inspection and strip leading / 24 | case [ 25 | {uri iftrue {_dir,"pub/",(uri![(uri~"/"condense),"_"]) .file.get as 'content}}, 26 | {content}, 27 | {[method,lines] handlecb} 28 | ] wrapresp 29 | } 30 | }; 31 | 'docsserver is {; 32 | 'lastcat is 0; 33 | "XXL docs" pagetmpl ( 34 | docs :: { 35 | x@'cat=lastcat not ifelse({cat is 'lastcat; "

",(x@'cat),"

"},""), 36 | "

",(x@'name),"

37 |

",(x@'desc),"

" 38 | } 39 | ) 40 | }; 41 | docsserver mkhttp as 'mywebapp; 42 | (port,host) show .net.bind mywebapp as 'handle; 43 | 44 | -------------------------------------------------------------------------------- /examples/factorial.xxl: -------------------------------------------------------------------------------- 1 | {['fac,x] show; self as 'fac; x as 'n < 2 show ifelse [1,{n show * (n-1 fac)}]} 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/ffi.xxl: -------------------------------------------------------------------------------- 1 | _dir,"charclass.xxl" load as 'chclass; 2 | 'incl is { 'srcpath sys as 'sp; 3 | ["def.h","proto.h","accessors.h"] each { "#include \"",sp,"/",x,"\"\n" } 4 | }; 5 | 'arity is {y~"y" any + 1}; // if the source mentions 'y' its arity 2! idiocy.. 6 | // write unary or binary function header, ex: VP xxlffi_myfuncname(VP x,VP y) { .. } 7 | 'funchdr is { 8 | x str as 'lbl; y as 'code; 9 | code arity = 2 ifelse [("VP xxlffi_",lbl,"(VP x,VP y){"),("VP xxlffi_",lbl,"(VP x){")] 10 | }; 11 | // write function body - header n code 12 | 'funcbody is { x funchdr y, 13 | "\n ",y,"\}\n\n" 14 | }; 15 | 'gensrc is { x as 'modn; y as 'funcs; 16 | []incl, 17 | (y key as 'k; y val as 'v; [k,v] >: funcbody) 18 | flat 19 | }; 20 | 'fnsafe {x split [] amend [{not in chclass.fnsafe},"_"] join ""}; 21 | 'compile is { y as 'modulename; y as 'funcs; 22 | ["/tmp/xxlffi-",(modulename fnsafe),".c"] 23 | File.path as 'outfn; 24 | modulename gensrc funcs as 'code show; 25 | [outfn,code] show; 26 | code file.set outfn; 27 | 'compshared from sys," ",outfn as 'cmd 28 | show 29 | // .file.set ([x,".c"] as 'cfn); 30 | // 'buildshared sys ,cfn shell show 31 | }; 32 | 33 | ['compile:compile] 34 | 35 | /* 36 | example: 37 | "examples/ffi.xxl" load as 'ffi; 38 | "/tmp/mymodule" ffi.comp ['double:"x * y"] 39 | */ 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/fibonacci.xxl: -------------------------------------------------------------------------------- 1 | { 2 | x as 'n; self as 'fib; 3 | n show; 4 | n<3 ifelse [1,{n as 'nn; nn-1 fib + (nn-2 fib)}] 5 | } as 'fib 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/groceries-0.xxl: -------------------------------------------------------------------------------- 1 | 'httpresponse is {"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n",(x str)}; 2 | 'taghandlers is ['list:{"
  • ",(x join "
  • "),"
"},'form:{"
"}]; 3 | 'groceriestbl is (['item,'bought]:[["Telescope carrying case", 0], ["Large elevator shim", 1]]); 4 | 'tobuy is {;{x@'bought=0} from groceriestbl}; 5 | 'thelist is {'list#([]tobuy@'item)}; 6 | 'updform is {'form#["add","item"]}; 7 | 'myapp is {x show; [thelist,updform] :: {[]x as 'item tag from taghandlers@item show} join "" httpresponse}; 8 | [8080,""] Net.bind myapp 9 | -------------------------------------------------------------------------------- /examples/json.xxl: -------------------------------------------------------------------------------- 1 | // enclose (c)urly(b)races, (s)quare(b)brackets, (q)uotes: 2 | 'ecb is {"{",x,"}"}; 'esb is {"[",x,"]"}; 'eq is {"\"",x,"\""}; 3 | 'jc is {join ","}; 'jac is {each y jc}; // join x with commas; apply y to each of x then join with commas 4 | 'pair is {encode,":",(y encode)}; // key:val pair for dict 5 | 'dict is {key as 'k; x val as 'v; [k],v >: pair jc ecb}; // get keys/vals, pair merge, commas, braces 6 | 7 | // wrap non-scalar values in appropriate way: 8 | 'many is {as 'el type case ('char, {el str eq}, 'dict, {el dict}, {el jac encode esb})}; 9 | 'encode is {ravel[many,str]}; // ravel calls x y[0] for arrays (len > 1), x y[1] for scalars 10 | 11 | 'test is { 12 | "hello" encode show; 13 | ["hello","there"] encode show; 14 | ['name:(1,2,3)] encode show; 15 | ['name:"Tom",'age:12] encode show; 16 | ['a:1,'b:2]$'table,['a:4,'b:5],['a:7,'b:8] encode show; 17 | }; 18 | [] test; 19 | 20 | -------------------------------------------------------------------------------- /examples/to-c.xxl: -------------------------------------------------------------------------------- 1 | 'id is {valctr as 'c+1 as 'valctr; x str,(c str) as 'id; id,ids as 'ids; id}; 2 | 'codebody is "//hello\n512 * 20 count sum"; 3 | 1 as 'valctr; // identifier # counter 4 | [""] as 'ids; // list of generated IDs 5 | 'pt is (codebody parse); // create parse tree from code string 6 | pt show; 7 | 'fmt_cmnt is {x}; // comments contain leading 8 | 'fmt_val is {"VP val",(y id),"=",x,";"}; // assign literal value to tmp VP 9 | 'fmt_int is {"ANONVAL(xi(",(x str),"))" fmt_val 'num}; // an integer 10 | 'fmt_name is {"getctx(CURCTX,ANONSTR(\"",(x str),"\"))" fmt_val 'ref}; // resolve in current ctx 11 | 'fmt_ws is {;}; // drop whitespace 12 | 'fmt_str is {x as 'el // different types of tagged strings 13 | tag case('comment,{el fmt_cmnt}, // depending on the tag: dispatch comments 14 | 'raw,{el fmt_resolve_name}, 'name,{el fmt_resolve_name}, // ..tagged names and unresolved literals, 15 | fmt_ws) flat}; // ..or whitespace 16 | pt :: {as 'el type case ('char,{el fmt_str}, 'int,{el fmt_int}, el)} join "\n" show; // generate/join code strings 17 | ids :: {"apply(",x,", "} // create expression (using reversed ids list) here 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/trees.xxl: -------------------------------------------------------------------------------- 1 | /* 2 | Parent-child trees in the style of Stevan Apter 3 | Please see the phenomenal 4 | http://archive.vector.org.uk/art10500340 5 | for full description of the technique. 6 | 7 | Sample data below: 8 | 9 | # tree path 10 | - ----- -------- 11 | 0 A A 12 | 1 B A B 13 | 2 C A B C 14 | 3 D A B D 15 | 4 E A E 16 | 5 F A E F 17 | 6 G A E F G 18 | 7 H A E F H 19 | 8 I A E F I 20 | 21 | Arthur has some interesting examples as well: 22 | http://kx.com/q/tree.q 23 | */ 24 | 25 | 'a,'b,'c,'d,'e,'f,'g,'h,'i as 'tree; 26 | 0,0,1,1,0,4,5,5,5 as 'p; 27 | 'leaves is {x len count except x}; 28 | 'paths is {x as 'p len count :: {x,(x recurse p$'int)flat}}; 29 | 30 | -------------------------------------------------------------------------------- /examples/web-ctr.xxl: -------------------------------------------------------------------------------- 1 | 2 | 'make_http_response is { 3 | [ 4 | "HTTP/1.0 200 OK", 5 | "Content-Type: text/plain", 6 | "Connection: close", 7 | "Server: xxl v0.0" 8 | ] show as 'template; 9 | template join "\r\n", 10 | "\r\n", 11 | "\r\n", 12 | x, 13 | "\r\n", 14 | "\r\n" 15 | flat 16 | }; 17 | 18 | 0 as 'ctr; 19 | 20 | (8080,"localhost") Net.bind { 21 | ctr + 1 as '.ctr repr make_http_response 22 | } 23 | -------------------------------------------------------------------------------- /examples/web-static-files.xxl: -------------------------------------------------------------------------------- 1 | "./html/" as 'root; 2 | { 3 | y as 'callback; 4 | x .net.bind { 5 | ['calling, x, callback] show; 6 | x callback as 'result; 7 | ['result,result] show; 8 | result type='char ifelse(result,{ 9 | "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n", 10 | "Server: xxl v0.0\r\n\r\n", 11 | (result flat) 12 | }) 13 | }; 14 | 'ok 15 | } as 'b; 16 | ['bind:b] as '.web; 17 | 18 | -------------------------------------------------------------------------------- /net.c: -------------------------------------------------------------------------------- 1 | // NETWORKING 2 | 3 | #include "def.h" 4 | #include "proto.h" 5 | #include "accessors.h" 6 | #include "vary.h" 7 | 8 | #ifdef STDLIBNET 9 | #define NETLOOPBLK IOBLOCKSZ 10 | int netr(int sock,void* b,size_t maxl) { 11 | return read(sock,b,maxl); // TODO chunk 12 | } 13 | VP netw(int sock,VP buf) { 14 | XRAY_log("netw %d\n",sock);XRAY_emit(buf); 15 | if(buf==NULL) return NULL; 16 | if(!IS_b(buf)&&!IS_c(buf)) return EXC(Tt(type),"netw only strings",xi(sock),buf); 17 | if(write(sock,BUF(buf),buf->n)n) PERR("netw"); 18 | return NULL; 19 | } 20 | VP netcall(VP data,VP addr) { 21 | int sock=socket(AF_INET, SOCK_STREAM, 0); 22 | struct sockaddr_in sin={0}; sin.sin_family=AF_INET; // TODO IPv6 23 | int port=AS_i(ELl(addr,0),0); sin.sin_port=htons(port); 24 | if(LEN(addr) > 1 && IS_c(ELl(addr,1))) { 25 | char host[64]={0}; 26 | strncpy(host,bfromx(ELl(addr,1)),64); 27 | struct hostent* server=gethostbyname(host); 28 | if(server==NULL)return EXC(Tt(host),"hostname not found",data,addr); 29 | bcopy((char*)server->h_addr,(char*)&sin.sin_addr.s_addr,server->h_length); 30 | } 31 | if(connect(sock,(struct sockaddr *)&sin, sizeof(sin)) < 0) { 32 | char* err=malloc(256); int len; 33 | snprintf(err,256,"couldn't connect to host/port: "); 34 | len=strlen(err); 35 | strerror_r(errno, err+len, 256-len); 36 | return EXC(Tt(call),err,data,addr); 37 | } 38 | VP w=netw(sock,data); if(w) return w; 39 | char input[NETLOOPBLK]={0}; 40 | int nread=netr(sock, input, NETLOOPBLK-1); 41 | shutdown(sock,SHUT_RDWR); close(sock); 42 | if(nread>0) { // dont i have a primitive for this 43 | VP res=xcsz(nread); memmove(BUF(res),input,nread); res->n=nread; return res; 44 | } else return NULL; 45 | } 46 | VP netserve(VP sockcb) { 47 | int sock=AS_i(LIST_item(sockcb,0),0), nread; 48 | VP cb=LIST_item(sockcb,1); 49 | VP resp, t1, t2, t3; 50 | char input[NETLOOPBLK]; 51 | /* 52 | if(remotea.sa_family==AF_INET) 53 | ip = inet_ntoa(((struct sockaddr_in *)&remotea)->sin_addr); 54 | else 55 | ip = "n/a"; 56 | */ 57 | XRAY_log("new connection %d\n",sock); 58 | memset(input, 0, NETLOOPBLK); 59 | nread=netr(sock, input, NETLOOPBLK-1); 60 | XRAY_log("read result %d\n", nread); 61 | if(nread > 0) { 62 | t1=xfroms(input); t2=xfroms("n/a"); t3=xln(2,t1,t2); 63 | resp=apply(cb,t3); 64 | xfree(t3);xfree(t2);xfree(t1); 65 | XRAY_log("netloop handler resp for %d\n",sock); XRAY_emit(resp); 66 | if(resp!=NULL && !IS_c(resp)) { 67 | XRAY_log("massaging\n");XRAY_emit(resp); 68 | resp=repr(resp); 69 | } 70 | netw(sock,resp); 71 | xfree(resp); 72 | } 73 | shutdown(sock,SHUT_RDWR); 74 | XRAY_log("netloop closing %d\n",sock); 75 | close(sock); 76 | return NULL; 77 | } 78 | VP netloop(VP xsock,VP cb) { 79 | int cons; 80 | struct sockaddr remotea={0}; 81 | socklen_t remotel={0}; 82 | int sock=AS_i(xsock,0); 83 | int n=0; 84 | printf("netloop starting..\n"); 85 | XRAY_emit(xsock); 86 | XRAY_emit(cb); 87 | for(;;) { 88 | printf("."); 89 | cons=accept(sock, &remotea, &remotel); 90 | netserve(xln(2,xi(cons),cb)); 91 | // thr_run1(x1(&netserve),xln(2,xi(cons),cb)); 92 | n++; 93 | } 94 | XRAY_log("netloop closing sock after %d\n",n); 95 | close(sock); 96 | return xl0(); 97 | } 98 | VP netbind(VP opts,VP cb) { 99 | XRAY_log("netbind\n");XRAY_emit(opts);XRAY_emit(cb); 100 | if(!LIST(opts)) return EXC(Tt(type),"bad network bind options",opts,cb); 101 | int sock, opt, port; 102 | char host[64]; 103 | struct linger lf= {0}; 104 | struct sockaddr_in sin= {0}; 105 | struct sockaddr remote; 106 | socklen_t remotel; 107 | sock=socket(sin.sin_family=AF_INET,SOCK_STREAM,IPPROTO_TCP); 108 | opt=1; 109 | setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); 110 | /* 111 | lf.l_onoff=1; 112 | lf.l_linger=0; 113 | setsockopt(sock,SOL_SOCKET,SO_LINGER,&lf,sizeof(lf)); 114 | */ 115 | //opt=5; setsockopt(sock,SOL_TCP,TCP_DEFER_ACCEPT,&opt,sizeof(opt)); 116 | if(!IS_i(ELl(opts,0))) return EXC(Tt(port),"bad port",opts,cb); 117 | port=AS_i(ELl(opts,0),0); 118 | sin.sin_port=htons(port); 119 | if(ELl(opts,1)->n >= 1 && IS_c(ELl(opts,1))) { 120 | strncpy(host,bfromx(ELl(opts,1)),64); 121 | if(inet_aton(host,&sin.sin_addr)==-1)return EXC(Tt(host),"hostname not found",opts,cb); 122 | } 123 | if(bind(sock,(struct sockaddr*)&sin,sizeof(sin))) { 124 | char* err=malloc(256); int len; 125 | snprintf(err,256,"couldn't bind to host/port: "); 126 | len=strlen(err); 127 | strerror_r(errno, err+len, 256-len); 128 | return EXC(Tt(bind),err,opts,cb); 129 | } 130 | listen(sock, 10); // XXX smarter listen backlog 131 | xref(cb); 132 | VP xsock=xi(sock); 133 | xref(xsock); 134 | thr_run(proj(2,&netloop,xsock,cb)); 135 | printf("net booted\n"); 136 | XRAY_emit(cb); 137 | return opts; 138 | } 139 | #endif 140 | 141 | -------------------------------------------------------------------------------- /proto.h: -------------------------------------------------------------------------------- 1 | // prototypes 2 | 3 | // from xxl.c 4 | VP abss(VP x); 5 | int _any(VP x); 6 | VP amend(VP x,VP y); 7 | VP and(VP x,VP y); 8 | VP any(VP x); 9 | VP apply(VP x,VP y); 10 | VP apply_simple_(VP x,int i); // faster way to index a simple type as new value 11 | VP apply2(const VP f,const VP x,const VP y); 12 | VP applyctx(VP ctx,VP x,VP y); 13 | VP append(VP x,VP y); 14 | VP appendbuf(VP x,buf_t buf,size_t nelem); 15 | int _arity(VP x); 16 | VP arity(VP x); 17 | VP aside(VP x,VP y); 18 | VP assign(VP x,VP k,VP val); 19 | VP base(VP x,VP y); 20 | VP behead(VP x); // everything except the first element 21 | const char* bfromx(VP x); 22 | VP bracketjoin(VP x,VP y); 23 | VP casee(VP x,VP y); 24 | VP cast(VP x,VP y); 25 | VP capacity(VP x); 26 | VP catenate(VP x,VP y); 27 | VP catenate_table(VP table, VP row); 28 | VP classdispatch(const VP ctx,const VP verb,const VP x,const VP y); 29 | VP clone(VP obj); 30 | VP condense(VP x); 31 | VP consecutivejoin(VP x, VP y); 32 | int _contains(VP x, VP y); 33 | VP contains(VP x, VP y); 34 | VP count(VP x); 35 | VP curtail(VP x); // everything except the last element 36 | VP deal(VP x,VP y); 37 | VP deep(VP obj,VP f); 38 | VP del(VP x,VP y); 39 | VP dict(VP x,VP y); 40 | VP divv(VP x,VP y); 41 | VP drop_(VP x,int i); 42 | VP drop(VP x,VP y); 43 | VP each(VP obj,VP fun); 44 | VP eachboth(VP obj,VP fun); 45 | VP eachleft(VP obj,VP fun); 46 | VP eachpair(VP obj,VP fun); 47 | VP eachright(VP obj,VP fun); 48 | VP emit(VP obj,VP tag); 49 | VP enlist(VP x); 50 | VP entag(VP x,VP t); 51 | VP entags(VP x,const char* name); 52 | int _equalm(const VP x,const int xi,const VP y,const int yi); 53 | int _equal(const VP x,const VP y); 54 | VP equal(const VP x,const VP y); 55 | VP evalin(VP str,VP ctx); 56 | VP evalinwith(VP tree,VP ctx,VP xarg); 57 | VP evalstrin(const char* str,VP ctx); 58 | VP evalstrinwith(const char* str, VP ctx, VP xarg); 59 | VP except(VP x,VP y); 60 | VP exhaust0(const VP x,const VP y,int collect); 61 | VP exhaust(const VP x,const VP y); 62 | VP extract(VP data,VP parts); 63 | VP extractas(VP data,VP parts); 64 | int _find1(VP x,VP y); 65 | int _findbuf(const VP x,const buf_t y); // returns index or -1 on not found 66 | VP find1(const VP x, const VP y); 67 | VP first(VP x); 68 | VP flatten(VP x); 69 | VP from(const VP x,const VP y); 70 | VP lookup(VP x,VP y); 71 | VP get(VP x); 72 | VP greater(VP x,VP y); 73 | VP identity(VP x); 74 | VP info(VP x); 75 | VP ifelse(VP x,VP y); 76 | VP iftrue(VP x,VP y); 77 | void init_thread_locals(); 78 | VP itemsz(VP x); 79 | VP join(VP list,VP sep); 80 | VP last(VP x); 81 | int _len(VP x); 82 | VP len(VP x); 83 | VP lesser(VP x,VP y); 84 | VP list(const VP x); // convert x to general list 85 | VP list2vec(VP obj); 86 | VP loadin(VP fn,VP ctx); 87 | VP key(const VP x); 88 | VP match(VP obj,VP pat); 89 | VP matchall(VP obj,VP pat); 90 | VP matchany(VP obj,VP pat); 91 | VP matcheasy(VP obj,VP pat); 92 | VP matchtag(VP obj,VP pat); 93 | int matchpass(VP obj,VP pat); 94 | VP make(VP x,VP y); 95 | VP make_table(VP keys,VP vals); 96 | VP matchall(VP obj,VP pat); 97 | VP matchany(VP obj,VP pat); 98 | VP matcheasy(VP obj,VP pat); 99 | VP matchexec(VP obj,VP pats); 100 | VP matchtag(const VP obj,const VP pat); 101 | VP max(VP x); 102 | VP mkworkspace(); 103 | VP min(VP x); 104 | VP minus(VP x,VP y); 105 | VP mod(VP x,VP y); 106 | VP neg(VP x); 107 | VP nest(VP x,VP y); 108 | VP not(VP x); 109 | VP numelem2base(VP num,int i,int base); 110 | VP orelse(VP x,VP y); 111 | VP over(VP x,VP y); 112 | VP or(VP x,VP y); 113 | VP parse(VP x); 114 | VP parseloopoper(VP x); 115 | VP parsestr(const char* str); 116 | VP partgroups(VP x); 117 | VP pick(VP x,VP y); // select items of x[0..n] where y[n]=1 118 | VP pickapart(VP x,VP y); 119 | VP pin(VP x,VP y); 120 | VP plus(VP x,VP y); 121 | VP proj(int type, void* func, VP left, VP right); 122 | VP range_(int start, int end); 123 | VP range(VP x,VP y); 124 | VP ravel(VP x,VP y); 125 | VP recurse(VP x,VP y); 126 | VP resolve(VP ctx,VP ptree); 127 | VP resolvekey(VP dict,VP key,int checkparents); 128 | void repl(VP ctx); 129 | VP repr(VP x); 130 | char* repr0(VP x,char* s,size_t len); 131 | char* reprA(VP x); 132 | VP reverse(VP x); 133 | VP rootctx(); 134 | VP scan(const VP x,const VP y); // returns a list if result vals dont match 135 | VP selftest(VP x); 136 | VP set(VP ctx,VP k,VP v); 137 | VP set_as(VP x,VP y); // as 138 | VP set_is(VP x,VP y); // is 139 | char* sfromxA(VP x); 140 | VP shift_(VP x,int i); 141 | VP shift(VP x,VP y); 142 | VP show(VP x); 143 | VP signaljoin(VP x,VP y); 144 | VP split(VP x,VP tok); 145 | VP str(VP x); 146 | VP str2num(VP x); 147 | VP str2tag(VP str); // turns string, or list of strings, into tag vector 148 | VP sum(VP x); 149 | VP sums(VP x); 150 | VP sys(VP x); 151 | VP table_row_dict_(VP tbl, int row); 152 | VP table_row_list_(VP tbl, int row); 153 | VP tagname(tag_t tag); 154 | const char* tagnames(const tag_t tag); 155 | VP tag(VP x); 156 | VP tagv(const char* name, VP x); 157 | VP take_(VP x,int i); 158 | VP take(VP x,VP y); 159 | tag_t _tagnum(VP name); 160 | tag_t _tagnums(const char* name); 161 | VP times(VP x,VP y); 162 | type_info_t typeinfo(type_t n); 163 | type_info_t typechar(char c); 164 | VP type(VP x); 165 | VP unionn(VP x,VP y); // available via or() 166 | VP upsert(VP x,VP y); 167 | int _upsertidx(VP x,VP y); 168 | VP val(const VP x); 169 | VP wide(VP obj,VP f); 170 | VP xalloc(type_t t,I32 initn); 171 | VP xfillrange(VP x,int from,int to,int byteval); 172 | VP xfree(VP x); 173 | VP xfroms(const char* str); 174 | VP xor(VP x,VP y); 175 | VP xray(VP x); 176 | VP xrealloc(VP x,I32 newn); 177 | VP xref(VP x); 178 | VP xreplace(VP x,VP newval); 179 | VP xsplice(const VP x,const VP idx,const VP replace); 180 | 181 | #ifdef THREAD 182 | void thr_run(VP ctx); 183 | void thr_run1(VP ctx,VP arg); 184 | #endif 185 | 186 | #ifdef STDLIBNET 187 | // from net.c 188 | VP netcall(VP data,VP addr); 189 | VP netbind(VP opts,VP callback); 190 | VP netloop(VP xsock,VP cb); 191 | #endif 192 | 193 | #ifdef STDLIBMBOX 194 | // from net.c 195 | VP mboxnew(VP x); 196 | VP mboxsend(VP mbox,VP msg); 197 | VP mboxpeek(VP mbox); 198 | VP mboxrecv(VP mbox); 199 | VP mboxquery(VP mbox,VP msg); 200 | VP mboxwait(VP mbox); // equivalent to recv, but will block until something comes in 201 | VP mboxwatch(VP mbox,VP cb); 202 | #endif 203 | 204 | #ifdef STDLIBFILE 205 | // stdlib 206 | VP filebasename(VP fn); 207 | VP filedirname(VP fn); 208 | VP filecwd(VP dummy); 209 | VP fileget(VP fn); 210 | VP filels(VP path); 211 | VP filepath(VP pathlist); 212 | VP fileset(VP str,VP fn); 213 | #endif 214 | 215 | #ifdef STDLIBSHAREDLIB 216 | VP sharedlibget(VP fn); 217 | VP sharedlibset(VP fn,VP funs); 218 | #endif 219 | 220 | #ifdef STDLIBSHELL 221 | VP shellget(VP cmd); 222 | #endif 223 | 224 | #ifdef STDLIBXD 225 | VP xdget(VP fname); 226 | VP xdset(VP fname,VP data); 227 | #endif 228 | 229 | -------------------------------------------------------------------------------- /repl.c: -------------------------------------------------------------------------------- 1 | // TODO transcripts ("test.txt" log) 2 | // TODO .xxlrc 3 | // TODO clear memory 4 | // TODO turn off inputs/outputs 5 | #include "def.h" 6 | #include "proto.h" 7 | #include "accessors.h" 8 | #include "vary.h" 9 | 10 | void banner() { 11 | printf("XXL %s by @tlack; http://github.com/tlack/xxl/\n",XXL_VER); 12 | } 13 | 14 | VP randtip() { 15 | VP tips=xl0(); 16 | tips=append(tips,xfroms("you can trace your program's behavior. type 'xray' to try it out.")); 17 | tips=append(tips,xfroms("type 'memwatch' to see how your program allocates memory.")); 18 | tips=append(tips,xfroms("you can reference previous commands or program output like a regular variable. type 'inputs first' or 'outputs last' to see.")); 19 | tips=append(tips,xfroms("is your XXL acting wonky? run the self tests with '[] selftest'. you can find their source in 'test-*.h'.")); 20 | VP tip=deal(tips,XI1); 21 | xfree(tips); 22 | return tip; 23 | } 24 | 25 | void tip() { 26 | VP before=xfroms("tip: "),after=xfroms(" ('tip' for more)"); 27 | VP tip=randtip(); 28 | VP str=flatten(catenate(catenate(before,tip),after)); 29 | show(str); 30 | xfree(str);xfree(tip);xfree(after);xfree(before); 31 | } 32 | 33 | void showexc(VP ctx,VP exc) { 34 | int i; VP clue,csel,strs=xfroms("code\nmessage\nx\ny"), labels=split(strs,xc('\n')); 35 | show(exc); 36 | printf("Oops. Exception:\n"); 37 | /* 38 | csel=xln(2,Tt(repl),Tt(clues)); clue=get(ctx,csel); 39 | if(!IS_EXC(clue)) { 40 | DUMP(clue); 41 | VP specific = apply(clue,ELl(exc,0)); 42 | printf("spec=%s\n", reprA(specific)); 43 | VP tmp = apply(specific,xln(2,Tt(caughtexec),exc)); 44 | printf("tmp=%s\n", reprA(tmp)); 45 | xfree(tmp); xfree(specific); 46 | } 47 | xfree(clue);xfree(csel); 48 | */ 49 | for(i=0;in;i++) { 50 | char* s=sfromxA(ELl(labels,i)); 51 | printf("%s: ",s); 52 | show(ELl(exc,i)); 53 | free(s); 54 | } 55 | xfree(labels); xfree(strs); 56 | } 57 | 58 | void repl(VP ctx) { 59 | VP in,out,t1,t2,t3; 60 | #define LINESZ 1024 61 | char line[LINESZ]; 62 | char* ret; 63 | int i; 64 | clock_t st,en; 65 | 66 | in=xl0(); 67 | set(ctx,Tt(inputs),in); 68 | out=xl0(); 69 | set(ctx,Tt(outputs),out); 70 | #ifdef STDLIBFILE 71 | set(ctx,Tt(_dir),filecwd(XI0)); 72 | #endif 73 | 74 | i=0; 75 | banner(); 76 | tip(); 77 | printf("\n"); 78 | 79 | for(;;) { 80 | // printf("xxl@%s> ", bfromx(get(ctx,t1))); 81 | //XRAY_LVL=2; 82 | printf("%d. ",i); 83 | memset(line, 0, LINESZ); 84 | ret = fgets(line, LINESZ, stdin); 85 | if(ret == NULL) 86 | break; 87 | if(line[0] == 0 || strncmp(line,"\n",LINESZ)==0) continue; 88 | if(strncmp(line,"\\\\\n",LINESZ)==0 || 89 | strncmp(line,"exit\n",LINESZ)==0 || 90 | strncmp(line,"quit\n",LINESZ)==0) 91 | break; 92 | if(strncmp(line,"clear\n",LINESZ)==0) { 93 | i=0; 94 | each(in,x1(&xfree)); in->n=0; 95 | each(out,x1(&xfree)); out->n=0; 96 | printf("\n\n----------------------------------------------\n\n"); // for text logs/scrollback 97 | printf("\033[2J\033[;H\033[0m"); 98 | continue; 99 | } 100 | if(strncmp(line,"tip\n",LINESZ)==0) { 101 | tip(); 102 | continue; 103 | } 104 | if(strncmp(line,"memwatch\n",LINESZ)==0) { 105 | if(MEM_WATCH) printf("memwatch off\n"),MEM_WATCH=0; 106 | else printf("memwatch on\n"),MEM_WATCH=1; 107 | continue; 108 | } 109 | if(strncmp(line,"xray\n",LINESZ)==0) { 110 | VP cmd; 111 | if(XRAY_LVL) cmd=xfroms("0 xray"); 112 | else cmd=xfroms("1 xray"); 113 | show(evalin(cmd,ctx)); 114 | xfree(cmd); 115 | continue; 116 | } 117 | st=clock(); 118 | t2=parsestr(line); 119 | in=append(in,t2); 120 | ctx=append(ctx,t2); // set code body for this context - doesnt actually append 121 | xfree(t2); 122 | t3=applyctx(ctx,NULL,NULL); 123 | en=clock(); 124 | printf("(%0.04f sec)\ninputs@%d: %s", ((double)(en-st)/CLOCKS_PER_SEC), i, line); 125 | if(t3==NULL) { 126 | out=append(out,xl0()); 127 | printf("null\n"); 128 | } else if(!IS_EXC(t3)) { 129 | out=append(out,t3); 130 | printf("outputs@%d:\n%s\n", i, bfromx(repr(t3))); 131 | } else { 132 | out=append(out,Tt(exception)); 133 | showexc(ctx,t3); 134 | } 135 | xfree(t3); 136 | printf("\n"); // the horror! 137 | i++; 138 | } 139 | xfree(in); 140 | xfree(out); 141 | return; 142 | } 143 | -------------------------------------------------------------------------------- /repr.h: -------------------------------------------------------------------------------- 1 | // Autogenerated file; see corresponding .js 2 | 3 | char* repr_b(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 4 | IF_RET(xn==0,FMT_into_s(sz,"xb0()",0)); 5 | if(!SIMPLE(x)) { FMT_into_s(sz,"'b(...)",0); return s; } 6 | else if(xn>1) FMT_into_s(sz,"(",0); 7 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 8 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 9 | for(i=0;in>1) FMT_into_s(sz,")",0); 18 | return s; } 19 | 20 | char* repr_i(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 21 | IF_RET(xn==0,FMT_into_s(sz,"xi0()",0)); 22 | if(!SIMPLE(x)) { FMT_into_s(sz,"'i(...)",0); return s; } 23 | else if(xn>1) FMT_into_s(sz,"(",0); 24 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 25 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 26 | for(i=0;in>1) FMT_into_s(sz,")",0); 35 | return s; } 36 | 37 | char* repr_j(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 38 | IF_RET(xn==0,FMT_into_s(sz,"xj0()",0)); 39 | if(!SIMPLE(x)) { FMT_into_s(sz,"'j(...)",0); return s; } 40 | else if(xn>1) FMT_into_s(sz,"(",0); 41 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 42 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 43 | for(i=0;in>1) FMT_into_s(sz,")",0); 52 | return s; } 53 | 54 | char* repr_f(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 55 | IF_RET(xn==0,FMT_into_s(sz,"xf0()",0)); 56 | if(!SIMPLE(x)) { FMT_into_s(sz,"'f(...)",0); return s; } 57 | else if(xn>1) FMT_into_s(sz,"(",0); 58 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 59 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 60 | for(i=0;in>1) FMT_into_s(sz,")",0); 69 | return s; } 70 | 71 | char* repr_1(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 72 | IF_RET(xn==0,FMT_into_s(sz,"x10()",0)); 73 | if(!SIMPLE(x)) { FMT_into_s(sz,"'1(...)",0); return s; } 74 | else if(xn>1) FMT_into_s(sz,"(",0); 75 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 76 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 77 | for(i=0;in>1) FMT_into_s(sz,")",0); 86 | return s; } 87 | 88 | char* repr_2(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; 89 | IF_RET(xn==0,FMT_into_s(sz,"x20()",0)); 90 | if(!SIMPLE(x)) { FMT_into_s(sz,"'2(...)",0); return s; } 91 | else if(xn>1) FMT_into_s(sz,"(",0); 92 | if(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) { 93 | skipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; } 94 | for(i=0;in>1) FMT_into_s(sz,")",0); 103 | return s; } 104 | 105 | -------------------------------------------------------------------------------- /repr.js: -------------------------------------------------------------------------------- 1 | var lib = require('./common.js'); 2 | console.log(lib.prelude); 3 | lib.each(lib.types, function(t) { 4 | if(t[6] == true) return; 5 | var tmpls = [ 6 | "char* repr_{{1}}(VP x,char* s,size_t sz) { int i,xn=x->n,skipn=0,skipstart=-1,skipend=-1; \n"+ 7 | "\tIF_RET(xn==0,FMT_into_s(sz,\"x{{1}}0()\",0));\n" + 8 | "\tif(!SIMPLE(x)) { FMT_into_s(sz,\"'{{1}}(...)\",0); return s; }\n"+ 9 | "\telse if(xn>1) FMT_into_s(sz,\"(\",0);\n"+ 10 | "\tif(REPR_MAX_ITEMS && xn > REPR_MAX_ITEMS) {\n"+ 11 | "\t\tskipn=xn-REPR_MAX_ITEMS; skipstart=(xn-skipn)/2; skipend=(xn+skipn)/2; }\n"+ 12 | "\tfor(i=0;in>1) FMT_into_s(sz,\")\",0);\n"+ 21 | "return s; }\n" 22 | ]; 23 | lib.each(tmpls,function(tmpl) { 24 | console.log(lib.exhaust(lib.projr(lib.repl,t),tmpl)); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /rootctx.h: -------------------------------------------------------------------------------- 1 | 2 | // postfix/unary operators 3 | // .. sequences and lists 4 | res=assign(res,xt(_tagnums(".|")),x1(&first)); 5 | res=assign(res,xt(_tagnums("|.")),x1(&last)); 6 | res=assign(res,xt(_tagnums("_|")),x1(&curtail)); 7 | res=assign(res,xt(_tagnums("|_")),x1(&behead)); 8 | // ..logic 9 | res=assign(res,xt(_tagnums("~>")),x1(&condense)); 10 | // named postfix verbs: 11 | res=assign(res,Tt(any),x1(&any)); 12 | res=assign(res,Tt(arity),x1(&arity)); 13 | res=assign(res,Tt(behead),x1(&behead)); 14 | res=assign(res,Tt(condense),x1(&condense)); 15 | res=assign(res,Tt(count),x1(&count)); 16 | res=assign(res,Tt(clone),x1(&clone)); 17 | res=assign(res,Tt(curtail),x1(&curtail)); 18 | res=assign(res,Tt(enlist),x1(&enlist)); 19 | res=assign(res,Tt(info),x1(&info)); 20 | res=assign(res,Tt(first),x1(first)); 21 | res=assign(res,Tt(flat),x1(&flatten)); 22 | res=assign(res,Tt(get),x1(&get)); 23 | res=assign(res,Tt(last),x1(&last)); 24 | res=assign(res,Tt(list),x1(&list)); 25 | res=assign(res,Tt(len),x1(&len)); 26 | res=assign(res,Tt(key),x1(&key)); 27 | res=assign(res,Tt(min),x1(&min)); 28 | res=assign(res,Tt(max),x1(&max)); 29 | res=assign(res,Tt(neg),x1(&neg)); 30 | res=assign(res,Tt(not),x1(¬)); 31 | res=assign(res,Tt(parse),x1(&parse)); 32 | res=assign(res,Tt(ranges),x1(&partgroups)); 33 | res=assign(res,Tt(repr),x1(&repr)); 34 | res=assign(res,Tt(rev),x1(&reverse)); 35 | res=assign(res,Tt(same),x1(&identity)); 36 | #ifdef DEBUG 37 | res=assign(res,Tt(selftest),x1(&selftest)); 38 | #endif 39 | res=assign(res,Tt(show),x1(&show)); 40 | res=assign(res,Tt(str),x1(&str)); 41 | res=assign(res,Tt(sum),x1(&sum)); 42 | res=assign(res,Tt(sums),x1(&sums)); 43 | res=assign(res,Tt(sys),x1(&sys)); 44 | res=assign(res,Tt(tag),x1(&tag)); 45 | res=assign(res,Tt(type),x1(&type)); 46 | res=assign(res,Tt(val),x1(&val)); 47 | res=assign(res,Tt(vec),x1(&list2vec)); 48 | res=assign(res,Tt(ver),xi(0)); 49 | res=assign(res,Tt(xray),x1(&xray)); 50 | 51 | // infix/binary verbs 52 | // operators: 53 | // .. sequences and lists: 54 | res=assign(res,xt(_tagnums("|,")),x2(&join)); 55 | res=assign(res,xt(_tagnums("||")),x2(&split)); 56 | res=assign(res,xt(_tagnums("#|")),x2(&take)); 57 | res=assign(res,xt(_tagnums("|#")),x2(&drop)); 58 | res=assign(res,xt(_tagnums("|?")),x2(&except)); 59 | // .. looping: 60 | res=assign(res,xt(_tagnums(".:")),x2(&from)); 61 | res=assign(res,Tt(::),x2(&each)); 62 | res=assign(res,xt(_tagnums(">:")),x2(&eachboth)); 63 | res=assign(res,xt(_tagnums("\\:")),x2(&eachleft)); 64 | res=assign(res,xt(_tagnums("/:")),x2(&eachright)); 65 | res=assign(res,xt(_tagnums("<:")),x2(&eachpair)); 66 | res=assign(res,xt(_tagnums("':")),x2(&over)); 67 | res=assign(res,xt(_tagnums(",:")),x2(&scan)); 68 | res=assign(res,xt(_tagnums("!:")),x2(&exhaust)); 69 | // .. math: 70 | res=assign(res,Tt(=),x2(&equal)); 71 | res=assign(res,Tt(+),x2(&plus)); 72 | res=assign(res,Tt(-),x2(&minus)); 73 | res=assign(res,Tt(*),x2(×)); 74 | res=assign(res,Tt(/),x2(&divv)); 75 | res=assign(res,Tt(%),x2(&mod)); 76 | res=assign(res,Tt(&),x2(&and)); 77 | res=assign(res,Tt(|),x2(&or)); 78 | res=assign(res,Tt(^),x2(&xor)); 79 | res=assign(res,xt(_tagnums("<")),x2(&lesser)); 80 | res=assign(res,xt(_tagnums(">")),x2(&greater)); 81 | // .. misc: 82 | res=assign(res,Tt(!),x2(&amend)); 83 | res=assign(res,Tt(@),x2(&apply)); 84 | res=assign(res,Tt(:),x2(&dict)); 85 | res=assign(res,Tt(?),x2(&find1)); 86 | res=assign(res,Tt($),x2(&make)); 87 | res=assign(res,Tt(#),x2(&pin)); 88 | res=assign(res,Tt(~),x2(&matchall)); 89 | res=assign(res,xt(_tagnums(",")),x2(&catenate)); 90 | // named infix verbs: 91 | res=assign(res,Tt(amend),x2(&amend)); 92 | res=assign(res,Tt(and),x2(&and)); 93 | res=assign(res,Tt(as),x2(&set_as)); 94 | res=assign(res,Tt(aside),x2(&aside)); 95 | res=assign(res,Tt(base),x2(&base)); 96 | res=assign(res,Tt(bracketj),x2(&bracketjoin)); 97 | res=assign(res,Tt(case),x2(&casee)); 98 | res=assign(res,Tt(consecj),x2(&consecutivejoin)); 99 | res=assign(res,Tt(deal),x2(&deal)); 100 | res=assign(res,Tt(deep),x2(&deep)); 101 | res=assign(res,Tt(del),x2(&del)); 102 | res=assign(res,Tt(drop),x2(&drop)); 103 | res=assign(res,Tt(each),x2(&each)); 104 | res=assign(res,Tt(eachb),x2(&eachboth)); 105 | res=assign(res,Tt(eachl),x2(&eachleft)); 106 | res=assign(res,Tt(eachr),x2(&eachright)); 107 | res=assign(res,Tt(emit),x2(&emit)); 108 | res=assign(res,Tt(evalin),x2(&evalin)); 109 | res=assign(res,Tt(except),x2(&except)); 110 | res=assign(res,Tt(extract),x2(&extract)); 111 | res=assign(res,Tt(extractas),x2(&extractas)); 112 | res=assign(res,Tt(exhaust),x2(&exhaust)); 113 | res=assign(res,Tt(from),x2(&from)); 114 | res=assign(res,Tt(ifelse),x2(&ifelse)); 115 | res=assign(res,Tt(iftrue),x2(&iftrue)); 116 | res=assign(res,Tt(in),x2(&matchany)); 117 | res=assign(res,Tt(is),x2(&set_is)); 118 | res=assign(res,Tt(join),x2(&join)); 119 | res=assign(res,Tt(loadin),x2(&loadin)); 120 | res=assign(res,Tt(make),x2(&make)); 121 | res=assign(res,Tt(match),x2(&matchall)); 122 | res=assign(res,Tt(matchstart),x2(&matcheasy)); 123 | res=assign(res,Tt(nest),x2(&nest)); 124 | res=assign(res,Tt(part),x2(&pickapart)); 125 | res=assign(res,Tt(pick),x2(&pick)); 126 | res=assign(res,Tt(pin),x2(&pin)); 127 | res=assign(res,Tt(or),x2(&or)); 128 | res=assign(res,Tt(orelse),x2(&orelse)); 129 | res=assign(res,Tt(over),x2(&over)); 130 | res=assign(res,Tt(range),x2(&range)); 131 | res=assign(res,Tt(ravel),x2(&ravel)); 132 | res=assign(res,Tt(recurse),x2(&recurse)); 133 | res=assign(res,Tt(rot),x2(&shift)); 134 | res=assign(res,Tt(scan),x2(&scan)); 135 | res=assign(res,Tt(split),x2(&split)); 136 | res=assign(res,Tt(take),x2(&take)); 137 | res=assign(res,Tt(wide),x2(&wide)); 138 | 139 | //stdlib 140 | VP d; 141 | #ifdef STDLIBFILE 142 | // note: assigns 'cwd' in root too 143 | d=xd0(); 144 | d=assign(d,Tt(basename),x1(&filebasename)); 145 | res=assign(res,Tt(cwd),x1(&filecwd)); 146 | d=assign(d,Tt(cwd),x1(&filecwd)); 147 | d=assign(d,Tt(dirname),x1(&filedirname)); 148 | d=assign(d,Tt(get),x1(&fileget)); 149 | d=assign(d,Tt(ls),x1(&filels)); 150 | d=assign(d,Tt(path),x1(&filepath)); 151 | d=assign(d,Tt(set),x2(&fileset)); 152 | res=assign(res,Tt(File),d); 153 | xfree(d); 154 | #endif 155 | #ifdef STDLIBMBOX 156 | d=xd0(); 157 | d=assign(d,Tt(new),x1(&mboxnew)); 158 | d=assign(d,Tt(peek),x1(&mboxpeek)); 159 | d=assign(d,Tt(query),x2(&mboxquery)); 160 | d=assign(d,Tt(recv),x1(&mboxrecv)); 161 | d=assign(d,Tt(send),x2(&mboxsend)); 162 | d=assign(d,Tt(wait),x1(&mboxwait)); 163 | d=assign(d,Tt(watch),x2(&mboxwatch)); 164 | res=assign(res,Tt(Mbox),d); 165 | xfree(d); 166 | #endif 167 | #ifdef STDLIBNET 168 | d=xd0(); 169 | d=assign(d,Tt(bind),x2(&netbind)); 170 | d=assign(d,Tt(call),x2(&netcall)); 171 | res=assign(res,Tt(Net),d); 172 | xfree(d); 173 | #endif 174 | #ifdef STDLIBSHAREDLIB 175 | d=xd0(); 176 | d=assign(d,Tt(get),x1(&sharedlibget)); 177 | d=assign(d,Tt(set),x2(&sharedlibset)); 178 | res=assign(res,Tt(Sharedlib),d); 179 | xfree(d); 180 | #endif 181 | #ifdef STDLIBSHELL 182 | d=xd0(); 183 | d=assign(d,Tt(get),x1(&shellget)); 184 | res=assign(res,Tt(Shell),d); 185 | xfree(d); 186 | #endif 187 | #ifdef STDLIBXD 188 | d=xd0(); 189 | d=assign(d,Tt(get),x1(&xdget)); 190 | d=assign(d,Tt(set),x2(&xdset)); 191 | res=assign(res,Tt(Xd),d); 192 | xfree(d); 193 | #endif 194 | 195 | -------------------------------------------------------------------------------- /stdlib.c: -------------------------------------------------------------------------------- 1 | // STANDARD LIBRARY 2 | 3 | #include "def.h" 4 | #include "proto.h" 5 | #include "accessors.h" 6 | #include "vary.h" 7 | 8 | #ifdef STDLIBGLOB 9 | #include 10 | #endif 11 | 12 | #ifdef STDLIBSHAREDLIB 13 | #include 14 | #endif 15 | 16 | #ifdef STDLIBFILE 17 | VP filebasename(VP fn) { 18 | VP fname=fn; 19 | if(!IS_c(fname)) fname=filepath(fn); 20 | if(!IS_c(fname)) return EXC(Tt(type),"basename filename must be string or pathlist",fn,0); 21 | char* str=sfromxA(fname); 22 | VP res=xfroms(basename(str)); 23 | xfree(fname); free(str); 24 | return res; 25 | } 26 | VP filedirname(VP fn) { 27 | VP fname=fn; 28 | if(!IS_c(fname)) fname=filepath(fn); 29 | if(!IS_c(fname)) return EXC(Tt(type),"dirname filename must be string or pathlist",fn,0); 30 | char* str=sfromxA(fname); 31 | VP res=xfroms(dirname(str)), slash=xc('/'); 32 | res=append(res,slash); 33 | free(str); 34 | return res; 35 | } 36 | VP filecwd(VP dummy) { 37 | char cwd[1024]; 38 | if(getcwd(cwd,sizeof(cwd))!=NULL) return xfroms(cwd); 39 | else return EXC(Tt(open),"couldnt get current working directory",0,0); 40 | } 41 | VP fileget(VP fn) { 42 | int r, fd; char buf[IOBLOCKSZ]; VP fname=fn; 43 | if(!IS_c(fname)) fname=filepath(fn); 44 | if(!IS_c(fname)) return EXC(Tt(type),"readfile filename must be string or pathlist",fn,0); 45 | //XRAY_LVL++;XRAY_log("fileget\n");XRAY_emit(fn);XRAY_LVL--; 46 | if(LEN(fname)==1 && AS_c(fname,0)=='-') fd=STDIN_FILENO; 47 | else { 48 | char* str=sfromxA(fname); 49 | fd=open(str,O_RDONLY); 50 | free(str); 51 | } 52 | if(fd<0) return EXC(Tt(open),"could not open file for reading",fname,0); 53 | VP acc=xcsz(IOBLOCKSZ); 54 | do { 55 | r=read(fd,buf,IOBLOCKSZ); 56 | if(r<=0) { xfree(acc); close(fd); return EXC(Tt(read),"could not read from file",fname,0); } 57 | else appendbuf(acc,(buf_t)&buf,r); 58 | } while (r==IOBLOCKSZ); 59 | close(fd); 60 | return acc; 61 | } 62 | int filelserr(const char* path, int eerrno) { 63 | return 0; 64 | } 65 | VP filels(VP path) { 66 | VP p=path; 67 | if(!IS_c(p)) p=filepath(p); 68 | if(!IS_c(p)) return EXC(Tt(type),"File.ls path must be string or pathlist",path,0); 69 | #ifndef STDLIBGLOB 70 | return EXC(Tt(nyi),"File.ls requires glob.h",path,0); 71 | #endif 72 | char* str=sfromxA(p); 73 | glob_t results; 74 | glob(str, 0, filelserr, &results); 75 | VP res=xlsz(5); //arb 76 | int i; 77 | for(i=0; in; 88 | for(i=0;in); 93 | appendbuf(acc,BUF(item),item->n); 94 | } 95 | xfree(sep); 96 | XRAY_log("filepath returning\n");XRAY_emit(acc); 97 | return acc; 98 | } 99 | VP fileset(VP str,VP fn) { 100 | VP fname=fn; 101 | if(!IS_c(fname)) fname=filepath(fn); 102 | if(!IS_c(fname)) return EXC(Tt(type),"writefile filename must be string or pathlist",fn,0); 103 | if(!IS_c(str)) return EXC(Tt(type),"writefile only deals writes strings right now",str,fn); 104 | char* fns=sfromxA(fname); 105 | int fd=open(fns,O_CREAT|O_WRONLY,0600); 106 | free(fns); 107 | if(fd<0) return EXC(Tt(open),"could not open file for writing",str,fname); 108 | if(write(fd,ELb(str,0),str->n)n) return EXC(Tt(write),"could not write file contents",str,fname); 109 | close(fd); 110 | return str; 111 | } 112 | #endif 113 | 114 | #ifdef STDLIBHTTP 115 | #ifdef STDLIBNET 116 | VP httpget(VP url) { 117 | } 118 | #endif 119 | #endif 120 | 121 | #ifdef STDLIBMBOX 122 | #ifdef THREAD 123 | #define IS_mbox(mb) (LIST(mb) && mb->tag==Ti(mbox)) 124 | #define MBOX_tm struct timespec tm;tm.tv_sec=5;tm.tv_nsec=0 125 | #define MBOX_usleep 5000 126 | VP mboxnew(VP x) { 127 | pthread_mutex_t *rm, *wm; VP res; 128 | rm = malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(rm, NULL); 129 | wm = malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(wm, NULL); 130 | return entags(xln(3, xj((long long)rm), xj((long long)wm), xl0()), "mbox"); 131 | } 132 | VP mboxsend(VP mbox,VP msg) { 133 | if(!IS_mbox(mbox)) { return EXC(Tt(type),"mbox.send needs a mailbox in x",mbox,msg); } 134 | pthread_mutex_t* wm=(pthread_mutex_t*)AS_j(LIST_item(mbox, 1),0); 135 | MBOX_tm; 136 | #ifndef THREAD_NO_TIMEDLOCK 137 | int ret=pthread_mutex_timedlock(wm, &tm); 138 | if(ret!=0) { return Tt(timeout); } 139 | #else 140 | int ret=pthread_mutex_lock(wm); 141 | if(ret!=0) { return Tt(nomutex); } 142 | #endif 143 | VP items=ELl(mbox,2); 144 | ELl(mbox,2)=append(items,msg); 145 | pthread_mutex_unlock(wm); 146 | return msg; 147 | } 148 | VP mboxrecv0(VP mbox,int pop) { 149 | pthread_mutex_t* rm=(pthread_mutex_t*)AS_j(LIST_item(mbox, 0),0); 150 | MBOX_tm; 151 | #ifndef THREAD_NO_TIMEDLOCK 152 | int ret=pthread_mutex_timedlock(rm, &tm); 153 | if(ret!=0) { return Tt(timeout); } 154 | #else 155 | int ret=pthread_mutex_lock(rm); 156 | if(ret!=0) { return Tt(nomutex); } 157 | #endif 158 | VP res=0; 159 | VP msgs=LIST_item(mbox,2); 160 | if(LEN(msgs)) { 161 | res=LIST_item(msgs,0); 162 | if(pop) ELl(mbox,2)=behead(msgs); 163 | } 164 | pthread_mutex_unlock(rm); 165 | return res; 166 | } 167 | VP mboxpeek(VP mbox) { 168 | if(!IS_mbox(mbox)) { return EXC(Tt(type),"mbox.recv needs a mailbox in x",mbox,0); } 169 | return mboxrecv0(mbox,0); 170 | } 171 | VP mboxrecv(VP mbox) { 172 | if(!IS_mbox(mbox)) { return EXC(Tt(type),"mbox.recv needs a mailbox in x",mbox,0); } 173 | return mboxrecv0(mbox,1); 174 | } 175 | VP mboxquery(VP mbox,VP msg) { 176 | XRAY_log("mboxquery\n");XRAY_emit(mbox);XRAY_emit(msg); 177 | VP me=mboxnew(XI0), tmp=xln(2,msg,me); 178 | mboxsend(mbox,tmp); 179 | while (1) { 180 | VP resp=mboxwait(me); if(resp) { xfree(tmp); xfree(me); return resp; } 181 | } 182 | return NULL; // todo timeouts 183 | } 184 | VP mboxwait(VP mbox) { 185 | XRAY_log("mboxwait\n");XRAY_emit(mbox); 186 | VP msg; 187 | tag_t ping=Ti(ping); 188 | int empties=0,founds=0; 189 | do { 190 | msg=mboxrecv(mbox); 191 | if(msg!=NULL) { 192 | if(LIST(msg) && LEN(msg)==2 && IS_t(LIST_item(msg,0)) && IS_mbox(LIST_item(msg,1)) && AS_t(LIST_item(msg,0),0)==ping) { 193 | VP tmp=xln(4,Tt(pong),mbox,xi(founds),xi(empties)); 194 | mboxsend(LIST_item(msg,1),tmp); 195 | xfree(tmp); 196 | } else return msg; 197 | } 198 | else { 199 | sched_yield(); 200 | empties++; if(empties>2) usleep(MAX(empties*100,MBOX_usleep)); // arb 201 | } 202 | } while (1); 203 | return NULL; // cant happen 204 | } 205 | VP mboxwatch0(VP args) { 206 | VP exitmsg=Tt(exit); 207 | VP mbox=LIST_item(args,0); 208 | VP cb=LIST_item(args,1); 209 | VP state=xl0(), newstate; 210 | VP msg; 211 | do { 212 | msg=mboxwait(mbox); 213 | newstate=apply2(cb, msg, state); 214 | xfree(state); 215 | state=newstate; 216 | xfree(msg); 217 | } while (state!=exitmsg); 218 | xfree(exitmsg); 219 | xfree(state); 220 | return NULL; 221 | } 222 | VP mboxwatch(VP mbox,VP callback) { 223 | if(!IS_mbox(mbox)) { return EXC(Tt(type),"Mbox.watch needs a mailbox in x",mbox,callback); } 224 | if(!CALLABLE(callback)) { return EXC(Tt(type),"Mbox.watch needs a callback in y",mbox,callback); } 225 | thr_run1(x1(&mboxwatch0),xln(2,mbox,callback)); 226 | return mbox; 227 | } 228 | #endif 229 | #endif 230 | 231 | 232 | #ifdef STDLIBSHAREDLIB 233 | VP sharedlibget(VP fn) { 234 | if(!IS_c(fn)) return EXC(Tt(type),".sharedlib.get requires a filename string as argument",fn,0); 235 | char* fns=sfromxA(fn); 236 | void* fp; 237 | fp=dlopen(fns,RTLD_LAZY); 238 | free(fns); 239 | if(fp==NULL) { 240 | printf("dlerr:%s\n",dlerror()); 241 | return EXC(Tt(open),".sharedlib.get could not open shared library",fn,0); 242 | } 243 | void* indexp; 244 | indexp=dlsym(fp,"XXL_INDEX"); 245 | if(indexp==NULL) return EXC(Tt(read),".sharedlib.get could not read index",fn,0); 246 | // XRAY_LVL=10; 247 | struct xxl_index_t* idx; 248 | idx=indexp; 249 | int i=0; 250 | VP contents=xd0(); 251 | while(idx[i].arity != 0) { 252 | void* itemp; 253 | itemp=dlsym(fp,idx[i].implfunc); 254 | if(itemp==NULL) { xfree(contents); return EXC(Tt(read),".sharedlib.get could not read item",fn,0); } 255 | if(idx[i].arity == 1) 256 | contents=assign(contents,xt(_tagnums(idx[0].name)),x1(itemp)); 257 | else 258 | contents=assign(contents,xt(_tagnums(idx[0].name)),x2(itemp)); 259 | idx++; 260 | } 261 | XRAY_emit(contents); 262 | return contents; 263 | } 264 | VP sharedlibset(VP fn,VP funcs) { 265 | return EXC(Tt(nyi),".sharedlib.set nyi",fn,funcs); 266 | } 267 | #endif 268 | 269 | #ifdef STDLIBSHELL 270 | VP shellget(VP cmd) { 271 | if(!IS_c(cmd)) return EXC(Tt(type),".shell.get requires command arg as a string",cmd,0); 272 | char buf[IOBLOCKSZ]={0}; size_t r; char* cmds=sfromxA(cmd); 273 | FILE* fp=popen(cmds,"r"); 274 | if(fp==NULL) return free(cmds),EXC(Tt(popen),"popen failed",cmd,0); 275 | VP acc=xcsz(IOBLOCKSZ); 276 | while(fgets(buf,IOBLOCKSZ-1,fp)!=NULL) 277 | appendbuf(acc,(buf_t)buf,strlen(buf)); 278 | fclose(fp); 279 | return free(cmds),acc; 280 | } 281 | #endif 282 | 283 | #ifdef STDLIBXD 284 | VP xdget0_(VP fname,int fd) { 285 | int sz; 286 | if(read(fd,&sz,4)<4) return EXC(Tt(write),"could not read file size",fname,0); 287 | if(sz!=sizeof(struct V)) return EXC(Tt(read),"could not read file structure due to size",fname,0); 288 | VP data=calloc(sz,1); 289 | if(read(fd,data,sz)rc=1; 291 | data->alloc=1; 292 | data->dyn=calloc(data->sz,1); 293 | if(CONTAINER(data)) { 294 | int i=0, dn=LEN(data); 295 | for(i=0; isz); 297 | return data; 298 | } 299 | VP xdget(const VP fn) { 300 | VP fname=fn; 301 | if(!IS_c(fname)) fname=filepath(fn); 302 | if(!IS_c(fname)) return EXC(Tt(type),"xdget filename must be string or pathlist",fn,0); 303 | char* fns=sfromxA(fname); 304 | int fd=open(fns,O_RDONLY); 305 | if(!fd) perror("open"); 306 | free(fns); 307 | if(fd<0) return EXC(Tt(open),"could not open file for reading",fname,0); 308 | char hdr[4]; 309 | if(read(fd,hdr,4)<4) return EXC(Tt(read),"could not write file header",fname,0); 310 | VP res=xdget0_(fname,fd); 311 | close(fd); 312 | return res; 313 | } 314 | VP xdset0_(VP fname,int fd, const VP data) { 315 | int sz=sizeof(struct V); 316 | if(write(fd,&sz,4)<4) return EXC(Tt(write),"could not write file size",fname,data); 317 | if(write(fd,data,sz)sz); 322 | return NULL; 323 | } 324 | VP xdset(const VP data,const VP fn) { 325 | VP fname=fn; 326 | if(!IS_c(fname)) fname=filepath(fn); 327 | if(!IS_c(fname)) return EXC(Tt(type),"xdset filename must be string or pathlist",fn,0); 328 | char* fns=sfromxA(fname); 329 | int fd=open(fns,O_CREAT|O_WRONLY,0600); 330 | if(!fd) perror("open"); 331 | free(fns); 332 | if(fd<0) return EXC(Tt(open),"could not open file for writing",fname,data); 333 | if(write(fd,"XXL0",4)<4) return EXC(Tt(write),"could not write file header",fname,data); 334 | VP res=xdset0_(fname,fd,data); 335 | close(fd); 336 | if(IS_EXC(res)) return res; 337 | else return data; 338 | } 339 | #endif 340 | 341 | -------------------------------------------------------------------------------- /test-match.h: -------------------------------------------------------------------------------- 1 | 2 | VP a,b,res; 3 | 4 | printf("TEST_MATCH\n"); 5 | // test mixing int vectors and lists of int vectors 6 | res=match(xin(1,1),xln(1,xi(1))); 7 | ASSERT(_equal(res,xin(1,0)),"ma0"); 8 | res=match(xln(1,xi(1)),xln(1,xi(1))); 9 | ASSERT(_equal(res,xin(1,0)),"ma1"); 10 | res=match(xln(1,xi(1)),xln(1,xi(1))); 11 | ASSERT(_equal(res,xin(1,0)),"ma2"); 12 | 13 | // simpler stuff 14 | res=match(xin(1,1),xin(1,1)); 15 | ASSERT(_equal(res,xin(1,0)),"ma"); 16 | res=match(xin(2,1,2),xin(1,1)); 17 | ASSERT(_equal(res,xin(1,0)),"mb"); 18 | res=match(xin(2,1,2),xin(1,2)); 19 | ASSERT(_equal(res,xin(1,1)),"mc"); 20 | res=match(xin(3,1,2,3),xin(1,2)); 21 | ASSERT(_equal(res,xin(1,1)),"mcc"); 22 | res=match(xin(3,1,2,3),xin(1,3)); 23 | ASSERT(_equal(res,xin(1,2)),"mccc"); 24 | 25 | // simple anyof 26 | res=match(xin(2,1,2),tagv("anyof",xin(1,2))); 27 | ASSERT(_equal(res,xin(1,1)),"md"); 28 | res=match(xin(2,1,2),tagv("anyof",xin(2,2,3))); 29 | ASSERT(_equal(res,xin(1,1)),"me"); 30 | res=match(xin(2,1,2),tagv("anyof",xin(2,1,3))); 31 | ASSERT(_equal(res,xin(1,0)),"mf"); 32 | res=match(xin(2,1,2),tagv("anyof",xin(2,1,3))); 33 | ASSERT(_equal(res,xin(1,0)),"mg"); 34 | 35 | // simple greedy, start, exact 36 | res=match(xin(2,5,6),tagv("greedy",xin(1,5))); 37 | ASSERT(_equal(res,xin(1,0)),"mh0"); 38 | res=match(xin(2,5,6),tagv("greedy",xin(1,6))); 39 | ASSERT(_equal(res,xin(1,1)),"mh0a"); 40 | 41 | res=match(xin(3,5,5,7),tagv("greedy",xin(1,5))); 42 | ASSERT(_equal(res,xin(2,0,1)),"mh0b"); 43 | res=match(xin(4,3,3,9,9),tagv("greedy",xin(1,9))); 44 | ASSERT(_equal(res,xin(2,2,3)),"mh1"); 45 | res=match(xin(4,2,9,2,2),tagv("greedy",xin(1,9))); 46 | ASSERT(_equal(res,xin(1,1)),"mh2"); 47 | 48 | res=match(xin(4,2,1,1,1),tagv("greedy",xin(1,1))); 49 | ASSERT(_equal(res,xin(3,1,2,3)),"mh3"); 50 | 51 | res=match(xin(3,1,1,2),tagv("start",xin(1,1))); 52 | ASSERT(_equal(res,xin(1,0)),"mi"); 53 | res=match(xin(3,1,1,2),tagv("start",xin(1,2))); 54 | ASSERT(_equal(res,xi0()),"mj"); 55 | res=match(xin(3,1,1,2),tagv("exact",xin(1,1))); 56 | ASSERT(_equal(res,xi0()),"mk"); 57 | res=match(xin(3,1,1,2),tagv("exact",xin(2,1,1))); 58 | ASSERT(_equal(res,xi0()),"ml"); 59 | res=match(xin(3,1,1,2),tagv("exact",xin(3,1,1,2))); 60 | ASSERT(_equal(res,xin(3,0,1,2)),"mn"); 61 | 62 | res=match(xin(4,1,2,3,4),xin(2,3,4)); 63 | ASSERT(_equal(res,xin(2,2,3)),"mo"); 64 | 65 | // mixed types 66 | res=match(xin(4,7,8,5,6),xln(3, 67 | tagv("anyof", xin(2,7,8)), 68 | tagv("greedy", xi0()), 69 | tagv("anyof", xin(2,5,6)))); 70 | ASSERT(_equal(res,xin(4,0,1,2,3)),"mp"); 71 | 72 | res=match(xin(4,9,8,7,6),tagv("greedy", xln(3, 73 | tagv("anyof", xin(2,9,8)), 74 | xi0(), 75 | tagv("anyof", xin(1,6))))); 76 | ASSERT(_equal(res,xin(4,0,1,2,3)),"mq"); 77 | 78 | ASSERT(_equal(match(xin(4,1,2,3,4),xin(4,1,2,3,4)),xin(4,0,1,2,3)),"m0"); 79 | ASSERT(_equal(match(xin(4,1,2,3,4),xin(2,1,2)), xin(2,0,1)),"m1"); 80 | ASSERT(_equal(match(xin(4,1,2,3,4),xin(1,1)), xin(1,0)),"m2"); 81 | ASSERT(_equal(match(xin(4,1,2,3,4),xin(1,2)), xin(1,1)),"m3"); 82 | ASSERT(_equal(match(xin(4,1,2,3,4),xin(2,2,3)), xin(2,1,2)),"m4"); 83 | 84 | ASSERT(_equal(match(xln(1,xi(9)),xin(2,9,8)), xin(1,0)),"ml0"); 85 | ASSERT(_equal(match(xln(2,xi(9),xi(8)),xin(2,9,8)),xin(2,0,1)),"ml1"); 86 | 87 | ASSERT(_equal( 88 | match( 89 | a=xin(4,1,2,3,4), 90 | b=tagv("anyof",xin(4,5,6,7,8)) 91 | ), res=xi0()), "m5"); 92 | xfree(a);xfree(b);xfree(res); 93 | 94 | ASSERT(_equal( 95 | match( 96 | a=xin(5,1,2,3,4,5), 97 | b=tagv("anyof",xin(3,5,6,7)) 98 | ), res=xin(1,4)), "m6"); 99 | ASSERT(_equal( 100 | match( 101 | xin(5,5,8,7,6,4), 102 | tagv("anyof",xin(4,9,8,7,6)) 103 | ), xin(3,1,2,3)), "m7"); 104 | ASSERT(_equal( 105 | match( 106 | xin(5,5,8,7,6,4), 107 | tagv("anyof",xin(3,1,1,1)) 108 | ), xi0()), "m7b"); 109 | ASSERT(_equal( 110 | apply(xin(5,5,8,7,6,4), match( 111 | xin(5,5,8,7,6,4), 112 | tagv("anyof",xin(4,9,8,7,6)) 113 | )), xin(3,8,7,6)), "m8"); 114 | ASSERT(_equal( 115 | match(xin(5,1,2,3,4,1), 116 | tagv("greedy", 117 | xln(3, xi(1), 118 | tagv("anyof",xin(3,2,3,4)), 119 | xi(1)) 120 | )), xin(5,0,1,2,3,4)), "m9"); 121 | ASSERT(_equal( 122 | match( 123 | xln(3,xfroms("\""),xfroms("blah"),xfroms("\"")), 124 | tagv("greedy", 125 | xln(3,xfroms("\""),xc0(),xfroms("\""))) 126 | ),xin(3,0,1,2)), "m10"); 127 | ASSERT(_equal( 128 | match( 129 | xln(4,xi(100),xfroms("\""),xfroms("blah"),xfroms("\"")), 130 | tagv("greedy", 131 | xln(3,xfroms("\""),xc0(),xfroms("\""))) 132 | ),xin(3,1,2,3)), "m11"); 133 | ASSERT(_equal( 134 | match(xin(5,1,0,1,0,2),xi(1)), 135 | xin(2,0,2)), "m multi0"); 136 | 137 | ASSERT(_equal( 138 | matcheasy( 139 | xin(5,1,2,1,2,3), 140 | xi(1) 141 | ), xbn(5,1,0,1,0,0)),"matcheasy 0"); 142 | 143 | a=xfroms("hello\"there\".."); 144 | ASSERT(_equal( 145 | pick(a, 146 | signaljoin(xi(1), matcheasy(a,xc('"'))) 147 | ),xfroms("\"there")), "p sj 0"); 148 | 149 | /* 150 | a=xfroms("wha{ts{up}hello}.."); 151 | ASSERT(_equal( 152 | expand( 153 | bracketjoin( 154 | xi(1), xln(2, 155 | matcheasy(a,xc('{')), 156 | matcheasy(a,xc('}')) 157 | )) 158 | ),xfroms("{up")), "p bj 0"); 159 | 160 | a=xfroms("//abc\n//def\n"); 161 | b=matcheasy(a,xc('/')); 162 | ASSERT(_equal( 163 | pickapart(a, 164 | bracketjoin( 165 | xb(1), 166 | xln(2, 167 | consecutivejoin( 168 | xb(1),xln(2,b,b) 169 | ), 170 | matcheasy(a,xc('\n')) 171 | ) 172 | )), 173 | xln(2,xfroms("//abc"),xfroms("//def")) 174 | ), "p bj cj 1"); 175 | 176 | a=xfroms("x/y\n//abc\n//def\n"); 177 | b=matcheasy(a,xc('/')); 178 | ASSERT(_equal( 179 | pickapart(a, 180 | bracketjoin( 181 | xb(1), 182 | xln(2, 183 | consecutivejoin( 184 | xb(1),xln(2,b,b) 185 | ), 186 | matcheasy(a,xc('\n')) 187 | ) 188 | )), 189 | xln(2,xfroms("//abc"),xfroms("//def")) 190 | ), "p bj cj 2"); 191 | */ 192 | 193 | /* 194 | a=xin(4, 1, 2, 3, 4); 195 | b=xin(4, 1, 2, 3, 4); 196 | res=match(a,b); 197 | DUMP(res); 198 | ASSERT(res->n==4 && AS_i(res,0) == 0 && AS_i(res,3)==3, "match 0"); 199 | xfree(res); xfree(a); xfree(b); 200 | 201 | a=xin(4, 1, 2, 3, 4); 202 | b=xin(2, 1, 2); 203 | res=match(a,b); 204 | DUMP(res); 205 | ASSERT(res->n==2 && AS_i(res,0) == 0 && AS_i(res,1)==1, "match 1"); 206 | xfree(res); xfree(a); xfree(b); 207 | 208 | a=xin(4, 1, 2, 3, 4); 209 | b=xin(2, 2, 3); 210 | res=match(a,b); 211 | DUMP(res); 212 | */ 213 | -------------------------------------------------------------------------------- /tests/lambda-in-comment.xxl: -------------------------------------------------------------------------------- 1 | /* {1} */ 2 | 3 | -------------------------------------------------------------------------------- /tests/returns-of-loads.xxl: -------------------------------------------------------------------------------- 1 | 1+2; 2 | ['a:1,'b:999] 3 | -------------------------------------------------------------------------------- /tests/sharedlib-test.c: -------------------------------------------------------------------------------- 1 | // 2 | // Demonstration of using shared libraries in XXL 3 | // Use like this: 4 | // xxl 0>"./tests/sharedlib-test.so" .sharedlib.get as 'mylib 5 | // (0.0310 sec) 6 | // inputs@0: "./tests/sharedlib-test.so" .sharedlib.get as 'mylib 7 | // outputs@0: ['test:'1(...)] 8 | // xxl 1>mylib@'test@666 9 | // testfunc 10 | // '2(...) 11 | // 100i 12 | // (0.0000 sec) 13 | // inputs@1: mylib@'test@666 14 | // outputs@1: 666i 15 | // 16 | #define STDLIBSHAREDLIB 1 17 | 18 | #include "../def.h" 19 | #include "../proto.h" 20 | #include "../accessors.h" 21 | 22 | VP testfunc(VP x) { 23 | printf("testfunc\n"); 24 | PF_LVL=10; 25 | printf("%s\n", reprA(x)); 26 | VP res=xln(3,xi(111),x,xi(444)); 27 | DUMP(res); 28 | PF_LVL=0; 29 | printf("%s\n", reprA(res)); 30 | return res; 31 | } 32 | 33 | struct xxl_index_t XXL_INDEX[] = { 34 | { "test", "testfunc", 1 }, 35 | { "", "", 0 } 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /tests/sharedlib-test.sh: -------------------------------------------------------------------------------- 1 | gcc -Wall -pedantic -DSTDLIBSHAREDLIB -fPIC -shared \ 2 | sharedlib-test.c ../xxl.o ../repl.o ../net.o -o sharedlib-test.so 3 | -------------------------------------------------------------------------------- /tests/simple-func.xxl: -------------------------------------------------------------------------------- 1 | {x*y} as 'mul; 2 | 10 mul 7 3 | -------------------------------------------------------------------------------- /tests/string-brace.xxl: -------------------------------------------------------------------------------- 1 | {x,"}"} 2 | 3 | -------------------------------------------------------------------------------- /tests/test-basics.h: -------------------------------------------------------------------------------- 1 | 2 | VP a,b,c,d; int i, tc; 3 | 4 | a=xalloc(T_i,1); 5 | EL(a,int,0)=1; 6 | ASSERT(EL(a,int,0)==1,"x0"); 7 | ASSERT(AS_i(a,0)==1,"AS_i0"); 8 | xfree(a); 9 | a=xi(99); 10 | b=xi(99); 11 | ASSERT(EL(a,int,0)==99,"x1"); 12 | ASSERT(_equal(a,b)==1,"_equal0"); 13 | ASSERT(_equal(b,a)==1,"_equal1"); 14 | ASSERT(_equal(a,a)==1,"_equal2"); 15 | ASSERT(_equal(b,b)==1,"_equal3"); 16 | a=append(a,xi(98)); 17 | ASSERT(EL(a,int,0)==99,"x2"); 18 | ASSERT(EL(a,int,1)==98,"x3"); 19 | ASSERT(_equal(a,b)==0,"_equal4"); 20 | ASSERT(_equal(b,a)==0,"_equal5"); 21 | c=xi(0); 22 | XRAY_emit(apply(a,c)); 23 | XRAY_emit(b); 24 | ASSERT(_equal(apply(a,c),b)==1,"apply eq 0"); 25 | xfree(b); 26 | xfree(c); 27 | b=xi(98); 28 | ASSERT(_contains(a,b)==1,"_contains 0"); 29 | c=xi(10); 30 | ASSERT(_contains(a,c)==0,"_contains 1"); 31 | ASSERT(AS_i(contains(a,b),0)==1,"contains 0"); 32 | ASSERT(AS_i(contains(a,c),0)==0,"contains 1"); 33 | xfree(b); 34 | xfree(a); 35 | xfree(c); 36 | ASSERT(!_equal(xi(-1),xi(1)),"xi neg 0"); 37 | a=xin(5,1,2,3,4,100); 38 | ASSERT(a->n==5,"_xin 0"); 39 | ASSERT(EL(a,int,4)==100,"_xin 1"); 40 | a=xian(a,3,200,300,400); 41 | ASSERT(EL(a,int,4)==100,"xian 2"); 42 | ASSERT(EL(a,int,7)==400,"xian 3"); 43 | ASSERT(EL(a,int,0)==1,"xian 4"); 44 | ASSERT(a->n==8,"xian 5"); 45 | #define NADD 1024 46 | for(i=0;in==8+NADD,"xia 1"); 50 | ASSERT(EL(a,int,0)==1,"xia 1b"); 51 | ASSERT(EL(a,int,1)==2,"xia 1c"); 52 | ASSERT(EL(a,int,NADD+7)==(NADD-1)*3,"xia 2"); 53 | xfree(a); 54 | a=xl0(); 55 | b=xi(100); 56 | append(a,b); 57 | ASSERT(a->n=1,"append i 0"); 58 | xfree(b); 59 | b = ELl(a,0); 60 | ASSERT(b->n==1,"append i 1"); 61 | ASSERT(EL(b,int,0)==100,"append i 2"); 62 | append(a,xfroms("test")); 63 | append(a,xfroms("test2")); 64 | XRAY_emit(a); 65 | ASSERT(a->n==3,"append str 1"); 66 | ASSERT(ELl(a,1)->n==4,"append str 2"); // test\0 67 | ASSERT(ELl(a,2)->n==5,"append str 2"); // test2\0 68 | ASSERT(_contains(a,ELl(a,2))==1,"str contains 0"); 69 | ASSERT(_contains(a,xfroms("tes"))==0,"str contains 1"); 70 | ASSERT(_equal(take(xin(3,1,2,3),xi(1)),xi(1)),"take 0"); 71 | ASSERT(_equal(take(xin(3,1,2,3),xi(2)),xin(2,1,2)),"take 1"); 72 | ASSERT(_equal(take(xin(3,1,2,3),xi(-2)),xin(2,2,3)),"take 2"); 73 | ASSERT(_equal(take(xin(3,1,2,3),xi(-1)),xi(3)),"take 3"); 74 | ASSERT(_equal(take(xin(3,1,2,3),xi(0)),xi0()),"take 4"); 75 | ASSERT(_equal(take(xin(3,1,2,3),xi(4)),xin(4,1,2,3,1)),"take 5"); 76 | ASSERT(_equal(take(xin(3,1,2,3),xi(3)),xin(3,1,2,3)),"take 6"); 77 | ASSERT(_equal(take(xi(1),xi(3)),xin(3,1,1,1)),"take 7"); 78 | ASSERT(_equal(take(xi(1),xi(-3)),xin(3,1,1,1)),"take 8"); 79 | ASSERT(_equal(take(xi(-1),xi(-3)),xin(3,-1,-1,-1)),"take 9"); 80 | ASSERT(_equal(take(xin(2,7,9),xi(-3)),xin(3,9,7,9)),"take 10"); 81 | 82 | ASSERT(_equal(drop(xin(3,5,6,7),xi(1)),xin(2,6,7)),"drop 1"); 83 | ASSERT(_equal(drop(xin(3,5,6,7),xi(-1)),xin(2,5,6)),"drop 2"); 84 | ASSERT(_equal(drop(xin(3,5,6,7),xi(0)),xin(3,5,6,7)),"drop 3"); 85 | 86 | upsert(a,xfroms("test")); 87 | ASSERT(a->n==3,"upsert 1"); 88 | b = xi(101); 89 | upsert(a,b); 90 | xfree(b); 91 | XRAY_emit(a); 92 | ASSERT(a->n==4,"upsert 2"); 93 | ASSERT(_find1(a,xfroms("test"))==1,"_find1 0"); 94 | ASSERT(_find1(a,xfroms("est"))==-1,"_find1 1"); 95 | ASSERT(_find1(a,xfroms("tes"))==-1,"_find1 2"); 96 | xfree(a); 97 | a = xd0(); 98 | b = apply(a,xfroms("a")); 99 | XRAY_emit(a); 100 | XRAY_emit(b); 101 | ASSERT(b==NULL,"apply 0"); 102 | b = xln(2,xi(1),xi(10)); // key:value dict 103 | append(a,b); 104 | xfree(b); 105 | d = xi(1); 106 | c = apply(a,d); 107 | ASSERT(_equal(c,xi(10))==1,"apply equal 0"); 108 | xfree(a); xfree(c); xfree(d); 109 | 110 | a = xd0(); 111 | b = xln(2,xln(1,xfroms("name")),xfroms("tom")); 112 | a=append(a,b); 113 | c=apply(a,xln(1,xfroms("name"))); 114 | XRAY_emit(c); 115 | ASSERT(IS_c(c) && memcmp(BUF(c),"tom",c->n)==0,"apply equal str"); 116 | xfree(c); 117 | 118 | a = xd0(); 119 | b = xln(2,xln(1,xfroms("over")),xfroms("tom")); 120 | a=append(a,b); 121 | xfree(b); 122 | b=xln(2,xln(1,xfroms("ver")),xfroms("frank")); 123 | a=append(a,b); 124 | c=apply(a,xln(1,xfroms("ver"))); 125 | XRAY_emit(c); 126 | ASSERT(IS_c(c) && memcmp(BUF(c),"frank",c->n)==0,"apply equal str 2"); 127 | xfree(c); 128 | xfree(a); 129 | 130 | a=xd0(); 131 | b=xln(2,xln(1,xfroms("over")),xfroms("tom")); 132 | a=append(a,b); 133 | xfree(b); 134 | b=xln(2,xln(1,xfroms("over")),xfroms("tom")); 135 | a=append(a,b); 136 | xfree(b); 137 | b=xln(2,xln(1,xfroms("ver")),xfroms("frank")); 138 | a=append(a,b); 139 | c=apply(a,xln(1,xfroms("ver"))); 140 | XRAY_emit(c); 141 | ASSERT(IS_c(c) && memcmp(BUF(c),"frank",c->n)==0,"apply equal str 3"); 142 | xfree(c); 143 | xfree(a); 144 | 145 | a=xd0(); 146 | b=xln(2,xln(1,xfroms("over")),xfroms("tom")); 147 | a=append(a,b); 148 | xfree(b); 149 | b=xln(2,xln(1,xfroms("over")),xfroms("tom")); 150 | a=append(a,b); 151 | xfree(b); 152 | b=xln(2,xln(1,xfroms("ver")),xfroms("frank")); 153 | a=append(a,b); 154 | c=apply(a,xln(1,xfroms("over"))); 155 | XRAY_emit(c); 156 | ASSERT(IS_c(c) && memcmp(BUF(c),"tom",c->n)==0,"apply equal str 3"); 157 | xfree(c); 158 | xfree(a); 159 | 160 | a=xd0(); 161 | b=xln(2,xln(1,xfroms("aa")),xfroms("tom")); 162 | a=append(a,b); 163 | XRAY_log("o0 0"); 164 | XRAY_emit(a); 165 | xfree(b); 166 | b=xln(2,xln(1,xfroms("aa")),xfroms("frank")); 167 | a=append(a,b); 168 | XRAY_log("o0 1");XRAY_emit(a); 169 | xfree(b); 170 | c=apply(a,xfroms("aa")); 171 | XRAY_log("o0 2");XRAY_emit(c); 172 | XRAY_emit(c); 173 | ASSERT(IS_c(c) && memcmp(BUF(c),"frank",c->n)==0,"apply dictionary overlap 0"); 174 | xfree(c); 175 | 176 | c=apply(a,xln(1,xfroms(""))); 177 | ASSERT(c==NULL,"apply empty search"); 178 | XRAY_emit(c); 179 | xfree(c); 180 | xfree(a); 181 | 182 | _tagnums(""); 183 | a=xin(3,10,9,8); 184 | a->tag=_tagnums("test tag"); 185 | ASSERT(strcmp(bfromx(tagname(a->tag)),"test tag")==0,"tag name 0"); 186 | xfree(a); 187 | 188 | a=xin(3,1,2,3); b=make(a,xt(Ti(byte))); 189 | XRAY_emit(b); 190 | ASSERT(_equal(a,b)&&b->n==3&&AS_b(b,2)==3,"cib"); 191 | xfree(a);xfree(b); 192 | a=xin(3,1,2,3); b=make(a,xt(Ti(octa))); 193 | XRAY_emit(b); 194 | ASSERT(_equal(a,b)&&b->n==3&&AS_o(b,2)==3,"cio"); 195 | xfree(a); 196 | xfree(b); 197 | a=xbn(2,9,8); b=make(a,xt(Ti(byte))); 198 | XRAY_emit(b); 199 | ASSERT(_equal(a,b)&&b->n==2&&AS_b(b,0)==9,"cbb"); 200 | xfree(a);xfree(b); 201 | 202 | ASSERT(_equal(count(xb(3)),xbn(3,0,1,2)),"count b"); 203 | ASSERT(_equal(count(xo(3)),xon(3,0,1,2)),"count o"); 204 | 205 | c=and(xi(0),xi(1)); 206 | XRAY_emit(c); 207 | ASSERT(c->n==1 && _equal(c, xi(0)), "and 0"); 208 | c=and(xi(1),xi(0)); 209 | ASSERT(c->n==1 && _equal(c, xi(0)), "and 1"); 210 | c=or(xi(0),xi(1)); 211 | XRAY_emit(c); 212 | ASSERT(c->n==1 && _equal(c, xi(1)), "and 0"); 213 | c=or(xi(1),xi(0)); 214 | ASSERT(c->n==1 && _equal(c, xi(1)), "and 1"); 215 | 216 | c=min(xin(3,1,2,3)); 217 | XRAY_emit(c); 218 | ASSERT(c->n==1 && _equal(c, xi(1)), "min 0"); 219 | c=min(xin(3,1,2,-3)); 220 | ASSERT(c->n==1 && _equal(c, xi(-3)), "min 1"); 221 | 222 | c=max(xin(3,1,2,3)); 223 | XRAY_emit(c); 224 | ASSERT(c->n==1 && _equal(c, xi(3)), "max 0"); 225 | c=max(xin(3,1,2,-3)); 226 | ASSERT(c->n==1 && _equal(c, xi(2)), "max 1"); 227 | 228 | c=deal(xi(10),xi(100)); 229 | XRAY_emit(c); 230 | ASSERT(c->n==100 && _equal(min(c),xi(0)), "deal 0"); 231 | 232 | ASSERT(_equal(condense(xbn(5,0,1,1,0,1)),xin(3,1,2,4)), "condense 0"); 233 | ASSERT(_equal(shift(xbn(3,5,6,7),xb(1)),xbn(3,6,7,5)),"rot0"); 234 | ASSERT(_equal(shift(xbn(3,5,6,7),xb(-1)),xbn(3,7,5,6)),"rot1"); 235 | ASSERT(_equal(shift(xin(3,5,6,7),xi(555)),xin(3,5,6,7)),"rot2"); 236 | ASSERT(_equal(shift(xin(3,5,6,7),xi(-555)),xin(3,5,6,7)),"rot3"); 237 | ASSERT(_equal(reverse(xi(1)),xi(1)),"rev0"); 238 | ASSERT(_equal(reverse(xin(3,9,7,6)),xin(3,6,7,9)),"rev1"); 239 | 240 | ASSERT(_equal(amend(xin(4,6,0,0,6),xln(2,xin(2,1,2),xi(7))),xin(4,6,7,7,6)),"amend0"); 241 | 242 | a=xin(3,2,2,7); // my favorite show 243 | b=clone(a); 244 | a=amend(a,xln(2,xi(0),xi(1))); 245 | ASSERT(_equal(a,a)&&!_equal(a,b),"clone0"); 246 | xfree(a);xfree(b); 247 | 248 | c=xi(100); 249 | a=xln(3,xi(0),c,xi(0)); 250 | b=clone(a); 251 | c=amend(c,xln(2,xi(0),xi(5))); 252 | ASSERT(_equal(a,a)&&!_equal(a,b)&&_equal(ELl(b,1),xi(100)),"clone1"); 253 | xfree(a);xfree(b);xfree(c); 254 | 255 | ASSERT(_equal(greater(xi(2),xi(1)),xb(1)),"greater0"); 256 | ASSERT(_equal(greater(xi(1),xi(2)),xb(0)),"greater1"); 257 | ASSERT(_equal(greater(xi(-2),xi(1)),xb(0)),"greater2"); 258 | ASSERT(_equal(greater(xi(1),xi(-2)),xb(1)),"greater3"); 259 | ASSERT(_equal(greater(xin(3,1,2,3),xi(2)),xbn(3,0,0,1)),"greater4"); 260 | ASSERT(_equal(lesser(xi(2),xi(1)),xb(0)),"lesser0"); 261 | ASSERT(_equal(lesser(xi(1),xi(2)),xb(1)),"lesser1"); 262 | ASSERT(_equal(lesser(xi(-2),xi(1)),xb(1)),"lesser2"); 263 | ASSERT(_equal(lesser(xi(1),xi(-2)),xb(0)),"lesser3"); 264 | ASSERT(_equal(lesser(xin(3,1,2,3),xi(2)),xbn(3,1,0,0)),"lesser4"); 265 | 266 | ASSERT(_equal(xf(3.0), plus(xf(1.5),xf(1.5))), "float 0"); 267 | 268 | a=xi(3); 269 | ASSERT(_equal(a, plus(xf(1.5),xf(1.5))), "float int compare 0"); 270 | xfree(a); 271 | 272 | a=xin(5,1,2,3,4,5); 273 | b=split(a,xi(3)); 274 | XRAY_emit(b); 275 | ASSERT(_equal(xln(2,xin(2,1,2),xin(2,4,5)),b),"split int token"); 276 | 277 | a=xfroms("abXYcd"); 278 | b=split(a,xfroms("XY")); 279 | ASSERT(b->n==2 && _equal(b,xln(2,xfroms("ab"),xfroms("cd"))),"split double char token"); 280 | 281 | a=xfroms(".hello.there"); 282 | b=split(a,xfroms(".")); 283 | XRAY_emit(b); 284 | ASSERT(_equal(xln(3,xc0(),xfroms("hello"),xfroms("there")),b),"split char token 0"); 285 | a=xfroms(".hello..there."); 286 | b=split(a,xfroms(".")); 287 | XRAY_emit(b); 288 | ASSERT(_equal(xln(5,xc0(),xfroms("hello"),xc0(),xfroms("there"),xc0()),b),"split char token 1"); 289 | xfree(a);xfree(b); 290 | 291 | a=xd0();a=assign(a,Tt(q),xi(10));a=assign(a,Tt(w),xi(11));b=key(a); 292 | ASSERT(_equal(b,xln(2,Tt(q),Tt(w))),"key0"); 293 | ASSERT(_equal(key(xin(3,5,6,7)),xin(3,0,1,2)),"key1"); 294 | 295 | a=xin(2,1,2); b=join(a,xi(3)); 296 | ASSERT(_equal(b,xin(3,1,3,2)),"join 0"); 297 | a=xi(1); b=join(a,xi(3)); 298 | ASSERT(_equal(b,xi(1)),"join 1"); 299 | a=xln(3,xfroms("a"),xfroms("b"),xfroms("c")); b=join(a,xfroms("/")); 300 | ASSERT(_equal(b,xfroms("a/b/c")),"join 2"); 301 | 302 | a=xin(3,1,-2,3); b=xin(3,-1,2,-3); 303 | ASSERT(_equal(neg(a),b),"neg0"); 304 | 305 | a=xfroms("hello"); 306 | i=_find1(a,xfroms("el")); 307 | ASSERT(i==1,"find nonscalar 0"); 308 | i=_find1(a,xfroms("ex")); 309 | ASSERT(i==-1,"find nonscalar 1"); 310 | 311 | 312 | -------------------------------------------------------------------------------- /tests/test-ctx.h: -------------------------------------------------------------------------------- 1 | ctx=mkworkspace(); 2 | tmp1=xl(proj(2,&plus,xi(2),0)); 3 | append(ctx,tmp1); 4 | tmp2=apply(ctx,xi(3)); 5 | XRAY_emit(tmp2); 6 | ASSERT(_equal(tmp2,xi(5)),"test ctx 0"); 7 | xfree(ctx); xfree(tmp1); xfree(tmp2); 8 | 9 | ctx=mkworkspace(); 10 | tmp1=xl(proj(2,&plus,0,xi(3))); 11 | append(ctx,tmp1); 12 | tmp2=apply(ctx,xi(3)); 13 | XRAY_emit(tmp2); 14 | ASSERT(_equal(tmp2,xi(6)),"test ctx 1"); 15 | xfree(ctx); xfree(tmp1); xfree(tmp2); 16 | 17 | ctx=mkworkspace(); 18 | tmp1=xln(2,proj(2,&plus,0,xi(2)),proj(2,&plus,0,xi(5))); 19 | append(ctx,tmp1); 20 | tmp2=apply(ctx,xi(3)); 21 | XRAY_emit(tmp2); 22 | ASSERT(_equal(tmp2,xi(10)),"test ctx 2"); 23 | xfree(ctx); xfree(tmp1); xfree(tmp2); 24 | 25 | ctx=mkworkspace(); 26 | tmp1=xln(2,xi(2),proj(2,&plus,xi(5),0)); 27 | append(ctx,tmp1); 28 | tmp2=apply(ctx,xi(3)); 29 | XRAY_emit(tmp2); 30 | ASSERT(_equal(tmp2,xi(7)),"test ctx 3"); 31 | xfree(ctx); xfree(tmp1); xfree(tmp2); 32 | 33 | ctx=mkworkspace(); // simple unary function application 34 | tmp1=xl(proj(1,&count,0,0)); 35 | append(ctx,tmp1); 36 | tmp2=apply(ctx,xi(4)); 37 | XRAY_emit(tmp2); 38 | ASSERT(_equal(tmp2,xin(4,0,1,2,3)),"test ctx 4"); 39 | xfree(ctx); xfree(tmp1); xfree(tmp2); 40 | 41 | ctx=mkworkspace(); // try applying an index to a function result 42 | tmp1=xln(2,proj(1,&count,0,0),xi(2)); 43 | append(ctx,tmp1); 44 | tmp2=apply(ctx,xi(5)); 45 | XRAY_emit(tmp2); 46 | ASSERT(_equal(tmp2,xi(2)),"test ctx 5"); 47 | xfree(ctx); xfree(tmp1); xfree(tmp2); 48 | 49 | ctx=mkworkspace(); // subexpression 50 | tmp1=xln(2,proj(2,&plus,xi(2),0),proj(1,&count,0,0)); 51 | append(ctx,tmp1); 52 | tmp2=apply(ctx,xi(4)); 53 | XRAY_emit(tmp2); 54 | ASSERT(_equal(tmp2,xin(6,0,1,2,3,4,5)),"test ctx 6"); 55 | xfree(ctx); xfree(tmp1); xfree(tmp2); 56 | 57 | ctx=mkworkspace(); 58 | append(ctx,parsestr("(\"abc\",(\"def\"))")); 59 | tmp1=apply(ctx,xl0()); 60 | XRAY_emit(tmp1); 61 | 62 | ctx=mkworkspace(); 63 | append(ctx,parsestr("1+1")); 64 | tmp1=apply(ctx,0); 65 | XRAY_emit(tmp1); 66 | ASSERT(_equal(tmp1,xi(2)),"test parsestr 0"); 67 | xfree(ctx);xfree(tmp1); 68 | 69 | ctx=mkworkspace(); 70 | append(ctx,parsestr("+1")); 71 | tmp1=apply(ctx,xi(1)); 72 | XRAY_emit(tmp1); 73 | ASSERT(_equal(tmp1,xi(2)),"test parsestr 1"); 74 | xfree(ctx);xfree(tmp1); 75 | 76 | ctx=mkworkspace(); 77 | append(ctx,parsestr("1+x")); 78 | tmp1=apply(ctx,xi(1)); 79 | XRAY_emit(tmp1); 80 | ASSERT(_equal(tmp1,xi(2)),"test parsestr 2"); 81 | xfree(ctx);xfree(tmp1); 82 | 83 | ctx=mkworkspace(); 84 | append(ctx,parsestr("1+x*2")); 85 | tmp1=apply(ctx,xi(1)); 86 | XRAY_emit(tmp1); 87 | ASSERT(_equal(tmp1,xi(4)),"test parsestr 3"); 88 | xfree(ctx);xfree(tmp1); 89 | 90 | ctx=mkworkspace(); 91 | append(ctx,parsestr("1+x*2+4")); 92 | tmp1=apply(ctx,xi(1)); 93 | XRAY_emit(tmp1); 94 | ASSERT(_equal(tmp1,xi(8)),"test parsestr 4"); 95 | xfree(ctx);xfree(tmp1); 96 | 97 | ctx=mkworkspace(); 98 | append(ctx,parsestr("1,2")); 99 | tmp1=apply(ctx,xi(1)); 100 | XRAY_emit(tmp1); 101 | ASSERT(_equal(tmp1,xin(2,1,2)),"test parsestr 5"); 102 | xfree(ctx);xfree(tmp1); 103 | 104 | ctx=mkworkspace(); 105 | append(ctx,parsestr("1,2+x*2+4")); 106 | tmp1=apply(ctx,xi(1)); 107 | XRAY_emit(tmp1); 108 | ASSERT(_equal(tmp1,xin(2,8,10)),"test parsestr 6"); 109 | xfree(ctx);xfree(tmp1); 110 | 111 | ctx=mkworkspace(); 112 | append(ctx,parsestr("2,4 over +")); 113 | tmp1=apply(ctx,xi(1)); 114 | XRAY_emit(tmp1); 115 | ASSERT(_equal(tmp1,xi(6)),"test parsestr 6b - adverb over with + ref"); 116 | xfree(ctx);xfree(tmp1); 117 | 118 | ctx=mkworkspace(); 119 | append(ctx,parsestr("(2,4) over +")); 120 | tmp1=apply(ctx,xi(1)); 121 | XRAY_emit(tmp1); 122 | ASSERT(_equal(tmp1,xi(6)),"test parsestr 7"); 123 | xfree(ctx);xfree(tmp1); 124 | 125 | ctx=mkworkspace(); 126 | append(ctx,parsestr("1+(2,3)")); 127 | tmp1=apply(ctx,xi(1)); 128 | XRAY_emit(tmp1); 129 | ASSERT(_equal(tmp1,xin(2,3,4)),"test parsestr 8"); 130 | xfree(ctx);xfree(tmp1); 131 | 132 | ctx=mkworkspace(); 133 | append(ctx,parsestr("(1+2,3)+(2,3)")); 134 | tmp1=apply(ctx,xi(1)); 135 | XRAY_emit(tmp1); 136 | ASSERT(_equal(tmp1,xin(2,5,6)),"test parsestr 9"); 137 | xfree(ctx);xfree(tmp1); 138 | 139 | ctx=mkworkspace(); 140 | append(ctx,parsestr("(1+(2*3))")); 141 | tmp1=apply(ctx,0); 142 | XRAY_emit(tmp1); 143 | ASSERT(_equal(tmp1,xi(7)),"test parsestr 10"); 144 | xfree(ctx);xfree(tmp1); 145 | 146 | ctx=mkworkspace(); 147 | append(ctx,parsestr("/* test */2")); 148 | tmp1=apply(ctx,0); 149 | XRAY_emit(tmp1); 150 | ASSERT(_equal(tmp1,xi(2)),"test parsestr 11"); 151 | xfree(ctx);xfree(tmp1); 152 | 153 | ctx=mkworkspace(); 154 | append(ctx,parsestr("*100 //test")); 155 | tmp1=apply(ctx,xi(2)); 156 | XRAY_emit(tmp1); 157 | ASSERT(_equal(tmp1,xi(200)),"test parsestr 12"); 158 | xfree(ctx);xfree(tmp1); 159 | 160 | ctx=mkworkspace(); 161 | append(ctx,parsestr("1000 /* test */ * /* x */ (100*100) //test")); 162 | tmp1=apply(ctx,xi(2)); 163 | XRAY_emit(tmp1); 164 | ASSERT(_equal(tmp1,xi(10000000)),"test parsestr 13"); 165 | xfree(ctx);xfree(tmp1); 166 | 167 | ctx=mkworkspace(); 168 | append(ctx,parsestr("{x*3}")); 169 | tmp1=apply(ctx,xi(2)); 170 | XRAY_emit(tmp1); 171 | ASSERT(_equal(tmp1,xi(6)),"test parsestr 14 - x value in closure"); 172 | xfree(ctx);xfree(tmp1); 173 | 174 | ctx=mkworkspace(); 175 | append(ctx,parsestr("{3*x}")); 176 | tmp1=apply(ctx,xi(2)); 177 | XRAY_emit(tmp1); 178 | ASSERT(_equal(tmp1,xi(6)),"test parsestr 15"); 179 | xfree(ctx);xfree(tmp1); 180 | 181 | ctx=mkworkspace(); 182 | append(ctx,parsestr("{*3}")); 183 | tmp1=apply(ctx,xi(2)); 184 | XRAY_emit(tmp1); 185 | ASSERT(_equal(tmp1,xi(6)),"test parsestr 16"); 186 | xfree(ctx);xfree(tmp1); 187 | 188 | ctx=mkworkspace(); 189 | append(ctx,parsestr("5 {x*y} x")); 190 | tmp1=apply(ctx,xi(2)); 191 | XRAY_emit(tmp1); 192 | ASSERT(_equal(tmp1,xi(10)),"test parsestr y in func body"); 193 | xfree(ctx);xfree(tmp1); 194 | 195 | ctx=mkworkspace(); 196 | append(ctx,parsestr("{count}")); 197 | tmp1=apply(ctx,xi(3)); 198 | XRAY_emit(tmp1); 199 | ASSERT(_equal(tmp1,xin(3,0,1,2)),"test parsestr count in func body"); 200 | xfree(ctx);xfree(tmp1); 201 | 202 | ctx=mkworkspace(); 203 | append(ctx,parsestr("count+2 each {count}")); 204 | tmp1=apply(ctx,xi(3)); 205 | XRAY_emit(tmp1); 206 | ASSERT(_equal(tmp1,xln(3,xin(2,0,1),xin(3,0,1,2),xin(4,0,1,2,3))),"test parsestr 18"); 207 | xfree(ctx);xfree(tmp1); 208 | 209 | /* 210 | * this test should probably never have passed 211 | * it doesnt make sense to resolve 'y' as a variable from scope 212 | * think of the chaos that could cause when you intend a projection and you 213 | * get a parent scope's ctx value y! i'm disabling this for now 214 | ctx=mkworkspace(); 215 | tmp1=xd0(); 216 | assign(tmp1,Tt(y),xi(7)); 217 | append(ctx,tmp1); 218 | append(ctx,parsestr("+y*3")); 219 | tmp1=apply(ctx,xi(2)); 220 | XRAY_emit(tmp1); 221 | ASSERT(_equal(tmp1,xi(27)),"test parsestr 19"); 222 | xfree(ctx);xfree(tmp1); 223 | */ 224 | 225 | ctx=mkworkspace(); 226 | assign(KEYS(ctx),Tt(y),xi(7)); 227 | append(ctx,parsestr("x as 'n * 2 as 'doublen")); 228 | tmp1=apply(ctx,xi(2)); 229 | XRAY_emit(tmp1); 230 | ASSERT(_equal(tmp1,xi(4)),"test as 0"); 231 | xfree(ctx);xfree(tmp1); 232 | 233 | ctx=mkworkspace(); 234 | append(ctx,parsestr("\"z\"")); 235 | tmp1=apply(ctx,0); 236 | XRAY_emit(tmp1); 237 | ASSERT(_equal(tmp1,entags(xc('z'),"string")),"test parsestr 21"); 238 | xfree(ctx);xfree(tmp1); 239 | 240 | ctx=mkworkspace(); 241 | append(ctx,parsestr("\"a\" as 's;s+1")); 242 | tmp1=apply(ctx,0); 243 | XRAY_emit(tmp1); 244 | ASSERT(_equal(tmp1,entags(xc('b'),"string")),"test as 1"); 245 | xfree(ctx);xfree(tmp1); 246 | 247 | ctx=mkworkspace(); 248 | append(ctx,parsestr("[1,2,3]")); 249 | tmp1=apply(ctx,0); 250 | XRAY_emit(tmp1); 251 | ASSERT(_equal(tmp1,xln(3,xi(1),xi(2),xi(3))),"test parsestr list literal 23"); 252 | xfree(ctx);xfree(tmp1); 253 | 254 | ctx=mkworkspace(); 255 | append(ctx,parsestr("['a:1]")); 256 | tmp1=apply(ctx,0); 257 | XRAY_emit(tmp1); 258 | ASSERT(_equal(apply(tmp1,Tt(a)),xi(1)),"test parsestr dict literal 24"); 259 | xfree(ctx);xfree(tmp1); 260 | 261 | ctx=mkworkspace(); 262 | append(ctx,parsestr("['a:1,'b:2]")); 263 | tmp1=apply(ctx,0); 264 | XRAY_emit(repr(tmp1)); 265 | tmp2=xfroms("['a:1, 'b:2]"); 266 | XRAY_emit(tmp1);XRAY_emit(tmp2); 267 | ASSERT(_equal(repr(tmp1),tmp2),"test parsestr dict literal 25"); 268 | xfree(ctx);xfree(tmp1);xfree(tmp2); 269 | 270 | ctx=mkworkspace(); 271 | ctx=append(ctx,parsestr("[\"aaa\"]")); 272 | tmp2=apply(ctx,0); 273 | ctx=append(ctx,parsestr("(\"aaa\")")); 274 | tmp1=apply(ctx,0); 275 | XRAY_emit(tmp2); 276 | XRAY_emit(tmp1); 277 | // ASSERT(_equal(tmp1,tmp2),"test parsestr string equivalence 0"); 278 | xfree(tmp1);xfree(tmp2); 279 | 280 | ctx=mkworkspace(); 281 | ctx=append(ctx,parsestr("[1,\"aaa\"]")); 282 | tmp2=apply(ctx,0); 283 | ctx=append(ctx,parsestr("(1,\"aaa\")")); 284 | tmp1=apply(ctx,0); 285 | XRAY_emit(tmp2); 286 | XRAY_emit(tmp1); 287 | // ASSERT(_equal(tmp1,tmp2),"test parsestr string equivalence 1"); 288 | xfree(tmp1);xfree(tmp2); 289 | 290 | ctx=mkworkspace(); 291 | append(ctx,parsestr("['a:(1,2),'b:\"barf\"]")); 292 | tmp1=apply(ctx,0); 293 | XRAY_emit(tmp1); 294 | XRAY_emit(repr(tmp1)); 295 | ASSERT(_equal(repr(tmp1),xfroms("['a:(1,2), 'b:\"barf\"]")),"test parsestr dict literal 26"); 296 | xfree(ctx);xfree(tmp1); 297 | 298 | ctx=mkworkspace(); 299 | append(ctx,parsestr("('a,'b):((1,2),\"barf\")")); 300 | tmp1=apply(ctx,0); 301 | XRAY_emit(tmp1); 302 | ASSERT(_equal(repr(tmp1),xfroms("['a:(1,2), 'b:\"barf\"]")),"test parsestr dict literal 27"); 303 | 304 | ctx=mkworkspace(); 305 | append(ctx,parsestr("5 {x*y} as 'f;3 f")); 306 | tmp1=apply(ctx,xi(2)); 307 | XRAY_emit(tmp1); 308 | ASSERT(_equal(tmp1,xi(15)),"test func as var 1"); 309 | xfree(ctx);xfree(tmp1); 310 | 311 | ctx=mkworkspace(); 312 | append(ctx,parsestr("5 {x*y} as 'f;f 3")); // note - technically invalid but still works! nice 313 | tmp1=apply(ctx,xi(2)); 314 | XRAY_emit(tmp1); 315 | ASSERT(_equal(tmp1,xi(15)),"test func as var 2"); 316 | xfree(ctx);xfree(tmp1); 317 | 318 | ctx=mkworkspace(); 319 | append(ctx,parsestr(";* as 'f;4 f 6")); // leading ; disables auto-left-projection of invisible x 320 | tmp1=apply(ctx,xi(2)); 321 | XRAY_emit(tmp1); 322 | ASSERT(_equal(tmp1,xi(24)),"test func as var 3"); 323 | xfree(ctx);xfree(tmp1); 324 | 325 | ctx=mkworkspace(); 326 | append(ctx,parsestr(";* as 'xyzzyxyzzy;4 xyzzyxyzzy 6")); // leading ; disables auto-left-projection of invisible x 327 | tmp1=apply(ctx,xi(2)); 328 | XRAY_emit(tmp1); 329 | ASSERT(_equal(tmp1,xi(24)),"test func as var 4 long name"); 330 | xfree(ctx);xfree(tmp1); 331 | 332 | ctx=mkworkspace(); 333 | append(ctx,parsestr(";{x*2}as 'doub;7doub")); 334 | tmp1=apply(ctx,xi(3)); 335 | XRAY_emit(tmp1); 336 | ASSERT(_equal(tmp1,xi(14)),"test func as var 4"); 337 | xfree(ctx);xfree(tmp1); 338 | 339 | ctx=mkworkspace(); 340 | append(ctx,parsestr(";{x*y}as 'mul;7mul as 'ms;10ms")); 341 | tmp1=apply(ctx,xi(3)); 342 | ASSERT(_equal(tmp1,xi(70)),"test func as dyadic var"); 343 | xfree(ctx);xfree(tmp1); 344 | 345 | ctx=mkworkspace(); 346 | append(ctx,parsestr("{x*y}as 'mul;7mul")); 347 | tmp1=apply(ctx,xi(3)); 348 | ASSERT(_equal(tmp1,xi(21)),"test func as dyadic y"); 349 | xfree(ctx);xfree(tmp1); 350 | 351 | ctx=mkworkspace(); 352 | append(ctx,parsestr("{x*y}as 'mul;7mul")); 353 | tmp1=apply(ctx,xi(3)); 354 | ASSERT(_equal(tmp1,xi(21)),"test func as dyadic y"); 355 | xfree(ctx);xfree(tmp1); 356 | 357 | ctx=mkworkspace(); 358 | append(ctx,parsestr("[3,4,5]each{+2}")); 359 | tmp1=apply(ctx,xi(3)); 360 | ASSERT(_equal(tmp1,xln(3,xi(5),xi(6),xi(7))),"test apply simple lambda"); 361 | xfree(ctx);xfree(tmp1); 362 | 363 | ctx=mkworkspace(); 364 | append(ctx,parsestr("['q:1,'w:2] as 'd;d")); 365 | tmp1=apply(ctx,0); 366 | tmp2=evalstrin("['q:1, 'w:2]", ctx); 367 | ASSERT(_equal(tmp1,tmp2),"test evalstrin and complex variables"); 368 | xfree(ctx);xfree(tmp1);xfree(tmp2); 369 | 370 | ctx=mkworkspace(); 371 | append(ctx,parsestr("['q:1,'w:2] as 'd;d ! ('w,5)")); 372 | tmp1=apply(ctx,0); 373 | tmp2=evalstrin("['q:1, 'w:5]", ctx); 374 | ASSERT(_equal(tmp1,tmp2),"test amend dict val"); 375 | xfree(ctx);xfree(tmp1);xfree(tmp2); 376 | 377 | ctx=mkworkspace(); 378 | append(ctx,parsestr("['q:1,'w:2] as 'd;d,['w:5]")); 379 | tmp1=apply(ctx,0); 380 | tmp2=evalstrin("['q:1, 'w:5]", ctx); 381 | XRAY_emit(tmp1);XRAY_emit(tmp2); 382 | ASSERT(_equal(tmp1,tmp2),"test join dict literal"); 383 | xfree(ctx);xfree(tmp1);xfree(tmp2); 384 | 385 | ctx=mkworkspace(); 386 | append(ctx,parsestr(";{x*y}as 'z;7 z 6")); // without the semicolon the system tries to use xl0 as x.. helpfully 387 | // note: last part above used to read 'z 7 6' but the interpreter was getting 388 | // confused by the context (z) sometimes being treated as data and sometimes 389 | // as invokable. the correct syntax to use with z here is 7 z 6, so i've 390 | // updated it as such. this convenience feature has created a lot of 391 | // annoyance. 392 | tmp1=apply(ctx,xl0()); 393 | ASSERT(_equal(tmp1,xi(42)),"test y projection"); 394 | xfree(ctx);xfree(tmp1); 395 | 396 | ctx=mkworkspace(); 397 | append(ctx,parsestr("\"a\\\"b\\\"c\r\n\"")); 398 | tmp1=apply(ctx,xl0()); 399 | ASSERT(_equal(tmp1,xcn(7,'a','"','b','"','c',13,10)),"parse quoted string"); 400 | xfree(ctx);xfree(tmp1); 401 | 402 | ctx=mkworkspace(); 403 | append(ctx,parsestr("\"\"")); 404 | tmp1=apply(ctx,0); 405 | ASSERT(_equal(tmp1,xc0()),"parse empty quoted string"); 406 | 407 | tmp1=parsestr("{x*3}"); // returns lambda and repr of auto-included \n; only care about former 408 | XRAY_emit(tmp1); 409 | tmp2=ELl(tmp1,0); 410 | XRAY_emit(tmp2); 411 | ASSERT(LIST(tmp2) && tmp2->tag==Ti(lambda) && tmp2->n==2 && _equal(ELl(tmp2,1),xi(1)),"test lambda internals 0"); 412 | xfree(ctx);xfree(tmp1); 413 | XRAY_emit(ctx);XRAY_emit(tmp1); 414 | 415 | tmp1=parsestr("/*{1}*/"); 416 | XRAY_emit(tmp1); 417 | ASSERT(LIST(tmp1) && ELl(tmp1,0)->tag==Ti(comment) && ELl(tmp1,1)->tag==Ti(ws),"lambda in comment"); 418 | xfree(tmp1); 419 | 420 | tmp1=parsestr("{/*a*/}"); 421 | XRAY_emit(tmp1); 422 | ASSERT(LIST(tmp1) && ELl(tmp1,0)->tag==Ti(lambda) 423 | && ELl(ELl(ELl(tmp1,0),0),0)->tag==Ti(comment) 424 | && ELl(tmp1,1)->tag==Ti(ws),"comment in lambda"); 425 | xfree(tmp1); 426 | 427 | VP a,b,c; 428 | c=mkworkspace(); 429 | b=parsestr("\n//x\n"); 430 | ASSERT(b->n==2 && ELl(b,0)->tag==Ti(ws) && ELl(b,1)->tag==Ti(comment) && ELl(b,1)->n==4,"comment after newline"); 431 | xfree(c);xfree(b); 432 | 433 | c=mkworkspace(); 434 | b=parsestr("\n//x\n\n//y"); 435 | ASSERT(b->n==4 && ELl(b,0)->tag==Ti(ws) && ELl(b,1)->tag==Ti(comment) && ELl(b,1)->n==4,"comment after newline part deux"); 436 | xfree(c);xfree(b); 437 | 438 | c=mkworkspace(); 439 | b=parsestr(":a::b::c:"); 440 | XRAY_emit(b); 441 | ASSERT(b->n==8 && 442 | ELl(b,0)->tag==Ti(raw) && 443 | ELl(b,1)->tag==Ti(name) && 444 | ELl(b,2)->tag==Ti(oper) && 445 | ELl(b,3)->tag==Ti(name) && 446 | ELl(b,4)->tag==Ti(oper) && 447 | ELl(b,5)->tag==Ti(name) && 448 | ELl(b,6)->tag==Ti(raw), "long oper"); 449 | xfree(c);xfree(b); 450 | 451 | -------------------------------------------------------------------------------- /tests/test-eval.h: -------------------------------------------------------------------------------- 1 | 2 | VP a; 3 | printf("TEST_EVAL\n"); 4 | ASSERT( 5 | _equal( 6 | parsestr("// "), 7 | entags(xfroms("// \n"),"comment") 8 | ), "tec0"); 9 | ASSERT( 10 | _equal( 11 | parsestr("/* */"), 12 | xln(2,entags(xfroms("/* */"),"comment"),xfroms("\n")) 13 | ), "tec0b"); 14 | ASSERT( 15 | _equal( 16 | parsestr("/*a*/ /*z*/"), 17 | xln(4, 18 | entags(xfroms("/*a*/"),"comment"), 19 | xfroms(" "), 20 | entags(xfroms("/*z*/"),"comment"), 21 | xfroms("\n")) 22 | ), "tec1bbbb"); 23 | ASSERT( 24 | _equal( 25 | parsestr("//x"), 26 | xl(entags(xfroms("//x\n"),"comment")) 27 | ), "tec1"); 28 | ASSERT( 29 | _equal( 30 | parsestr("/*x*/"), 31 | xln(2,entags(xfroms("/*x*/"),"comment"),xfroms("\n")) 32 | ), "tec1b"); 33 | ASSERT( 34 | _equal( 35 | parsestr("//xy"), 36 | xl(entags(xfroms("//xy\n"),"comment")) 37 | ), "tec1c"); 38 | ASSERT( 39 | _equal( 40 | parsestr("//x "), 41 | xl(entags(xfroms("//x \n"),"comment")) 42 | ), "tec2"); 43 | ASSERT( 44 | _equal( 45 | parsestr("// x"), 46 | xl(entags(xfroms("// x\n"),"comment")) 47 | ), "tec2b"); 48 | ASSERT( 49 | _equal( 50 | parsestr("// abc "), 51 | xl(entags(xfroms("// abc \n"),"comment")) 52 | ), "tec3"); 53 | ASSERT( 54 | _equal( 55 | parsestr("// a\n//b"), 56 | xln(2, 57 | entags(xfroms("// a\n"),"comment"), 58 | entags(xfroms("//b\n"),"comment")) 59 | ), "tec4"); 60 | ASSERT( 61 | _equal( 62 | parsestr("/* abc */"), 63 | xln(2,entags(xfroms("/* abc */"),"comment"),xfroms("\n")) 64 | ), "tec5"); 65 | ASSERT( 66 | _equal( 67 | parsestr("1"), 68 | xln(2,xi(1),xfroms("\n")) 69 | ), "tei0"); 70 | ASSERT( 71 | _equal( 72 | parsestr("1//blah"), 73 | xln(2, 74 | xi(1), 75 | entags(xfroms("//blah\n"),"comment")) 76 | ), "teic0"); 77 | ASSERT( 78 | _equal( 79 | parsestr("1//blah\n2"), 80 | xln(4, 81 | xi(1), 82 | entags(xfroms("//blah\n"),"comment"), 83 | xi(2), 84 | xfroms("\n") 85 | ) 86 | ), "teic1"); 87 | //DUMP(parsestr("// test")); 88 | //parsestr("// test\nx:\"Hello!\"\ncount 1024"); 89 | -------------------------------------------------------------------------------- /tests/test-logic.h: -------------------------------------------------------------------------------- 1 | VP d; 2 | 3 | c=mkworkspace(); 4 | b=evalstrin("(1,2,3,4)@2",c); 5 | ASSERT(_equal(b,xi(3)),"test apply num 0"); 6 | 7 | c=mkworkspace(); 8 | b=evalstrin("1 iftrue 3",c); 9 | ASSERT(_equal(b,xi(3)),"test if 0"); 10 | xfree(c);xfree(b); 11 | 12 | c=mkworkspace(); 13 | b=evalstrin("1 iftrue 3",c); 14 | ASSERT(_equal(b,xi(3)),"test if 0"); 15 | xfree(c);xfree(b); 16 | 17 | c=mkworkspace(); 18 | b=evalstrin("1 iftrue {3}",c); 19 | ASSERT(_equal(b,xi(3)),"test if 0 f"); 20 | xfree(c);xfree(b); 21 | 22 | c=mkworkspace(); 23 | b=evalstrin("1 ifelse (3,2)",c); 24 | ASSERT(_equal(b,xi(3)),"test if 1"); 25 | xfree(c);xfree(b); 26 | 27 | c=mkworkspace(); 28 | b=evalstrin("0 ifelse (3,2)",c); 29 | ASSERT(_equal(b,xi(2)),"test if 2"); 30 | xfree(c);xfree(b); 31 | 32 | c=mkworkspace(); 33 | b=evalstrin("1 ifelse ({x*2},{x*3})",c); 34 | ASSERT(_equal(b,xi(2)),"test if 3"); 35 | xfree(c);xfree(b); 36 | 37 | c=mkworkspace(); 38 | b=evalstrin("[[4,5],[6,7]]@[0,1]",c); 39 | ASSERT(_equal(b,xi(5)),"test apply at depth 0"); 40 | xfree(c);xfree(b); 41 | 42 | c=mkworkspace(); 43 | b=evalstrin("['a:(1,2,3),'b:(4,5,6)]@['b,2]",c); 44 | ASSERT(_equal(b,xi(6)),"test apply at depth in dict"); 45 | xfree(c);xfree(b); 46 | 47 | /* 48 | this doesnt work yet - probably rightfully.. 49 | c=mkworkspace(); 50 | b=evalstrin("(1,2)as 'd;(3,4)as 'e;(d,e)",c); 51 | ASSERT(_equal(b,xin(4,1,2,3,4)),"compound subexpr 0"); 52 | xfree(c);xfree(b); 53 | */ 54 | 55 | #ifdef STDLIBFILE 56 | c=mkworkspace(); 57 | b=evalstrin("File.get",c); 58 | XRAY_emit(b); 59 | ASSERT(_equal(b,x1(&fileget)),"stdlib file reference"); 60 | xfree(c);xfree(b); 61 | c=mkworkspace(); 62 | b=evalstrin("'File#\"def.h\" get",c); 63 | XRAY_emit(b); 64 | ASSERT(IS_c(b)&&b->n>5000,"stdlib modular get def.h"); 65 | xfree(c);xfree(b); 66 | c=mkworkspace(); 67 | b=evalstrin("[\"a\",\"b\",\".x\"] File.path",c); 68 | ASSERT(_equal(b,xfroms("a/b.x")),"File.path"); 69 | c=mkworkspace(); 70 | b=evalstrin("\"/a/b/c\" File.basename",c); 71 | ASSERT(_equal(b,xfroms("c")),"File.basename"); 72 | xfree(b);xfree(c); 73 | c=mkworkspace(); 74 | b=evalstrin("\"/a/b/c\" File.dirname",c); 75 | ASSERT(_equal(b,xfroms("/a/b/")),"File.dirname"); 76 | xfree(b);xfree(c); 77 | #endif 78 | 79 | c=mkworkspace(); 80 | b=evalstrin("543 as 'zebra; 'zebra get",c); 81 | ASSERT(IS_i(b) && AS_i(b,0) == 543,"test . get"); 82 | xfree(c);xfree(b); 83 | 84 | c=mkworkspace(); 85 | b=evalstrin("['abc:100,'xyz:999]each{-1}",c); 86 | a=evalstrin("['abc:99,'xyz:998]",c); 87 | ASSERT(_equal(repr(b),repr(a)),"dict each"); 88 | 89 | c=mkworkspace(); 90 | b=evalstrin("7 as 'p;[[p]]",c); 91 | ASSERT(_equal(b,xl(xl(xi(7)))),"nested simple listexpr"); 92 | 93 | c=mkworkspace(); 94 | b=evalstrin("[(1,2,3),(9,8,7)] eachb +",c); 95 | ASSERT(_equal(b,xin(3,10,10,10)),"eachboth"); 96 | 97 | c=mkworkspace(); 98 | b=evalstrin("[(1,2,3),(9,8,7)] >: +",c); 99 | ASSERT(_equal(b,xin(3,10,10,10)),"eachboth short"); 100 | 101 | c=mkworkspace(); 102 | b=evalstrin("[(1,2,3),3] \\: +",c); 103 | ASSERT(_equal(b,xin(3,4,5,6)),"eachleft short"); 104 | 105 | c=mkworkspace(); 106 | b=evalstrin("[3,(1,2,3)] /: +",c); 107 | ASSERT(_equal(b,xin(3,4,5,6)),"eachright short"); 108 | 109 | c=mkworkspace(); 110 | b=evalstrin("2,3,4 :: (*2)",c); 111 | ASSERT(_equal(b,xin(3,4,6,8)),"each as ::"); 112 | 113 | c=mkworkspace(); 114 | b=evalstrin("\"hello\"!((1,2,5),\"x\")",c); 115 | ASSERT(_equal(b,xfroms("hxxlox")),"amend many indices one value"); 116 | 117 | c=mkworkspace(); 118 | b=evalstrin("[]!(1,\"jordache\")",c); 119 | ASSERT(_equal(repr(b),xfroms("[null, \"jordache\"]")),"amend empty list"); 120 | xfree(b); xfree(c); 121 | 122 | c=mkworkspace(); 123 | b=evalstrin("\"abc\"~\"\"![0,1]",c); 124 | ASSERT(_equal(b,xbn(3,1,0,0)),"amend byte vec with int"); 125 | xfree(b); xfree(c); 126 | 127 | c=mkworkspace(); 128 | b=evalstrin("'z is 20; 30 as 'b;z*b",c); 129 | XRAY_emit(b); 130 | ASSERT(_equal(b,xi(600)),"is vs as"); 131 | 132 | c=mkworkspace(); 133 | b=evalstrin("['a:1,'b:2] make 'table,[3,4],[5,6],[7,8],[[9,10],[11,12]] as 't; t@'a vec + (t@'b vec) = (3,7,11,15,19,23)",c); 134 | ASSERT(_equal(b,XI1), "table 0"); 135 | 136 | c=mkworkspace(); 137 | b=evalstrin("['a:1,'b:'j] make 'table,[3,'z],[5,'q],[7,'m],[[9,'b],[11,'m]] as 't; [(t@'b)],(t@'a) >: {x str,(y str)} join \"\"",c); 138 | ASSERT(_equal(b,xfroms("j1z3q5m7b9m11")), "table 1"); 139 | 140 | c=mkworkspace(); 141 | b=evalstrin("['a:1,'b:'j] make 'table,[3,'z],[5,'q],[7,'m],[[9,'b],[11,'m]]@0",c); 142 | ASSERT(_equal(repr(b),xfroms("['a:1, 'b:'j]")),"table scalar subscript"); 143 | 144 | c=mkworkspace(); 145 | b=evalstrin("['a:1,'b:'j] make 'table,[3,'z],[5,'q],[7,'m],[[9,'b],[11,'m]]@(1,2)@'a vec sum",c); 146 | ASSERT(_equal(b,xi(8)),"table vector subscript"); 147 | 148 | c=mkworkspace(); 149 | b=evalstrin("('a,'b,'c):[]",c); 150 | ASSERT(IS_EXC(b), "unlike vectors check when making table"); 151 | 152 | c=mkworkspace(); 153 | b=evalstrin("('a,'b,'c):[['a,2,4], ['b,4,6]]as 't len*(t@'c vec)sum",c); 154 | ASSERT(_equal(b,xi(20)),"table built with a list of lists"); 155 | 156 | c=mkworkspace(); 157 | b=apply_simple_(evalstrin("1,2,3",c),0); 158 | ASSERT(_equal(b,xi(1)),"apply_simple_ 0"); 159 | xfree(b);xfree(c); 160 | 161 | c=mkworkspace(); 162 | b=evalstrin("[\"B1\"]",c); 163 | ASSERT(LIST(b) && IS_c(LIST_first(b)), "listexpr with non-scalar simple content"); 164 | 165 | c=mkworkspace(); 166 | b=evalstrin("('a,'b,'c):[['a,2,4],['b,4,6]]~{x}",c); 167 | ASSERT(_equal(repr(b),xfroms("[['a:'a, 'b:2, 'c:4], ['a:'b, 'b:4, 'c:6]]")),"matcheasy with table - identity"); 168 | 169 | c=mkworkspace(); 170 | b=evalstrin("('a,'b,'c):[ ['a,2,4], ['b,4,6] ]first",c); 171 | ASSERT(_equal(repr(b),xfroms("['a:'a, 'b:2, 'c:4]")),"table first"); 172 | 173 | c=mkworkspace(); 174 | b=evalstrin("1,2,3 recurse {rot1}",c); 175 | ASSERT(_equal(repr(b),xfroms("[(2,3,1), (3,1,2)]")),"recurse0"); 176 | 177 | c=mkworkspace(); 178 | b=evalstrin("1,2,3 exhaust {rot1}",c); 179 | ASSERT(_equal(repr(b),xfroms("(3,1,2)")),"exhaust0"); 180 | 181 | c=mkworkspace(); 182 | b=evalstrin("1,2,3 except 4",c); 183 | ASSERT(_equal(repr(b),xfroms("(1,2,3)")),"except0"); 184 | 185 | c=mkworkspace(); 186 | b=evalstrin("1,2,3 except (3)",c); 187 | ASSERT(_equal(repr(b),xfroms("(1,2)")),"except1"); 188 | 189 | c=mkworkspace(); 190 | b=evalstrin("1,2,3 except (3,1)",c); 191 | ASSERT(_equal(repr(b),xfroms("2")),"except2"); 192 | 193 | c=mkworkspace(); 194 | b=evalstrin("[1,2,3]::{\"{\"}flat",c); 195 | XRAY_emit(repr(b)); 196 | ASSERT(_equal(repr(b),xfroms("\"{{{\"")),"bracequote"); 197 | 198 | c=mkworkspace(); 199 | b=evalstrin("[[1,2,3],[4,5,6]]join\":\"",c); 200 | ASSERT(_equal(repr(b),xfroms("[[1, 2, 3], \":\", [4, 5, 6]]")),"join list flat"); 201 | 202 | c=mkworkspace(); 203 | b=evalstrin("\"a\"range\"d\"",c); 204 | ASSERT(_equal(repr(b),repr(xfroms("abcd"))),"range with chars"); 205 | xfree(c); 206 | 207 | c=mkworkspace(); 208 | b=evalstrin("65535 base 16",c); 209 | ASSERT(_equal(repr(b),repr(xfroms("ffff"))),"base 16 0"); 210 | b=evalstrin("45325235 base 16",c); //arb 211 | ASSERT(_equal(repr(b),repr(xfroms("2b39bb3"))),"base 16 1"); 212 | b=evalstrin("45325235 as 'z base 16 base 16 = z",c); //arb 213 | ASSERT(_equal(b,xi(1)),"base 16 2"); 214 | xfree(c); 215 | 216 | c=mkworkspace(); 217 | b=evalstrin("[1,2,3]del0",c); 218 | a=evalstrin("[2,3]",c); 219 | ASSERT(_equal(repr(b),repr(a)),"del list 0"); 220 | 221 | c=mkworkspace(); 222 | b=evalstrin("[1,2,3]del2",c); 223 | a=evalstrin("[1,2]",c); 224 | ASSERT(_equal(repr(b),repr(a)),"del list 1"); 225 | 226 | c=mkworkspace(); 227 | b=evalstrin("[1,2,3]del4",c); 228 | a=evalstrin("[1,2,3]",c); 229 | ASSERT(_equal(repr(b),repr(a)),"del list 2"); 230 | 231 | c=mkworkspace(); 232 | b=evalstrin("['a:1,'b:2,'c:3]del 'b",c); 233 | a=evalstrin("['a:1,'c:3]",c); 234 | ASSERT(_equal(repr(b),repr(a)),"del dict 0"); 235 | 236 | c=mkworkspace(); 237 | b=evalstrin("['a:1,'b:2,'c:3]del 'z",c); 238 | a=evalstrin("['a:1,'b:2,'c:3]",c); 239 | ASSERT(_equal(repr(b),repr(a)),"del dict 1"); 240 | xfree(c);xfree(b);xfree(a); 241 | 242 | c=mkworkspace(); 243 | b=evalstrin("['a:1;'b:2]as 'z;4 as 'z.b;z",c); 244 | a=evalstrin("['a:1;'b:4]",c); 245 | ASSERT(_equal(repr(b),repr(a)),"set at depth 0"); 246 | b=evalstrin("'inner is ['bb:['c:10]]; 'outer is ['b:['ba:5,'bb:inner]]; ['z:10,outer] as 't; t.b.bb.c",c); 247 | ASSERT(_equal(b,xi(10)),"index at very deep 0"); 248 | 249 | b=evalstrin("(1,2)from(4,5,6)",c); 250 | ASSERT(_equal(b,xin(2,5,6)),"from 0"); 251 | 252 | 253 | -------------------------------------------------------------------------------- /tests/test-nest.h: -------------------------------------------------------------------------------- 1 | // historical note: 2 | // nest() used to always break apart the matched pieces, as shown here: 3 | // a=xin(3,1,2,3); 4 | // b=xin(2,1,3); 5 | // ASSERT(_equal(c, xl(xln(3, xi(1), xi(2), xi(3)))), "nest 0"); 6 | // this is because of the dumb iterative algorithm in the old version; 7 | // though part of the api's contract, i dont think it makes sense. 8 | // i'd like to avoid this for like-typed inputs for now, so im changing 9 | // these tests. it still does wrap non-list results in a list, because 10 | // nest is supposed to "create" lists out of items (like and unlike) 11 | // @tlack 1/25 12 | a=xin(3,1,2,3); 13 | b=xin(2,1,3); 14 | c=nest(a,b); 15 | XRAY_emit(c); 16 | XRAY_emit(info(c)); 17 | if(LIST(c)) 18 | XRAY_emit(info(ELl(c,0))); 19 | ASSERT(_equal(c, xl(xin(3, 1, 2, 3))), "nest 0"); 20 | 21 | a=xin(5,9,0,0,0,8); 22 | b=xin(2,9,8); 23 | c=nest(a,b); 24 | XRAY_emit(c); 25 | ASSERT(_equal(c,xl(xin(5,9,0,0,0,8))),"nest 1"); 26 | 27 | a=xin(5,9,0,0,0,8); 28 | b=xin(2,6,6); 29 | c=nest(a,b); 30 | XRAY_log("nest2:\n"); 31 | XRAY_emit(c); 32 | XRAY_emit(info(c)); 33 | ASSERT(_equal(c,xin(5,9,0,0,0,8)),"nest 2"); 34 | 35 | a=xin(5,9,1,0,2,8); 36 | b=xin(2,1,2); 37 | XRAY_log("nest3 call:\n"); 38 | c=nest(a,b); 39 | XRAY_emit(c); 40 | ASSERT(_equal(c,xln(3,xi(9),xl(xin(3,1,0,2)),xi(8))),"nest 3"); 41 | 42 | a=xin(5,9,1,0,2,8); 43 | b=xin(2,2,8); 44 | XRAY_log("nest4 call:\n"); 45 | c=nest(a,b); 46 | XRAY_emit(c); 47 | ASSERT(_equal(c,xln(4,xi(9),xi(1),xi(0),xin(2,2,8))),"nest 4"); 48 | 49 | a=xin(7,9,1,1,0,2,2,8); 50 | b=xin(2,1,2); 51 | XRAY_log("nest5 call:\n"); 52 | c=exhaust(a,proj(2,&nest,0,b)); 53 | //c=nest(a,b); 54 | XRAY_emit(c); 55 | ASSERT(_equal(c,xln(3, 56 | xi(9), 57 | xln(3, xi(1), 58 | xin(3, 1,0,2), 59 | xi(2)), 60 | xi(8))),"nest 5"); 61 | 62 | a=xin(5,7,7,0,8,8); 63 | b=xln(2, xin(2,7,7), xin(2,8,8)); 64 | c=nest(a,b); 65 | XRAY_emit(c); 66 | XRAY_emit(info(c)); 67 | XRAY_emit(each(c,x1(&info))); 68 | ASSERT(_equal(c, xl( xin(5,7,7,0,8,8) )), "nest multi 0"); 69 | 70 | -------------------------------------------------------------------------------- /tests/test-semantics.h: -------------------------------------------------------------------------------- 1 | VP a,b,c; 2 | a=mkworkspace(); 3 | b=evalstrin("['a:1]$'table as 'z,['b:2]",a); 4 | XRAY_emit(b); 5 | ASSERT(_len(b)==2 && _len(KEYS(b))==2,"table append dict"); 6 | xfree(b); 7 | b=evalstrin("[1,2]as 'z!z,3 as 'b;z len=(b len)",a); 8 | ASSERT(NUM_val(b)==0,"list not shadowed"); 9 | xfree(b); 10 | b=evalstrin("['a:1]as 'z,['b,2]as 'b;z len=(b len)",a); 11 | c=evalstrin("z len*(b len)",a); 12 | XRAY_emit(b); 13 | XRAY_emit(c); 14 | ASSERT(NUM_val(b)==0 && NUM_val(c)==2,"dict not shadowed"); 15 | xfree(b); 16 | xfree(c); 17 | b=evalstrin("['a:1]$'table as 'z,['b:2]as 'b;z len=(b len)",a); 18 | XRAY_emit(key(a)); 19 | ASSERT(NUM_val(b)==0,"table not shadowed"); 20 | xfree(b); 21 | 22 | b=evalstrin("['a:1]$'table,['a:5],['a:7]@'a over +",a); 23 | ASSERT(NUM_val(b)==13,"table get sym"); 24 | 25 | b=evalstrin("[\"abc\":1]$'table,[\"abc\":5],[\"abc\":7]@\"abc\" over +",a); 26 | ASSERT(NUM_val(b)==13,"table get string col"); 27 | 28 | /* 29 | * b=evalstrin("['a:1,'b:2] make 'table as 't; 128 count :: {t,['a:x,'b:(7*x)] as 't};t",a); 30 | ASSERT(_len(b)==129,"table append a few"); 31 | c=evalstrin("t@'b sum",a); 32 | ASSERT(NUM_val(c)==56898,"table count a few"); 33 | */ 34 | b=evalstrin("'blah is 6; 10 {x as '.blah}; blah",a); 35 | ASSERT(_equal(b,xi(10)), "assign global in anonymous lambda"); 36 | b=evalstrin("'blah is 6; {x as '.blah} as 'cb; 10 cb; blah",a); 37 | ASSERT(_equal(b,xi(10)), "assign global in assigned lambda"); 38 | xfree(b); 39 | b=evalstrin("'addermaker is {10+x as 'a; {x+a as '.a}}; 100 addermaker as 'myadd; 1 range 5 :: myadd",a); 40 | ASSERT(_equal(b,xin(5,111,113,116,120,125)),"test adder"); 41 | xfree(b); 42 | xfree(a); 43 | a=mkworkspace(); 44 | b=evalstrin("'fun is {'addermaker is {10+x as 'a; {x+a as '.a}}; x addermaker as 'myadd; 1 range 5 :: { myadd }}; 100 fun",a); 45 | ASSERT(_equal(b,xin(5,111,113,116,120,125)),"test adder nested"); 46 | xfree(a); 47 | 48 | a=mkworkspace(); 49 | b=evalstrin("'emit is {y}; 'route is {1 emit 'z as 'a;a}; []route=('z)",a); 50 | ASSERT(_equal(b,XI1),"test bug regarding dyadic functions and applyexpr not resetting xxl_cur_ctx which screws up apply()"); 51 | xfree(a); 52 | 53 | // TODO scope tests 54 | // TODO self tests 55 | 56 | -------------------------------------------------------------------------------- /tests/test-y-in-lambda.xxl: -------------------------------------------------------------------------------- 1 | {y+2*x} as 'p; 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/undefined-x.xxl: -------------------------------------------------------------------------------- 1 | x+1 2 | 3 | -------------------------------------------------------------------------------- /tools/syntax/vim-build.xxl: -------------------------------------------------------------------------------- 1 | 'LANGREF is ([]sys@'srcpath,"/doc/lang.xxl"); // CONFIG 2 | 'TMPL is (_dir,"vim-template.vim"); // 3 | 4 | LANGREF load@'name::{"syn keyword xxlPrim ",x}join"\n" as 'kws; 5 | TMPL .file.get split "__KEYWORDS__" join kws 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools/syntax/vim-syntax.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: XXL 3 | " Maintainer: Thomas Lackner 4 | " Latest Revision: 29 Feb 2016 5 | if exists("b:current_syntax") 6 | finish 7 | endif 8 | syn keyword xxlTodo TODO FIXME FIX XXX "NB." NOTE GOTCHA contained 9 | syn match xxlComment "/\*.*\*/" contains=xxlTodo 10 | syn match xxlComment "//.*$" contains=xxlTodo 11 | syn region xxlComment start="/\*" end="\*/" contains=xxlTodo 12 | syn region xxlString start=+"+ skip=+\\.+ end=+"+ 13 | syn region xxlBlock start="{" end="}" fold transparent 14 | syn match xxlSym "'[A-Za-z_\?\.]\+\s*" 15 | syn match xxlName "[A-Za-z_\?\.]\+\s*" 16 | syn match xxlTypeSym "\'\(list\|tag\|byte\|char\|int\|long\|float\|dict\|table\)\W" 17 | syn match xxlSep ";" 18 | syn match xxlNum '\d\+' 19 | syn match xxlNum '[-+]\d\+' 20 | syn match xxlNum '\d\+\.\d*' 21 | syn match xxlNum '[-+]\d\+\.\d*' 22 | syn match xxlNum '[-+]\=\d[[:digit:]]*[eE][\-+]\=\d\+' 23 | syn match xxlNum '\d[[:digit:]]*[eE][\-+]\=\d\+' 24 | syn match xxlNum '[-+]\=\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' 25 | syn match xxlNum '\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' 26 | syn keyword xxlSpecial . 27 | syn keyword xxlPrim as 28 | syn keyword xxlPrim is 29 | syn keyword xxlPrim get 30 | syn keyword xxlPrim split 31 | syn keyword xxlPrim join 32 | syn keyword xxlPrim take 33 | syn keyword xxlPrim drop 34 | syn keyword xxlPrim enlist 35 | syn keyword xxlPrim except 36 | syn keyword xxlPrim flat 37 | syn keyword xxlPrim case 38 | syn keyword xxlPrim each 39 | syn keyword xxlPrim parse 40 | syn keyword xxlPrim show 41 | syn keyword xxlPrim sys 42 | syn keyword xxlPrim any 43 | syn keyword xxlPrim arity 44 | syn keyword xxlPrim behead 45 | syn keyword xxlPrim condense 46 | syn keyword xxlPrim count 47 | syn keyword xxlPrim clone 48 | syn keyword xxlPrim curtail 49 | syn keyword xxlPrim info 50 | syn keyword xxlPrim first 51 | syn keyword xxlPrim last 52 | syn keyword xxlPrim list 53 | syn keyword xxlPrim len 54 | syn keyword xxlPrim key 55 | syn keyword xxlPrim min 56 | syn keyword xxlPrim max 57 | syn keyword xxlPrim neg 58 | syn keyword xxlPrim not 59 | syn keyword xxlPrim repr 60 | syn keyword xxlPrim rev 61 | syn keyword xxlPrim selftest 62 | syn keyword xxlPrim str 63 | syn keyword xxlPrim sum 64 | syn keyword xxlPrim sums 65 | syn keyword xxlPrim tag 66 | syn keyword xxlPrim type 67 | syn keyword xxlPrim val 68 | syn keyword xxlPrim vec 69 | syn keyword xxlPrim xray 70 | syn keyword xxlPrim :: 71 | syn keyword xxlPrim amend 72 | syn keyword xxlPrim and 73 | syn keyword xxlPrim aside 74 | syn keyword xxlPrim base 75 | syn keyword xxlPrim bracketj 76 | syn keyword xxlPrim call 77 | syn keyword xxlPrim consecj 78 | syn keyword xxlPrim deal 79 | syn keyword xxlPrim deep 80 | syn keyword xxlPrim eachl 81 | syn keyword xxlPrim eachr 82 | syn keyword xxlPrim emit 83 | syn keyword xxlPrim evalin 84 | syn keyword xxlPrim exhaust 85 | syn keyword xxlPrim get 86 | syn keyword xxlPrim iftrue 87 | syn keyword xxlPrim ifelse 88 | syn keyword xxlPrim in 89 | syn keyword xxlPrim loadin 90 | syn keyword xxlPrim make 91 | syn keyword xxlPrim nest 92 | syn keyword xxlPrim pick 93 | syn keyword xxlPrim or 94 | syn keyword xxlPrim orelse 95 | syn keyword xxlPrim over 96 | syn keyword xxlPrim range 97 | syn keyword xxlPrim ravel 98 | syn keyword xxlPrim recurse 99 | syn keyword xxlPrim rot 100 | syn keyword xxlPrim scan 101 | syn keyword xxlPrim wide 102 | 103 | let b:current_syntax = "xxl" 104 | hi def link xxlBlock Statement 105 | hi def link xxlComment Comment 106 | hi def link xxlNum Constant 107 | hi def link xxlName Identifier 108 | hi def link xxlPrim Special 109 | hi def link xxlSep Separator 110 | hi def link xxlSpecial Special 111 | hi def link xxlString Constant 112 | hi def link xxlSym Identifier 113 | hi def link xxlTodo Todo 114 | hi def link xxlTypeSym Type 115 | 116 | -------------------------------------------------------------------------------- /tools/syntax/vim-template.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: XXL 3 | " Maintainer: Thomas Lackner 4 | " Latest Revision: 29 Feb 2016 5 | if exists("b:current_syntax") 6 | finish 7 | endif 8 | syn keyword xxlTodo TODO FIXME FIX XXX "NB." NOTE GOTCHA contained 9 | syn match xxlComment "/\*.*\*/" contains=xxlTodo 10 | syn match xxlComment "//.*$" contains=xxlTodo 11 | syn region xxlComment start="/\*" end="\*/" contains=xxlTodo 12 | syn region xxlString start=+"+ skip=+\\.+ end=+"+ 13 | syn region xxlBlock start="{" end="}" fold transparent 14 | syn match xxlSym "'[A-Za-z_\?\.]\+\s*" 15 | syn match xxlName "[A-Za-z_\?\.]\+\s*" 16 | syn match xxlTypeSym "\'\(list\|tag\|byte\|char\|int\|long\|float\|dict\|table\)\W" 17 | syn match xxlSep ";" 18 | syn match xxlNum '\d\+' 19 | syn match xxlNum '[-+]\d\+' 20 | syn match xxlNum '\d\+\.\d*' 21 | syn match xxlNum '[-+]\d\+\.\d*' 22 | syn match xxlNum '[-+]\=\d[[:digit:]]*[eE][\-+]\=\d\+' 23 | syn match xxlNum '\d[[:digit:]]*[eE][\-+]\=\d\+' 24 | syn match xxlNum '[-+]\=\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' 25 | syn match xxlNum '\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' 26 | syn keyword xxlSpecial . 27 | syn keyword xxlPrim as 28 | syn keyword xxlPrim is 29 | syn keyword xxlPrim get 30 | __KEYWORDS__ 31 | 32 | let b:current_syntax = "xxl" 33 | hi def link xxlBlock Statement 34 | hi def link xxlComment Comment 35 | hi def link xxlNum Constant 36 | hi def link xxlName Identifier 37 | hi def link xxlPrim Special 38 | hi def link xxlSep Separator 39 | hi def link xxlSpecial Special 40 | hi def link xxlString Constant 41 | hi def link xxlSym Identifier 42 | hi def link xxlTodo Todo 43 | hi def link xxlTypeSym Type 44 | -------------------------------------------------------------------------------- /txpost/CONFIG-default.xxl: -------------------------------------------------------------------------------- 1 | [ 2 | 'HOST:"localhost", 3 | 'PORT:8000, 4 | 'PRETTY:"http://localhost:8000/", 5 | 'ROOT:"/tmp/txpost", 6 | 'KEYCH:"0123456789abcdefijkmnpqrstvxyz-_", 7 | 'MINLEN:16 8 | ] 9 | 10 | 11 | -------------------------------------------------------------------------------- /txpost/app.xxl: -------------------------------------------------------------------------------- 1 | _dir,"/CONFIG.xxl" load as 'c; 2 | 'emit is {[y,x]show;x}; 3 | 'keyfn is {[c.ROOT,("x",(x@0 orelse "")),("y",(x@1 orelse "")),x] show join "/"}; 4 | 'filterkey is {in(c.KEYCH as 'kc)condense from x show}; 5 | 'makekey is {filterkey as 'ks; (c.KEYCH list deal (c.MINLEN-(ks len)|0),"-" join ""),ks}; 6 | 'POST is {y File.set (x makekey show as 'k keyfn show); 'ok#(c.PRETTY,k)}; 7 | 'GET is {filterkey keyfn as 'k File.get ifelse [{'ok#x},('unk#k," not found")]}; 8 | 'status is ['ok:"200 OK",'unk:"404 Not Found"]; 9 | 'wrapresp is {x show tag from status as 'hdr; x str as 'resp len str as 'szs; 10 | "HTTP/1.0 ",hdr,"\r\nContent-Length: ",szs,"\r\n", 11 | "Connection: close\r\n","Server: xxl v0.0\r\n\r\n", 12 | resp show}; 13 | 'route is { 14 | x first split "\r\n" as 'bparts; 15 | x first split "\r\n\r\n"@1 as 'body; 16 | bparts first split" "as 'req; // request line 17 | req first as 'method; 18 | req@1 behead orelse "index" as 'path emit 'path; 19 | method first="P" ifelse [{path show POST body},{path show GET}] wrapresp 20 | }; 21 | 'webh is {x route}; 22 | (c.PORT,c.HOST) Net.bind webh; 23 | // utility stuff: 24 | 'mkroot is {[c.KEYCH],c.KEYCH/:{[x,y]\:{[c.ROOT,("x",x),("y",y)]File.path as 'p;"mkdir -p '",p,"'" Shell.get}}} 25 | 26 | -------------------------------------------------------------------------------- /txpost/start.sh: -------------------------------------------------------------------------------- 1 | ../x app.xxl 2 | -------------------------------------------------------------------------------- /txpost/test.sh: -------------------------------------------------------------------------------- 1 | curl -vvvvv http://txpo.st/ 2 | dt=`date +%Y%m%d%H%M%S` 3 | URL=`curl --verbose --data "hello world! $dt" http://txpo.st/t0` 4 | echo $URL 5 | curl -vvvvv $URL 6 | curl --verbose --data "hax $dt" http://txpo.st/ 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | // Autogenerated file; see corresponding .js 2 | 3 | static type_info_t TYPES[] = { 4 | { 0, 'l', sizeof(VP), "list", &repr_l }, 5 | { 1, 't', sizeof(tag_t), "tag", &repr_t }, 6 | { 2, 'c', sizeof(char), "char", &repr_c }, 7 | { 3, 'b', sizeof(int8_t), "byte", &repr_b }, 8 | { 4, 'i', sizeof(int), "int", &repr_i }, 9 | { 5, 'j', sizeof(__int64_t), "long", &repr_j }, 10 | { 6, 'o', sizeof(__int128_t), "octa", &repr_o }, 11 | { 7, 'f', sizeof(double), "float", &repr_f }, 12 | { 8, 'd', sizeof(VP), "dict", &repr_d }, 13 | { 9, 'a', sizeof(VP), "table", &repr_a }, 14 | { 10, '1', sizeof(unaryFunc*), "f1", &repr_1 }, 15 | { 11, '2', sizeof(binaryFunc*), "f2", &repr_2 }, 16 | { 12, 'p', sizeof(Proj), "proj", &repr_p }, 17 | { 13, 'x', sizeof(VP), "ctx", &repr_x }, 18 | }; 19 | -------------------------------------------------------------------------------- /types.js: -------------------------------------------------------------------------------- 1 | var lib = require('./common.js'); 2 | console.log(lib.prelude); 3 | console.log('static type_info_t TYPES[] = { '); 4 | lib.each(lib.types,function(t) { 5 | var tmpls=[ 6 | "{ {{0}}, '{{1}}', sizeof({{3}}), \"{{2}}\", &repr_{{1}} }," 7 | ]; 8 | lib.each(tmpls,function(tmpl) { 9 | console.log(lib.exhaust(lib.projr(lib.repl,t),tmpl)); 10 | }); 11 | }); 12 | console.log('};'); 13 | 14 | -------------------------------------------------------------------------------- /util/memusg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # memusg -- Measure memory usage of processes 3 | # Usage: memusg COMMAND [ARGS]... 4 | # 5 | # Author: Jaeho Shin 6 | # Created: 2010-08-16 7 | ############################################################################ 8 | # Copyright 2010 Jaeho Shin. # 9 | # # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); # 11 | # you may not use this file except in compliance with the License. # 12 | # You may obtain a copy of the License at # 13 | # # 14 | # http://www.apache.org/licenses/LICENSE-2.0 # 15 | # # 16 | # Unless required by applicable law or agreed to in writing, software # 17 | # distributed under the License is distributed on an "AS IS" BASIS, # 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 19 | # See the License for the specific language governing permissions and # 20 | # limitations under the License. # 21 | ############################################################################ 22 | set -um 23 | 24 | # check input 25 | [[ $# -gt 0 ]] || { sed -n '2,/^#$/ s/^# //p' <"$0"; exit 1; } 26 | 27 | # TODO support more options: peak, footprint, sampling rate, etc. 28 | 29 | pgid=$(ps -o pgid= $$) 30 | # make sure we're in a separate process group 31 | if [[ "$pgid" == "$(ps -o pgid= $(ps -o ppid= $$))" ]]; then 32 | cmd= 33 | set -- "$0" "$@" 34 | for a; do cmd+="'${a//"'"/"'\\''"}' "; done 35 | exec bash -i -c "$cmd" 36 | fi 37 | 38 | # detect operating system and prepare measurement 39 | case $(uname) in 40 | Darwin|*BSD) sizes() { /bin/ps -o rss= -g $1; } ;; 41 | Linux) sizes() { /bin/ps -o rss= -$1; } ;; 42 | *) echo "$(uname): unsupported operating system" >&2; exit 2 ;; 43 | esac 44 | 45 | # monitor the memory usage in the background. 46 | ( 47 | peak=0 48 | while sizes=$(sizes $pgid) 49 | do 50 | set -- $sizes 51 | sample=$((${@/#/+})) 52 | let peak="sample > peak ? sample : peak" 53 | sleep 0.1 54 | done 55 | echo "memusg: peak=$peak" >&2 56 | ) & 57 | monpid=$! 58 | 59 | 60 | # run the given command 61 | exec "$@" -------------------------------------------------------------------------------- /util/vg: -------------------------------------------------------------------------------- 1 | rm vg.log 2 | valgrind ./0 >vg.log 2>&1 3 | more vg.log 4 | 5 | 6 | -------------------------------------------------------------------------------- /vary.js: -------------------------------------------------------------------------------- 1 | // 2 | // In C, it's difficult to have code that is variadic based on run time 3 | // parameters. For instance you can't make C easily create a long as variable 4 | // "a" in some cases and a byte as variable "a" in other cases based on some 5 | // runtime variable's contents. You have to switch based on the type, often 6 | // allocate memory and do a lot of extra work, and that makes everything 7 | // complicated and time consuming to write. 8 | // 9 | // This code creates some macros that make it easier to write C code that 10 | // varies by type. 11 | // 12 | // TODO VARY_*() macros need to handle general list more robustly 13 | // TODO VARY_*() should be able to cast to best sizes in some circumstances 14 | // TODO consider switching to ribosome of these kinds of scripts 15 | // TODO VARY_*() macros should be rewritten in terms of the minimum subset of types they accept 16 | // 17 | var lib = require('./common.js'); 18 | function skip(t) { 19 | t=t[1]; 20 | return (lib.dontcast.indexOf(t)!=-1)?true:false; 21 | } 22 | 23 | console.log(lib.prelude + 24 | "// vary on a single element. unpacks x[i] into a C variable \n"+ 25 | "// called _x, of the correct c native type. then executes \n"+ 26 | "// your code (stmt). If it's a type that can't be unpacked, \n"+ 27 | "// the TAG of the type is set in failvar, you can handle it. \n\n"+ 28 | "// VARY_EL varies over one element: x[i]. \n"+ 29 | "#define VARY_EL(x,i,stmt,failvar) ({ \\"); 30 | var tmpls=[ 31 | "\tif(x->t=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}};}\\", 32 | "\tif(x->t=={{x0}}){/*{{x2}}*/\\\n"+ 33 | "\t\t{{x3}} _x=AS_{{x1}}(x,i);\\\n"+ 34 | "\t\tstmt;}\\" 35 | ]; 36 | lib.each(lib.types,function(tx) { 37 | if(skip(tx))tmpl=tmpls[0]; 38 | else tmpl=tmpls[1]; 39 | var a=[]; 40 | for(var i in tx)a["x"+i]=tx[i]; 41 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 42 | }); 43 | console.log("})"); 44 | 45 | console.log(lib.prelude + 46 | "// same as above, but doesnt allow floats (think bitwise operations)\n" + 47 | "#define VARY_EL_NOFLOAT(x,i,stmt,failvar) ({ \\"); 48 | var tmpls=[ 49 | "\tif(x->t=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}};}\\", 50 | "\tif(x->t=={{x0}}){/*{{x2}}*/\\\n"+ 51 | "\t\t{{x3}} _x=AS_{{x1}}(x,i);\\\n"+ 52 | "\t\tstmt;}\\" 53 | ]; 54 | lib.each(lib.types,function(tx) { 55 | if(tx[1]=='f' || skip(tx))tmpl=tmpls[0]; 56 | else tmpl=tmpls[1]; 57 | var a=[]; 58 | for(var i in tx)a["x"+i]=tx[i]; 59 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 60 | }); 61 | console.log("})"); 62 | 63 | console.log("#define VARY_EACH(x,stmt,failvar) ({ \\\n" + 64 | "\tint _i=0,_xn=x->n,_xt=x->t; /*XRAY_log(\"VE\");DUMP(x);*/\\"); 65 | var tmpl="\tif(_xt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 66 | lib.each(lib.types,function(tx) { 67 | if(skip(tx)){ 68 | var a=[]; 69 | for(var i in tx)a["x"+i]=tx[i]; 70 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 71 | } 72 | }); 73 | var tmpl="\tif(_xt=={{x0}}){/*{{x2}}*/ \\\n" + 74 | "\t\t{{x3}} _x,_xtmp=0;\\\n" + 75 | "\t\twhile (_i < _xn) { _x=AS_{{x1}}(x,_i); /* printf(\"%d {{5}}\\n\", _i, _x); */ stmt; _i++; }\\\n" + 76 | "\t}\\"; 77 | lib.each(lib.types,function(tx) { 78 | if(skip(tx))return; 79 | var a=[]; 80 | for(var i in tx)a["x"+i]=tx[i]; 81 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 82 | }); 83 | console.log("})"); 84 | 85 | console.log("#define VARY_EACH_NOFLOAT(x,stmt,failvar) ({ \\\n" + 86 | "\tint _i=0,_xn=x->n,_xt=x->t; /*XRAY_log(\"VE\");DUMP(x);*/\\"); 87 | var tmpl="\tif(_xt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 88 | lib.each(lib.types,function(tx) { 89 | if(skip(tx) || tx[1]=="f"){ 90 | var a=[]; 91 | for(var i in tx)a["x"+i]=tx[i]; 92 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 93 | } 94 | }); 95 | var tmpl="\tif(_xt=={{x0}}){/*{{x2}}*/ \\\n" + 96 | "\t\t{{x3}} _x,_xtmp=0;\\\n" + 97 | "\t\twhile (_i < _xn) { _x=AS_{{x1}}(x,_i); /* printf(\"%d {{5}}\\n\", _i, _x); */ stmt; _i++; }\\\n" + 98 | "\t}\\"; 99 | lib.each(lib.types,function(tx) { 100 | if(skip(tx) || tx[1]=="f")return; 101 | var a=[]; 102 | for(var i in tx)a["x"+i]=tx[i]; 103 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 104 | }); 105 | console.log("})"); 106 | 107 | console.log("#define VARY_EACHLIST(x,stmt,failvar) ({ \\\n" + 108 | "\tint _i=0,_xn=x->n,_xt=x->t; /*XRAY_log(\"VE\");DUMP(x);*/\\"); 109 | var tmpl="\tif(_xt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 110 | lib.each(lib.types,function(tx) { 111 | if(tx[1] != 'l' && skip(tx)){ 112 | var a=[]; 113 | for(var i in tx)a["x"+i]=tx[i]; 114 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 115 | } 116 | }); 117 | var tmpl="\tif(_xt=={{x0}}){/*{{x2}}*/ \\\n" + 118 | "\t\t{{x3}} _x,_xtmp=0;\\\n" + 119 | "\t\twhile (_i < _xn) { _x=AS_{{x1}}(x,_i); /* printf(\"%d {{5}}\\n\", _i, _x); */ stmt; _i++; }\\\n" + 120 | "\t}\\"; 121 | lib.each(lib.types,function(tx) { 122 | if(tx[1] != 'l' && skip(tx))return; 123 | var a=[]; 124 | for(var i in tx)a["x"+i]=tx[i]; 125 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 126 | }); 127 | console.log("})"); 128 | 129 | console.log("#define VARY_EACHBOTH(x,y,stmt,failvar) ({ \\\n" + 130 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 131 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 132 | lib.each(lib.types,function(tx) { 133 | if(tx[1] != 'l' && skip(tx)){ 134 | var a=[]; 135 | for(var i in tx)a["x"+i]=tx[i]; 136 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 137 | } 138 | }); 139 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 140 | "\t\t{{x3}} _x,_xtmp=0; {{y3}} _y,_ytmp;\\\n" + 141 | "\t\twhile (_i<_xn && _j<_yn) { _x=AS_{{x1}}(x,_i%_xn); _y=AS_{{y1}}(y,_j%_yn); stmt; \\\n"+ 142 | "\t\tif(!SCALAR(x)) {_i++;} _j++; }\\\n" + 143 | "\t}\\"; 144 | lib.each(lib.types,function(tx) { 145 | if(skip(tx))return; 146 | lib.each(lib.types, function(ty) { 147 | if(skip(ty))return; 148 | var a=[]; 149 | for(var i in tx)a["x"+i]=tx[i]; 150 | for(var i in ty)a["y"+i]=ty[i]; 151 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 152 | }); 153 | }); 154 | console.log("})"); 155 | 156 | // identical to VARY_EACHBOTH, but doesnt allow floats 157 | console.log("#define VARY_EACHBOTH_NOFLOAT(x,y,stmt,failvar) ({ \\\n" + 158 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 159 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 160 | lib.each(lib.types,function(tx) { 161 | if(tx[1] != 'l' && skip(tx)){ 162 | var a=[]; 163 | for(var i in tx)a["x"+i]=tx[i]; 164 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 165 | } 166 | }); 167 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 168 | "\t\t{{x3}} _x,_xtmp=0; {{y3}} _y,_ytmp;\\\n" + 169 | "\t\twhile (_i<_xn && _j<_yn) { _x=AS_{{x1}}(x,_i%_xn); _y=AS_{{y1}}(y,_j%_yn); stmt; \\\n"+ 170 | "\t\tif(!SCALAR(x)) {_i++;} _j++; }\\\n" + 171 | "\t}\\"; 172 | lib.each(lib.types,function(tx) { 173 | if(tx[1]=="f" || skip(tx))return; 174 | lib.each(lib.types, function(ty) { 175 | if(ty[1]=="f" || skip(ty))return; 176 | var a=[]; 177 | for(var i in tx)a["x"+i]=tx[i]; 178 | for(var i in ty)a["y"+i]=ty[i]; 179 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 180 | }); 181 | }); 182 | console.log("})"); 183 | 184 | // identical to VARY_EACHBOTH, but allows x or y to be a list 185 | console.log("#define VARY_EACHBOTHLIST(x,y,stmt,failvar) ({ \\\n" + 186 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 187 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 188 | lib.each(lib.types,function(tx) { 189 | if(tx[1] != 'l' && skip(tx)){ 190 | var a=[]; 191 | for(var i in tx)a["x"+i]=tx[i]; 192 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 193 | } 194 | }); 195 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 196 | "\t\t{{x3}} _x,_xtmp=0; {{y3}} _y,_ytmp;\\\n" + 197 | "\t\twhile (_i<_xn && _j<_yn) { _x=AS_{{x1}}(x,_i%_xn); _y=AS_{{y1}}(y,_j%_yn); stmt; \\\n"+ 198 | "\t\tif(!SCALAR(x)) {_i++;} _j++; }\\\n" + 199 | "\t}\\"; 200 | lib.each(lib.types,function(tx) { 201 | if(tx[1] != 'l' && skip(tx))return; 202 | lib.each(lib.types, function(ty) { 203 | if(skip(ty))return; 204 | var a=[]; 205 | for(var i in tx)a["x"+i]=tx[i]; 206 | for(var i in ty)a["y"+i]=ty[i]; 207 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 208 | }); 209 | }); 210 | console.log("})"); 211 | 212 | console.log("#define VARY_EACHLEFT(x,y,stmt,failvar) ({ \\\n" + 213 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 214 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 215 | lib.each(lib.types,function(tx) { 216 | if(skip(tx)){ 217 | var a=[]; 218 | for(var i in tx)a["x"+i]=tx[i]; 219 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 220 | } 221 | }); 222 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 223 | "\t\t{{x3}} _x;{{y3}} _y; _y=AS_{{y1}}(y,0);\\\n" + 224 | "\t\twhile (_i < _xn) { _x=AS_{{x1}}(x,_i); stmt; _i++; }\\\n" + 225 | "\t}\\"; 226 | lib.each(lib.types,function(tx) { 227 | if(skip(tx))return; 228 | lib.each(lib.types, function(ty) { 229 | if(skip(ty))return; 230 | var a=[]; 231 | for(var i in tx)a["x"+i]=tx[i]; 232 | for(var i in ty)a["y"+i]=ty[i]; 233 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 234 | }); 235 | }); 236 | console.log("})"); 237 | 238 | console.log("#define VARY_EACHRIGHT(x,y,stmt,failvar) ({ \\\n" + 239 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 240 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 241 | lib.each(lib.types,function(tx) { 242 | if(skip(tx)){ 243 | var a=[]; 244 | for(var i in tx)a["x"+i]=tx[i]; 245 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 246 | } 247 | }); 248 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 249 | "\t\t{{x3}} _x;{{y3}} _y; _x=AS_{{x1}}(x,0);\\\n" + 250 | "\t\twhile (_j < _yn) { _y=AS_{{y1}}(y,_j); stmt; _j++; }\\\n" + 251 | "\t}\\"; 252 | lib.each(lib.types,function(tx) { 253 | if(skip(tx))return; 254 | lib.each(lib.types, function(ty) { 255 | if(skip(ty))return; 256 | var a=[]; 257 | for(var i in tx)a["x"+i]=tx[i]; 258 | for(var i in ty)a["y"+i]=ty[i]; 259 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 260 | }); 261 | }); 262 | console.log("})"); 263 | 264 | console.log("#define VARY_EACHRIGHT_NOFLOAT(x,y,stmt,failvar) ({ \\\n" + 265 | "\tint _i=0,_j=0,_xn=x->n,_yn=y->n,_xt=x->t,_yt=y->t;\\"); 266 | var tmpl="\tif(_xt=={{x0}}||_yt=={{x0}}){/*cant vary {{x2}}*/ failvar={{x0}}; }\\"; 267 | lib.each(lib.types,function(tx) { 268 | if(skip(tx)||tx[1]=="f"){ 269 | var a=[]; 270 | for(var i in tx)a["x"+i]=tx[i]; 271 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 272 | } 273 | }); 274 | var tmpl="\tif(_xt=={{x0}}&&_yt=={{y0}}){/*{{x2}} x {{y2}}*/ \\\n" + 275 | "\t\t{{x3}} _x;{{y3}} _y; _x=AS_{{x1}}(x,0);\\\n" + 276 | "\t\twhile (_j < _yn) { _y=AS_{{y1}}(y,_j); stmt; _j++; }\\\n" + 277 | "\t}\\"; 278 | lib.each(lib.types,function(tx) { 279 | if(skip(tx)||tx[1]=="f")return; 280 | lib.each(lib.types, function(ty) { 281 | if(skip(ty)||ty[1]=="f")return; 282 | var a=[]; 283 | for(var i in tx)a["x"+i]=tx[i]; 284 | for(var i in ty)a["y"+i]=ty[i]; 285 | console.log(lib.exhaust(lib.projr(lib.repl,a),tmpl)); 286 | }); 287 | }); 288 | console.log("})"); 289 | 290 | -------------------------------------------------------------------------------- /workbench/app.xxl: -------------------------------------------------------------------------------- 1 | // XXL Workbench, a web-based XXL development environment 2 | "localhost" as 'host; // configure these 3 | 8080 as 'port; 4 | _dir,"/ui.xxl" load as 'pagetmpl; // load html interface from ui.xxl (and css.xxl in turn) 5 | 6 | 'noshow is {x}; 7 | 'safe is ('A is (26count as 'l+65$'char),('a is (l+97$'char)),".,-+!$*'()"); // rfc1738 8 | 'urldec is {;" ",x,"%" split "%" as 'p first behead,(p behead curtail :: { "0x",(x take 2)base16$'char,(x drop 2)}orelse"") flat}; 9 | 'urlenc is {;"z",x||[]![{in safe not},{"%",(x$'int base 16)}] |# 1 ,| ""}; 10 | 'wrapresp is {x str as 'resp len str as 'szs; 11 | "HTTP/1.0 200 OK\r\nContent-Length: ",szs,"\r\n", 12 | "Connection: close\r\n","Server: xxl v0.0\r\n\r\n", 13 | resp}; 14 | 'makehttpserver is {; 15 | ['http,x] noshow; x as 'handlecb; 16 | { 17 | ['innerhttp,x] noshow; 18 | x first split "\r\n" as 'lines; // HTTP requests are separated with CRLF 19 | lines first split" " as 'method; // separate request line.. GET /file HTTP/1.0 20 | method@1 behead as 'uri show // pull out uri for further inspection and strip leading / 21 | case [ 22 | {uri show & uri@0="?"},{uri drop 1 urldec show evalin .}, 23 | {uri iftrue {_dir,"pub/",(uri![(uri~"/"condense),"_"]) show File.get as 'content}},{content}, 24 | {[method,lines] handlecb} 25 | ] wrapresp 26 | } 27 | }; 28 | 'workbench is {; 29 | ['inhandler,x] noshow;"Welcome" pagetmpl "" 30 | }; 31 | workbench makehttpserver as 'mywebapp; 32 | (port,host) show Net.bind mywebapp as 'handle; 33 | 34 | -------------------------------------------------------------------------------- /workbench/css.xxl: -------------------------------------------------------------------------------- 1 | "#282828" as 'bg; 2 | "#3d4041" as 'btnbg; 3 | "#4d5051" as 'btnbghl; 4 | "#9a9b9c" as 'btnfg; 5 | "#9ca9ab" as 'fg; 6 | "#f3f5f5" as 'headingfg; 7 | "#363838" as 'prbg; // prompts (input type=text) 8 | " 9 | * { box-sizing: border-box; } 10 | html { 11 | height: 100%; 12 | width: 100%; 13 | } 14 | a { 15 | color: ",fg,"; 16 | font-weight: bold; 17 | text-decoration: none; 18 | } 19 | a:hover { color: white; } 20 | p a { font-weight: normal; text-decoration: underline; } 21 | body { 22 | background: ",bg," no-repeat; 23 | color: ",fg,"; 24 | font-family:'Open Sans',Arial,'Lucida Grande',sans-serif; 25 | font-size: 1.1rem; 26 | height: 100%; 27 | line-height: 1.5rem; 28 | padding-top: 2rem; 29 | width: 100%; 30 | } 31 | @media only screen and (orientation:landscape) { 32 | body { 33 | background-image: url(bgxxl.jpg); 34 | background-size: cover; 35 | } 36 | } 37 | @media only screen and (orientation:landscape) 38 | and (min-device-width:768px) 39 | and (-webkit-min-device-pixel-ratio: 2) { 40 | body { 41 | background-image: url(bgxxl.jpg); 42 | background-size: cover; 43 | } 44 | } 45 | @media only screen and (orientation:landscape) 46 | and (min-width:1000px) { 47 | body { 48 | background-image: url(bgxxl.jpg); 49 | background-size: cover; 50 | } 51 | } 52 | h1 { 53 | background: url(logo.png) no-repeat; 54 | background-size:cover; 55 | height: 22px; 56 | text-indent:-5000px; 57 | width: 250px; 58 | } 59 | @media only screen and (min-width:1000px) { 60 | h1 { 61 | height: 45px; 62 | width: 500px; 63 | } 64 | } 65 | h2 { 66 | color: ",headingfg,"; 67 | font-size: 2rem; 68 | font-weight: 300; 69 | } 70 | iframe { 71 | background: ",btnbg,"; 72 | border: 0; 73 | margin: 0; 74 | outline none; 75 | position: fixed; 76 | bottom: 2rem; right: 2rem; 77 | max-height: 25%; 78 | max-width: 25%; 79 | } 80 | ins { 81 | border-radius: 3px; 82 | font-family: Consolas,'Liberation Mono', Menlo, Courier, monospace; 83 | font-size: 95%; 84 | padding: 0.2em 0.4em; margin: 0; 85 | background-color: rgba(0,0,0,0.1); 86 | text-decoration: none; 87 | } 88 | section { 89 | clear: both; 90 | margin-bottom: 1rem; margin-left: 2rem; margin-right: 2rem; 91 | } 92 | .menu { 93 | clear: both; display: block; 94 | } 95 | @media only screen and (min-width:700px) { 96 | .menu { 97 | position: fixed; right: 2rem; top: 2rem; 98 | } 99 | } 100 | .menu a { 101 | background: ",btnbg,"; 102 | box-shadow: 0px 0px 5px rgba(0,0,0,0.5); 103 | border-radius: 5px; 104 | color: ",btnfg,"; 105 | display: inline-block; 106 | font-size: 2rem; line-height: 1.5rem; 107 | margin-bottom: 1rem; margin-right: 2rem; 108 | height: 4rem; 109 | padding: 1rem 0 0 0; 110 | text-align: center; text-decoration: none; 111 | transition: 0.2s all; 112 | vertical-align: top; 113 | width: 5rem; 114 | } 115 | @media only screen and (min-width:700px) { 116 | .menu a { margin-bottom: 0; width: 6rem; } 117 | .pg { margin-top: 4rem; } 118 | } 119 | .menu a:last-child { margin-right: 0; padding-top: 1.25rem; // hamburger thing is optically too high } 120 | .menu a small { 121 | display: none; font-size: .7rem; 122 | } 123 | .menu a:hover { 124 | background: ",btnbghl,"; color: white; height: 6rem; 125 | } 126 | .menu a:hover small { 127 | display: block; margin-top: 1rem; 128 | } 129 | .modal { 130 | position: fixed; 131 | background: ",btnbg,"; 132 | display: none; 133 | left: 0%; top: 0%; 134 | width: 100%; height: 100%; 135 | min-height: 700px; 136 | padding: 2.5%; 137 | z-index: 999; 138 | } 139 | @media screen and (min-width: 760px) { 140 | .modal { 141 | left: 5%; top: 5%; 142 | width: 90%; height: 90%; 143 | } 144 | } 145 | .modal h2 { 146 | border-top: 1px solid ",btnbghl,"; 147 | margin: 4rem 0 2rem 0; padding: 4rem 0 0 0; 148 | font-family: 'times new roman', serif; 149 | font-style: italic; font-size: 2rem; font-weight: 300; 150 | letter-spacing: 2px; 151 | } 152 | .modal h2:first-child { border-top: 0; margin-top: 0; padding-top: 0; } 153 | .modal .modal-close { float: right; font-size: 2rem; z-index: 999; } 154 | .modal .modal-close a { color: white; } 155 | @media screen and (min-width: 760px) { 156 | .modal-active .modal { 157 | display: block; 158 | } 159 | .modal-active .all { 160 | -webkit-filter: grayscale(0.5) blur(10px); 161 | filter: grayscale(1) blur(10px); 162 | } 163 | } 164 | .pr { 165 | background: ",prbg,"; 166 | border: 1px solid ",bg,"; 167 | border-radius: 3px; 168 | color:",fg,"; 169 | font-size: 1.5em; 170 | outline: none; 171 | padding: 20px; 172 | transition: 0.2s all; 173 | width: calc(100% - 1rem); 174 | } 175 | .pr:focus { color: white; } 176 | .tip { clear: both; display: none; } 177 | @media only screen and (min-width:700px) { 178 | .tip { max-width: 400px; } 179 | } 180 | .tmpl { display: none; } 181 | #repl { 182 | font-size: 1.5rem; 183 | } 184 | #repl ol { 185 | font-size: 0.8rem; 186 | margin: 0 0 0 -10px; padding: 0; 187 | vertical-align: top; 188 | } 189 | #repl ol li { 190 | margin-top: 1rem; 191 | } 192 | #repl .o { 193 | margin-left: 1rem; 194 | } 195 | #repl .perf { 196 | display: block; 197 | float: right; 198 | font-style: italic; 199 | margin-right: 1rem; 200 | opacity: 0.5; 201 | } 202 | #repl .pr { 203 | background: rgba(0,0,0,0.05); 204 | margin-left: 10px; 205 | padding: 0; 206 | width: calc(100% - 1rem); 207 | } 208 | #repl .pr:focus { 209 | background: ",prbg,"; 210 | font-size: 2rem; 211 | } 212 | " 213 | 214 | -------------------------------------------------------------------------------- /workbench/pub/app.js: -------------------------------------------------------------------------------- 1 | // configure these: 2 | var PIP_REFRESH = 5*1000; // how often should picture-in-picture refresh? 3 | // code begins here 4 | var KEYSEND=13, KEYHELP=16; 5 | var PIPS={}, TIME; 6 | function $(x) {return document.querySelector(x);} 7 | function $$(x) {return mkarray(document.querySelectorAll(x));} 8 | function $li() {return $('ol li:last-child ');} 9 | function $pr() {return $('ol li:last-child .pr');} 10 | function domempty($) { $.innerHTML=''; } 11 | function get(url,cb) { 12 | var req = new XMLHttpRequest(); 13 | req.open('GET', url, true); 14 | req.onload = function() { 15 | console.log(req); 16 | if (req.status >= 200 && req.status < 400) cb(true,req.responseText); 17 | else { alert('onload error'); cb(false,req); } 18 | }; 19 | req.onerror = function(why) { alert(JSON.stringify(why)); cb(false, req); } 20 | req.send(); 21 | } 22 | function mkarray(x) {return Array.prototype.slice.call(x);} 23 | function mkdom(htmlstr) { 24 | var d=document.createElement('div'); d.innerHTML="
"+htmlstr+"
"; return d.childNodes[0];} 25 | function modal(html) { // open with html string or DOM nodes, close with "" 26 | var $b=$('body'), bc=$b.className; 27 | if(html=="") { $b.className = bc.replace(' modal-active',''); return; } // close 28 | if(html[0]==".") html=$(html).innerHTML; 29 | if(typeof(html)==typeof("")) html=mkdom(html); 30 | domempty($('.modal-inner')); 31 | $('.modal-inner').appendChild(html); 32 | $b.className = bc+' modal-active'; 33 | repl.bind(); 34 | return; 35 | } 36 | function init() {repl.bind(); repl.draw(); setInterval(pip.draw, pip.REFRESH); } 37 | function show(x) {console.log(x); return x; } 38 | function Bclose() {return modal(""); } 39 | function Bmenu() {return modal(".menudlg"); } 40 | function Bshare() {return modal(".savedlg"); } 41 | function Bpip() {return modal(".pipdlg"); } 42 | var pip={ 43 | REFRESH:PIP_REFRESH, 44 | body: function(content) {return "
/pipclose
'+content;}, 45 | draw: function() { 46 | if(PIPS.length == 0) return; 47 | var $p=$("#pips"); 48 | for(var cmd in PIPS) { 49 | var pipwin=PIPS[cmd]; 50 | if(!pipwin) { 51 | var pipwin = document.createElement('iframe'); pipwin.src = 'about:blank'; 52 | $p.appendChild(pipwin); PIPS[cmd]=pipwin; 53 | } 54 | var cw=pipwin.contentWindow.document; 55 | server.eval(cmd, function(res,data) { 56 | if (!res) data="Error: "+data; 57 | cw.open(); cw.write(pip.body(data)); cw.close(); }); 58 | } 59 | }, 60 | } 61 | var server={ 62 | eval: function(cmdstr, cb) { get('?'+encodeURIComponent(cmdstr), cb); } 63 | } 64 | var repl={ 65 | $:$('#repl'), 66 | bind: function() { 67 | $$('.pr').forEach(function(e){ 68 | if(e.className.match(/demo/)) e.addEventListener('click', repl.ev.demo, false); 69 | else e.addEventListener('keydown', repl.ev.key, false); 70 | }); 71 | }, 72 | cmd: { 73 | 'pip': function(args) { 74 | if (!args) { domempty($('#pips')); return; } 75 | PIPS[args]=""; pip.draw(); repl.output('Picture-in-picture started'); return true; } 76 | }, 77 | draw:function() { 78 | repl.$.appendChild(show(mkdom('
    '))); 79 | repl.draw_.input(); 80 | }, 81 | draw_:{ 82 | input:function() { 83 | var item=document.createElement('li'); 84 | item.innerHTML=repl.draw_.pr(); 85 | console.log(item); 86 | $('#repl ol').appendChild(item); 87 | $pr().focus(); 88 | }, 89 | pr:function() { return ""; } 90 | }, 91 | ev:{ 92 | demo:function() { 93 | var tgt=window.event?window.event.target:e.target; 94 | repl.draw_.input(); modal(""); 95 | var p=$pr(); $pr().value=tgt.value; $pr().focus(); 96 | }, 97 | key:function() { 98 | var CR=KEYSEND; 99 | var ch=show(window.event?window.event.keyCode:e.which); 100 | var tgt=window.event?window.event.target:e.target; 101 | if(ch==CR) { $pr().blur(); modal(""); repl.evalstr(tgt.value); } 102 | return true; 103 | } 104 | }, 105 | evalresp:function(ok,resp) { 106 | if(!ok) $li().appendChild(mkdom("
    Error: "+JSON.stringify(resp)+"
    ")); 107 | else { 108 | if(TIME) { resp = ""+(Date.now()-TIME)+"ms"+resp; } 109 | repl.output(resp); 110 | } 111 | }, 112 | evalstr:function(s) { 113 | if(s[0]=='/') { var w=s.substr(1).split(' '); console.log(w); if(repl.cmd[w[0]] && repl.cmd[w[0]](w.slice(1).join(' ')))return false; } 114 | TIME=Date.now(); 115 | server.eval(s, repl.evalresp); 116 | }, 117 | output:function(html) { 118 | $li().appendChild(mkdom("
    "+html+"
    ")); 119 | repl.draw_.input(); 120 | } 121 | } 122 | init(); 123 | -------------------------------------------------------------------------------- /workbench/pub/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/bg.jpg -------------------------------------------------------------------------------- /workbench/pub/bgxxl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/bgxxl.jpg -------------------------------------------------------------------------------- /workbench/pub/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/favicon-16x16.png -------------------------------------------------------------------------------- /workbench/pub/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/favicon-32x32.png -------------------------------------------------------------------------------- /workbench/pub/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/favicon-96x96.png -------------------------------------------------------------------------------- /workbench/pub/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlack/xxl/58991190bb05faa86e07086cbb70029297d4333c/workbench/pub/logo.png -------------------------------------------------------------------------------- /workbench/ui.xxl: -------------------------------------------------------------------------------- 1 | { 2 | _dir,"css.xxl" load as 'css; 3 | []sys@'ver as 'ver; 4 | " 5 | 6 | 7 | XXL Workbench ",x," 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |

    XXL Workbench

    17 | 23 | 24 |
    25 |
    26 | ",y," 27 |
    28 |
    29 |
    30 | 31 |
    32 |
    33 | 54 |
    55 |

    Picture in Picture

    56 |

    57 | Enter an XXL expression below. Workbench will evaluate it every 5 seconds and show its result in the lower right 58 | of your web browser. 59 |

    60 | 61 |
    62 |
    63 |

    Save

    64 | Use /save to share your session history up to now. 65 | You can see your previous sessions by typing /load. 66 |

    67 | 68 |

    Share

    69 | Type /share [short dscription] to upload your session to the XXL pastebin. 70 | You'll get back a URL you can send to anyone you want. 71 |

    72 | 73 |

    74 | Don't worry. Your pastebin uploads aren't shown publicly to anyone unless you share the URL. 75 |

    76 |
    77 |
    78 | * { color: white; font-family:'Open Sans',Arial,'Lucida Grande',sans-serif; } 79 |
    80 |
    81 | 82 | 83 | " 84 | } 85 | 86 | -------------------------------------------------------------------------------- /x: -------------------------------------------------------------------------------- 1 | DIR=`dirname $(readlink -f $0)` 2 | echo $DIR 3 | XXL=$DIR/xxl 4 | RUN="$XXL " 5 | 6 | errcho() { echo "$@" 1>&2; } 7 | 8 | if which rlwrap >/dev/null; then 9 | errcho using rlwrap 10 | RUN="rlwrap $RUN" 11 | fi 12 | 13 | if which llvm-symbolizer-3.6 >/dev/null; then 14 | errcho using ASAN_SYMBOLIZER_PATH 15 | ASAN_SYMBOLIZER_PATH=`which llvm-symbolizer-3.6` 16 | export ASAN_SYMBOLIZER_PATH 17 | fi 18 | 19 | $RUN $* 20 | 21 | 22 | --------------------------------------------------------------------------------