History

rephasor initial implementation

Paul Batchelor committed 5 years ago

Commit 028ae442 parents 92f2327 936bd7c60 files · +4535 −77Browse files

Unified · Split

60 files
  1. Makefile +52 −43
  2. core.org +25 −0
  3. dsp/bezier.org +0 −0
  4. dsp/bigverb.org +0 −0
  5. dsp/biramp.org +0 −0
  6. dsp/bitnoise.org +0 −0
  7. dsp/chaosnoise.org +0 −0
  8. dsp/dcblocker.org +0 −0
  9. dsp/expmap.org +0 −0
  10. dsp/fmpair.org +0 −0
  11. dsp/modalres.org +0 −0
  12. dsp/osc.org +0 −0
  13. dsp/oscf.org +0 −0
  14. dsp/peakeq.org +0 −0
  15. dsp/phasewarp.org +0 −0
  16. dsp/phasor.org +0 −0
  17. dsp/phsclk.org +0 −0
  18. dsp/rephasor.org +12 −4
  19. dsp/rline.org +0 −0
  20. dsp/scale.org +0 −0
  21. dsp/scrubber.org +0 −0
  22. dsp/swell.org +0 −0
  23. dsp/valp1.org +0 −0
  24. dsp/vardelay.org +0 −0
  25. examples/Makefile +1 −1
  26. examples/ex2.c +4 −5
  27. examples/ex3.c +109 −0
  28. examples/ex4.lil +5 −0
  29. examples/hello.lil +3 −0
  30. examples/phasor.lil +5 −0
  31. lil/LICENSE +18 −0
  32. lil/lil.c +3526 −0
  33. lil/lil.h +153 −0
  34. mkdb.janet +20 −20
  35. nodes/arith/arith.c +90 −0
  36. nodes/arith/arith.h +7 −0
  37. nodes/arith/config.mk +2 −0
  38. nodes/arith/l_arith.c +27 −0
  39. nodes/config.mk +3 −0
  40. nodes/loader.c +50 −0
  41. nodes/phasor/config.mk +2 −0
  42. nodes/phasor/l_phasor.c +26 −0
  43. nodes/phasor/phasor.c +88 −0
  44. nodes/phasor/phasor.h +4 −0
  45. nodes/rephasor/config.mk +2 −0
  46. nodes/rephasor/l_rephasor.c +27 −0
  47. nodes/rephasor/rephasor.c +93 −0
  48. nodes/rephasor/rephasor.h +4 −0
  49. nodes/rephasor/test.lil +12 −0
  50. nodes/scale/config.mk +1 −0
  51. nodes/scale/l_scale.c +44 −0
  52. nodes/scale/scale.c +35 −3
  53. nodes/scale/scale.h +1 −0
  54. nodes/sine/config.mk +1 −0
  55. nodes/sine/l_sine.c +27 −0
  56. nodes/sine/sine.c +1 −1
  57. nodes/sklil.c +18 −0
  58. nodes/sklil.h +10 −0
  59. nodes/wavout/config.mk +1 −0
  60. nodes/wavout/l_wavout.c +26 −0
Makefile+52−43
@@ -8,59 +8,65 @@ WORGLE_FLAGS=-g -Werror · 7 unmodified lines
88 C89?=$(CC) -std=c89
99 C99?=$(CC) -std=c99
1010
11−CFLAGS += -Ipatchwerk -I.
11+CFLAGS += -Ipatchwerk -I. -Inodes
1212 CFLAGS += -Wall
1313 CFLAGS += -O3
1414 CFLAGS += -g
1515
1616 TANGLED=\
17−bigverb.c bigverb.h \
18−bitnoise.c bitnoise.h \
19−chaosnoise.c chaosnoise.h \
20−dcblocker.c dcblocker.h \
21−fmpair.c fmpair.h \
22−modalres.c modalres.h \
23−osc.c osc.h \
24−peakeq.c peakeq.h \
25−phasewarp.c phasewarp.h \
26−rline.c rline.h \
27−valp1.c valp1.h \
28−vardelay.c vardelay.h \
29−oscf.c oscf.h \
30−bezier.c bezier.h \
31−phasor.c phasor.h \
32−swell.c swell.h \
33−biramp.c biramp.h \
34−core.c core.h \
35−expmap.c expmap.h \
36−scale.c scale.h \
37−rephasor.c rephasor.h \
17+dsp/bigverb.c dsp/bigverb.h \
18+dsp/bitnoise.c dsp/bitnoise.h \
19+dsp/chaosnoise.c dsp/chaosnoise.h \
20+dsp/dcblocker.c dsp/dcblocker.h \
21+dsp/fmpair.c dsp/fmpair.h \
22+dsp/modalres.c dsp/modalres.h \
23+dsp/osc.c dsp/osc.h \
24+dsp/peakeq.c dsp/peakeq.h \
25+dsp/phasewarp.c dsp/phasewarp.h \
26+dsp/rline.c dsp/rline.h \
27+dsp/valp1.c dsp/valp1.h \
28+dsp/vardelay.c dsp/vardelay.h \
29+dsp/oscf.c dsp/oscf.h \
30+dsp/bezier.c dsp/bezier.h \
31+dsp/phasor.c dsp/phasor.h \
32+dsp/swell.c dsp/swell.h \
33+dsp/biramp.c dsp/biramp.h \
34+dsp/expmap.c dsp/expmap.h \
35+dsp/scale.c dsp/scale.h \
36+dsp/rephasor.c dsp/rephasor.h \
37+
38+TANGLED+=core.c core.h
3839
3940 OBJ=\
40−bigverb.o \
41−bitnoise.o \
42−chaosnoise.o \
43−dcblocker.o \
44−fmpair.o \
45−modalres.o \
46−osc.o \
47−peakeq.o \
48−phasewarp.o \
49−rline.o \
50−valp1.o \
51−vardelay.o \
52−oscf.o \
53−bezier.o \
54−phasor.o \
55−swell.o \
56−biramp.o \
41+dsp/bigverb.o \
42+dsp/bitnoise.o \
43+dsp/chaosnoise.o \
44+dsp/dcblocker.o \
45+dsp/fmpair.o \
46+dsp/modalres.o \
47+dsp/osc.o \
48+dsp/peakeq.o \
49+dsp/phasewarp.o \
50+dsp/rline.o \
51+dsp/valp1.o \
52+dsp/vardelay.o \
53+dsp/oscf.o \
54+dsp/bezier.o \
55+dsp/phasor.o \
56+dsp/swell.o \
57+dsp/biramp.o \
5758 core.o \
5859 patchwerk/patchwerk.o \
59−scale.o \
60−rephasor.o \
60+dsp/scale.o \
61+dsp/rephasor.o \
6162
6263 include nodes/config.mk
6364
65+OBJ+=lil/lil.c99
66+OBJ+=lil/lil_main.c99
67+OBJ+=nodes/loader.o
68+OBJ+=nodes/sklil.o
69+
6470 .SUFFIX: .org .c
6571
6672 .SUFFIXES: .org .c
@@ -78,7 +84,7 @@ include nodes/config.mk · 11 unmodified lines
7884 @echo "$(C99) $<"
7985 @$(C99) -c $(CFLAGS) $< -o $@
8086
81−default: libsndkit.a
87+default: tangle sndkit libsndkit.a
8288
8389 sync:
8490 weewiki sync
@@ -130,10 +136,13 @@ keys.db: keys.txt · 45 unmodified lines
130136
131137 tangle: worgle/worglite $(TANGLED)
132138
133−libsndkit.a: tangle $(OBJ)
139+libsndkit.a: $(OBJ)
134140 @echo "Building $@"
135141 @$(AR) rcs $@ $(OBJ)
136142
143+sndkit: main.o $(OBJ)
144+ $(CC) $(CFLAGS) $^ -o $@
145+
137146 clean:
138147 $(RM) $(TANGLED)
139148 $(RM) worgle/worglite
core.org+25−0
@@ -118,6 +118,31 @@ void sk_core_compute(sk_core *core) · 117 unmodified lines
118118 }
119119 #+END_SRC
120120
121+=sk_core_computes= is like =sk_core_compute=, but computes
122+an approximuate number of seconds of audio. This value
123+gets rounded to the nearest block. The number of blocks
124+rendered gets rendered.
125+
126+#+NAME: funcdefs
127+#+BEGIN_SRC c
128+size_t sk_core_computes(sk_core *core, SKFLT secs);
129+#+END_SRC
130+
131+#+NAME: funcs
132+#+BEGIN_SRC c
133+size_t sk_core_computes(sk_core *core, SKFLT secs)
134+{
135+ size_t nblocks, n;
136+ nblocks = sk_core_seconds_to_blocks(core, secs);
137+
138+ for (n = 0; n < nblocks; n++) {
139+ sk_core_compute(core);
140+ }
141+
142+ return nblocks;
143+}
144+#+END_SRC
145+
121146 Building up nodes involves interacting with the patchwerk
122147 API. To get the top level struct of that opaquely, use
123148 =sk_core_patch=.
dsp/bezier.orgrenamed from bezier.org+0−0

File renamed without changes.

dsp/bigverb.orgrenamed from bigverb.org+0−0

File renamed without changes.

dsp/biramp.orgrenamed from biramp.org+0−0

File renamed without changes.

dsp/bitnoise.orgrenamed from bitnoise.org+0−0

File renamed without changes.

dsp/chaosnoise.orgrenamed from chaosnoise.org+0−0

File renamed without changes.

dsp/dcblocker.orgrenamed from dcblocker.org+0−0

File renamed without changes.

dsp/expmap.orgrenamed from expmap.org+0−0

File renamed without changes.

dsp/fmpair.orgrenamed from fmpair.org+0−0

File renamed without changes.

dsp/modalres.orgrenamed from modalres.org+0−0

File renamed without changes.

dsp/osc.orgrenamed from osc.org+0−0

File renamed without changes.

dsp/oscf.orgrenamed from oscf.org+0−0

File renamed without changes.

dsp/peakeq.orgrenamed from peakeq.org+0−0

File renamed without changes.

dsp/phasewarp.orgrenamed from phasewarp.org+0−0

File renamed without changes.

dsp/phasor.orgrenamed from phasor.org+0−0

File renamed without changes.

dsp/phsclk.orgrenamed from phsclk.org+0−0

File renamed without changes.

dsp/rephasor.orgrenamed from rephasor.org+12−4
@@ -133,6 +133,7 @@ SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in); · 132 unmodified lines
133133 SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in)
134134 {
135135 SKFLT out;
136+ SKFLT delta;
136137 out = 0;
137138 <<set_output>>
138139 <<calculate_delta>>
@@ -144,14 +145,18 @@ SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in) · 5 unmodified lines
144145
145146 The current phase of the internal phasor is set to be
146147 the output of the current sample. If it is negative, it
147−assumed to be initalized but not set, and the current
148+is assumed to be initalized but not set, and the current
148149 phasor signal is set to be the output, and the
149150 internal phasor value is set to be the current external
150151 phasor value.
151152
152153 #+NAME: set_output
153154 #+BEGIN_SRC c
155+if (rp->phs < 0) {
156+ rp->phs = in;
157+}
154158
159+out = rp->phs;
155160 #+END_SRC
156161
157162 The =delta= amount is calculated next. This is the absolute
@@ -162,7 +167,8 @@ initialized, the delta value is zero. · 4 unmodified lines
162167
163168 #+NAME: calculate_delta
164169 #+BEGIN_SRC c
165−
170+if (rp->extphs < 0 || in < rp->extphs) delta = 0;
171+else delta = in - rp->extphs;
166172 #+END_SRC
167173
168174 At this point, it is safe to cache the external phasor
@@ -170,7 +176,7 @@ signal. · 1 unmodified line
170176
171177 #+NAME: cache_external_phasor
172178 #+BEGIN_SRC c
173−
179+rp->extphs = in;
174180 #+END_SRC
175181
176182 The internal phasor is updated. The increment value
@@ -179,5 +185,7 @@ Wraparound is applied so that the range is within 0 and 1. · 2 unmodified lines
179185
180186 #+NAME: update_internal_phasor
181187 #+BEGIN_SRC c
182−
188+rp->phs += delta * rp->scale;
189+while (rp->phs >= 1.0) rp->phs -= 1.0;
190+while (rp->phs < 0.0) rp->phs += 1.0;
183191 #+END_SRC
dsp/rline.orgrenamed from rline.org+0−0

File renamed without changes.

dsp/scale.orgrenamed from scale.org+0−0

File renamed without changes.

dsp/scrubber.orgrenamed from scrubber.org+0−0

File renamed without changes.

dsp/swell.orgrenamed from swell.org+0−0

File renamed without changes.

dsp/valp1.orgrenamed from valp1.org+0−0

File renamed without changes.

dsp/vardelay.orgrenamed from vardelay.org+0−0

File renamed without changes.

examples/Makefile+1−1
@@ -1,4 +1,4 @@
1−EX=ex1.bin ex2.bin
1+EX=ex1.bin ex2.bin ex3.bin
22
33 LDFLAGS=-L../
44 CFLAGS=-I../ -I../patchwerk -I../nodes
examples/ex2.c+4−5
@@ -5,6 +5,7 @@ · 4 unmodified lines
55 #include "wavout/wavout.h"
66 #include "sine/sine.h"
77 #include "scale/scale.h"
8+#include "arith/arith.h"
89
910 int patch(sk_core *core)
1011 {
@@ -14,16 +15,14 @@ int patch(sk_core *core) · 3 unmodified lines
1415
1516 rc = sk_core_constant(core, 5);
1617 SK_ERROR_CHECK(rc);
17− rc = sk_core_constant(core, 1);
18+ rc = sk_core_constant(core, 40);
1819 SK_ERROR_CHECK(rc);
1920 rc = sk_node_sine(core);
2021 SK_ERROR_CHECK(rc);
2122
22− rc = sk_core_constant(core, 200);
23+ rc = sk_core_constant(core, 440);
2324 SK_ERROR_CHECK(rc);
24− rc = sk_core_constant(core, 300);
25− SK_ERROR_CHECK(rc);
26− rc = sk_node_biscale(core);
25+ rc = sk_node_add(core);
2726 SK_ERROR_CHECK(rc);
2827
2928 rc = sk_core_constant(core, 0.1);
examples/ex3.c+109−0
@@ -0,0 +1,109 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sine/sine.h"
8+#include "wavout/wavout.h"
9+#include "arith/arith.h"
10+
11+
12+#define ARITY_CHECK(LIL, NODE, ARGC, NARGS) \
13+if (ARGC < NARGS) { \
14+ lil_set_error(lil, NODE ": not enough args."); \
15+ return NULL; \
16+}
17+
18+const char * patch=
19+"sine 350 0.2;"
20+"sine [add [sine 0.1 100] 440] 0.2;"
21+"add zz zz;"
22+"wavout zz test.wav;"
23+;
24+
25+static void param(sk_core *core, lil_value_t arg)
26+{
27+ const char *sarg;
28+ sarg = lil_to_string(arg);
29+
30+ if (!strcmp(sarg, "zz") || strlen(sarg) == 0) {
31+ return;
32+ }
33+
34+ sk_core_constant(core, lil_to_double(arg));
35+}
36+
37+static lil_value_t sine(lil_t lil, size_t argc, lil_value_t *argv)
38+{
39+ sk_core *core;
40+ core = lil_get_data(lil);
41+
42+ ARITY_CHECK(lil, "sine", argc, 2);
43+
44+ param(core, argv[0]);
45+ param(core, argv[1]);
46+
47+ sk_node_sine(core);
48+ return NULL;
49+}
50+
51+static lil_value_t add(lil_t lil, size_t argc, lil_value_t *argv)
52+{
53+ sk_core *core;
54+ core = lil_get_data(lil);
55+
56+ param(core, argv[0]);
57+ param(core, argv[1]);
58+
59+ sk_node_add(core);
60+ return NULL;
61+}
62+
63+static lil_value_t wavout(lil_t lil, size_t argc, lil_value_t *argv)
64+{
65+ sk_core *core;
66+
67+ core = lil_get_data(lil);
68+
69+ param(core, argv[0]);
70+
71+ sk_node_wavout(core, lil_to_string(argv[1]));
72+ return NULL;
73+}
74+
75+int main(int argc, char *argv[])
76+{
77+ lil_t lil;
78+ lil_value_t val;
79+ sk_core *core;
80+ const char *err_msg;
81+ unsigned int nblocks, n;
82+ size_t pos;
83+
84+ lil = lil_new();
85+ core = sk_core_new(44100);
86+ lil_set_data(lil, core);
87+
88+ lil_register(lil, "sine", sine);
89+ lil_register(lil, "wavout", wavout);
90+ lil_register(lil, "add", add);
91+ val = lil_parse(lil, patch, strlen(patch), 0);
92+ lil_free_value(val);
93+
94+ if (lil_error(lil, &err_msg, &pos)) {
95+ fprintf(stderr, "lil: error at %i: %s\n", (int)pos, err_msg);
96+ goto clean;
97+ }
98+
99+ nblocks = sk_core_seconds_to_blocks(core, 10);
100+
101+ for (n = 0; n < nblocks; n++) {
102+ sk_core_compute(core);
103+ }
104+
105+ clean:
106+ lil_free(lil);
107+ sk_core_del(core);
108+ return 0;
109+}
examples/ex4.lil+5−0
@@ -0,0 +1,5 @@
1+# basically ex3
2+sine 350 0.2
3+sine [add [sine 0.1 100] 440] 0.2
4+add zz zz
5+wavout zz test.wav
examples/hello.lil+3−0
@@ -0,0 +1,3 @@
1+sine 440 0.5
2+wavout zz "sine.wav"
3+computes 40
examples/phasor.lil+5−0
@@ -0,0 +1,5 @@
1+phasor 1 0
2+biscale zz 220 440
3+sine zz 0.5
4+wavout zz "phasor.wav"
5+computes 10
lil/LICENSE+18−0
@@ -0,0 +1,18 @@
1+LIL - Little Interpreted Language
2+Copyright (C) 2010-2019 Kostas Michalopoulos
3+
4+This software is provided 'as-is', without any express or implied
5+warranty. In no event will the authors be held liable for any damages
6+arising from the use of this software.
7+
8+Permission is granted to anyone to use this software for any purpose,
9+including commercial applications, and to alter it and redistribute it
10+freely, subject to the following restrictions:
11+
12+1. The origin of this software must not be misrepresented; you must not
13+ claim that you wrote the original software. If you use this software
14+ in a product, an acknowledgment in the product documentation would be
15+ appreciated but is not required.
16+2. Altered source versions must be plainly marked as such, and must not be
17+ misrepresented as being the original software.
18+3. This notice may not be removed or altered from any source distribution.
lil/lil.c+3526−0
@@ -0,0 +1,3526 @@
1+/*
2+ * LIL - Little Interpreted Language
3+ * Copyright (C) 2010-2013 Kostas Michalopoulos
4+ *
5+ * This software is provided 'as-is', without any express or implied
6+ * warranty. In no event will the authors be held liable for any damages
7+ * arising from the use of this software.
8+ *
9+ * Permission is granted to anyone to use this software for any purpose,
10+ * including commercial applications, and to alter it and redistribute it
11+ * freely, subject to the following restrictions:
12+ *
13+ * 1. The origin of this software must not be misrepresented; you must not
14+ * claim that you wrote the original software. If you use this software
15+ * in a product, an acknowledgment in the product documentation would be
16+ * appreciated but is not required.
17+ * 2. Altered source versions must be plainly marked as such, and must not be
18+ * misrepresented as being the original software.
19+ * 3. This notice may not be removed or altered from any source distribution.
20+ *
21+ * Kostas Michalopoulos <badsector@runtimelegend.com>
22+ */
23+
24+#define __LIL_C_FILE__
25+#include <stdlib.h>
26+#include <stdio.h>
27+#include <string.h>
28+#include <ctype.h>
29+#include <math.h>
30+#include "lil.h"
31+
32+/* Enable pools for reusing values, lists and environments. This will use more memory and
33+ * will rely on the runtime/OS to free the pools once the program ends, but will cause
34+ * considerably less memory fragmentation and improve the script execution performance. */
35+/*#define LIL_ENABLE_POOLS*/
36+
37+/* Enable limiting recursive calls to lil_parse - this can be used to avoid call stack
38+ * overflows and is also useful when running through an automated fuzzer like AFL */
39+/*#define LIL_ENABLE_RECLIMIT 10000*/
40+
41+/* Visual C++ does not have atoll (Pelles C does and thinks it is fully MSVC compatible) */
42+#if defined(_MSC_VER) && !defined(__POCC__)
43+#define atoll _atoi64
44+/* disable warning about unsafe standard C calls */
45+#pragma warning(disable:4996)
46+/* disable float/int conversion warnings */
47+#pragma warning(disable:4244)
48+#endif
49+
50+#define ERROR_NOERROR 0
51+#define ERROR_DEFAULT 1
52+#define ERROR_FIXHEAD 2
53+
54+#define CALLBACKS 8
55+#define MAX_CATCHER_DEPTH 16384
56+#define HASHMAP_CELLS 256
57+#define HASHMAP_CELLMASK 0xFF
58+
59+/* note: static lil_xxx functions might become public later */
60+
61+struct hashentry_t
62+{
63+ char* k;
64+ void* v;
65+};
66+
67+struct hashcell_t
68+{
69+ struct hashentry_t* e;
70+ size_t c;
71+};
72+
73+typedef struct _hashmap_t
74+{
75+ struct hashcell_t cell[HASHMAP_CELLS];
76+} hashmap_t;
77+
78+struct _lil_value_t
79+{
80+ size_t l;
81+#ifdef LIL_ENABLE_POOLS
82+ size_t c;
83+#endif
84+ char* d;
85+};
86+
87+struct _lil_var_t
88+{
89+ char* n;
90+ char* w;
91+ struct _lil_env_t* env;
92+ lil_value_t v;
93+};
94+
95+struct _lil_env_t
96+{
97+ struct _lil_env_t* parent;
98+ lil_func_t func;
99+ lil_value_t catcher_for;
100+ lil_var_t* var;
101+ size_t vars;
102+ hashmap_t varmap;
103+ lil_value_t retval;
104+ int retval_set;
105+ int breakrun;
106+};
107+
108+struct _lil_list_t
109+{
110+ lil_value_t* v;
111+ size_t c;
112+ size_t cap;
113+};
114+
115+struct _lil_func_t
116+{
117+ char* name;
118+ lil_value_t code;
119+ lil_list_t argnames;
120+ lil_func_proc_t proc;
121+};
122+
123+struct _lil_t
124+{
125+ const char* code; /* need save on parse */
126+ const char* rootcode;
127+ size_t clen; /* need save on parse */
128+ size_t head; /* need save on parse */
129+ int ignoreeol;
130+ lil_func_t* cmd;
131+ size_t cmds;
132+ size_t syscmds;
133+ hashmap_t cmdmap;
134+ char* catcher;
135+ int in_catcher;
136+ char* dollarprefix;
137+ lil_env_t env;
138+ lil_env_t rootenv;
139+ lil_env_t downenv;
140+ lil_value_t empty;
141+ int error;
142+ size_t err_head;
143+ char* err_msg;
144+ lil_callback_proc_t callback[CALLBACKS];
145+ size_t parse_depth;
146+ void* data;
147+ char* embed;
148+ size_t embedlen;
149+};
150+
151+typedef struct _expreval_t
152+{
153+ const char* code;
154+ size_t len, head;
155+ lilint_t ival;
156+ double dval;
157+ int type;
158+ int error;
159+} expreval_t;
160+
161+static lil_value_t next_word(lil_t lil);
162+static void register_stdcmds(lil_t lil);
163+
164+#ifdef LIL_ENABLE_POOLS
165+static lil_value_t* pool;
166+static int poolsize, poolcap;
167+static lil_list_t* listpool;
168+static size_t listpoolsize, listpoolcap;
169+static lil_env_t* envpool;
170+static size_t envpoolsize, envpoolcap;
171+#endif
172+
173+static char* strclone(const char* s)
174+{
175+ size_t len = strlen(s) + 1;
176+ char* ns = malloc(len);
177+ if (!ns) return NULL;
178+ memcpy(ns, s, len);
179+ return ns;
180+}
181+
182+static unsigned long hm_hash(const char* key)
183+{
184+ unsigned long hash = 5381;
185+ int c;
186+ while ((c = *key++)) hash = ((hash << 5) + hash) + c;
187+ return hash;
188+}
189+
190+static void hm_init(hashmap_t* hm)
191+{
192+ memset(hm, 0, sizeof(hashmap_t));
193+}
194+
195+static void hm_destroy(hashmap_t* hm)
196+{
197+ size_t i, j;
198+ for (i=0; i<HASHMAP_CELLS; i++) {
199+ for (j=0; j<hm->cell[i].c; j++)
200+ free(hm->cell[i].e[j].k);
201+ free(hm->cell[i].e);
202+ }
203+}
204+
205+static void hm_put(hashmap_t* hm, const char* key, void* value)
206+{
207+ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK);
208+ size_t i;
209+ for (i=0; i<cell->c; i++)
210+ if (!strcmp(key, cell->e[i].k)) {
211+ cell->e[i].v = value;
212+ return;
213+ }
214+ cell->e = realloc(cell->e, sizeof(struct hashentry_t)*(cell->c + 1));
215+ cell->e[cell->c].k = strclone(key);
216+ cell->e[cell->c].v = value;
217+ cell->c++;
218+}
219+
220+static void* hm_get(hashmap_t* hm, const char* key)
221+{
222+ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK);
223+ size_t i;
224+ for (i = 0; i<cell->c; i++)
225+ if (!strcmp(key, cell->e[i].k))
226+ return cell->e[i].v;
227+ return NULL;
228+}
229+
230+static int hm_has(hashmap_t* hm, const char* key)
231+{
232+ struct hashcell_t* cell = hm->cell + (hm_hash(key) & HASHMAP_CELLMASK);
233+ size_t i;
234+ for (i = 0; i < cell->c; i++)
235+ if (!strcmp(key, cell->e[i].k))
236+ return 1;
237+ return 0;
238+}
239+
240+#ifdef LIL_ENABLE_POOLS
241+static lil_value_t alloc_from_pool(void)
242+{
243+ if (poolsize > 0) {
244+ poolsize--;
245+ return pool[poolsize];
246+ } else {
247+ lil_value_t val = calloc(1, sizeof(struct _lil_value_t));
248+ return val;
249+ }
250+}
251+
252+static void release_to_pool(lil_value_t val)
253+{
254+ if (poolsize == poolcap) {
255+ poolcap = poolcap ? (poolcap + poolcap / 2) : 64;
256+ pool = realloc(pool, sizeof(lil_value_t)*poolcap);
257+ }
258+ pool[poolsize++] = val;
259+}
260+
261+static void ensure_capacity(lil_value_t val, size_t cap)
262+{
263+ if (val->c < cap) {
264+ val->c = cap + 128;
265+ val->d = realloc(val->d, val->c);
266+ }
267+}
268+#endif
269+
270+static lil_value_t alloc_value_len(const char* str, size_t len)
271+{
272+#ifdef LIL_ENABLE_POOLS
273+ lil_value_t val = alloc_from_pool();
274+#else
275+ lil_value_t val = calloc(1, sizeof(struct _lil_value_t));
276+#endif
277+ if (!val) return NULL;
278+ if (str) {
279+ val->l = len;
280+#ifdef LIL_ENABLE_POOLS
281+ ensure_capacity(val, len + 1);
282+#else
283+ val->d = malloc(len + 1);
284+ if (!val->d) {
285+ free(val);
286+ return NULL;
287+ }
288+#endif
289+ memcpy(val->d, str, len);
290+ val->d[len] = 0;
291+ } else {
292+ val->l = 0;
293+#ifdef LIL_ENABLE_POOLS
294+ ensure_capacity(val, 1);
295+ val->d[0] = '\0';
296+#else
297+ val->d = NULL;
298+#endif
299+ }
300+ return val;
301+}
302+
303+static lil_value_t alloc_value(const char* str)
304+{
305+ return alloc_value_len(str, str ? strlen(str) : 0);
306+}
307+
308+lil_value_t lil_clone_value(lil_value_t src)
309+{
310+ lil_value_t val;
311+ if (!src) return NULL;
312+#ifdef LIL_ENABLE_POOLS
313+ val = alloc_from_pool();
314+#else
315+ val = calloc(1, sizeof(struct _lil_value_t));
316+#endif
317+ if (!val) return NULL;
318+ val->l = src->l;
319+ if (src->l) {
320+#ifdef LIL_ENABLE_POOLS
321+ ensure_capacity(val, val->l + 1);
322+#else
323+ val->d = malloc(val->l + 1);
324+ if (!val->d) {
325+ free(val);
326+ return NULL;
327+ }
328+#endif
329+ memcpy(val->d, src->d, val->l + 1);
330+ } else {
331+#ifdef LIL_ENABLE_POOLS
332+ ensure_capacity(val, 1);
333+ val->d[0] = '\0';
334+#else
335+ val->d = NULL;
336+#endif
337+ }
338+ return val;
339+}
340+
341+int lil_append_char(lil_value_t val, char ch)
342+{
343+#ifdef LIL_ENABLE_POOLS
344+ ensure_capacity(val, val->l + 2);
345+ val->d[val->l++] = ch;
346+ val->d[val->l] = '\0';
347+#else
348+ char* new = realloc(val->d, val->l + 2);
349+ if (!new) return 0;
350+ new[val->l++] = ch;
351+ new[val->l] = 0;
352+ val->d = new;
353+#endif
354+ return 1;
355+}
356+
357+int lil_append_string_len(lil_value_t val, const char* s, size_t len)
358+{
359+#ifndef LIL_ENABLE_POOLS
360+ char* new;
361+#endif
362+ if (!s || !s[0]) return 1;
363+#ifdef LIL_ENABLE_POOLS
364+ ensure_capacity(val, val->l + len + 1);
365+ memcpy(val->d + val->l, s, len + 1);
366+#else
367+ new = realloc(val->d, val->l + len + 1);
368+ if (!new) return 0;
369+ memcpy(new + val->l, s, len + 1);
370+ val->d = new;
371+#endif
372+ val->l += len;
373+ return 1;
374+}
375+
376+int lil_append_string(lil_value_t val, const char* s)
377+{
378+ return lil_append_string_len(val, s, strlen(s));
379+}
380+
381+int lil_append_val(lil_value_t val, lil_value_t v)
382+{
383+#ifndef LIL_ENABLE_POOLS
384+ char* new;
385+#endif
386+ if (!v || !v->l) return 1;
387+#ifdef LIL_ENABLE_POOLS
388+ ensure_capacity(val, val->l + v->l + 1);
389+ memcpy(val->d + val->l, v->d, v->l + 1);
390+#else
391+ new = realloc(val->d, val->l + v->l + 1);
392+ if (!new) return 0;
393+ memcpy(new + val->l, v->d, v->l + 1);
394+ val->d = new;
395+#endif
396+ val->l += v->l;
397+ return 1;
398+}
399+
400+void lil_free_value(lil_value_t val)
401+{
402+ if (!val) return;
403+#ifdef LIL_ENABLE_POOLS
404+ release_to_pool(val);
405+#else
406+ free(val->d);
407+ free(val);
408+#endif
409+}
410+
411+lil_list_t lil_alloc_list(void)
412+{
413+ lil_list_t list;
414+#ifdef LIL_ENABLE_POOLS
415+ if (listpoolsize > 0)
416+ return listpool[--listpoolsize];
417+#endif
418+ list = calloc(1, sizeof(struct _lil_list_t));
419+ list->v = NULL;
420+ return list;
421+}
422+
423+void lil_free_list(lil_list_t list)
424+{
425+ size_t i;
426+ if (!list) return;
427+ for (i = 0; i<list->c; i++) lil_free_value(list->v[i]);
428+#ifdef LIL_ENABLE_POOLS
429+ list->c = 0;
430+ if (listpoolsize == listpoolcap) {
431+ listpoolcap = listpoolcap ? (listpoolcap + listpoolcap / 2) : 32;
432+ listpool = realloc(listpool, sizeof(lil_list_t)*listpoolcap);
433+ }
434+ listpool[listpoolsize++] = list;
435+#else
436+ free(list->v);
437+ free(list);
438+#endif
439+}
440+
441+void lil_list_append(lil_list_t list, lil_value_t val)
442+{
443+ if (list->c == list->cap) {
444+ size_t cap = list->cap ? (list->cap + list->cap / 2) : 32;
445+ lil_value_t* nv = realloc(list->v, sizeof(lil_value_t)*cap);
446+ if (!nv) return;
447+ list->cap = cap;
448+ list->v = nv;
449+ }
450+ list->v[list->c++] = val;
451+}
452+
453+size_t lil_list_size(lil_list_t list)
454+{
455+ return list->c;
456+}
457+
458+lil_value_t lil_list_get(lil_list_t list, size_t index)
459+{
460+ return index >= list->c ? NULL : list->v[index];
461+}
462+
463+static int needs_escape(const char* str)
464+{
465+ size_t i;
466+ if (!str || !str[0]) return 1;
467+ for (i=0; str[i]; i++)
468+ if (ispunct(str[i]) || isspace(str[i])) return 1;
469+ return 0;
470+}
471+
472+lil_value_t lil_list_to_value(lil_list_t list, int do_escape)
473+{
474+ lil_value_t val = alloc_value(NULL);
475+ size_t i, j;
476+ for (i=0; i<list->c; i++) {
477+ int escape = do_escape ? needs_escape(lil_to_string(list->v[i])) : 0;
478+ if (i) lil_append_char(val, ' ');
479+ if (escape) {
480+ lil_append_char(val, '{');
481+ for (j=0; j < list->v[i]->l; j++) {
482+ if (list->v[i]->d[j] == '{')
483+ lil_append_string(val, "}\"\\o\"{");
484+ else if (list->v[i]->d[j] == '}')
485+ lil_append_string(val, "}\"\\c\"{");
486+ else lil_append_char(val, list->v[i]->d[j]);
487+ }
488+ lil_append_char(val, '}');
489+ } else lil_append_val(val, list->v[i]);
490+ }
491+ return val;
492+}
493+
494+lil_env_t lil_alloc_env(lil_env_t parent)
495+{
496+ lil_env_t env;
497+#ifdef LIL_ENABLE_POOLS
498+ if (envpoolsize > 0) {
499+ size_t i, j;
500+ env = envpool[--envpoolsize];
501+ env->parent = parent;
502+ env->func = NULL;
503+ env->catcher_for = NULL;
504+ env->var = NULL;
505+ env->vars = 0;
506+ env->retval = NULL;
507+ env->retval_set = 0;
508+ env->breakrun = 0;
509+ for (i = 0; i < HASHMAP_CELLS; i++) {
510+ for (j = 0; j < env->varmap.cell[i].c; j++)
511+ free(env->varmap.cell[i].e[j].k);
512+ env->varmap.cell[i].c = 0;
513+ }
514+ return env;
515+ }
516+#endif
517+ env = calloc(1, sizeof(struct _lil_env_t));
518+ env->parent = parent;
519+ return env;
520+}
521+
522+void lil_free_env(lil_env_t env)
523+{
524+ size_t i;
525+ if (!env) return;
526+ lil_free_value(env->retval);
527+#ifdef LIL_ENABLE_POOLS
528+ for (i = 0; i<env->vars; i++) {
529+ free(env->var[i]->n);
530+ lil_free_value(env->var[i]->v);
531+ free(env->var[i]->w);
532+ free(env->var[i]);
533+ }
534+ free(env->var);
535+ if (envpoolsize == envpoolcap) {
536+ envpoolcap = envpoolcap ? (envpoolcap + envpoolcap / 2) : 64;
537+ envpool = realloc(envpool, sizeof(lil_env_t)*envpoolcap);
538+ }
539+ envpool[envpoolsize++] = env;
540+#else
541+ hm_destroy(&env->varmap);
542+ for (i=0; i<env->vars; i++) {
543+ free(env->var[i]->n);
544+ lil_free_value(env->var[i]->v);
545+ free(env->var[i]->w);
546+ free(env->var[i]);
547+ }
548+ free(env->var);
549+ free(env);
550+#endif
551+}
552+
553+static lil_var_t lil_find_local_var(lil_t lil, lil_env_t env, const char* name)
554+{
555+ #if 0
556+ if (env->vars > 0) {
557+ size_t i = env->vars - 1;
558+ while (1) {
559+ if (!strcmp(env->var[i]->n, name)) return env->var[i];
560+ if (!i) break;
561+ i--;
562+ }
563+ }
564+ return NULL;
565+ #else
566+ return hm_get(&env->varmap, name);
567+ #endif
568+}
569+
570+static lil_var_t lil_find_var(lil_t lil, lil_env_t env, const char* name)
571+{
572+ lil_var_t r = lil_find_local_var(lil, env, name);
573+ return r ? r : (env == lil->rootenv ? NULL : lil_find_var(lil, lil->rootenv, name));
574+}
575+
576+static lil_func_t find_cmd(lil_t lil, const char* name)
577+{
578+ #if 0
579+ if (lil->cmds > 0) {
580+ size_t i = lil->cmds - 1;
581+ while (1) {
582+ if (!strcmp(lil->cmd[i]->name, name)) return lil->cmd[i];
583+ if (!i) break;
584+ i--;
585+ }
586+ }
587+ return NULL;
588+ #else
589+ return hm_get(&lil->cmdmap, name);
590+ #endif
591+}
592+
593+static lil_func_t add_func(lil_t lil, const char* name)
594+{
595+ lil_func_t cmd;
596+ lil_func_t* ncmd;
597+ cmd = find_cmd(lil, name);
598+ if (cmd) {
599+ if (cmd->argnames) lil_free_list(cmd->argnames);
600+ lil_free_value(cmd->code);
601+ cmd->argnames = NULL;
602+ cmd->code = NULL;
603+ cmd->proc = NULL;
604+ return cmd;
605+ }
606+ cmd = calloc(1, sizeof(struct _lil_func_t));
607+ cmd->name = strclone(name);
608+ ncmd = realloc(lil->cmd, sizeof(lil_func_t)*(lil->cmds + 1));
609+ if (!ncmd) {
610+ free(cmd);
611+ return NULL;
612+ }
613+ lil->cmd = ncmd;
614+ ncmd[lil->cmds++] = cmd;
615+ hm_put(&lil->cmdmap, name, cmd);
616+ return cmd;
617+}
618+
619+static void del_func(lil_t lil, lil_func_t cmd)
620+{
621+ size_t i, index = lil->cmds;
622+ for (i=0; i < lil->cmds; i++)
623+ if (lil->cmd[i] == cmd) {
624+ index = i;
625+ break;
626+ }
627+ if (index == lil->cmds) return;
628+ hm_put(&lil->cmdmap, cmd->name, 0);
629+ if (cmd->argnames) lil_free_list(cmd->argnames);
630+ lil_free_value(cmd->code);
631+ free(cmd->name);
632+ free(cmd);
633+ lil->cmds--;
634+ for (i=index; i < lil->cmds; i++) lil->cmd[i] = lil->cmd[i + 1];
635+}
636+
637+int lil_register(lil_t lil, const char* name, lil_func_proc_t proc)
638+{
639+ lil_func_t cmd = add_func(lil, name);
640+ if (!cmd) return 0;
641+ cmd->proc = proc;
642+ return 1;
643+}
644+
645+lil_var_t lil_set_var(lil_t lil, const char* name, lil_value_t val, int local)
646+{
647+ lil_var_t* nvar;
648+ lil_env_t env = local == LIL_SETVAR_GLOBAL ? lil->rootenv : lil->env;
649+ int freeval = 0;
650+ if (!name[0]) return NULL;
651+ if (local != LIL_SETVAR_LOCAL_NEW) {
652+ lil_var_t var = lil_find_var(lil, env, name);
653+ if (local == LIL_SETVAR_LOCAL_ONLY && var && var->env == lil->rootenv && var->env != env)
654+ var = NULL;
655+ if (((!var && env == lil->rootenv) || (var && var->env == lil->rootenv)) && lil->callback[LIL_CALLBACK_SETVAR]) {
656+ lil_setvar_callback_proc_t proc = (lil_setvar_callback_proc_t)lil->callback[LIL_CALLBACK_SETVAR];
657+ lil_value_t newval = val;
658+ int r = proc(lil, name, &newval);
659+ if (r < 0) return NULL;
660+ if (r) {
661+ val = newval;
662+ freeval = 1;
663+ }
664+ }
665+ if (var) {
666+ lil_free_value(var->v);
667+ var->v = freeval ? val : lil_clone_value(val);
668+ if (var->w) {
669+ lil_env_t save_env;
670+ save_env = lil->env;
671+ lil->env = var->env;
672+ lil_free_value(lil_parse(lil, var->w, 0, 1));
673+ lil->env = save_env;
674+ }
675+ return var;
676+ }
677+ }
678+
679+ nvar = realloc(env->var, sizeof(lil_var_t)*(env->vars + 1));
680+ if (!nvar) {
681+ /* TODO: report memory error */
682+ return NULL;
683+ }
684+ env->var = nvar;
685+ nvar[env->vars] = calloc(1, sizeof(struct _lil_var_t));
686+ nvar[env->vars]->n = strclone(name);
687+ nvar[env->vars]->w = NULL;
688+ nvar[env->vars]->env = env;
689+ nvar[env->vars]->v = freeval ? val : lil_clone_value(val);
690+ hm_put(&env->varmap, name, nvar[env->vars]);
691+ return nvar[env->vars++];
692+}
693+
694+lil_value_t lil_get_var(lil_t lil, const char* name)
695+{
696+ return lil_get_var_or(lil, name, lil->empty);
697+}
698+
699+lil_value_t lil_get_var_or(lil_t lil, const char* name, lil_value_t defvalue)
700+{
701+ lil_var_t var = lil_find_var(lil, lil->env, name);
702+ lil_value_t retval = var ? var->v : defvalue;
703+ if (lil->callback[LIL_CALLBACK_GETVAR] && (!var || var->env == lil->rootenv)) {
704+ lil_getvar_callback_proc_t proc = (lil_getvar_callback_proc_t)lil->callback[LIL_CALLBACK_GETVAR];
705+ lil_value_t newretval = retval;
706+ if (proc(lil, name, &newretval))
707+ retval = newretval;
708+ }
709+ return retval;
710+}
711+
712+lil_env_t lil_push_env(lil_t lil)
713+{
714+ lil_env_t env = lil_alloc_env(lil->env);
715+ lil->env = env;
716+ return env;
717+}
718+
719+void lil_pop_env(lil_t lil)
720+{
721+ if (lil->env->parent) {
722+ lil_env_t next = lil->env->parent;
723+ lil_free_env(lil->env);
724+ lil->env = next;
725+ }
726+}
727+
728+lil_t lil_new(void)
729+{
730+ lil_t lil = calloc(1, sizeof(struct _lil_t));
731+ lil->rootenv = lil->env = lil_alloc_env(NULL);
732+ lil->empty = alloc_value(NULL);
733+ lil->dollarprefix = strclone("set ");
734+ hm_init(&lil->cmdmap);
735+ register_stdcmds(lil);
736+ return lil;
737+}
738+
739+static int islilspecial(char ch)
740+{
741+ return ch == '$' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '"' || ch == '\'' || ch == ';';
742+}
743+
744+static int eolchar(char ch)
745+{
746+ return ch == '\n' || ch == '\r' || ch == ';';
747+}
748+
749+static int ateol(lil_t lil)
750+{
751+ return !(lil->ignoreeol) && eolchar(lil->code[lil->head]);
752+}
753+
754+static void skip_spaces(lil_t lil)
755+{
756+ while (lil->head < lil->clen) {
757+ if (lil->code[lil->head] == '#') {
758+ if (lil->code[lil->head + 1] == '#' && lil->code[lil->head + 2] != '#') {
759+ lil->head += 2;
760+ while (lil->head < lil->clen) {
761+ if ((lil->code[lil->head] == '#') && (lil->code[lil->head + 1] == '#') && (lil->code[lil->head + 2] != '#')) {
762+ lil->head += 2;
763+ break;
764+ }
765+ lil->head++;
766+ }
767+ } else {
768+ while (lil->head < lil->clen && !eolchar(lil->code[lil->head])) lil->head++;
769+ }
770+ } else if (lil->code[lil->head] == '\\' && eolchar(lil->code[lil->head + 1])) {
771+ lil->head++;
772+ while (lil->head < lil->clen && eolchar(lil->code[lil->head])) lil->head++;
773+ } else if (eolchar(lil->code[lil->head])) {
774+ if (lil->ignoreeol) lil->head++;
775+ else break;
776+ } else if (isspace(lil->code[lil->head]))
777+ lil->head++;
778+ else break;
779+ }
780+}
781+
782+static lil_value_t get_bracketpart(lil_t lil)
783+{
784+ size_t cnt = 1;
785+ int save_eol = lil->ignoreeol;
786+ lil->ignoreeol = 0;
787+ lil_value_t val, cmd = alloc_value(NULL);
788+ lil->head++;
789+ while (lil->head < lil->clen) {
790+ if (lil->code[lil->head] == '[') {
791+ lil->head++;
792+ cnt++;
793+ lil_append_char(cmd, '[');
794+ } else if (lil->code[lil->head] == ']') {
795+ lil->head++;
796+ if (--cnt == 0) break;
797+ else lil_append_char(cmd, ']');
798+ } else {
799+ lil_append_char(cmd, lil->code[lil->head++]);
800+ }
801+ }
802+ val = lil_parse_value(lil, cmd, 0);
803+ lil_free_value(cmd);
804+ lil->ignoreeol = save_eol;
805+ return val;
806+}
807+
808+static lil_value_t get_dollarpart(lil_t lil)
809+{
810+ lil_value_t val, name, tmp;
811+ lil->head++;
812+ name = next_word(lil);
813+ tmp = alloc_value(lil->dollarprefix);
814+ lil_append_val(tmp, name);
815+ lil_free_value(name);
816+ val = lil_parse_value(lil, tmp, 0);
817+ lil_free_value(tmp);
818+ return val;
819+}
820+
821+static lil_value_t next_word(lil_t lil)
822+{
823+ lil_value_t val;
824+ size_t start;
825+ skip_spaces(lil);
826+ if (lil->code[lil->head] == '$') {
827+ val = get_dollarpart(lil);
828+ } else if (lil->code[lil->head] == '{') {
829+ size_t cnt = 1;
830+ lil->head++;
831+ val = alloc_value(NULL);
832+ while (lil->head < lil->clen) {
833+ if (lil->code[lil->head] == '{') {
834+ lil->head++;
835+ cnt++;
836+ lil_append_char(val, '{');
837+ } else if (lil->code[lil->head] == '}') {
838+ lil->head++;
839+ if (--cnt == 0) break;
840+ else lil_append_char(val, '}');
841+ } else {
842+ lil_append_char(val, lil->code[lil->head++]);
843+ }
844+ }
845+ } else if (lil->code[lil->head] == '[') {
846+ val = get_bracketpart(lil);
847+ } else if (lil->code[lil->head] == '"' || lil->code[lil->head] == '\'') {
848+ char sc = lil->code[lil->head++];
849+ val = alloc_value(NULL);
850+ while (lil->head < lil->clen) {
851+ if (lil->code[lil->head] == '[' || lil->code[lil->head] == '$') {
852+ lil_value_t tmp = lil->code[lil->head] == '$' ? get_dollarpart(lil) : get_bracketpart(lil);
853+ lil_append_val(val, tmp);
854+ lil_free_value(tmp);
855+ lil->head--; /* avoid skipping the char below */
856+ } else if (lil->code[lil->head] == '\\') {
857+ lil->head++;
858+ switch (lil->code[lil->head]) {
859+ case 'b': lil_append_char(val, '\b'); break;
860+ case 't': lil_append_char(val, '\t'); break;
861+ case 'n': lil_append_char(val, '\n'); break;
862+ case 'v': lil_append_char(val, '\v'); break;
863+ case 'f': lil_append_char(val, '\f'); break;
864+ case 'r': lil_append_char(val, '\r'); break;
865+ case '0': lil_append_char(val, 0); break;
866+ case 'a': lil_append_char(val, '\a'); break;
867+ case 'c': lil_append_char(val, '}'); break;
868+ case 'o': lil_append_char(val, '{'); break;
869+ default: lil_append_char(val, lil->code[lil->head]); break;
870+ }
871+ } else if (lil->code[lil->head] == sc) {
872+ lil->head++;
873+ break;
874+ } else {
875+ lil_append_char(val, lil->code[lil->head]);
876+ }
877+ lil->head++;
878+ }
879+ } else {
880+ start = lil->head;
881+ while (lil->head < lil->clen && !isspace(lil->code[lil->head]) && !islilspecial(lil->code[lil->head])) {
882+ lil->head++;
883+ }
884+ val = alloc_value_len(lil->code + start, lil->head - start);
885+ }
886+ return val ? val : alloc_value(NULL);
887+}
888+
889+static lil_list_t substitute(lil_t lil)
890+{
891+ lil_list_t words = lil_alloc_list();
892+
893+ skip_spaces(lil);
894+ while (lil->head < lil->clen && !ateol(lil) && !lil->error) {
895+ lil_value_t w = alloc_value(NULL);
896+ do {
897+ size_t head = lil->head;
898+ lil_value_t wp = next_word(lil);
899+ if (head == lil->head) { /* something wrong, the parser can't proceed */
900+ lil_free_value(w);
901+ lil_free_value(wp);
902+ lil_free_list(words);
903+ return NULL;
904+ }
905+ lil_append_val(w, wp);
906+ lil_free_value(wp);
907+ } while (lil->head < lil->clen && !eolchar(lil->code[lil->head]) && !isspace(lil->code[lil->head]) && !lil->error);
908+ skip_spaces(lil);
909+
910+ lil_list_append(words, w);
911+ }
912+
913+ return words;
914+}
915+
916+lil_list_t lil_subst_to_list(lil_t lil, lil_value_t code)
917+{
918+ const char* save_code = lil->code;
919+ size_t save_clen = lil->clen;
920+ size_t save_head = lil->head;
921+ int save_igeol = lil->ignoreeol;
922+ lil_list_t words;
923+ lil->code = lil_to_string(code);
924+ lil->clen = code->l;
925+ lil->head = 0;
926+ lil->ignoreeol = 1;
927+ words = substitute(lil);
928+ if (!words) words = lil_alloc_list();
929+ lil->code = save_code;
930+ lil->clen = save_clen;
931+ lil->head = save_head;
932+ lil->ignoreeol = save_igeol;
933+ return words;
934+}
935+
936+lil_value_t lil_subst_to_value(lil_t lil, lil_value_t code)
937+{
938+ lil_list_t words = lil_subst_to_list(lil, code);
939+ lil_value_t val;
940+ val = lil_list_to_value(words, 0);
941+ lil_free_list(words);
942+ return val;
943+}
944+
945+lil_value_t lil_parse(lil_t lil, const char* code, size_t codelen, int funclevel)
946+{
947+ const char* save_code = lil->code;
948+ size_t save_clen = lil->clen;
949+ size_t save_head = lil->head;
950+ lil_value_t val = NULL;
951+ lil_list_t words = NULL;
952+ if (!save_code) lil->rootcode = code;
953+ lil->code = code;
954+ lil->clen = codelen ? codelen : strlen(code);
955+ lil->head = 0;
956+ skip_spaces(lil);
957+ lil->parse_depth++;
958+#ifdef LIL_ENABLE_RECLIMIT
959+ if (lil->parse_depth > LIL_ENABLE_RECLIMIT) {
960+ lil_set_error(lil, "Too many recursive calls");
961+ goto cleanup;
962+ }
963+#endif
964+ if (lil->parse_depth == 1) lil->error = 0;
965+ if (funclevel) lil->env->breakrun = 0;
966+ while (lil->head < lil->clen && !lil->error) {
967+ if (words) lil_free_list(words);
968+ if (val) lil_free_value(val);
969+ val = NULL;
970+
971+ words = substitute(lil);
972+ if (!words || lil->error) goto cleanup;
973+
974+ if (words->c) {
975+ lil_func_t cmd = find_cmd(lil, lil_to_string(words->v[0]));
976+ if (!cmd) {
977+ if (words->v[0]->l) {
978+ if (lil->catcher) {
979+ if (lil->in_catcher < MAX_CATCHER_DEPTH) {
980+ lil_value_t args;
981+ lil->in_catcher++;
982+ lil_push_env(lil);
983+ lil->env->catcher_for = words->v[0];
984+ args = lil_list_to_value(words, 1);
985+ lil_set_var(lil, "args", args, LIL_SETVAR_LOCAL_NEW);
986+ lil_free_value(args);
987+ val = lil_parse(lil, lil->catcher, 0, 1);
988+ lil_pop_env(lil);
989+ lil->in_catcher--;
990+ } else {
991+ char* msg = malloc(words->v[0]->l + 64);
992+ sprintf(msg, "catcher limit reached while trying to call unknown function %s", words->v[0]->d);
993+ lil_set_error_at(lil, lil->head, msg);
994+ free(msg);
995+ goto cleanup;
996+ }
997+ } else {
998+ char* msg = malloc(words->v[0]->l + 32);
999+ sprintf(msg, "unknown function %s", words->v[0]->d);
1000+ lil_set_error_at(lil, lil->head, msg);
1001+ free(msg);
1002+ goto cleanup;
1003+ }
1004+ }
1005+ }
1006+ if (cmd) {
1007+ if (cmd->proc) {
1008+ size_t shead = lil->head;
1009+ val = cmd->proc(lil, words->c - 1, words->v + 1);
1010+ if (lil->error == ERROR_FIXHEAD) {
1011+ lil->error = ERROR_DEFAULT;
1012+ lil->err_head = shead;
1013+ }
1014+ } else {
1015+ lil_push_env(lil);
1016+ lil->env->func = cmd;
1017+ if (cmd->argnames->c == 1 && !strcmp(lil_to_string(cmd->argnames->v[0]), "args")) {
1018+ lil_value_t args = lil_list_to_value(words, 1);
1019+ lil_set_var(lil, "args", args, LIL_SETVAR_LOCAL_NEW);
1020+ lil_free_value(args);
1021+ } else {
1022+ size_t i;
1023+ for (i=0; i<cmd->argnames->c; i++) {
1024+ lil_set_var(lil, lil_to_string(cmd->argnames->v[i]), i < words->c - 1 ? words->v[i + 1] : lil->empty, LIL_SETVAR_LOCAL_NEW);
1025+ }
1026+ }
1027+ val = lil_parse_value(lil, cmd->code, 1);
1028+ lil_pop_env(lil);
1029+ }
1030+ }
1031+ }
1032+
1033+ if (lil->env->breakrun) goto cleanup;
1034+
1035+ skip_spaces(lil);
1036+ while (ateol(lil)) lil->head++;
1037+ skip_spaces(lil);
1038+ }
1039+cleanup:
1040+ if (lil->error && lil->callback[LIL_CALLBACK_ERROR] && lil->parse_depth == 1) {
1041+ lil_error_callback_proc_t proc = (lil_error_callback_proc_t)lil->callback[LIL_CALLBACK_ERROR];
1042+ proc(lil, lil->err_head, lil->err_msg);
1043+ }
1044+ if (words) lil_free_list(words);
1045+ lil->code = save_code;
1046+ lil->clen = save_clen;
1047+ lil->head = save_head;
1048+ if (funclevel && lil->env->retval_set) {
1049+ if (val) lil_free_value(val);
1050+ val = lil->env->retval;
1051+ lil->env->retval = NULL;
1052+ lil->env->retval_set = 0;
1053+ lil->env->breakrun = 0;
1054+ }
1055+ lil->parse_depth--;
1056+ return val ? val : alloc_value(NULL);
1057+}
1058+
1059+lil_value_t lil_parse_value(lil_t lil, lil_value_t val, int funclevel)
1060+{
1061+ if (!val || !val->d || !val->l) return alloc_value(NULL);
1062+ return lil_parse(lil, val->d, val->l, funclevel);
1063+}
1064+
1065+LILAPI lil_value_t lil_call(lil_t lil, const char* funcname, size_t argc, lil_value_t* argv)
1066+{
1067+ lil_func_t cmd = find_cmd(lil, funcname);
1068+ lil_value_t r = NULL;
1069+ if (cmd) {
1070+ if (cmd->proc)
1071+ r = cmd->proc(lil, argc, argv);
1072+ else {
1073+ size_t i;
1074+ lil_push_env(lil);
1075+ lil->env->func = cmd;
1076+ if (cmd->argnames->c == 1 && !strcmp(lil_to_string(cmd->argnames->v[0]), "args")) {
1077+ lil_list_t args = lil_alloc_list();
1078+ lil_value_t argsval;
1079+ for (i=0; i<argc; i++)
1080+ lil_list_append(args, lil_clone_value(argv[i]));
1081+ argsval = lil_list_to_value(args, 0);
1082+ lil_set_var(lil, "args", argsval, LIL_SETVAR_LOCAL_NEW);
1083+ lil_free_value(argsval);
1084+ lil_free_list(args);
1085+ } else {
1086+ for (i=0; i<cmd->argnames->c; i++)
1087+ lil_set_var(lil, lil_to_string(cmd->argnames->v[i]), i < argc ? argv[i] : NULL, LIL_SETVAR_LOCAL_NEW);
1088+ }
1089+ r = lil_parse_value(lil, cmd->code, 1);
1090+ lil_pop_env(lil);
1091+ }
1092+ }
1093+ return r;
1094+}
1095+
1096+void lil_callback(lil_t lil, int cb, lil_callback_proc_t proc)
1097+{
1098+ if (cb < 0 || cb > CALLBACKS) return;
1099+ lil->callback[cb] = proc;
1100+}
1101+
1102+void lil_set_error(lil_t lil, const char* msg)
1103+{
1104+ if (lil->error) return;
1105+ free(lil->err_msg);
1106+ lil->error = ERROR_FIXHEAD;
1107+ lil->err_head = 0;
1108+ lil->err_msg = strclone(msg ? msg : "");
1109+}
1110+
1111+void lil_set_error_at(lil_t lil, size_t pos, const char* msg)
1112+{
1113+ if (lil->error) return;
1114+ free(lil->err_msg);
1115+ lil->error = ERROR_DEFAULT;
1116+ lil->err_head = pos;
1117+ lil->err_msg = strclone(msg ? msg : "");
1118+}
1119+
1120+int lil_error(lil_t lil, const char** msg, size_t* pos)
1121+{
1122+ if (!lil->error) return 0;
1123+ *msg = lil->err_msg;
1124+ *pos = lil->err_head;
1125+ lil->error = ERROR_NOERROR;
1126+ return 1;
1127+}
1128+
1129+#define EE_INT 0
1130+#define EE_FLOAT 1
1131+#define EERR_NO_ERROR 0
1132+#define EERR_SYNTAX_ERROR 1
1133+#define EERR_INVALID_TYPE 2
1134+#define EERR_DIVISION_BY_ZERO 3
1135+#define EERR_INVALID_EXPRESSION 4
1136+
1137+static void ee_expr(expreval_t* ee);
1138+
1139+static int ee_invalidpunct(int ch)
1140+{
1141+ return ispunct(ch) && ch != '!' && ch != '~' && ch != '(' && ch != ')' && ch != '-' && ch != '+';
1142+}
1143+
1144+static void ee_skip_spaces(expreval_t* ee)
1145+{
1146+ while (ee->head < ee->len && isspace(ee->code[ee->head])) ee->head++;
1147+}
1148+
1149+static void ee_numeric_element(expreval_t* ee)
1150+{
1151+ lilint_t fpart = 0, fpartlen = 1;
1152+ ee->type = EE_INT;
1153+ ee_skip_spaces(ee);
1154+ ee->ival = 0;
1155+ ee->dval = 0;
1156+ while (ee->head < ee->len) {
1157+ if (ee->code[ee->head] == '.') {
1158+ if (ee->type == EE_FLOAT) break;
1159+ ee->type = EE_FLOAT;
1160+ ee->head++;
1161+ } else if (!isdigit(ee->code[ee->head])) break;
1162+ if (ee->type == EE_INT)
1163+ ee->ival = ee->ival*10 + (ee->code[ee->head] - '0');
1164+ else {
1165+ fpart = fpart*10 + (ee->code[ee->head] - '0');
1166+ fpartlen *= 10;
1167+ }
1168+ ee->head++;
1169+ }
1170+ if (ee->type == EE_FLOAT)
1171+ ee->dval = ee->ival + (double)fpart/(double)fpartlen;
1172+}
1173+
1174+static void ee_element(expreval_t* ee)
1175+{
1176+ if (isdigit(ee->code[ee->head])) {
1177+ ee_numeric_element(ee);
1178+ return;
1179+ }
1180+
1181+ /* for anything else that might creep in (usually from strings), we set the
1182+ * value to 1 so that strings evaluate as "true" when used in conditional
1183+ * expressions */
1184+ ee->type = EE_INT;
1185+ ee->ival = 1;
1186+ ee->error = EERR_INVALID_EXPRESSION; /* special flag, will be cleared */
1187+}
1188+
1189+static void ee_paren(expreval_t* ee)
1190+{
1191+ ee_skip_spaces(ee);
1192+ if (ee->code[ee->head] == '(') {
1193+ ee->head++;
1194+ ee_expr(ee);
1195+ ee_skip_spaces(ee);
1196+ if (ee->code[ee->head] == ')') ee->head++;
1197+ else ee->error = EERR_SYNTAX_ERROR;
1198+ } else ee_element(ee);
1199+}
1200+
1201+static void ee_unary(expreval_t* ee)
1202+{
1203+ ee_skip_spaces(ee);
1204+ if (ee->head < ee->len && !ee->error &&
1205+ (ee->code[ee->head] == '-' ||
1206+ ee->code[ee->head] == '+' ||
1207+ ee->code[ee->head] == '~' ||
1208+ ee->code[ee->head] == '!')) {
1209+ char op = ee->code[ee->head++];
1210+ ee_unary(ee);
1211+ if (ee->error) return;
1212+ switch (op) {
1213+ case '-':
1214+ switch (ee->type) {
1215+ case EE_FLOAT:
1216+ ee->dval = -ee->dval;
1217+ break;
1218+ case EE_INT:
1219+ ee->ival = -ee->ival;
1220+ break;
1221+ default:
1222+ ee->error = EERR_INVALID_TYPE;
1223+ break;
1224+ }
1225+ break;
1226+ case '+':
1227+ /* ignore it, doesn't change a thing */
1228+ break;
1229+ case '~':
1230+ switch (ee->type) {
1231+ case EE_FLOAT:
1232+ ee->ival = ~((lilint_t)ee->dval);
1233+ ee->type = EE_INT;
1234+ break;
1235+ case EE_INT:
1236+ ee->ival = ~ee->ival;
1237+ break;
1238+ default:
1239+ ee->error = EERR_INVALID_TYPE;
1240+ break;
1241+ }
1242+ break;
1243+ case '!':
1244+ switch (ee->type) {
1245+ case EE_FLOAT:
1246+ ee->dval = !ee->dval;
1247+ break;
1248+ case EE_INT:
1249+ ee->ival = !ee->ival;
1250+ break;
1251+ default:
1252+ ee->error = EERR_INVALID_TYPE;
1253+ break;
1254+ }
1255+ break;
1256+ }
1257+ } else {
1258+ ee_paren(ee);
1259+ }
1260+}
1261+
1262+static void ee_muldiv(expreval_t* ee)
1263+{
1264+ ee_unary(ee);
1265+ if (ee->error) return;
1266+ ee_skip_spaces(ee);
1267+ while (ee->head < ee->len && !ee->error && !ee_invalidpunct(ee->code[ee->head + 1]) &&
1268+ (ee->code[ee->head] == '*' ||
1269+ ee->code[ee->head] == '/' ||
1270+ ee->code[ee->head] == '\\' ||
1271+ ee->code[ee->head] == '%')) {
1272+ double odval = ee->dval;
1273+ lilint_t oival = ee->ival;
1274+
1275+ switch (ee->code[ee->head]) {
1276+ case '*':
1277+ switch (ee->type) {
1278+ case EE_FLOAT:
1279+ ee->head++;
1280+ ee_unary(ee);
1281+ if (ee->error) return;
1282+ switch (ee->type) {
1283+ case EE_FLOAT:
1284+ ee->dval = ee->dval*odval;
1285+ break;
1286+ case EE_INT:
1287+ ee->dval = ee->ival*odval;
1288+ ee->type = EE_FLOAT;
1289+ break;
1290+ default:
1291+ ee->error = EERR_INVALID_TYPE;
1292+ break;
1293+ }
1294+ break;
1295+ case EE_INT:
1296+ ee->head++;
1297+ ee_unary(ee);
1298+ if (ee->error) return;
1299+ switch (ee->type) {
1300+ case EE_FLOAT:
1301+ ee->dval = ee->dval*oival;
1302+ ee->type = EE_FLOAT;
1303+ break;
1304+ case EE_INT:
1305+ ee->ival = ee->ival*oival;
1306+ break;
1307+ default:
1308+ ee->error = EERR_INVALID_TYPE;
1309+ break;
1310+ }
1311+ break;
1312+ default:
1313+ ee->error = EERR_INVALID_TYPE;
1314+ break;
1315+ }
1316+ break;
1317+ case '%':
1318+ switch (ee->type) {
1319+ case EE_FLOAT:
1320+ ee->head++;
1321+ ee_unary(ee);
1322+ if (ee->error) return;
1323+ switch (ee->type) {
1324+ case EE_FLOAT:
1325+ if (ee->dval == 0.0) {
1326+ ee->error = EERR_DIVISION_BY_ZERO;
1327+ } else {
1328+ ee->dval = fmod(odval, ee->dval);
1329+ }
1330+ break;
1331+ case EE_INT:
1332+ if (ee->ival == 0) {
1333+ ee->error = EERR_DIVISION_BY_ZERO;
1334+ } else {
1335+ ee->dval = fmod(odval, ee->ival);
1336+ }
1337+ ee->type = EE_FLOAT;
1338+ break;
1339+ default:
1340+ ee->error = EERR_INVALID_TYPE;
1341+ break;
1342+ }
1343+ break;
1344+ case EE_INT:
1345+ ee->head++;
1346+ ee_unary(ee);
1347+ if (ee->error) return;
1348+ switch (ee->type) {
1349+ case EE_FLOAT:
1350+ if (ee->dval == 0.0) {
1351+ ee->error = EERR_DIVISION_BY_ZERO;
1352+ } else {
1353+ ee->dval = fmod(oival, ee->dval);
1354+ }
1355+ break;
1356+ case EE_INT:
1357+ if (ee->ival == 0) {
1358+ ee->error = EERR_DIVISION_BY_ZERO;
1359+ } else {
1360+ ee->ival = oival%ee->ival;
1361+ }
1362+ break;
1363+ default:
1364+ ee->error = EERR_INVALID_TYPE;
1365+ break;
1366+ }
1367+ break;
1368+ }
1369+ break;
1370+ case '/':
1371+ switch (ee->type) {
1372+ case EE_FLOAT:
1373+ ee->head++;
1374+ ee_unary(ee);
1375+ if (ee->error) return;
1376+ switch (ee->type) {
1377+ case EE_FLOAT:
1378+ if (ee->dval == 0.0) {
1379+ ee->error = EERR_DIVISION_BY_ZERO;
1380+ } else {
1381+ ee->dval = odval/ee->dval;
1382+ }
1383+ break;
1384+ case EE_INT:
1385+ if (ee->ival == 0) {
1386+ ee->error = EERR_DIVISION_BY_ZERO;
1387+ } else {
1388+ ee->dval = odval/(double)ee->ival;
1389+ }
1390+ ee->type = EE_FLOAT;
1391+ break;
1392+ default:
1393+ ee->error = EERR_INVALID_TYPE;
1394+ break;
1395+ }
1396+ break;
1397+ case EE_INT:
1398+ ee->head++;
1399+ ee_unary(ee);
1400+ if (ee->error) return;
1401+ switch (ee->type) {
1402+ case EE_FLOAT:
1403+ if (ee->dval == 0.0) {
1404+ ee->error = EERR_DIVISION_BY_ZERO;
1405+ } else {
1406+ ee->dval = (double)oival/ee->dval;
1407+ }
1408+ break;
1409+ case EE_INT:
1410+ if (ee->ival == 0) {
1411+ ee->error = EERR_DIVISION_BY_ZERO;
1412+ } else {
1413+ ee->dval = (double)oival/(double)ee->ival;
1414+ }
1415+ ee->type = EE_FLOAT;
1416+ break;
1417+ default:
1418+ ee->error = EERR_INVALID_TYPE;
1419+ break;
1420+ }
1421+ break;
1422+ }
1423+ break;
1424+ case '\\':
1425+ switch (ee->type) {
1426+ case EE_FLOAT:
1427+ ee->head++;
1428+ ee_unary(ee);
1429+ if (ee->error) return;
1430+ switch (ee->type) {
1431+ case EE_FLOAT:
1432+ if (ee->dval == 0.0) {
1433+ ee->error = EERR_DIVISION_BY_ZERO;
1434+ } else {
1435+ ee->ival = (lilint_t)(odval/ee->dval);
1436+ }
1437+ ee->type = EE_INT;
1438+ break;
1439+ case EE_INT:
1440+ if (ee->ival == 0) {
1441+ ee->error = EERR_DIVISION_BY_ZERO;
1442+ } else {
1443+ ee->ival = (lilint_t)(odval/(double)ee->ival);
1444+ }
1445+ break;
1446+ default:
1447+ ee->error = EERR_INVALID_TYPE;
1448+ break;
1449+ }
1450+ break;
1451+ case EE_INT:
1452+ ee->head++;
1453+ ee_unary(ee);
1454+ if (ee->error) return;
1455+ switch (ee->type) {
1456+ case EE_FLOAT:
1457+ if (ee->dval == 0.0) {
1458+ ee->error = EERR_DIVISION_BY_ZERO;
1459+ } else {
1460+ ee->ival = (lilint_t)((double)oival/ee->dval);
1461+ }
1462+ ee->type = EE_INT;
1463+ break;
1464+ case EE_INT:
1465+ if (ee->ival == 0) {
1466+ ee->error = EERR_DIVISION_BY_ZERO;
1467+ } else {
1468+ ee->ival = oival/ee->ival;
1469+ }
1470+ break;
1471+ default:
1472+ ee->error = EERR_INVALID_TYPE;
1473+ break;
1474+ }
1475+ break;
1476+ default:
1477+ ee->error = EERR_INVALID_TYPE;
1478+ break;
1479+ }
1480+ break;
1481+ }
1482+
1483+ ee_skip_spaces(ee);
1484+ }
1485+}
1486+
1487+static void ee_addsub(expreval_t* ee)
1488+{
1489+ ee_muldiv(ee);
1490+ ee_skip_spaces(ee);
1491+ while (ee->head < ee->len && !ee->error && !ee_invalidpunct(ee->code[ee->head + 1]) &&
1492+ (ee->code[ee->head] == '+' ||
1493+ ee->code[ee->head] == '-')) {
1494+ double odval = ee->dval;
1495+ lilint_t oival = ee->ival;
1496+
1497+ switch (ee->code[ee->head]) {
1498+ case '+':
1499+ switch (ee->type) {
1500+ case EE_FLOAT:
1501+ ee->head++;
1502+ ee_muldiv(ee);
1503+ if (ee->error) return;
1504+ switch (ee->type) {
1505+ case EE_FLOAT:
1506+ ee->dval = ee->dval+odval;
1507+ break;
1508+ case EE_INT:
1509+ ee->dval = ee->ival+odval;
1510+ ee->type = EE_FLOAT;
1511+ break;
1512+ default:
1513+ ee->error = EERR_INVALID_TYPE;
1514+ break;
1515+ }
1516+ break;
1517+ case EE_INT:
1518+ ee->head++;
1519+ ee_muldiv(ee);
1520+ if (ee->error) return;
1521+ switch (ee->type) {
1522+ case EE_FLOAT:
1523+ ee->dval = ee->dval+oival;
1524+ ee->type = EE_FLOAT;
1525+ break;
1526+ case EE_INT:
1527+ ee->ival = ee->ival+oival;
1528+ break;
1529+ default:
1530+ ee->error = EERR_INVALID_TYPE;
1531+ break;
1532+ }
1533+ break;
1534+ default:
1535+ ee->error = EERR_INVALID_TYPE;
1536+ break;
1537+ }
1538+ break;
1539+ case '-':
1540+ switch (ee->type) {
1541+ case EE_FLOAT:
1542+ ee->head++;
1543+ ee_muldiv(ee);
1544+ if (ee->error) return;
1545+ switch (ee->type) {
1546+ case EE_FLOAT:
1547+ ee->dval = odval-ee->dval;
1548+ break;
1549+ case EE_INT:
1550+ ee->dval = odval-ee->ival;
1551+ ee->type = EE_FLOAT;
1552+ break;
1553+ default:
1554+ ee->error = EERR_INVALID_TYPE;
1555+ break;
1556+ }
1557+ break;
1558+ case EE_INT:
1559+ ee->head++;
1560+ ee_muldiv(ee);
1561+ if (ee->error) return;
1562+ switch (ee->type) {
1563+ case EE_FLOAT:
1564+ ee->dval = (double)oival-ee->dval;
1565+ ee->type = EE_FLOAT;
1566+ break;
1567+ case EE_INT:
1568+ ee->ival = oival-ee->ival;
1569+ break;
1570+ default:
1571+ ee->error = EERR_INVALID_TYPE;
1572+ break;
1573+ }
1574+ break;
1575+ default:
1576+ ee->error = EERR_INVALID_TYPE;
1577+ break;
1578+ }
1579+ break;
1580+ }
1581+
1582+ ee_skip_spaces(ee);
1583+ }
1584+}
1585+
1586+static void ee_shift(expreval_t* ee)
1587+{
1588+ ee_addsub(ee);
1589+ ee_skip_spaces(ee);
1590+ while (ee->head < ee->len && !ee->error &&
1591+ ((ee->code[ee->head] == '<' && ee->code[ee->head + 1] == '<') ||
1592+ (ee->code[ee->head] == '>' && ee->code[ee->head + 1] == '>'))) {
1593+ double odval = ee->dval;
1594+ lilint_t oival = ee->ival;
1595+ ee->head++;
1596+
1597+ switch (ee->code[ee->head]) {
1598+ case '<':
1599+ switch (ee->type) {
1600+ case EE_FLOAT:
1601+ ee->head++;
1602+ ee_addsub(ee);
1603+ if (ee->error) return;
1604+ switch (ee->type) {
1605+ case EE_FLOAT:
1606+ ee->ival = (lilint_t)odval << (lilint_t)ee->dval;
1607+ ee->type = EE_INT;
1608+ break;
1609+ case EE_INT:
1610+ ee->ival = (lilint_t)odval << ee->ival;
1611+ break;
1612+ default:
1613+ ee->error = EERR_INVALID_TYPE;
1614+ break;
1615+ }
1616+ break;
1617+ case EE_INT:
1618+ ee->head++;
1619+ ee_addsub(ee);
1620+ if (ee->error) return;
1621+ switch (ee->type) {
1622+ case EE_FLOAT:
1623+ ee->ival = oival << (lilint_t)ee->dval;
1624+ ee->type = EE_INT;
1625+ break;
1626+ case EE_INT:
1627+ ee->ival = oival << ee->ival;
1628+ break;
1629+ default:
1630+ ee->error = EERR_INVALID_TYPE;
1631+ break;
1632+ }
1633+ break;
1634+ default:
1635+ ee->error = EERR_INVALID_TYPE;
1636+ break;
1637+ }
1638+ break;
1639+ case '>':
1640+ switch (ee->type) {
1641+ case EE_FLOAT:
1642+ ee->head++;
1643+ ee_addsub(ee);
1644+ if (ee->error) return;
1645+ switch (ee->type) {
1646+ case EE_FLOAT:
1647+ ee->ival = (lilint_t)odval >> (lilint_t)ee->dval;
1648+ ee->type = EE_INT;
1649+ break;
1650+ case EE_INT:
1651+ ee->ival = (lilint_t)odval >> ee->ival;
1652+ break;
1653+ default:
1654+ ee->error = EERR_INVALID_TYPE;
1655+ break;
1656+ }
1657+ break;
1658+ case EE_INT:
1659+ ee->head++;
1660+ ee_addsub(ee);
1661+ if (ee->error) return;
1662+ switch (ee->type) {
1663+ case EE_FLOAT:
1664+ ee->ival = oival >> (lilint_t)ee->dval;
1665+ ee->type = EE_INT;
1666+ break;
1667+ case EE_INT:
1668+ ee->ival = oival >> ee->ival;
1669+ break;
1670+ default:
1671+ ee->error = EERR_INVALID_TYPE;
1672+ break;
1673+ }
1674+ break;
1675+ default:
1676+ ee->error = EERR_INVALID_TYPE;
1677+ break;
1678+ }
1679+ break;
1680+ }
1681+
1682+ ee_skip_spaces(ee);
1683+ }
1684+}
1685+
1686+static void ee_compare(expreval_t* ee)
1687+{
1688+ ee_shift(ee);
1689+ ee_skip_spaces(ee);
1690+ while (ee->head < ee->len && !ee->error &&
1691+ ((ee->code[ee->head] == '<' && !ee_invalidpunct(ee->code[ee->head + 1])) ||
1692+ (ee->code[ee->head] == '>' && !ee_invalidpunct(ee->code[ee->head + 1])) ||
1693+ (ee->code[ee->head] == '<' && ee->code[ee->head + 1] == '=') ||
1694+ (ee->code[ee->head] == '>' && ee->code[ee->head + 1] == '='))) {
1695+ double odval = ee->dval;
1696+ lilint_t oival = ee->ival;
1697+ int op = 4;
1698+ if (ee->code[ee->head] == '<' && !ee_invalidpunct(ee->code[ee->head + 1])) op = 1;
1699+ else if (ee->code[ee->head] == '>' && !ee_invalidpunct(ee->code[ee->head + 1])) op = 2;
1700+ else if (ee->code[ee->head] == '<' && ee->code[ee->head + 1] == '=') op = 3;
1701+
1702+ ee->head += op > 2 ? 2 : 1;
1703+
1704+ switch (op) {
1705+ case 1:
1706+ switch (ee->type) {
1707+ case EE_FLOAT:
1708+ ee_shift(ee);
1709+ if (ee->error) return;
1710+ switch (ee->type) {
1711+ case EE_FLOAT:
1712+ ee->ival = (odval < ee->dval)?1:0;
1713+ ee->type = EE_INT;
1714+ break;
1715+ case EE_INT:
1716+ ee->ival = (odval < ee->ival)?1:0;
1717+ break;
1718+ default:
1719+ ee->error = EERR_INVALID_TYPE;
1720+ break;
1721+ }
1722+ break;
1723+ case EE_INT:
1724+ ee_shift(ee);
1725+ if (ee->error) return;
1726+ switch (ee->type) {
1727+ case EE_FLOAT:
1728+ ee->ival = (oival < ee->dval)?1:0;
1729+ ee->type = EE_INT;
1730+ break;
1731+ case EE_INT:
1732+ ee->ival = (oival < ee->ival)?1:0;
1733+ break;
1734+ default:
1735+ ee->error = EERR_INVALID_TYPE;
1736+ break;
1737+ }
1738+ break;
1739+ default:
1740+ ee->error = EERR_INVALID_TYPE;
1741+ break;
1742+ }
1743+ break;
1744+ case 2:
1745+ switch (ee->type) {
1746+ case EE_FLOAT:
1747+ ee_shift(ee);
1748+ if (ee->error) return;
1749+ switch (ee->type) {
1750+ case EE_FLOAT:
1751+ ee->ival = (odval > ee->dval)?1:0;
1752+ ee->type = EE_INT;
1753+ break;
1754+ case EE_INT:
1755+ ee->ival = (odval > ee->ival)?1:0;
1756+ break;
1757+ default:
1758+ ee->error = EERR_INVALID_TYPE;
1759+ break;
1760+ }
1761+ break;
1762+ case EE_INT:
1763+ ee_shift(ee);
1764+ if (ee->error) return;
1765+ switch (ee->type) {
1766+ case EE_FLOAT:
1767+ ee->ival = (oival > ee->dval)?1:0;
1768+ ee->type = EE_INT;
1769+ break;
1770+ case EE_INT:
1771+ ee->ival = (oival > ee->ival)?1:0;
1772+ break;
1773+ default:
1774+ ee->error = EERR_INVALID_TYPE;
1775+ break;
1776+ }
1777+ break;
1778+ default:
1779+ ee->error = EERR_INVALID_TYPE;
1780+ break;
1781+ }
1782+ break;
1783+ case 3:
1784+ switch (ee->type) {
1785+ case EE_FLOAT:
1786+ ee_shift(ee);
1787+ if (ee->error) return;
1788+ switch (ee->type) {
1789+ case EE_FLOAT:
1790+ ee->ival = (odval <= ee->dval)?1:0;
1791+ ee->type = EE_INT;
1792+ break;
1793+ case EE_INT:
1794+ ee->ival = (odval <= ee->ival)?1:0;
1795+ break;
1796+ default:
1797+ ee->error = EERR_INVALID_TYPE;
1798+ break;
1799+ }
1800+ break;
1801+ case EE_INT:
1802+ ee_shift(ee);
1803+ if (ee->error) return;
1804+ switch (ee->type) {
1805+ case EE_FLOAT:
1806+ ee->ival = (oival <= ee->dval)?1:0;
1807+ ee->type = EE_INT;
1808+ break;
1809+ case EE_INT:
1810+ ee->ival = (oival <= ee->ival)?1:0;
1811+ break;
1812+ default:
1813+ ee->error = EERR_INVALID_TYPE;
1814+ break;
1815+ }
1816+ break;
1817+ default:
1818+ ee->error = EERR_INVALID_TYPE;
1819+ break;
1820+ }
1821+ break;
1822+ case 4:
1823+ switch (ee->type) {
1824+ case EE_FLOAT:
1825+ ee_shift(ee);
1826+ if (ee->error) return;
1827+ switch (ee->type) {
1828+ case EE_FLOAT:
1829+ ee->ival = (odval >= ee->dval)?1:0;
1830+ ee->type = EE_INT;
1831+ break;
1832+ case EE_INT:
1833+ ee->ival = (odval >= ee->ival)?1:0;
1834+ break;
1835+ default:
1836+ ee->error = EERR_INVALID_TYPE;
1837+ break;
1838+ }
1839+ break;
1840+ case EE_INT:
1841+ ee_shift(ee);
1842+ if (ee->error) return;
1843+ switch (ee->type) {
1844+ case EE_FLOAT:
1845+ ee->ival = (oival >= ee->dval)?1:0;
1846+ ee->type = EE_INT;
1847+ break;
1848+ case EE_INT:
1849+ ee->ival = (oival >= ee->ival)?1:0;
1850+ break;
1851+ default:
1852+ ee->error = EERR_INVALID_TYPE;
1853+ break;
1854+ }
1855+ break;
1856+ default:
1857+ ee->error = EERR_INVALID_TYPE;
1858+ break;
1859+ }
1860+ break;
1861+ }
1862+
1863+ ee_skip_spaces(ee);
1864+ }
1865+}
1866+
1867+static void ee_equals(expreval_t* ee)
1868+{
1869+ ee_compare(ee);
1870+ ee_skip_spaces(ee);
1871+ while (ee->head < ee->len && !ee->error &&
1872+ ((ee->code[ee->head] == '=' && ee->code[ee->head + 1] == '=') ||
1873+ (ee->code[ee->head] == '!' && ee->code[ee->head + 1] == '='))) {
1874+ double odval = ee->dval;
1875+ lilint_t oival = ee->ival;
1876+ int op = ee->code[ee->head] == '=' ? 1 : 2;
1877+ ee->head += 2;
1878+
1879+ switch (op) {
1880+ case 1:
1881+ switch (ee->type) {
1882+ case EE_FLOAT:
1883+ ee_compare(ee);
1884+ if (ee->error) return;
1885+ switch (ee->type) {
1886+ case EE_FLOAT:
1887+ ee->ival = (odval == ee->dval)?1:0;
1888+ ee->type = EE_INT;
1889+ break;
1890+ case EE_INT:
1891+ ee->ival = (odval == ee->ival)?1:0;
1892+ break;
1893+ default:
1894+ ee->error = EERR_INVALID_TYPE;
1895+ break;
1896+ }
1897+ break;
1898+ case EE_INT:
1899+ ee_compare(ee);
1900+ if (ee->error) return;
1901+ switch (ee->type) {
1902+ case EE_FLOAT:
1903+ ee->ival = (oival == ee->dval)?1:0;
1904+ ee->type = EE_INT;
1905+ break;
1906+ case EE_INT:
1907+ ee->ival = (oival == ee->ival)?1:0;
1908+ break;
1909+ default:
1910+ ee->error = EERR_INVALID_TYPE;
1911+ break;
1912+ }
1913+ break;
1914+ default:
1915+ ee->error = EERR_INVALID_TYPE;
1916+ break;
1917+ }
1918+ break;
1919+ case 2:
1920+ switch (ee->type) {
1921+ case EE_FLOAT:
1922+ ee_compare(ee);
1923+ if (ee->error) return;
1924+ switch (ee->type) {
1925+ case EE_FLOAT:
1926+ ee->ival = (odval != ee->dval)?1:0;
1927+ ee->type = EE_INT;
1928+ break;
1929+ case EE_INT:
1930+ ee->ival = (odval != ee->ival)?1:0;
1931+ break;
1932+ default:
1933+ ee->error = EERR_INVALID_TYPE;
1934+ break;
1935+ }
1936+ break;
1937+ case EE_INT:
1938+ ee_compare(ee);
1939+ if (ee->error) return;
1940+ switch (ee->type) {
1941+ case EE_FLOAT:
1942+ ee->ival = (oival != ee->dval)?1:0;
1943+ ee->type = EE_INT;
1944+ break;
1945+ case EE_INT:
1946+ ee->ival = (oival != ee->ival)?1:0;
1947+ break;
1948+ default:
1949+ ee->error = EERR_INVALID_TYPE;
1950+ break;
1951+ }
1952+ break;
1953+ default:
1954+ ee->error = EERR_INVALID_TYPE;
1955+ break;
1956+ }
1957+ break;
1958+ }
1959+
1960+ ee_skip_spaces(ee);
1961+ }
1962+}
1963+
1964+static void ee_bitand(expreval_t* ee)
1965+{
1966+ ee_equals(ee);
1967+ ee_skip_spaces(ee);
1968+ while (ee->head < ee->len && !ee->error &&
1969+ (ee->code[ee->head] == '&' && !ee_invalidpunct(ee->code[ee->head + 1]))) {
1970+ double odval = ee->dval;
1971+ lilint_t oival = ee->ival;
1972+ ee->head++;
1973+
1974+ switch (ee->type) {
1975+ case EE_FLOAT:
1976+ ee_equals(ee);
1977+ if (ee->error) return;
1978+ switch (ee->type) {
1979+ case EE_FLOAT:
1980+ ee->ival = (lilint_t)odval & (lilint_t)ee->dval;
1981+ ee->type = EE_INT;
1982+ break;
1983+ case EE_INT:
1984+ ee->ival = (lilint_t)odval & ee->ival;
1985+ break;
1986+ default:
1987+ ee->error = EERR_INVALID_TYPE;
1988+ break;
1989+ }
1990+ break;
1991+ case EE_INT:
1992+ ee_equals(ee);
1993+ if (ee->error) return;
1994+ switch (ee->type) {
1995+ case EE_FLOAT:
1996+ ee->ival = oival & (lilint_t)ee->dval;
1997+ ee->type = EE_INT;
1998+ break;
1999+ case EE_INT:
2000+ ee->ival = oival & ee->ival;
2001+ break;
2002+ default:
2003+ ee->error = EERR_INVALID_TYPE;
2004+ break;
2005+ }
2006+ break;
2007+ default:
2008+ ee->error = EERR_INVALID_TYPE;
2009+ break;
2010+ }
2011+
2012+ ee_skip_spaces(ee);
2013+ }
2014+}
2015+
2016+static void ee_bitor(expreval_t* ee)
2017+{
2018+ ee_bitand(ee);
2019+ ee_skip_spaces(ee);
2020+ while (ee->head < ee->len && !ee->error &&
2021+ (ee->code[ee->head] == '|' && !ee_invalidpunct(ee->code[ee->head + 1]))) {
2022+ double odval = ee->dval;
2023+ lilint_t oival = ee->ival;
2024+ ee->head++;
2025+
2026+ switch (ee->type) {
2027+ case EE_FLOAT:
2028+ ee_bitand(ee);
2029+ if (ee->error) return;
2030+ switch (ee->type) {
2031+ case EE_FLOAT:
2032+ ee->ival = (lilint_t)odval | (lilint_t)ee->dval;
2033+ ee->type = EE_INT;
2034+ break;
2035+ case EE_INT:
2036+ ee->ival = (lilint_t)odval | ee->ival;
2037+ break;
2038+ default:
2039+ ee->error = EERR_INVALID_TYPE;
2040+ break;
2041+ }
2042+ break;
2043+ case EE_INT:
2044+ ee_bitand(ee);
2045+ if (ee->error) return;
2046+ switch (ee->type) {
2047+ case EE_FLOAT:
2048+ ee->ival = oival | (lilint_t)ee->dval;
2049+ ee->type = EE_INT;
2050+ break;
2051+ case EE_INT:
2052+ ee->ival = oival | ee->ival;
2053+ break;
2054+ default:
2055+ ee->error = EERR_INVALID_TYPE;
2056+ break;
2057+ }
2058+ break;
2059+ default:
2060+ ee->error = EERR_INVALID_TYPE;
2061+ break;
2062+ }
2063+
2064+ ee_skip_spaces(ee);
2065+ }
2066+}
2067+
2068+static void ee_logand(expreval_t* ee)
2069+{
2070+ ee_bitor(ee);
2071+ ee_skip_spaces(ee);
2072+ while (ee->head < ee->len && !ee->error &&
2073+ (ee->code[ee->head] == '&' && ee->code[ee->head + 1] == '&')) {
2074+ double odval = ee->dval;
2075+ lilint_t oival = ee->ival;
2076+ ee->head += 2;
2077+
2078+ switch (ee->type) {
2079+ case EE_FLOAT:
2080+ ee_bitor(ee);
2081+ if (ee->error) return;
2082+ switch (ee->type) {
2083+ case EE_FLOAT:
2084+ ee->ival = (odval && ee->dval)?1:0;
2085+ ee->type = EE_INT;
2086+ break;
2087+ case EE_INT:
2088+ ee->ival = (odval && ee->ival)?1:0;
2089+ break;
2090+ default:
2091+ ee->error = EERR_INVALID_TYPE;
2092+ break;
2093+ }
2094+ break;
2095+ case EE_INT:
2096+ ee_bitor(ee);
2097+ if (ee->error) return;
2098+ switch (ee->type) {
2099+ case EE_FLOAT:
2100+ ee->ival = (oival && ee->dval)?1:0;
2101+ ee->type = EE_INT;
2102+ break;
2103+ case EE_INT:
2104+ ee->ival = (oival && ee->ival)?1:0;
2105+ break;
2106+ default:
2107+ ee->error = EERR_INVALID_TYPE;
2108+ break;
2109+ }
2110+ break;
2111+ default:
2112+ ee->error = EERR_INVALID_TYPE;
2113+ break;
2114+ }
2115+
2116+ ee_skip_spaces(ee);
2117+ }
2118+}
2119+
2120+static void ee_logor(expreval_t* ee)
2121+{
2122+ ee_logand(ee);
2123+ ee_skip_spaces(ee);
2124+ while (ee->head < ee->len && !ee->error &&
2125+ (ee->code[ee->head] == '|' && ee->code[ee->head + 1] == '|')) {
2126+ double odval = ee->dval;
2127+ lilint_t oival = ee->ival;
2128+ ee->head += 2;
2129+
2130+ switch (ee->type) {
2131+ case EE_FLOAT:
2132+ ee_logand(ee);
2133+ if (ee->error) return;
2134+ switch (ee->type) {
2135+ case EE_FLOAT:
2136+ ee->ival = (odval || ee->dval)?1:0;
2137+ ee->type = EE_INT;
2138+ break;
2139+ case EE_INT:
2140+ ee->ival = (odval || ee->ival)?1:0;
2141+ break;
2142+ default:
2143+ ee->error = EERR_INVALID_TYPE;
2144+ break;
2145+ }
2146+ break;
2147+ case EE_INT:
2148+ ee_logand(ee);
2149+ if (ee->error) return;
2150+ switch (ee->type) {
2151+ case EE_FLOAT:
2152+ ee->ival = (oival || ee->dval)?1:0;
2153+ ee->type = EE_INT;
2154+ break;
2155+ case EE_INT:
2156+ ee->ival = (oival || ee->ival)?1:0;
2157+ break;
2158+ default:
2159+ ee->error = EERR_INVALID_TYPE;
2160+ break;
2161+ }
2162+ break;
2163+ default:
2164+ ee->error = EERR_INVALID_TYPE;
2165+ break;
2166+ }
2167+
2168+ ee_skip_spaces(ee);
2169+ }
2170+}
2171+
2172+static void ee_expr(expreval_t* ee)
2173+{
2174+ ee_logor(ee);
2175+ /* invalid expression doesn't really matter, it is only used to stop
2176+ * the expression parsing. */
2177+ if (ee->error == EERR_INVALID_EXPRESSION) {
2178+ ee->error = EERR_NO_ERROR;
2179+ ee->ival = 1;
2180+ }
2181+}
2182+
2183+lil_value_t lil_eval_expr(lil_t lil, lil_value_t code)
2184+{
2185+ expreval_t ee;
2186+ code = lil_subst_to_value(lil, code);
2187+ if (lil->error) return NULL;
2188+ ee.code = lil_to_string(code);
2189+ /* an empty expression equals to 0 so that it can be used as a false value
2190+ * in conditionals */
2191+ if (!ee.code[0]) {
2192+ lil_free_value(code);
2193+ return lil_alloc_integer(0);
2194+ }
2195+ ee.head = 0;
2196+ ee.len = code->l;
2197+ ee.ival = 0;
2198+ ee.dval = 0;
2199+ ee.type = EE_INT;
2200+ ee.error = 0;
2201+ ee_expr(&ee);
2202+ lil_free_value(code);
2203+ if (ee.error) {
2204+ switch (ee.error) {
2205+ case EERR_DIVISION_BY_ZERO:
2206+ lil_set_error(lil, "division by zero in expression");
2207+ break;
2208+ case EERR_INVALID_TYPE:
2209+ lil_set_error(lil, "mixing invalid types in expression");
2210+ break;
2211+ case EERR_SYNTAX_ERROR:
2212+ lil_set_error(lil, "expression syntax error");
2213+ break;
2214+ }
2215+ return NULL;
2216+ }
2217+ if (ee.type == EE_INT)
2218+ return lil_alloc_integer(ee.ival);
2219+ else
2220+ return lil_alloc_double(ee.dval);
2221+}
2222+
2223+lil_value_t lil_unused_name(lil_t lil, const char* part)
2224+{
2225+ char* name = malloc(strlen(part) + 64);
2226+ lil_value_t val;
2227+ size_t i;
2228+ for (i=0; i<(size_t)-1; i++) {
2229+ sprintf(name, "!!un!%s!%09u!nu!!", part, (unsigned int)i);
2230+ if (find_cmd(lil, name)) continue;
2231+ if (lil_find_var(lil, lil->env, name)) continue;
2232+ val = lil_alloc_string(name);
2233+ free(name);
2234+ return val;
2235+ }
2236+ return NULL;
2237+}
2238+
2239+lil_value_t lil_arg(lil_value_t* argv, size_t index)
2240+{
2241+ return argv ? argv[index] : NULL;
2242+}
2243+
2244+const char* lil_to_string(lil_value_t val)
2245+{
2246+ return (val && val->l) ? val->d : "";
2247+}
2248+
2249+double lil_to_double(lil_value_t val)
2250+{
2251+ return atof(lil_to_string(val));
2252+}
2253+
2254+lilint_t lil_to_integer(lil_value_t val)
2255+{
2256+ return (lilint_t)atoll(lil_to_string(val));
2257+}
2258+
2259+int lil_to_boolean(lil_value_t val)
2260+{
2261+ const char* s = lil_to_string(val);
2262+ size_t i, dots = 0;
2263+ if (!s[0]) {return 0;}
2264+ for (i=0; s[i]; i++) {
2265+ if (s[i] != '0' && s[i] != '.') return 1;
2266+ if (s[i] == '.') {
2267+ if (dots) return 1;
2268+ dots = 1;
2269+ }
2270+ }
2271+ return 0;
2272+}
2273+
2274+lil_value_t lil_alloc_string(const char* str)
2275+{
2276+ return alloc_value(str);
2277+}
2278+
2279+lil_value_t lil_alloc_string_len(const char* str, size_t len)
2280+{
2281+ return alloc_value_len(str, len);
2282+}
2283+
2284+lil_value_t lil_alloc_double(double num)
2285+{
2286+ char buff[128];
2287+ sprintf(buff, "%f", num);
2288+ return alloc_value(buff);
2289+}
2290+
2291+lil_value_t lil_alloc_integer(lilint_t num)
2292+{
2293+ char buff[128];
2294+ sprintf(buff, LILINT_PRINTF, num);
2295+ return alloc_value(buff);
2296+}
2297+
2298+void lil_free(lil_t lil)
2299+{
2300+ size_t i;
2301+ if (!lil) return;
2302+ free(lil->err_msg);
2303+ lil_free_value(lil->empty);
2304+ while (lil->env) {
2305+ lil_env_t next = lil->env->parent;
2306+ lil_free_env(lil->env);
2307+ lil->env = next;
2308+ }
2309+ for (i=0; i<lil->cmds; i++) {
2310+ if (lil->cmd[i]->argnames)
2311+ lil_free_list(lil->cmd[i]->argnames);
2312+ lil_free_value(lil->cmd[i]->code);
2313+ free(lil->cmd[i]->name);
2314+ free(lil->cmd[i]);
2315+ }
2316+ hm_destroy(&lil->cmdmap);
2317+ free(lil->cmd);
2318+ free(lil->dollarprefix);
2319+ free(lil->catcher);
2320+ free(lil);
2321+}
2322+
2323+LILAPI void lil_set_data(lil_t lil, void* data)
2324+{
2325+ lil->data = data;
2326+}
2327+
2328+LILAPI void* lil_get_data(lil_t lil)
2329+{
2330+ return lil->data;
2331+}
2332+
2333+static LILCALLBACK void fnc_embed_write(lil_t lil, const char* msg)
2334+{
2335+ size_t len = strlen(msg) + 1;
2336+ lil->embed = realloc(lil->embed, lil->embedlen + len);
2337+ memcpy(lil->embed + lil->embedlen, msg, len);
2338+ lil->embedlen += len - 1;
2339+}
2340+
2341+char* lil_embedded(lil_t lil, const char* code, unsigned int flags)
2342+{
2343+ char* prev_embed = lil->embed;
2344+ size_t prev_embedlen = lil->embedlen;
2345+ lil_callback_proc_t prev_write = lil->callback[LIL_CALLBACK_WRITE];
2346+ char* lilcode = NULL;
2347+ size_t lilcodelen = 0;
2348+ char* cont = NULL;
2349+ size_t contlen = 0;
2350+ size_t head = 0, codelen = strlen(code);
2351+ char* result;
2352+
2353+ lil->callback[LIL_CALLBACK_WRITE] = (lil_callback_proc_t)fnc_embed_write;
2354+ lil->embed = NULL;
2355+ lil->embedlen = 0;
2356+
2357+ while (head < codelen) {
2358+ if (head < codelen - 4 &&
2359+ code[head] == '<' &&
2360+ code[head + 1] == '?' &&
2361+ code[head + 2] == 'l' &&
2362+ code[head + 3] == 'i' &&
2363+ code[head + 4] == 'l') {
2364+ head += 5;
2365+ if (contlen) {
2366+ lilcode = realloc(lilcode, lilcodelen + contlen + 10);
2367+ memcpy(lilcode + lilcodelen, "\nwrite {", 8);
2368+ memcpy(lilcode + lilcodelen + 8, cont, contlen);
2369+ lilcode[lilcodelen + contlen + 8] = '}';
2370+ lilcode[lilcodelen + contlen + 9] = '\n';
2371+ lilcodelen += contlen + 10;
2372+ free(cont);
2373+ cont = NULL;
2374+ contlen = 0;
2375+ }
2376+ while (head < codelen) {
2377+ if (head < codelen - 1 && code[head] == '?' && code[head + 1] == '>') {
2378+ head += 2;
2379+ break;
2380+ }
2381+ lilcode = realloc(lilcode, lilcodelen + 1);
2382+ lilcode[lilcodelen++] = code[head++];
2383+ }
2384+ lilcode = realloc(lilcode, lilcodelen + 1);
2385+ lilcode[lilcodelen++] = '\n';
2386+ } else {
2387+ if (code[head] == '{' || code[head] == '}') {
2388+ cont = realloc(cont, contlen + 6);
2389+ cont[contlen++] = '}';
2390+ cont[contlen++] = '"';
2391+ cont[contlen++] = '\\';
2392+ if (code[head] == '{')
2393+ cont[contlen++] = 'o';
2394+ else
2395+ cont[contlen++] = 'c';
2396+ cont[contlen++] = '"';
2397+ cont[contlen++] = '{';
2398+ head++;
2399+ } else {
2400+ cont = realloc(cont, contlen + 1);
2401+ cont[contlen++] = code[head++];
2402+ }
2403+ }
2404+ }
2405+ if (contlen) {
2406+ lilcode = realloc(lilcode, lilcodelen + contlen + 10);
2407+ memcpy(lilcode + lilcodelen, "\nwrite {", 8);
2408+ memcpy(lilcode + lilcodelen + 8, cont, contlen);
2409+ lilcode[lilcodelen + contlen + 8] = '}';
2410+ lilcode[lilcodelen + contlen + 9] = '\n';
2411+ lilcodelen += contlen + 10;
2412+ free(cont);
2413+ }
2414+
2415+ lilcode = realloc(lilcode, lilcodelen + 1);
2416+ lilcode[lilcodelen] = 0;
2417+ lil_free_value(lil_parse(lil, lilcode, 0, 1));
2418+ free(lilcode);
2419+ result = lil->embed ? lil->embed : strclone("");
2420+
2421+ lil->embed = prev_embed;
2422+ lil->embedlen = prev_embedlen;
2423+ lil->callback[LIL_CALLBACK_WRITE] = prev_write;
2424+
2425+ return result;
2426+}
2427+
2428+void lil_freemem(void* ptr)
2429+{
2430+ free(ptr);
2431+}
2432+
2433+void lil_write(lil_t lil, const char* msg)
2434+{
2435+ if (lil->callback[LIL_CALLBACK_WRITE]) {
2436+ lil_write_callback_proc_t proc = (lil_write_callback_proc_t)lil->callback[LIL_CALLBACK_WRITE];
2437+ proc(lil, msg);
2438+ } else printf("%s", msg);
2439+}
2440+
2441+static LILCALLBACK lil_value_t fnc_reflect(lil_t lil, size_t argc, lil_value_t* argv)
2442+{
2443+ lil_func_t func;
2444+ const char* type;
2445+ size_t i;
2446+ lil_value_t r;
2447+ if (!argc) return NULL;
2448+ type = lil_to_string(argv[0]);
2449+ if (!strcmp(type, "version")) {
2450+ return lil_alloc_string(LIL_VERSION_STRING);
2451+ }
2452+ if (!strcmp(type, "args")) {
2453+ if (argc < 2) return NULL;
2454+ func = find_cmd(lil, lil_to_string(argv[1]));
2455+ if (!func || !func->argnames) return NULL;
2456+ return lil_list_to_value(func->argnames, 1);
2457+ }
2458+ if (!strcmp(type, "body")) {
2459+ if (argc < 2) return NULL;
2460+ func = find_cmd(lil, lil_to_string(argv[1]));
2461+ if (!func || func->proc) return NULL;
2462+ return lil_clone_value(func->code);
2463+ }
2464+ if (!strcmp(type, "func-count")) {
2465+ return lil_alloc_integer(lil->cmds);
2466+ }
2467+ if (!strcmp(type, "funcs")) {
2468+ lil_list_t funcs = lil_alloc_list();
2469+ for (i=0; i<lil->cmds; i++)
2470+ lil_list_append(funcs, lil_alloc_string(lil->cmd[i]->name));
2471+ r = lil_list_to_value(funcs, 1);
2472+ lil_free_list(funcs);
2473+ return r;
2474+ }
2475+ if (!strcmp(type, "vars")) {
2476+ lil_list_t vars = lil_alloc_list();
2477+ lil_env_t env = lil->env;
2478+ while (env) {
2479+ for (i=0; i<env->vars; i++)
2480+ lil_list_append(vars, lil_alloc_string(env->var[i]->n));
2481+ env = env->parent;
2482+ }
2483+ r = lil_list_to_value(vars, 1);
2484+ lil_free_list(vars);
2485+ return r;
2486+ }
2487+ if (!strcmp(type, "globals")) {
2488+ lil_list_t vars = lil_alloc_list();
2489+ for (i=0; i<lil->rootenv->vars; i++)
2490+ lil_list_append(vars, lil_alloc_string(lil->rootenv->var[i]->n));
2491+ r = lil_list_to_value(vars, 1);
2492+ lil_free_list(vars);
2493+ return r;
2494+ }
2495+ if (!strcmp(type, "has-func")) {
2496+ const char* target;
2497+ if (argc == 1) return NULL;
2498+ target = lil_to_string(argv[1]);
2499+ return hm_has(&lil->cmdmap, target) ? lil_alloc_string("1") : NULL;
2500+ }
2501+ if (!strcmp(type, "has-var")) {
2502+ const char* target;
2503+ lil_env_t env = lil->env;
2504+ if (argc == 1) return NULL;
2505+ target = lil_to_string(argv[1]);
2506+ while (env) {
2507+ if (hm_has(&env->varmap, target)) return lil_alloc_string("1");
2508+ env = env->parent;
2509+ }
2510+ return NULL;
2511+ }
2512+ if (!strcmp(type, "has-global")) {
2513+ const char* target;
2514+ if (argc == 1) return NULL;
2515+ target = lil_to_string(argv[1]);
2516+ for (i=0; i<lil->rootenv->vars; i++)
2517+ if (!strcmp(target, lil->rootenv->var[i]->n)) return lil_alloc_string("1");
2518+ return NULL;
2519+ }
2520+ if (!strcmp(type, "error")) {
2521+ return lil->err_msg ? lil_alloc_string(lil->err_msg) : NULL;
2522+ }
2523+ if (!strcmp(type, "dollar-prefix")) {
2524+ lil_value_t r;
2525+ if (argc == 1) return lil_alloc_string(lil->dollarprefix);
2526+ r = lil_alloc_string(lil->dollarprefix);
2527+ free(lil->dollarprefix);
2528+ lil->dollarprefix = strclone(lil_to_string(argv[1]));
2529+ return r;
2530+ }
2531+ if (!strcmp(type, "this")) {
2532+ lil_env_t env = lil->env;
2533+ while (env != lil->rootenv && !env->catcher_for && !env->func) env = env->parent;
2534+ if (env->catcher_for) return lil_alloc_string(lil->catcher);
2535+ if (env == lil->rootenv) return lil_alloc_string(lil->rootcode);
2536+ return env->func ? env->func->code : NULL;
2537+ }
2538+ if (!strcmp(type, "name")) {
2539+ lil_env_t env = lil->env;
2540+ while (env != lil->rootenv && !env->catcher_for && !env->func) env = env->parent;
2541+ if (env->catcher_for) return env->catcher_for;
2542+ if (env == lil->rootenv) return NULL;
2543+ return env->func ? lil_alloc_string(env->func->name) : NULL;
2544+ }
2545+ return NULL;
2546+}
2547+
2548+static LILCALLBACK lil_value_t fnc_func(lil_t lil, size_t argc, lil_value_t* argv)
2549+{
2550+ lil_value_t name;
2551+ lil_func_t cmd;
2552+ lil_list_t fargs;
2553+ if (argc < 1) return NULL;
2554+ if (argc >= 3) {
2555+ name = lil_clone_value(argv[0]);
2556+ fargs = lil_subst_to_list(lil, argv[1]);
2557+ cmd = add_func(lil, lil_to_string(argv[0]));
2558+ cmd->argnames = fargs;
2559+ cmd->code = lil_clone_value(argv[2]);
2560+ } else {
2561+ name = lil_unused_name(lil, "anonymous-function");
2562+ if (argc < 2) {
2563+ lil_value_t tmp = lil_alloc_string("args");
2564+ fargs = lil_subst_to_list(lil, tmp);
2565+ lil_free_value(tmp);
2566+ cmd = add_func(lil, lil_to_string(name));
2567+ cmd->argnames = fargs;
2568+ cmd->code = lil_clone_value(argv[0]);
2569+ } else {
2570+ fargs = lil_subst_to_list(lil, argv[0]);
2571+ cmd = add_func(lil, lil_to_string(name));
2572+ cmd->argnames = fargs;
2573+ cmd->code = lil_clone_value(argv[1]);
2574+ }
2575+ }
2576+ return name;
2577+}
2578+
2579+static LILCALLBACK lil_value_t fnc_rename(lil_t lil, size_t argc, lil_value_t* argv)
2580+{
2581+ lil_value_t r;
2582+ lil_func_t func;
2583+ const char* oldname;
2584+ const char* newname;
2585+ if (argc < 2) return NULL;
2586+ oldname = lil_to_string(argv[0]);
2587+ newname = lil_to_string(argv[1]);
2588+ func = find_cmd(lil, oldname);
2589+ if (!func) {
2590+ char* msg = malloc(24 + strlen(oldname));
2591+ sprintf(msg, "unknown function '%s'", oldname);
2592+ lil_set_error_at(lil, lil->head, msg);
2593+ free(msg);
2594+ return NULL;
2595+ }
2596+ r = lil_alloc_string(func->name);
2597+ if (newname[0]) {
2598+ hm_put(&lil->cmdmap, oldname, 0);
2599+ hm_put(&lil->cmdmap, newname, func);
2600+ free(func->name);
2601+ func->name = strclone(newname);
2602+ } else {
2603+ del_func(lil, func);
2604+ }
2605+ return r;
2606+}
2607+
2608+static LILCALLBACK lil_value_t fnc_unusedname(lil_t lil, size_t argc, lil_value_t* argv)
2609+{
2610+ return lil_unused_name(lil, argc > 0 ? lil_to_string(argv[0]) : "unusedname");
2611+}
2612+
2613+static LILCALLBACK lil_value_t fnc_quote(lil_t lil, size_t argc, lil_value_t* argv)
2614+{
2615+ lil_value_t r;
2616+ size_t i;
2617+ if (argc < 1) return NULL;
2618+ r = alloc_value(NULL);
2619+ for (i=0; i<argc; i++) {
2620+ if (i) lil_append_char(r, ' ');
2621+ lil_append_val(r, argv[i]);
2622+ }
2623+ return r;
2624+}
2625+
2626+static LILCALLBACK lil_value_t fnc_set(lil_t lil, size_t argc, lil_value_t* argv)
2627+{
2628+ size_t i = 0;
2629+ lil_var_t var = NULL;
2630+ int access = LIL_SETVAR_LOCAL;
2631+ if (!argc) return NULL;
2632+ if (!strcmp(lil_to_string(argv[0]), "global")) {
2633+ i = 1;
2634+ access = LIL_SETVAR_GLOBAL;
2635+ }
2636+ while (i < argc) {
2637+ if (argc == i + 1) return lil_clone_value(lil_get_var(lil, lil_to_string(argv[i])));
2638+ var = lil_set_var(lil, lil_to_string(argv[i]), argv[i + 1], access);
2639+ i += 2;
2640+ }
2641+ return var ? lil_clone_value(var->v) : NULL;
2642+}
2643+
2644+static LILCALLBACK lil_value_t fnc_local(lil_t lil, size_t argc, lil_value_t* argv)
2645+{
2646+ size_t i;
2647+ for (i=0; i<argc; i++) {
2648+ const char* varname = lil_to_string(argv[i]);
2649+ if (!lil_find_local_var(lil, lil->env, varname))
2650+ lil_set_var(lil, varname, lil->empty, LIL_SETVAR_LOCAL_NEW);
2651+ }
2652+ return NULL;
2653+}
2654+
2655+static LILCALLBACK lil_value_t fnc_write(lil_t lil, size_t argc, lil_value_t* argv)
2656+{
2657+ size_t i;
2658+ lil_value_t msg = lil_alloc_string(NULL);
2659+ for (i=0; i<argc; i++) {
2660+ if (i) lil_append_char(msg, ' ');
2661+ lil_append_val(msg, argv[i]);
2662+ }
2663+ lil_write(lil, lil_to_string(msg));
2664+ lil_free_value(msg);
2665+ return NULL;
2666+}
2667+
2668+static LILCALLBACK lil_value_t fnc_print(lil_t lil, size_t argc, lil_value_t* argv)
2669+{
2670+ fnc_write(lil, argc, argv);
2671+ lil_write(lil, "\n");
2672+ return NULL;
2673+}
2674+
2675+static LILCALLBACK lil_value_t fnc_eval(lil_t lil, size_t argc, lil_value_t* argv)
2676+{
2677+ if (argc == 1) return lil_parse_value(lil, argv[0], 0);
2678+ if (argc > 1) {
2679+ lil_value_t val = alloc_value(NULL), r;
2680+ size_t i;
2681+ for (i=0; i<argc; i++) {
2682+ if (i) lil_append_char(val, ' ');
2683+ lil_append_val(val, argv[i]);
2684+ }
2685+ r = lil_parse_value(lil, val, 0);
2686+ lil_free_value(val);
2687+ return r;
2688+ }
2689+ return NULL;
2690+}
2691+
2692+static LILCALLBACK lil_value_t fnc_topeval(lil_t lil, size_t argc, lil_value_t* argv)
2693+{
2694+ lil_env_t thisenv = lil->env;
2695+ lil_env_t thisdownenv = lil->downenv;
2696+ lil_value_t r;
2697+ lil->env = lil->rootenv;
2698+ lil->downenv = thisenv;
2699+ r = fnc_eval(lil, argc, argv);
2700+ lil->downenv = thisdownenv;
2701+ lil->env = thisenv;
2702+ return r;
2703+}
2704+
2705+static LILCALLBACK lil_value_t fnc_upeval(lil_t lil, size_t argc, lil_value_t* argv)
2706+{
2707+ lil_env_t thisenv = lil->env;
2708+ lil_env_t thisdownenv = lil->downenv;
2709+ lil_value_t r;
2710+ if (lil->rootenv == thisenv) return fnc_eval(lil, argc, argv);
2711+ lil->env = thisenv->parent;
2712+ lil->downenv = thisenv;
2713+ r = fnc_eval(lil, argc, argv);
2714+ lil->env = thisenv;
2715+ lil->downenv = thisdownenv;
2716+ return r;
2717+}
2718+
2719+static LILCALLBACK lil_value_t fnc_downeval(lil_t lil, size_t argc, lil_value_t* argv)
2720+{
2721+ lil_value_t r;
2722+ lil_env_t upenv = lil->env;
2723+ lil_env_t downenv = lil->downenv;
2724+ if (!downenv) return fnc_eval(lil, argc, argv);
2725+ lil->downenv = NULL;
2726+ lil->env = downenv;
2727+ r = fnc_eval(lil, argc, argv);
2728+ lil->downenv = downenv;
2729+ lil->env = upenv;
2730+ return r;
2731+}
2732+
2733+static LILCALLBACK lil_value_t fnc_enveval(lil_t lil, size_t argc, lil_value_t* argv)
2734+{
2735+ lil_value_t r;
2736+ lil_list_t invars = NULL;
2737+ lil_list_t outvars = NULL;
2738+ lil_value_t* varvalues = NULL;
2739+ int codeindex;
2740+ size_t i;
2741+ if (argc < 1) return NULL;
2742+ if (argc == 1) codeindex = 0;
2743+ else if (argc >= 2) {
2744+ invars = lil_subst_to_list(lil, argv[0]);
2745+ varvalues = malloc(sizeof(lil_value_t)*lil_list_size(invars));
2746+ for (i=0; i<lil_list_size(invars); i++)
2747+ varvalues[i] = lil_clone_value(lil_get_var(lil, lil_to_string(lil_list_get(invars, i))));
2748+ if (argc > 2) {
2749+ codeindex = 2;
2750+ outvars = lil_subst_to_list(lil, argv[1]);
2751+ } else {
2752+ codeindex = 1;
2753+ }
2754+ }
2755+ lil_push_env(lil);
2756+ if (invars) {
2757+ for (i=0; i<lil_list_size(invars); i++) {
2758+ lil_set_var(lil, lil_to_string(lil_list_get(invars, i)), varvalues[i], LIL_SETVAR_LOCAL_NEW);
2759+ lil_free_value(varvalues[i]);
2760+ }
2761+ }
2762+ r = lil_parse_value(lil, argv[codeindex], 0);
2763+ if (invars || outvars) {
2764+ if (outvars) {
2765+ varvalues = realloc(varvalues, sizeof(lil_value_t)*lil_list_size(outvars));
2766+ for (i=0; i<lil_list_size(outvars); i++)
2767+ varvalues[i] = lil_clone_value(lil_get_var(lil, lil_to_string(lil_list_get(outvars, i))));
2768+ } else {
2769+ for (i=0; i<lil_list_size(invars); i++)
2770+ varvalues[i] = lil_clone_value(lil_get_var(lil, lil_to_string(lil_list_get(invars, i))));
2771+ }
2772+ }
2773+ lil_pop_env(lil);
2774+ if (invars) {
2775+ if (outvars) {
2776+ for (i=0; i<lil_list_size(outvars); i++) {
2777+ lil_set_var(lil, lil_to_string(lil_list_get(outvars, i)), varvalues[i], LIL_SETVAR_LOCAL);
2778+ lil_free_value(varvalues[i]);
2779+ }
2780+ } else {
2781+ for (i=0; i<lil_list_size(invars); i++) {
2782+ lil_set_var(lil, lil_to_string(lil_list_get(invars, i)), varvalues[i], LIL_SETVAR_LOCAL);
2783+ lil_free_value(varvalues[i]);
2784+ }
2785+ }
2786+ lil_free_list(invars);
2787+ if (outvars) lil_free_list(outvars);
2788+ free(varvalues);
2789+ }
2790+ return r;
2791+}
2792+
2793+static LILCALLBACK lil_value_t fnc_jaileval(lil_t lil, size_t argc, lil_value_t* argv)
2794+{
2795+ size_t i;
2796+ lil_t sublil;
2797+ lil_value_t r;
2798+ size_t base = 0;
2799+ if (!argc) return NULL;
2800+ if (!strcmp(lil_to_string(argv[0]), "clean")) {
2801+ base = 1;
2802+ if (argc == 1) return NULL;
2803+ }
2804+ sublil = lil_new();
2805+ if (base != 1) {
2806+ for (i=lil->syscmds; i<lil->cmds; i++) {
2807+ lil_func_t fnc = lil->cmd[i];
2808+ if (!fnc->proc) continue;
2809+ lil_register(sublil, fnc->name, fnc->proc);
2810+ }
2811+ }
2812+ r = lil_parse_value(sublil, argv[base], 1);
2813+ lil_free(sublil);
2814+ return r;
2815+}
2816+
2817+static LILCALLBACK lil_value_t fnc_count(lil_t lil, size_t argc, lil_value_t* argv)
2818+{
2819+ lil_list_t list;
2820+ char buff[64];
2821+ if (!argc) return alloc_value("0");
2822+ list = lil_subst_to_list(lil, argv[0]);
2823+ sprintf(buff, "%u", (unsigned int)list->c);
2824+ lil_free_list(list);
2825+ return alloc_value(buff);
2826+}
2827+
2828+static LILCALLBACK lil_value_t fnc_index(lil_t lil, size_t argc, lil_value_t* argv)
2829+{
2830+ lil_list_t list;
2831+ size_t index;
2832+ lil_value_t r;
2833+ if (argc < 2) return NULL;
2834+ list = lil_subst_to_list(lil, argv[0]);
2835+ index = (size_t)lil_to_integer(argv[1]);
2836+ if (index >= list->c)
2837+ r = NULL;
2838+ else
2839+ r = lil_clone_value(list->v[index]);
2840+ lil_free_list(list);
2841+ return r;
2842+}
2843+
2844+static LILCALLBACK lil_value_t fnc_indexof(lil_t lil, size_t argc, lil_value_t* argv)
2845+{
2846+ lil_list_t list;
2847+ size_t index;
2848+ lil_value_t r = NULL;
2849+ if (argc < 2) return NULL;
2850+ list = lil_subst_to_list(lil, argv[0]);
2851+ for (index = 0; index < list->c; index++)
2852+ if (!strcmp(lil_to_string(list->v[index]), lil_to_string(argv[1]))) {
2853+ r = lil_alloc_integer(index);
2854+ break;
2855+ }
2856+ lil_free_list(list);
2857+ return r;
2858+}
2859+
2860+static LILCALLBACK lil_value_t fnc_append(lil_t lil, size_t argc, lil_value_t* argv)
2861+{
2862+ lil_list_t list;
2863+ lil_value_t r;
2864+ size_t i, base = 1;
2865+ int access = LIL_SETVAR_LOCAL;
2866+ const char* varname;
2867+ if (argc < 2) return NULL;
2868+ varname = lil_to_string(argv[0]);
2869+ if (!strcmp(varname, "global")) {
2870+ if (argc < 3) return NULL;
2871+ varname = lil_to_string(argv[1]);
2872+ base = 2;
2873+ access = LIL_SETVAR_GLOBAL;
2874+ }
2875+ list = lil_subst_to_list(lil, lil_get_var(lil, varname));
2876+ for (i=base; i<argc; i++)
2877+ lil_list_append(list, lil_clone_value(argv[i]));
2878+ r = lil_list_to_value(list, 1);
2879+ lil_free_list(list);
2880+ lil_set_var(lil, varname, r, access);
2881+ return r;
2882+}
2883+
2884+static LILCALLBACK lil_value_t fnc_slice(lil_t lil, size_t argc, lil_value_t* argv)
2885+{
2886+ lil_list_t list, slice;
2887+ size_t i;
2888+ lilint_t from, to;
2889+ lil_value_t r;
2890+ if (argc < 1) return NULL;
2891+ if (argc < 2) return lil_clone_value(argv[0]);
2892+ from = lil_to_integer(argv[1]);
2893+ if (from < 0) from = 0;
2894+ list = lil_subst_to_list(lil, argv[0]);
2895+ to = argc > 2 ? lil_to_integer(argv[2]) : (lilint_t)list->c;
2896+ if (to > (lilint_t)list->c) to = list->c;
2897+ if (to < from) to = from;
2898+ slice = lil_alloc_list();
2899+ for (i=(size_t)from; i<(size_t)to; i++)
2900+ lil_list_append(slice, lil_clone_value(list->v[i]));
2901+ lil_free_list(list);
2902+ r = lil_list_to_value(slice, 1);
2903+ lil_free_list(slice);
2904+ return r;
2905+}
2906+
2907+static LILCALLBACK lil_value_t fnc_filter(lil_t lil, size_t argc, lil_value_t* argv)
2908+{
2909+ lil_list_t list, filtered;
2910+ size_t i;
2911+ lil_value_t r;
2912+ const char* varname = "x";
2913+ int base = 0;
2914+ if (argc < 1) return NULL;
2915+ if (argc < 2) return lil_clone_value(argv[0]);
2916+ if (argc > 2) {
2917+ base = 1;
2918+ varname = lil_to_string(argv[0]);
2919+ }
2920+ list = lil_subst_to_list(lil, argv[base]);
2921+ filtered = lil_alloc_list();
2922+ for (i=0; i<list->c && !lil->env->breakrun; i++) {
2923+ lil_set_var(lil, varname, list->v[i], LIL_SETVAR_LOCAL_ONLY);
2924+ r = lil_eval_expr(lil, argv[base + 1]);
2925+ if (lil_to_boolean(r))
2926+ lil_list_append(filtered, lil_clone_value(list->v[i]));
2927+ lil_free_value(r);
2928+ }
2929+ lil_free_list(list);
2930+ r = lil_list_to_value(filtered, 1);
2931+ lil_free_list(filtered);
2932+ return r;
2933+}
2934+
2935+static LILCALLBACK lil_value_t fnc_list(lil_t lil, size_t argc, lil_value_t* argv)
2936+{
2937+ lil_list_t list = lil_alloc_list();
2938+ lil_value_t r;
2939+ size_t i;
2940+ for (i=0; i<argc; i++)
2941+ lil_list_append(list, lil_clone_value(argv[i]));
2942+ r = lil_list_to_value(list, 1);
2943+ lil_free_list(list);
2944+ return r;
2945+}
2946+
2947+static LILCALLBACK lil_value_t fnc_subst(lil_t lil, size_t argc, lil_value_t* argv)
2948+{
2949+ if (argc < 1) return NULL;
2950+ return lil_subst_to_value(lil, argv[0]);
2951+}
2952+
2953+static LILCALLBACK lil_value_t fnc_concat(lil_t lil, size_t argc, lil_value_t* argv)
2954+{
2955+ lil_list_t list;
2956+ lil_value_t r, tmp;
2957+ size_t i;
2958+ if (argc < 1) return NULL;
2959+ r = lil_alloc_string("");
2960+ for (i=0; i<argc; i++) {
2961+ list = lil_subst_to_list(lil, argv[i]);
2962+ tmp = lil_list_to_value(list, 1);
2963+ lil_free_list(list);
2964+ lil_append_val(r, tmp);
2965+ lil_free_value(tmp);
2966+ }
2967+ return r;
2968+}
2969+
2970+static LILCALLBACK lil_value_t fnc_foreach(lil_t lil, size_t argc, lil_value_t* argv)
2971+{
2972+ lil_list_t list, rlist;
2973+ lil_value_t r;
2974+ size_t i, listidx = 0, codeidx = 1;
2975+ const char* varname = "i";
2976+ if (argc < 2) return NULL;
2977+ if (argc >= 3) {
2978+ varname = lil_to_string(argv[0]);
2979+ listidx = 1;
2980+ codeidx = 2;
2981+ }
2982+ rlist = lil_alloc_list();
2983+ list = lil_subst_to_list(lil, argv[listidx]);
2984+ for (i=0; i<list->c; i++) {
2985+ lil_value_t rv;
2986+ lil_set_var(lil, varname, list->v[i], LIL_SETVAR_LOCAL_ONLY);
2987+ rv = lil_parse_value(lil, argv[codeidx], 0);
2988+ if (rv->l) lil_list_append(rlist, rv);
2989+ else lil_free_value(rv);
2990+ if (lil->env->breakrun || lil->error) break;
2991+ }
2992+ r = lil_list_to_value(rlist, 1);
2993+ lil_free_list(list);
2994+ lil_free_list(rlist);
2995+ return r;
2996+}
2997+
2998+static LILCALLBACK lil_value_t fnc_return(lil_t lil, size_t argc, lil_value_t* argv)
2999+{
3000+ lil->env->breakrun = 1;
3001+ lil_free_value(lil->env->retval);
3002+ lil->env->retval = argc < 1 ? NULL : lil_clone_value(argv[0]);
3003+ lil->env->retval_set = 1;
3004+ return argc < 1 ? NULL : lil_clone_value(argv[0]);
3005+}
3006+
3007+static LILCALLBACK lil_value_t fnc_result(lil_t lil, size_t argc, lil_value_t* argv)
3008+{
3009+ if (argc > 0) {
3010+ lil_free_value(lil->env->retval);
3011+ lil->env->retval = lil_clone_value(argv[0]);
3012+ lil->env->retval_set = 1;
3013+ }
3014+ return lil->env->retval_set ? lil_clone_value(lil->env->retval) : NULL;
3015+}
3016+
3017+static LILCALLBACK lil_value_t fnc_expr(lil_t lil, size_t argc, lil_value_t* argv)
3018+{
3019+ if (argc == 1) return lil_eval_expr(lil, argv[0]);
3020+ if (argc > 1) {
3021+ lil_value_t val = alloc_value(NULL), r;
3022+ size_t i;
3023+ for (i=0; i<argc; i++) {
3024+ if (i) lil_append_char(val, ' ');
3025+ lil_append_val(val, argv[i]);
3026+ }
3027+ r = lil_eval_expr(lil, val);
3028+ lil_free_value(val);
3029+ return r;
3030+ }
3031+ return NULL;
3032+}
3033+
3034+static lil_value_t real_inc(lil_t lil, const char* varname, float v)
3035+{
3036+ lil_value_t pv = lil_get_var(lil, varname);
3037+ double dv = lil_to_double(pv) + v;
3038+ if (fmod(dv, 1))
3039+ pv = lil_alloc_double(dv);
3040+ else
3041+ pv = lil_alloc_integer((lilint_t)dv);
3042+ lil_set_var(lil, varname, pv, LIL_SETVAR_LOCAL);
3043+ return pv;
3044+}
3045+
3046+static LILCALLBACK lil_value_t fnc_inc(lil_t lil, size_t argc, lil_value_t* argv)
3047+{
3048+ if (argc < 1) return NULL;
3049+ return real_inc(lil, lil_to_string(argv[0]), argc > 1 ? lil_to_double(argv[1]) : 1);
3050+}
3051+
3052+static LILCALLBACK lil_value_t fnc_dec(lil_t lil, size_t argc, lil_value_t* argv)
3053+{
3054+ if (argc < 1) return NULL;
3055+ return real_inc(lil, lil_to_string(argv[0]), -(argc > 1 ? lil_to_double(argv[1]) : 1));
3056+}
3057+
3058+static LILCALLBACK lil_value_t fnc_read(lil_t lil, size_t argc, lil_value_t* argv)
3059+{
3060+ FILE* f;
3061+ size_t size;
3062+ char* buffer;
3063+ lil_value_t r;
3064+ if (argc < 1) return NULL;
3065+ if (lil->callback[LIL_CALLBACK_READ]) {
3066+ lil_read_callback_proc_t proc = (lil_read_callback_proc_t) lil->callback[LIL_CALLBACK_READ];
3067+ buffer = proc(lil, lil_to_string(argv[0]));
3068+ } else {
3069+ f = fopen(lil_to_string(argv[0]), "rb");
3070+ if (!f) return NULL;
3071+ fseek(f, 0, SEEK_END);
3072+ size = ftell(f);
3073+ fseek(f, 0, SEEK_SET);
3074+ buffer = malloc(size + 1);
3075+ fread(buffer, 1, size, f);
3076+ buffer[size] = 0;
3077+ fclose(f);
3078+ }
3079+ r = lil_alloc_string(buffer);
3080+ free(buffer);
3081+ return r;
3082+}
3083+
3084+static LILCALLBACK lil_value_t fnc_store(lil_t lil, size_t argc, lil_value_t* argv)
3085+{
3086+ FILE* f;
3087+ const char* buffer;
3088+ if (argc < 2) return NULL;
3089+ if (lil->callback[LIL_CALLBACK_STORE]) {
3090+ lil_store_callback_proc_t proc = (lil_store_callback_proc_t)lil->callback[LIL_CALLBACK_STORE];
3091+ proc(lil, lil_to_string(argv[0]), lil_to_string(argv[1]));
3092+ } else {
3093+ f = fopen(lil_to_string(argv[0]), "wb");
3094+ if (!f) return NULL;
3095+ buffer = lil_to_string(argv[1]);
3096+ fwrite(buffer, 1, strlen(buffer), f);
3097+ fclose(f);
3098+ }
3099+ return lil_clone_value(argv[1]);
3100+}
3101+
3102+static LILCALLBACK lil_value_t fnc_if(lil_t lil, size_t argc, lil_value_t* argv)
3103+{
3104+ lil_value_t val, r = NULL;
3105+ int base = 0, not = 0, v;
3106+ if (argc < 1) return NULL;
3107+ if (!strcmp(lil_to_string(argv[0]), "not")) base = not = 1;
3108+ if (argc < (size_t)base + 2) return NULL;
3109+ val = lil_eval_expr(lil, argv[base]);
3110+ if (!val || lil->error) return NULL;
3111+ v = lil_to_boolean(val);
3112+ if (not) v = !v;
3113+ if (v) {
3114+ r = lil_parse_value(lil, argv[base + 1], 0);
3115+ } else if (argc > (size_t)base + 2) {
3116+ r = lil_parse_value(lil, argv[base + 2], 0);
3117+ }
3118+ lil_free_value(val);
3119+ return r;
3120+}
3121+
3122+static LILCALLBACK lil_value_t fnc_while(lil_t lil, size_t argc, lil_value_t* argv)
3123+{
3124+ lil_value_t val, r = NULL;
3125+ int base = 0, not = 0, v;
3126+ if (argc < 1) return NULL;
3127+ if (!strcmp(lil_to_string(argv[0]), "not")) base = not = 1;
3128+ if (argc < (size_t)base + 2) return NULL;
3129+ while (!lil->error && !lil->env->breakrun) {
3130+ val = lil_eval_expr(lil, argv[base]);
3131+ if (!val || lil->error) return NULL;
3132+ v = lil_to_boolean(val);
3133+ if (not) v = !v;
3134+ if (!v) {
3135+ lil_free_value(val);
3136+ break;
3137+ }
3138+ if (r) lil_free_value(r);
3139+ r = lil_parse_value(lil, argv[base + 1], 0);
3140+ lil_free_value(val);
3141+ }
3142+ return r;
3143+}
3144+
3145+static LILCALLBACK lil_value_t fnc_for(lil_t lil, size_t argc, lil_value_t* argv)
3146+{
3147+ lil_value_t val, r = NULL;
3148+ if (argc < 4) return NULL;
3149+ lil_free_value(lil_parse_value(lil, argv[0], 0));
3150+ while (!lil->error && !lil->env->breakrun) {
3151+ val = lil_eval_expr(lil, argv[1]);
3152+ if (!val || lil->error) return NULL;
3153+ if (!lil_to_boolean(val)) {
3154+ lil_free_value(val);
3155+ break;
3156+ }
3157+ if (r) lil_free_value(r);
3158+ r = lil_parse_value(lil, argv[3], 0);
3159+ lil_free_value(val);
3160+ lil_free_value(lil_parse_value(lil, argv[2], 0));
3161+ }
3162+ return r;
3163+}
3164+
3165+
3166+static LILCALLBACK lil_value_t fnc_char(lil_t lil, size_t argc, lil_value_t* argv)
3167+{
3168+ char s[2];
3169+ if (!argc) return NULL;
3170+ s[0] = (char)lil_to_integer(argv[0]);
3171+ s[1] = 0;
3172+ return lil_alloc_string(s);
3173+}
3174+
3175+static LILCALLBACK lil_value_t fnc_charat(lil_t lil, size_t argc, lil_value_t* argv)
3176+{
3177+ size_t index;
3178+ char chstr[2];
3179+ const char* str;
3180+ if (argc < 2) return NULL;
3181+ str = lil_to_string(argv[0]);
3182+ index = (size_t)lil_to_integer(argv[1]);
3183+ if (index >= strlen(str)) return NULL;
3184+ chstr[0] = str[index];
3185+ chstr[1] = 0;
3186+ return lil_alloc_string(chstr);
3187+}
3188+
3189+static LILCALLBACK lil_value_t fnc_codeat(lil_t lil, size_t argc, lil_value_t* argv)
3190+{
3191+ size_t index;
3192+ const char* str;
3193+ if (argc < 2) return NULL;
3194+ str = lil_to_string(argv[0]);
3195+ index = (size_t)lil_to_integer(argv[1]);
3196+ if (index >= strlen(str)) return NULL;
3197+ return lil_alloc_integer(str[index]);
3198+}
3199+
3200+static LILCALLBACK lil_value_t fnc_substr(lil_t lil, size_t argc, lil_value_t* argv)
3201+{
3202+ const char* str;
3203+ lil_value_t r;
3204+ size_t start, end, i, slen;
3205+ if (argc < 2) return NULL;
3206+ str = lil_to_string(argv[0]);
3207+ if (!str[0]) return NULL;
3208+ slen = strlen(str);
3209+ start = (size_t)atoll(lil_to_string(argv[1]));
3210+ end = argc > 2 ? (size_t)atoll(lil_to_string(argv[2])) : slen;
3211+ if (end > slen) end = slen;
3212+ if (start >= end) return NULL;
3213+ r = lil_alloc_string("");
3214+ for (i=start; i<end; i++)
3215+ lil_append_char(r, str[i]);
3216+ return r;
3217+}
3218+
3219+static LILCALLBACK lil_value_t fnc_strpos(lil_t lil, size_t argc, lil_value_t* argv)
3220+{
3221+ const char* hay;
3222+ const char* str;
3223+ size_t min = 0;
3224+ if (argc < 2) return lil_alloc_integer(-1);
3225+ hay = lil_to_string(argv[0]);
3226+ if (argc > 2) {
3227+ min = (size_t)atoll(lil_to_string(argv[2]));
3228+ if (min >= strlen(hay)) return lil_alloc_integer(-1);
3229+ }
3230+ str = strstr(hay + min, lil_to_string(argv[1]));
3231+ if (!str) return lil_alloc_integer(-1);
3232+ return lil_alloc_integer(str - hay);
3233+}
3234+
3235+static LILCALLBACK lil_value_t fnc_length(lil_t lil, size_t argc, lil_value_t* argv)
3236+{
3237+ size_t i, total = 0;
3238+ for (i=0; i<argc; i++) {
3239+ if (i) total++;
3240+ total += strlen(lil_to_string(argv[i]));
3241+ }
3242+ return lil_alloc_integer((lilint_t)total);
3243+}
3244+
3245+static lil_value_t real_trim(const char* str, const char* chars, int left, int right)
3246+{
3247+ int base = 0;
3248+ lil_value_t r = NULL;
3249+ if (left) {
3250+ while (str[base] && strchr(chars, str[base])) base++;
3251+ if (!right) r = lil_alloc_string(str[base] ? str + base : NULL);
3252+ }
3253+ if (right) {
3254+ size_t len;
3255+ char* s;
3256+ s = strclone(str + base);
3257+ len = strlen(s);
3258+ while (len && strchr(chars, s[len - 1])) len--;
3259+ s[len] = 0;
3260+ r = lil_alloc_string(s);
3261+ free(s);
3262+ }
3263+ return r;
3264+}
3265+
3266+static LILCALLBACK lil_value_t fnc_trim(lil_t lil, size_t argc, lil_value_t* argv)
3267+{
3268+ if (!argc) return NULL;
3269+ return real_trim(lil_to_string(argv[0]), argc < 2 ? " \f\n\r\t\v" : lil_to_string(argv[1]), 1, 1);
3270+}
3271+
3272+static LILCALLBACK lil_value_t fnc_ltrim(lil_t lil, size_t argc, lil_value_t* argv)
3273+{
3274+ if (!argc) return NULL;
3275+ return real_trim(lil_to_string(argv[0]), argc < 2 ? " \f\n\r\t\v" : lil_to_string(argv[1]), 1, 0);
3276+}
3277+
3278+static LILCALLBACK lil_value_t fnc_rtrim(lil_t lil, size_t argc, lil_value_t* argv)
3279+{
3280+ if (!argc) return NULL;
3281+ return real_trim(lil_to_string(argv[0]), argc < 2 ? " \f\n\r\t\v" : lil_to_string(argv[1]), 0, 1);
3282+}
3283+
3284+static LILCALLBACK lil_value_t fnc_strcmp(lil_t lil, size_t argc, lil_value_t* argv)
3285+{
3286+ if (argc < 2) return NULL;
3287+ return lil_alloc_integer(strcmp(lil_to_string(argv[0]), lil_to_string(argv[1])));
3288+}
3289+
3290+static LILCALLBACK lil_value_t fnc_streq(lil_t lil, size_t argc, lil_value_t* argv)
3291+{
3292+ if (argc < 2) return NULL;
3293+ return lil_alloc_integer(strcmp(lil_to_string(argv[0]), lil_to_string(argv[1]))?0:1);
3294+}
3295+
3296+static LILCALLBACK lil_value_t fnc_repstr(lil_t lil, size_t argc, lil_value_t* argv)
3297+{
3298+ const char* from;
3299+ const char* to;
3300+ char* src;
3301+ const char* sub;
3302+ size_t idx;
3303+ size_t fromlen;
3304+ size_t tolen;
3305+ size_t srclen;
3306+ lil_value_t r;
3307+ if (argc < 1) return NULL;
3308+ if (argc < 3) return lil_clone_value(argv[0]);
3309+ from = lil_to_string(argv[1]);
3310+ to = lil_to_string(argv[2]);
3311+ if (!from[0]) return NULL;
3312+ src = strclone(lil_to_string(argv[0]));
3313+ srclen = strlen(src);
3314+ fromlen = strlen(from);
3315+ tolen = strlen(to);
3316+ while ((sub = strstr(src, from))) {
3317+ char* newsrc = malloc(srclen - fromlen + tolen + 1);
3318+ idx = sub - src;
3319+ if (idx) memcpy(newsrc, src, idx);
3320+ memcpy(newsrc + idx, to, tolen);
3321+ memcpy(newsrc + idx + tolen, src + idx + fromlen, srclen - idx - fromlen);
3322+ srclen = srclen - fromlen + tolen;
3323+ free(src);
3324+ src = newsrc;
3325+ src[srclen] = 0;
3326+ }
3327+ r = lil_alloc_string(src);
3328+ free(src);
3329+ return r;
3330+}
3331+
3332+static LILCALLBACK lil_value_t fnc_split(lil_t lil, size_t argc, lil_value_t* argv)
3333+{
3334+ lil_list_t list;
3335+ const char* sep = " ";
3336+ size_t i;
3337+ lil_value_t val;
3338+ const char* str;
3339+ if (argc == 0) return NULL;
3340+ if (argc > 1) {
3341+ sep = lil_to_string(argv[1]);
3342+ if (!sep || !sep[0]) return lil_clone_value(argv[0]);
3343+ }
3344+ val = lil_alloc_string("");
3345+ str = lil_to_string(argv[0]);
3346+ list = lil_alloc_list();
3347+ for (i=0; str[i]; i++) {
3348+ if (strchr(sep, str[i])) {
3349+ lil_list_append(list, val);
3350+ val = lil_alloc_string("");
3351+ } else {
3352+ lil_append_char(val, str[i]);
3353+ }
3354+ }
3355+ lil_list_append(list, val);
3356+ val = lil_list_to_value(list, 1);
3357+ lil_free_list(list);
3358+ return val;
3359+}
3360+
3361+static LILCALLBACK lil_value_t fnc_try(lil_t lil, size_t argc, lil_value_t* argv)
3362+{
3363+ lil_value_t r;
3364+ if (argc < 1) return NULL;
3365+ if (lil->error) return NULL;
3366+ r = lil_parse_value(lil, argv[0], 0);
3367+ if (lil->error) {
3368+ lil->error = ERROR_NOERROR;
3369+ lil_free_value(r);
3370+ if (argc > 1) r = lil_parse_value(lil, argv[1], 0);
3371+ else r = 0;
3372+ }
3373+ return r;
3374+}
3375+
3376+static LILCALLBACK lil_value_t fnc_error(lil_t lil, size_t argc, lil_value_t* argv)
3377+{
3378+ lil_set_error(lil, argc > 0 ? lil_to_string(argv[0]) : NULL);
3379+ return NULL;
3380+}
3381+
3382+static LILCALLBACK lil_value_t fnc_exit(lil_t lil, size_t argc, lil_value_t* argv)
3383+{
3384+ if (lil->callback[LIL_CALLBACK_EXIT]) {
3385+ lil_exit_callback_proc_t proc = (lil_exit_callback_proc_t)lil->callback[LIL_CALLBACK_EXIT];
3386+ proc(lil, argc > 0 ? argv[0] : NULL);
3387+ }
3388+ return NULL;
3389+}
3390+
3391+static LILCALLBACK lil_value_t fnc_source(lil_t lil, size_t argc, lil_value_t* argv)
3392+{
3393+ FILE* f;
3394+ size_t size;
3395+ char* buffer;
3396+ lil_value_t r;
3397+ if (argc < 1) return NULL;
3398+ if (lil->callback[LIL_CALLBACK_SOURCE]) {
3399+ lil_source_callback_proc_t proc = (lil_source_callback_proc_t)lil->callback[LIL_CALLBACK_SOURCE];
3400+ buffer = proc(lil, lil_to_string(argv[0]));
3401+ } else if (lil->callback[LIL_CALLBACK_READ]) {
3402+ lil_read_callback_proc_t proc = (lil_read_callback_proc_t)lil->callback[LIL_CALLBACK_READ];
3403+ buffer = proc(lil, lil_to_string(argv[0]));
3404+ } else {
3405+ f = fopen(lil_to_string(argv[0]), "rb");
3406+ if (!f) return NULL;
3407+ fseek(f, 0, SEEK_END);
3408+ size = ftell(f);
3409+ fseek(f, 0, SEEK_SET);
3410+ buffer = malloc(size + 1);
3411+ fread(buffer, 1, size, f);
3412+ buffer[size] = 0;
3413+ fclose(f);
3414+ }
3415+ r = lil_parse(lil, buffer, 0, 0);
3416+ free(buffer);
3417+ return r;
3418+}
3419+
3420+static LILCALLBACK lil_value_t fnc_lmap(lil_t lil, size_t argc, lil_value_t* argv)
3421+{
3422+ lil_list_t list;
3423+ size_t i;
3424+ if (argc < 2) return NULL;
3425+ list = lil_subst_to_list(lil, argv[0]);
3426+ for (i=1; i<argc; i++)
3427+ lil_set_var(lil, lil_to_string(argv[i]), lil_list_get(list, i - 1), LIL_SETVAR_LOCAL);
3428+ lil_free_list(list);
3429+ return NULL;
3430+}
3431+
3432+static LILCALLBACK lil_value_t fnc_rand(lil_t lil, size_t argc, lil_value_t* argv)
3433+{
3434+ return lil_alloc_double(rand()/(double)RAND_MAX);
3435+}
3436+
3437+static LILCALLBACK lil_value_t fnc_catcher(lil_t lil, size_t argc, lil_value_t* argv)
3438+{
3439+ if (argc == 0) {
3440+ return lil_alloc_string(lil->catcher);
3441+ } else {
3442+ const char* catcher = lil_to_string(argv[0]);
3443+ free(lil->catcher);
3444+ lil->catcher = catcher[0] ? strclone(catcher) : NULL;
3445+ }
3446+ return NULL;
3447+}
3448+
3449+static LILCALLBACK lil_value_t fnc_watch(lil_t lil, size_t argc, lil_value_t* argv)
3450+{
3451+ size_t i;
3452+ const char* wcode;
3453+ if (argc < 2) return NULL;
3454+ wcode = lil_to_string(argv[argc - 1]);
3455+ for (i=0; i + 1 < argc; i++) {
3456+ const char* vname = lil_to_string(argv[i]);
3457+ lil_var_t v;
3458+ if (!vname[0]) continue;
3459+ v = lil_find_var(lil, lil->env, lil_to_string(argv[i]));
3460+ if (!v) v = lil_set_var(lil, vname, NULL, LIL_SETVAR_LOCAL_NEW);
3461+ free(v->w);
3462+ v->w = wcode[0] ? strclone(wcode) : NULL;
3463+ }
3464+ return NULL;
3465+}
3466+
3467+static void register_stdcmds(lil_t lil)
3468+{
3469+ lil_register(lil, "reflect", fnc_reflect);
3470+ lil_register(lil, "func", fnc_func);
3471+ lil_register(lil, "rename", fnc_rename);
3472+ lil_register(lil, "unusedname", fnc_unusedname);
3473+ lil_register(lil, "quote", fnc_quote);
3474+ lil_register(lil, "set", fnc_set);
3475+ lil_register(lil, "local", fnc_local);
3476+ lil_register(lil, "write", fnc_write);
3477+ lil_register(lil, "print", fnc_print);
3478+ lil_register(lil, "eval", fnc_eval);
3479+ lil_register(lil, "topeval", fnc_topeval);
3480+ lil_register(lil, "upeval", fnc_upeval);
3481+ lil_register(lil, "downeval", fnc_downeval);
3482+ lil_register(lil, "enveval", fnc_enveval);
3483+ lil_register(lil, "jaileval", fnc_jaileval);
3484+ lil_register(lil, "count", fnc_count);
3485+ lil_register(lil, "index", fnc_index);
3486+ lil_register(lil, "indexof", fnc_indexof);
3487+ lil_register(lil, "filter", fnc_filter);
3488+ lil_register(lil, "list", fnc_list);
3489+ lil_register(lil, "append", fnc_append);
3490+ lil_register(lil, "slice", fnc_slice);
3491+ lil_register(lil, "subst", fnc_subst);
3492+ lil_register(lil, "concat", fnc_concat);
3493+ lil_register(lil, "foreach", fnc_foreach);
3494+ lil_register(lil, "return", fnc_return);
3495+ lil_register(lil, "result", fnc_result);
3496+ lil_register(lil, "expr", fnc_expr);
3497+ lil_register(lil, "inc", fnc_inc);
3498+ lil_register(lil, "dec", fnc_dec);
3499+ lil_register(lil, "read", fnc_read);
3500+ lil_register(lil, "store", fnc_store);
3501+ lil_register(lil, "if", fnc_if);
3502+ lil_register(lil, "while", fnc_while);
3503+ lil_register(lil, "for", fnc_for);
3504+ lil_register(lil, "char", fnc_char);
3505+ lil_register(lil, "charat", fnc_charat);
3506+ lil_register(lil, "codeat", fnc_codeat);
3507+ lil_register(lil, "substr", fnc_substr);
3508+ lil_register(lil, "strpos", fnc_strpos);
3509+ lil_register(lil, "length", fnc_length);
3510+ lil_register(lil, "trim", fnc_trim);
3511+ lil_register(lil, "ltrim", fnc_ltrim);
3512+ lil_register(lil, "rtrim", fnc_rtrim);
3513+ lil_register(lil, "strcmp", fnc_strcmp);
3514+ lil_register(lil, "streq", fnc_streq);
3515+ lil_register(lil, "repstr", fnc_repstr);
3516+ lil_register(lil, "split", fnc_split);
3517+ lil_register(lil, "try", fnc_try);
3518+ lil_register(lil, "error", fnc_error);
3519+ lil_register(lil, "exit", fnc_exit);
3520+ lil_register(lil, "source", fnc_source);
3521+ lil_register(lil, "lmap", fnc_lmap);
3522+ lil_register(lil, "rand", fnc_rand);
3523+ lil_register(lil, "catcher", fnc_catcher);
3524+ lil_register(lil, "watch", fnc_watch);
3525+ lil->syscmds = lil->cmds;
3526+}
lil/lil.h+153−0
@@ -0,0 +1,153 @@
1+/*
2+ * LIL - Little Interpreted Language
3+ * Copyright (C) 2010-2013 Kostas Michalopoulos
4+ *
5+ * This software is provided 'as-is', without any express or implied
6+ * warranty. In no event will the authors be held liable for any damages
7+ * arising from the use of this software.
8+ *
9+ * Permission is granted to anyone to use this software for any purpose,
10+ * including commercial applications, and to alter it and redistribute it
11+ * freely, subject to the following restrictions:
12+ *
13+ * 1. The origin of this software must not be misrepresented; you must not
14+ * claim that you wrote the original software. If you use this software
15+ * in a product, an acknowledgment in the product documentation would be
16+ * appreciated but is not required.
17+ * 2. Altered source versions must be plainly marked as such, and must not be
18+ * misrepresented as being the original software.
19+ * 3. This notice may not be removed or altered from any source distribution.
20+ *
21+ * Kostas Michalopoulos <badsector@runtimelegend.com>
22+ */
23+
24+#ifndef __LIL_H_INCLUDED__
25+#define __LIL_H_INCLUDED__
26+
27+#define LIL_VERSION_STRING "0.1"
28+
29+#define LIL_SETVAR_GLOBAL 0
30+#define LIL_SETVAR_LOCAL 1
31+#define LIL_SETVAR_LOCAL_NEW 2
32+#define LIL_SETVAR_LOCAL_ONLY 3
33+
34+#define LIL_CALLBACK_EXIT 0
35+#define LIL_CALLBACK_WRITE 1
36+#define LIL_CALLBACK_READ 2
37+#define LIL_CALLBACK_STORE 3
38+#define LIL_CALLBACK_SOURCE 4
39+#define LIL_CALLBACK_ERROR 5
40+#define LIL_CALLBACK_SETVAR 6
41+#define LIL_CALLBACK_GETVAR 7
42+
43+#define LIL_EMBED_NOFLAGS 0x0000
44+
45+#if defined(LILDLL) && (defined(WIN32) || defined(_WIN32))
46+#ifdef __LIL_C_FILE__
47+#define LILAPI __declspec(dllexport __stdcall)
48+#else
49+#define LILAPI __declspec(dllimport __stdcall)
50+#endif
51+#define LILCALLBACK __declspec(__stdcall)
52+#else
53+#define LILAPI
54+#define LILCALLBACK
55+#endif
56+
57+#ifdef LILINT_LONGLONG
58+typedef long long int lilint_t;
59+#define LILINT_PRINTF "%lli"
60+#else
61+#ifdef LILINT_INT64
62+typedef __int64 lilint_t;
63+#define LILINT_PRINTF "%I64i"
64+#else
65+#ifndef LILINT_CUSTOM
66+#include <stdint.h>
67+#include <inttypes.h>
68+typedef int64_t lilint_t;
69+#define LILINT_PRINTF "%"PRIi64
70+#endif
71+#endif
72+#endif
73+
74+typedef struct _lil_value_t* lil_value_t;
75+typedef struct _lil_func_t* lil_func_t;
76+typedef struct _lil_var_t* lil_var_t;
77+typedef struct _lil_env_t* lil_env_t;
78+typedef struct _lil_list_t* lil_list_t;
79+typedef struct _lil_t* lil_t;
80+typedef LILCALLBACK lil_value_t (*lil_func_proc_t)(lil_t lil, size_t argc, lil_value_t* argv);
81+typedef LILCALLBACK void (*lil_exit_callback_proc_t)(lil_t lil, lil_value_t arg);
82+typedef LILCALLBACK void (*lil_write_callback_proc_t)(lil_t lil, const char* msg);
83+typedef LILCALLBACK char* (*lil_read_callback_proc_t)(lil_t lil, const char* name);
84+typedef LILCALLBACK char* (*lil_source_callback_proc_t)(lil_t lil, const char* name);
85+typedef LILCALLBACK void (*lil_store_callback_proc_t)(lil_t lil, const char* name, const char* data);
86+typedef LILCALLBACK void (*lil_error_callback_proc_t)(lil_t lil, size_t pos, const char* msg);
87+typedef LILCALLBACK int (*lil_setvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value);
88+typedef LILCALLBACK int (*lil_getvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value);
89+typedef LILCALLBACK void (*lil_callback_proc_t)(void);
90+
91+LILAPI lil_t lil_new(void);
92+LILAPI void lil_free(lil_t lil);
93+
94+LILAPI int lil_register(lil_t lil, const char* name, lil_func_proc_t proc);
95+
96+LILAPI lil_value_t lil_parse(lil_t lil, const char* code, size_t codelen, int funclevel);
97+LILAPI lil_value_t lil_parse_value(lil_t lil, lil_value_t val, int funclevel);
98+LILAPI lil_value_t lil_call(lil_t lil, const char* funcname, size_t argc, lil_value_t* argv);
99+
100+LILAPI void lil_callback(lil_t lil, int cb, lil_callback_proc_t proc);
101+
102+LILAPI void lil_set_error(lil_t lil, const char* msg);
103+LILAPI void lil_set_error_at(lil_t lil, size_t pos, const char* msg);
104+LILAPI int lil_error(lil_t lil, const char** msg, size_t* pos);
105+
106+LILAPI const char* lil_to_string(lil_value_t val);
107+LILAPI double lil_to_double(lil_value_t val);
108+LILAPI lilint_t lil_to_integer(lil_value_t val);
109+LILAPI int lil_to_boolean(lil_value_t val);
110+
111+LILAPI lil_value_t lil_alloc_string(const char* str);
112+LILAPI lil_value_t lil_alloc_double(double num);
113+LILAPI lil_value_t lil_alloc_integer(lilint_t num);
114+LILAPI void lil_free_value(lil_value_t val);
115+
116+LILAPI lil_value_t lil_clone_value(lil_value_t src);
117+LILAPI int lil_append_char(lil_value_t val, char ch);
118+LILAPI int lil_append_string(lil_value_t val, const char* s);
119+LILAPI int lil_append_val(lil_value_t val, lil_value_t v);
120+
121+LILAPI lil_list_t lil_alloc_list(void);
122+LILAPI void lil_free_list(lil_list_t list);
123+LILAPI void lil_list_append(lil_list_t list, lil_value_t val);
124+LILAPI size_t lil_list_size(lil_list_t list);
125+LILAPI lil_value_t lil_list_get(lil_list_t list, size_t index);
126+LILAPI lil_value_t lil_list_to_value(lil_list_t list, int do_escape);
127+
128+LILAPI lil_list_t lil_subst_to_list(lil_t lil, lil_value_t code);
129+LILAPI lil_value_t lil_subst_to_value(lil_t lil, lil_value_t code);
130+
131+LILAPI lil_env_t lil_alloc_env(lil_env_t parent);
132+LILAPI void lil_free_env(lil_env_t env);
133+LILAPI lil_env_t lil_push_env(lil_t lil);
134+LILAPI void lil_pop_env(lil_t lil);
135+
136+LILAPI lil_var_t lil_set_var(lil_t lil, const char* name, lil_value_t val, int local);
137+LILAPI lil_value_t lil_get_var(lil_t lil, const char* name);
138+LILAPI lil_value_t lil_get_var_or(lil_t lil, const char* name, lil_value_t defvalue);
139+
140+LILAPI lil_value_t lil_eval_expr(lil_t lil, lil_value_t code);
141+LILAPI lil_value_t lil_unused_name(lil_t lil, const char* part);
142+
143+LILAPI lil_value_t lil_arg(lil_value_t* argv, size_t index);
144+
145+LILAPI void lil_set_data(lil_t lil, void* data);
146+LILAPI void* lil_get_data(lil_t lil);
147+
148+LILAPI char* lil_embedded(lil_t lil, const char* code, unsigned int flags);
149+LILAPI void lil_freemem(void* ptr);
150+
151+LILAPI void lil_write(lil_t lil, const char* msg);
152+
153+#endif
mkdb.janet+20−20
@@ -9,31 +9,31 @@ · 8 unmodified lines
99 # linked pages
1010
1111 (ww-add-link "index" "index.org")
12−(ww-add-link "bigverb" "bigverb.org")
13−(ww-add-link "osc" "osc.org")
14−(ww-add-link "dcblocker" "dcblocker.org")
15−(ww-add-link "fmpair" "fmpair.org")
16−(ww-add-link "vardelay" "vardelay.org")
17−(ww-add-link "rline" "rline.org")
18−(ww-add-link "peakeq" "peakeq.org")
19−(ww-add-link "modalres" "modalres.org")
20−(ww-add-link "phasewarp" "phasewarp.org")
12+(ww-add-link "bigverb" "dsp/bigverb.org")
13+(ww-add-link "osc" "dsp/osc.org")
14+(ww-add-link "dcblocker" "dsp/dcblocker.org")
15+(ww-add-link "fmpair" "dsp/fmpair.org")
16+(ww-add-link "vardelay" "dsp/vardelay.org")
17+(ww-add-link "rline" "dsp/rline.org")
18+(ww-add-link "peakeq" "dsp/peakeq.org")
19+(ww-add-link "modalres" "dsp/modalres.org")
20+(ww-add-link "phasewarp" "dsp/phasewarp.org")
2121 (ww-add-link "curated" "curated.org")
2222 (ww-add-link "wiki_index" "wiki_index.org")
2323 (ww-add-link "algos" "algos.org")
24−(ww-add-link "bitnoise" "bitnoise.org")
24+(ww-add-link "bitnoise" "dsp/bitnoise.org")
2525 (ww-add-link "keywords" "keywords.org")
26−(ww-add-link "valp1" "valp1.org")
27−(ww-add-link "chaosnoise" "chaosnoise.org")
28−(ww-add-link "oscf" "oscf.org")
29−(ww-add-link "bezier" "bezier.org")
30−(ww-add-link "expmap" "expmap.org")
31−(ww-add-link "phsclk" "phsclk.org")
32−(ww-add-link "phasor" "phasor.org")
33−(ww-add-link "swell" "swell.org")
34−(ww-add-link "biramp" "biramp.org")
26+(ww-add-link "valp1" "dsp/valp1.org")
27+(ww-add-link "chaosnoise" "dsp/chaosnoise.org")
28+(ww-add-link "oscf" "dsp/oscf.org")
29+(ww-add-link "bezier" "dsp/bezier.org")
30+(ww-add-link "expmap" "dsp/expmap.org")
31+(ww-add-link "phsclk" "dsp/phsclk.org")
32+(ww-add-link "phasor" "dsp/phasor.org")
33+(ww-add-link "swell" "dsp/swell.org")
34+(ww-add-link "biramp" "dsp/biramp.org")
3535 (ww-add-link "core" "core.org")
36−(ww-add-link "scale" "scale.org")
36+(ww-add-link "scale" "dsp/scale.org")
3737
3838 # sync and close
3939
nodes/arith/arith.c+90−0
@@ -0,0 +1,90 @@
1+
2+#include <math.h>
3+#include <stdlib.h>
4+#include <stdint.h>
5+#include "patchwerk.h"
6+#include "core.h"
7+
8+struct arith_n {
9+ pw_cable *a;
10+ pw_cable *b;
11+ pw_cable *out;
12+};
13+
14+static void add_compute(pw_node *node)
15+{
16+ int blksize;
17+ int n;
18+ struct arith_n *arith;
19+
20+ blksize = pw_node_blksize(node);
21+
22+ arith = (struct arith_n *)pw_node_get_data(node);
23+
24+ for (n = 0; n < blksize; n++) {
25+ PWFLT a, b, out;
26+
27+ a = pw_cable_get(arith->a, n);
28+ b = pw_cable_get(arith->b, n);
29+ out = a + b;
30+
31+ pw_cable_set(arith->out, n, out);
32+ }
33+}
34+
35+static void destroy(pw_node *node)
36+{
37+ pw_patch *patch;
38+ int rc;
39+ void *ud;
40+ rc = pw_node_get_patch(node, &patch);
41+ if (rc != PW_OK) return;
42+ pw_node_cables_free(node);
43+ ud = pw_node_get_data(node);
44+ pw_memory_free(patch, &ud);
45+}
46+
47+int sk_node_add(sk_core *core)
48+{
49+ pw_patch *patch;
50+ pw_node *node;
51+ int rc;
52+ sk_param a;
53+ sk_param b;
54+ void *ud;
55+ struct arith_n *arith;
56+
57+ rc = sk_param_get(core, &b);
58+ SK_ERROR_CHECK(rc);
59+ rc = sk_param_get(core, &a);
60+ SK_ERROR_CHECK(rc);
61+
62+ patch = sk_core_patch(core);
63+
64+ rc = pw_memory_alloc(patch, sizeof(struct arith_n), &ud);
65+ SK_PW_ERROR_CHECK(rc);
66+ arith = (struct arith_n *)ud;
67+
68+ rc = pw_patch_new_node(patch, &node);
69+ SK_PW_ERROR_CHECK(rc);
70+
71+ rc = pw_node_cables_alloc(node, 3);
72+ SK_PW_ERROR_CHECK(rc);
73+
74+ pw_node_set_block(node, 2);
75+
76+ pw_node_get_cable(node, 0, &arith->a);
77+ pw_node_get_cable(node, 1, &arith->b);
78+ pw_node_get_cable(node, 2, &arith->out);
79+
80+ pw_node_set_data(node, arith);
81+ pw_node_set_compute(node, add_compute);
82+ pw_node_set_destroy(node, destroy);
83+
84+ sk_param_set(core, node, &a, 0);
85+ sk_param_set(core, node, &b, 1);
86+ sk_param_out(core, node, 2);
87+ return 0;
88+}
89+
90+/* TODO: mul, sub, div */
nodes/arith/arith.h+7−0
@@ -0,0 +1,7 @@
1+#ifndef SK_NODE_ARITH_H
2+#define SK_NODE_ARITH_H
3+int sk_node_add(sk_core *core);
4+int sk_node_mul(sk_core *core);
5+int sk_node_sub(sk_core *core);
6+int sk_node_div(sk_core *core);
7+#endif
nodes/arith/config.mk+2−0
@@ -0,0 +1,2 @@
1+OBJ+=nodes/arith/arith.o
2+OBJ+=nodes/arith/l_arith.o
nodes/arith/l_arith.c+27−0
@@ -0,0 +1,27 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "arith.h"
9+
10+static lil_value_t add(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "add", argc, 2);
16+
17+ sklil_param(core, argv[0]);
18+ sklil_param(core, argv[1]);
19+
20+ sk_node_add(core);
21+ return NULL;
22+}
23+
24+void sklil_load_arith(lil_t lil)
25+{
26+ lil_register(lil, "add", add);
27+}
nodes/config.mk+3−0
@@ -1,3 +1,6 @@
11 include nodes/sine/config.mk
22 include nodes/wavout/config.mk
33 include nodes/scale/config.mk
4+include nodes/arith/config.mk
5+include nodes/phasor/config.mk
6+include nodes/rephasor/config.mk
nodes/loader.c+50−0
@@ -0,0 +1,50 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include "lil/lil.h"
4+#include "patchwerk/patchwerk.h"
5+#include "core.h"
6+#include "sklil.h"
7+
8+void sklil_load_sine(lil_t lil);
9+void sklil_load_wavout(lil_t lil);
10+void sklil_load_arith(lil_t lil);
11+void sklil_load_scale(lil_t lil);
12+void sklil_load_phasor(lil_t lil);
13+void sklil_load_rephasor(lil_t lil);
14+
15+void sklil_nodes(lil_t lil)
16+{
17+ sklil_load_sine(lil);
18+ sklil_load_wavout(lil);
19+ sklil_load_arith(lil);
20+ sklil_load_scale(lil);
21+ sklil_load_phasor(lil);
22+ sklil_load_rephasor(lil);
23+}
24+
25+static lil_value_t computes(lil_t lil, size_t argc, lil_value_t *argv)
26+{
27+ sk_core *core;
28+ core = lil_get_data(lil);
29+
30+ SKLIL_ARITY_CHECK(lil, "computes", argc, 1);
31+
32+ sk_core_computes(core, lil_to_double(argv[0]));
33+ return NULL;
34+}
35+
36+void sklil_loader(lil_t lil)
37+{
38+ sk_core *core;
39+ core = sk_core_new(44100);
40+ lil_set_data(lil, core);
41+ sklil_nodes(lil);
42+ lil_register(lil, "computes", computes);
43+}
44+
45+void sklil_clean(lil_t lil)
46+{
47+ sk_core *core;
48+ core = lil_get_data(lil);
49+ sk_core_del(core);
50+}
nodes/phasor/config.mk+2−0
@@ -0,0 +1,2 @@
1+OBJ+=nodes/phasor/phasor.o
2+OBJ+=nodes/phasor/l_phasor.o
nodes/phasor/l_phasor.c+26−0
@@ -0,0 +1,26 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "phasor.h"
9+
10+static lil_value_t phasor(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "phasor", argc, 2);
16+
17+ sklil_param(core, argv[0]);
18+
19+ sk_node_phasor(core, lil_to_double(argv[1]));
20+ return NULL;
21+}
22+
23+void sklil_load_phasor(lil_t lil)
24+{
25+ lil_register(lil, "phasor", phasor);
26+}
nodes/phasor/phasor.c+88−0
@@ -0,0 +1,88 @@
1+#include <math.h>
2+#include <stdlib.h>
3+#include <stdint.h>
4+#include "patchwerk.h"
5+#include "core.h"
6+#define SK_PHASOR_PRIV
7+#include "dsp/phasor.h"
8+
9+struct phasor_n {
10+ pw_cable *freq;
11+ pw_cable *out;
12+ sk_phasor phasor;
13+};
14+
15+static void compute(pw_node *node)
16+{
17+ int blksize;
18+ int n;
19+ struct phasor_n *phasor;
20+
21+ blksize = pw_node_blksize(node);
22+
23+ phasor = (struct phasor_n *)pw_node_get_data(node);
24+
25+ for (n = 0; n < blksize; n++) {
26+ PWFLT out, f;
27+ f = pw_cable_get(phasor->freq, n);
28+
29+ sk_phasor_freq(&phasor->phasor, f);
30+ out = sk_phasor_tick(&phasor->phasor);
31+
32+ pw_cable_set(phasor->out, n, out);
33+ }
34+}
35+
36+static void destroy(pw_node *node)
37+{
38+ pw_patch *patch;
39+ int rc;
40+ void *ud;
41+ rc = pw_node_get_patch(node, &patch);
42+ if (rc != PW_OK) return;
43+ pw_node_cables_free(node);
44+ ud = pw_node_get_data(node);
45+ pw_memory_free(patch, &ud);
46+}
47+
48+int sk_node_phasor(sk_core *core, SKFLT iphs)
49+{
50+ pw_patch *patch;
51+ pw_node *node;
52+ int rc;
53+ sk_param freq;
54+ void *ud;
55+ struct phasor_n *phasor;
56+ int sr;
57+
58+ rc = sk_param_get(core, &freq);
59+ SK_ERROR_CHECK(rc);
60+
61+ patch = sk_core_patch(core);
62+
63+ rc = pw_memory_alloc(patch, sizeof(struct phasor_n), &ud);
64+ SK_PW_ERROR_CHECK(rc);
65+ phasor = (struct phasor_n *)ud;
66+
67+ sr = pw_patch_srate_get(patch);
68+ sk_phasor_init(&phasor->phasor, sr, iphs);
69+
70+ rc = pw_patch_new_node(patch, &node);
71+ SK_PW_ERROR_CHECK(rc);
72+
73+ rc = pw_node_cables_alloc(node, 2);
74+ SK_PW_ERROR_CHECK(rc);
75+
76+ pw_node_set_block(node, 1);
77+
78+ pw_node_get_cable(node, 0, &phasor->freq);
79+ pw_node_get_cable(node, 1, &phasor->out);
80+
81+ pw_node_set_data(node, phasor);
82+ pw_node_set_compute(node, compute);
83+ pw_node_set_destroy(node, destroy);
84+
85+ sk_param_set(core, node, &freq, 0);
86+ sk_param_out(core, node, 1);
87+ return 0;
88+}
nodes/phasor/phasor.h+4−0
@@ -0,0 +1,4 @@
1+#ifndef SK_NODE_PHASOR_H
2+#define SK_NODE_PHASOR_H
3+int sk_node_phasor(sk_core *core, SKFLT iphs);
4+#endif
nodes/rephasor/config.mk+2−0
@@ -0,0 +1,2 @@
1+OBJ+=nodes/rephasor/rephasor.o
2+OBJ+=nodes/rephasor/l_rephasor.o
nodes/rephasor/l_rephasor.c+27−0
@@ -0,0 +1,27 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "rephasor.h"
9+
10+static lil_value_t rephasor(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "rephasor", argc, 2);
16+
17+ sklil_param(core, argv[0]);
18+ sklil_param(core, argv[1]);
19+
20+ sk_node_rephasor(core);
21+ return NULL;
22+}
23+
24+void sklil_load_rephasor(lil_t lil)
25+{
26+ lil_register(lil, "rephasor", rephasor);
27+}
nodes/rephasor/rephasor.c+93−0
@@ -0,0 +1,93 @@
1+#include <math.h>
2+#include <stdlib.h>
3+#include <stdint.h>
4+#include "patchwerk.h"
5+#include "core.h"
6+#define SK_REPHASOR_PRIV
7+#include "dsp/rephasor.h"
8+
9+struct rephasor_n {
10+ pw_cable *ext;
11+ pw_cable *scale;
12+ pw_cable *out;
13+ sk_rephasor rephasor;
14+};
15+
16+static void compute(pw_node *node)
17+{
18+ int blksize;
19+ int n;
20+ struct rephasor_n *rephasor;
21+
22+ blksize = pw_node_blksize(node);
23+
24+ rephasor = (struct rephasor_n *)pw_node_get_data(node);
25+
26+ for (n = 0; n < blksize; n++) {
27+ PWFLT out, ext, scale;
28+ ext = pw_cable_get(rephasor->ext, n);
29+ scale = pw_cable_get(rephasor->scale, n);
30+
31+ sk_rephasor_scale(&rephasor->rephasor, scale);
32+ out = sk_rephasor_tick(&rephasor->rephasor, ext);
33+
34+ pw_cable_set(rephasor->out, n, out);
35+ }
36+}
37+
38+static void destroy(pw_node *node)
39+{
40+ pw_patch *patch;
41+ int rc;
42+ void *ud;
43+ rc = pw_node_get_patch(node, &patch);
44+ if (rc != PW_OK) return;
45+ pw_node_cables_free(node);
46+ ud = pw_node_get_data(node);
47+ pw_memory_free(patch, &ud);
48+}
49+
50+int sk_node_rephasor(sk_core *core)
51+{
52+ pw_patch *patch;
53+ pw_node *node;
54+ int rc;
55+ sk_param ext;
56+ sk_param scale;
57+ void *ud;
58+ struct rephasor_n *rephasor;
59+
60+ rc = sk_param_get(core, &scale);
61+ SK_ERROR_CHECK(rc);
62+ rc = sk_param_get(core, &ext);
63+ SK_ERROR_CHECK(rc);
64+
65+ patch = sk_core_patch(core);
66+
67+ rc = pw_memory_alloc(patch, sizeof(struct rephasor_n), &ud);
68+ SK_PW_ERROR_CHECK(rc);
69+ rephasor = (struct rephasor_n *)ud;
70+
71+ sk_rephasor_init(&rephasor->rephasor);
72+
73+ rc = pw_patch_new_node(patch, &node);
74+ SK_PW_ERROR_CHECK(rc);
75+
76+ rc = pw_node_cables_alloc(node, 3);
77+ SK_PW_ERROR_CHECK(rc);
78+
79+ pw_node_set_block(node, 2);
80+
81+ pw_node_get_cable(node, 0, &rephasor->ext);
82+ pw_node_get_cable(node, 1, &rephasor->scale);
83+ pw_node_get_cable(node, 2, &rephasor->out);
84+
85+ pw_node_set_data(node, rephasor);
86+ pw_node_set_compute(node, compute);
87+ pw_node_set_destroy(node, destroy);
88+
89+ sk_param_set(core, node, &ext, 0);
90+ sk_param_set(core, node, &scale, 1);
91+ sk_param_out(core, node, 2);
92+ return 0;
93+}
nodes/rephasor/rephasor.h+4−0
@@ -0,0 +1,4 @@
1+#ifndef SK_NODE_REPHASOR_H
2+#define SK_NODE_REPHASOR_H
3+int sk_node_rephasor(sk_core *core);
4+#endif
nodes/rephasor/test.lil+12−0
@@ -0,0 +1,12 @@
1+# a sine wave modulated by a phasor
2+scale [phasor 1 0] 220 440
3+sine zz 0.2
4+
5+# same thing, but with a slightly slower phasor
6+# cable management coming soon
7+scale [rephasor [phasor 1 0] 0.75] 220 440
8+sine zz 0.2
9+add zz zz
10+
11+wavout zz "test.wav"
12+computes 10
nodes/scale/config.mk+1−0
@@ -1 +1,2 @@
11 OBJ+=nodes/scale/scale.o
2+OBJ+=nodes/scale/l_scale.o
nodes/scale/l_scale.c+44−0
@@ -0,0 +1,44 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "scale.h"
9+
10+static lil_value_t biscale(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "biscale", argc, 3);
16+
17+ sklil_param(core, argv[0]);
18+ sklil_param(core, argv[1]);
19+ sklil_param(core, argv[2]);
20+
21+ sk_node_biscale(core);
22+ return NULL;
23+}
24+
25+static lil_value_t scale(lil_t lil, size_t argc, lil_value_t *argv)
26+{
27+ sk_core *core;
28+ core = lil_get_data(lil);
29+
30+ SKLIL_ARITY_CHECK(lil, "scale", argc, 3);
31+
32+ sklil_param(core, argv[0]);
33+ sklil_param(core, argv[1]);
34+ sklil_param(core, argv[2]);
35+
36+ sk_node_scale(core);
37+ return NULL;
38+}
39+
40+void sklil_load_scale(lil_t lil)
41+{
42+ lil_register(lil, "biscale", biscale);
43+ lil_register(lil, "scale", scale);
44+}
nodes/scale/scale.c+35−3
@@ -3,7 +3,7 @@ · 2 unmodified lines
33 #include <stdint.h>
44 #include "patchwerk.h"
55 #include "core.h"
6−#include "../../scale.h"
6+#include "dsp/scale.h"
77
88 struct scale_n {
99 pw_cable *in;
@@ -34,6 +34,28 @@ static void biscale_compute(pw_node *node) · 24 unmodified lines
3434 }
3535 }
3636
37+static void scale_compute(pw_node *node)
38+{
39+ int blksize;
40+ int n;
41+ struct scale_n *scale;
42+
43+ blksize = pw_node_blksize(node);
44+
45+ scale = (struct scale_n *)pw_node_get_data(node);
46+
47+ for (n = 0; n < blksize; n++) {
48+ PWFLT out, in, min, max;
49+
50+ in = pw_cable_get(scale->in, n);
51+ min = pw_cable_get(scale->min, n);
52+ max = pw_cable_get(scale->max, n);
53+ out = sk_scale(in, min, max);
54+
55+ pw_cable_set(scale->out, n, out);
56+ }
57+}
58+
3759 static void destroy(pw_node *node)
3860 {
3961 pw_patch *patch;
@@ -46,7 +68,7 @@ static void destroy(pw_node *node) · 6 unmodified lines
4668 pw_memory_free(patch, &ud);
4769 }
4870
49−int sk_node_biscale(sk_core *core)
71+static int node_scale(sk_core *core, pw_function compute)
5072 {
5173 pw_patch *patch;
5274 pw_node *node;
@@ -84,7 +106,7 @@ int sk_node_biscale(sk_core *core) · 31 unmodified lines
84106 pw_node_get_cable(node, 3, &scale->out);
85107
86108 pw_node_set_data(node, scale);
87− pw_node_set_compute(node, biscale_compute);
109+ pw_node_set_compute(node, compute);
88110 pw_node_set_destroy(node, destroy);
89111
90112 sk_param_set(core, node, &in, 0);
@@ -93,3 +115,13 @@ int sk_node_biscale(sk_core *core) · 2 unmodified lines
93115 sk_param_out(core, node, 3);
94116 return 0;
95117 }
118+
119+int sk_node_biscale(sk_core *core)
120+{
121+ return node_scale(core, biscale_compute);
122+}
123+
124+int sk_node_scale(sk_core *core)
125+{
126+ return node_scale(core, scale_compute);
127+}
nodes/scale/scale.h+1−0
@@ -1,4 +1,5 @@
11 #ifndef SK_NODE_SCALE_H
22 #define SK_NODE_SCALE_H
33 int sk_node_biscale(sk_core *core);
4+int sk_node_scale(sk_core *core);
45 #endif
nodes/sine/config.mk+1−0
@@ -1 +1,2 @@
11 OBJ+=nodes/sine/sine.o
2+OBJ+=nodes/sine/l_sine.o
nodes/sine/l_sine.c+27−0
@@ -0,0 +1,27 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "sine.h"
9+
10+static lil_value_t sine(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "sine", argc, 2);
16+
17+ sklil_param(core, argv[0]);
18+ sklil_param(core, argv[1]);
19+
20+ sk_node_sine(core);
21+ return NULL;
22+}
23+
24+void sklil_load_sine(lil_t lil)
25+{
26+ lil_register(lil, "sine", sine);
27+}
nodes/sine/sine.c+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
55 #include "core.h"
66 #define SK_OSC_PRIV
77 #include "sine.h"
8−#include "osc.h"
8+#include "dsp/osc.h"
99
1010 #ifndef M_PI
1111 #define M_PI 3.14159265358979323846
nodes/sklil.c+18−0
@@ -0,0 +1,18 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+
8+void sklil_param(sk_core *core, lil_value_t arg)
9+{
10+ const char *sarg;
11+ sarg = lil_to_string(arg);
12+
13+ if (!strcmp(sarg, "zz") || strlen(sarg) == 0) {
14+ return;
15+ }
16+
17+ sk_core_constant(core, lil_to_double(arg));
18+}
nodes/sklil.h+10−0
@@ -0,0 +1,10 @@
1+#ifndef SKLIL_H
2+#define SKLIL_H
3+#define SKLIL_ARITY_CHECK(LIL, NODE, ARGC, NARGS) \
4+if (ARGC < NARGS) { \
5+ lil_set_error(LIL, NODE ": not enough args."); \
6+ return NULL; \
7+}
8+
9+void sklil_param(sk_core *core, lil_value_t arg);
10+#endif
nodes/wavout/config.mk+1−0
@@ -1 +1,2 @@
11 OBJ+=nodes/wavout/wavout.c99
2+OBJ+=nodes/wavout/l_wavout.o
nodes/wavout/l_wavout.c+26−0
@@ -0,0 +1,26 @@
1+#include <stdlib.h>
2+#include <stdio.h>
3+#include <string.h>
4+#include "lil/lil.h"
5+#include "patchwerk/patchwerk.h"
6+#include "core.h"
7+#include "sklil.h"
8+#include "wavout.h"
9+
10+static lil_value_t wavout(lil_t lil, size_t argc, lil_value_t *argv)
11+{
12+ sk_core *core;
13+ core = lil_get_data(lil);
14+
15+ SKLIL_ARITY_CHECK(lil, "wavout", argc, 2);
16+
17+ sklil_param(core, argv[0]);
18+
19+ sk_node_wavout(core, lil_to_string(argv[1]));
20+ return NULL;
21+}
22+
23+void sklil_load_wavout(lil_t lil)
24+{
25+ lil_register(lil, "wavout", wavout);
26+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t