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
8C89?=$(CC) -std=c898C89?=$(CC) -std=c89
9C99?=$(CC) -std=c999C99?=$(CC) -std=c99
10 10
11CFLAGS += -Ipatchwerk -I.11CFLAGS += -Ipatchwerk -I. -Inodes
12CFLAGS += -Wall12CFLAGS += -Wall
13CFLAGS += -O313CFLAGS += -O3
14CFLAGS += -g14CFLAGS += -g
15 15
16TANGLED=\16TANGLED=\
17bigverb.c bigverb.h \17dsp/bigverb.c dsp/bigverb.h \
18bitnoise.c bitnoise.h \18dsp/bitnoise.c dsp/bitnoise.h \
19chaosnoise.c chaosnoise.h \19dsp/chaosnoise.c dsp/chaosnoise.h \
20dcblocker.c dcblocker.h \20dsp/dcblocker.c dsp/dcblocker.h \
21fmpair.c fmpair.h \21dsp/fmpair.c dsp/fmpair.h \
22modalres.c modalres.h \22dsp/modalres.c dsp/modalres.h \
23osc.c osc.h \23dsp/osc.c dsp/osc.h \
24peakeq.c peakeq.h \24dsp/peakeq.c dsp/peakeq.h \
25phasewarp.c phasewarp.h \25dsp/phasewarp.c dsp/phasewarp.h \
26rline.c rline.h \26dsp/rline.c dsp/rline.h \
27valp1.c valp1.h \27dsp/valp1.c dsp/valp1.h \
28vardelay.c vardelay.h \28dsp/vardelay.c dsp/vardelay.h \
29oscf.c oscf.h \29dsp/oscf.c dsp/oscf.h \
30bezier.c bezier.h \30dsp/bezier.c dsp/bezier.h \
31phasor.c phasor.h \31dsp/phasor.c dsp/phasor.h \
32swell.c swell.h \32dsp/swell.c dsp/swell.h \
33biramp.c biramp.h \33dsp/biramp.c dsp/biramp.h \
34core.c core.h \34dsp/expmap.c dsp/expmap.h \
35expmap.c expmap.h \35dsp/scale.c dsp/scale.h \
36scale.c scale.h \36dsp/rephasor.c dsp/rephasor.h \
37rephasor.c rephasor.h \37
38TANGLED+=core.c core.h
38 39
39OBJ=\40OBJ=\
40bigverb.o \41dsp/bigverb.o \
41bitnoise.o \42dsp/bitnoise.o \
42chaosnoise.o \43dsp/chaosnoise.o \
43dcblocker.o \44dsp/dcblocker.o \
44fmpair.o \45dsp/fmpair.o \
45modalres.o \46dsp/modalres.o \
46osc.o \47dsp/osc.o \
47peakeq.o \48dsp/peakeq.o \
48phasewarp.o \49dsp/phasewarp.o \
49rline.o \50dsp/rline.o \
50valp1.o \51dsp/valp1.o \
51vardelay.o \52dsp/vardelay.o \
52oscf.o \53dsp/oscf.o \
53bezier.o \54dsp/bezier.o \
54phasor.o \55dsp/phasor.o \
55swell.o \56dsp/swell.o \
56biramp.o \57dsp/biramp.o \
57core.o \58core.o \
58patchwerk/patchwerk.o \59patchwerk/patchwerk.o \
59scale.o \60dsp/scale.o \
60rephasor.o \61dsp/rephasor.o \
61 62
62include nodes/config.mk63include nodes/config.mk
63 64
65OBJ+=lil/lil.c99
66OBJ+=lil/lil_main.c99
67OBJ+=nodes/loader.o
68OBJ+=nodes/sklil.o
69
64.SUFFIX: .org .c70.SUFFIX: .org .c
65 71
66.SUFFIXES: .org .c72.SUFFIXES: .org .c
@@ -78,7 +84,7 @@ include nodes/config.mk · 11 unmodified lines
78 @echo "$(C99) $<"84 @echo "$(C99) $<"
79 @$(C99) -c $(CFLAGS) $< -o $@85 @$(C99) -c $(CFLAGS) $< -o $@
80 86
81default: libsndkit.a87default: tangle sndkit libsndkit.a
82 88
83sync:89sync:
84 weewiki sync90 weewiki sync
@@ -130,10 +136,13 @@ keys.db: keys.txt · 45 unmodified lines
130 136
131tangle: worgle/worglite $(TANGLED)137tangle: worgle/worglite $(TANGLED)
132 138
133libsndkit.a: tangle $(OBJ)139libsndkit.a: $(OBJ)
134 @echo "Building $@"140 @echo "Building $@"
135 @$(AR) rcs $@ $(OBJ)141 @$(AR) rcs $@ $(OBJ)
136 142
143sndkit: main.o $(OBJ)
144 $(CC) $(CFLAGS) $^ -o $@
145
137clean:146clean:
138 $(RM) $(TANGLED)147 $(RM) $(TANGLED)
139 $(RM) worgle/worglite148 $(RM) worgle/worglite
core.org+25−0
@@ -118,6 +118,31 @@ void sk_core_compute(sk_core *core) · 117 unmodified lines
118}118}
119#+END_SRC119#+END_SRC
120 120
121=sk_core_computes= is like =sk_core_compute=, but computes
122an approximuate number of seconds of audio. This value
123gets rounded to the nearest block. The number of blocks
124rendered gets rendered.
125
126#+NAME: funcdefs
127#+BEGIN_SRC c
128size_t sk_core_computes(sk_core *core, SKFLT secs);
129#+END_SRC
130
131#+NAME: funcs
132#+BEGIN_SRC c
133size_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
121Building up nodes involves interacting with the patchwerk146Building up nodes involves interacting with the patchwerk
122API. To get the top level struct of that opaquely, use147API. To get the top level struct of that opaquely, use
123=sk_core_patch=.148=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
133SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in)133SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in)
134{134{
135 SKFLT out;135 SKFLT out;
136 SKFLT delta;
136 out = 0;137 out = 0;
137 <<set_output>>138 <<set_output>>
138 <<calculate_delta>>139 <<calculate_delta>>
@@ -144,14 +145,18 @@ SKFLT sk_rephasor_tick(sk_rephasor *rp, SKFLT in) · 5 unmodified lines
144 145
145The current phase of the internal phasor is set to be146The current phase of the internal phasor is set to be
146the output of the current sample. If it is negative, it147the output of the current sample. If it is negative, it
147assumed to be initalized but not set, and the current148is assumed to be initalized but not set, and the current
148phasor signal is set to be the output, and the149phasor signal is set to be the output, and the
149internal phasor value is set to be the current external150internal phasor value is set to be the current external
150phasor value.151phasor value.
151 152
152#+NAME: set_output153#+NAME: set_output
153#+BEGIN_SRC c154#+BEGIN_SRC c
155if (rp->phs < 0) {
156 rp->phs = in;
157}
154 158
159out = rp->phs;
155#+END_SRC160#+END_SRC
156 161
157The =delta= amount is calculated next. This is the absolute162The =delta= amount is calculated next. This is the absolute
@@ -162,7 +167,8 @@ initialized, the delta value is zero. · 4 unmodified lines
162 167
163#+NAME: calculate_delta168#+NAME: calculate_delta
164#+BEGIN_SRC c169#+BEGIN_SRC c
165 170if (rp->extphs < 0 || in < rp->extphs) delta = 0;
171else delta = in - rp->extphs;
166#+END_SRC172#+END_SRC
167 173
168At this point, it is safe to cache the external phasor174At this point, it is safe to cache the external phasor
@@ -170,7 +176,7 @@ signal. · 1 unmodified line
170 176
171#+NAME: cache_external_phasor177#+NAME: cache_external_phasor
172#+BEGIN_SRC c178#+BEGIN_SRC c
173 179rp->extphs = in;
174#+END_SRC180#+END_SRC
175 181
176The internal phasor is updated. The increment value182The 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
179 185
180#+NAME: update_internal_phasor186#+NAME: update_internal_phasor
181#+BEGIN_SRC c187#+BEGIN_SRC c
182 188rp->phs += delta * rp->scale;
189while (rp->phs >= 1.0) rp->phs -= 1.0;
190while (rp->phs < 0.0) rp->phs += 1.0;
183#+END_SRC191#+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 @@
1EX=ex1.bin ex2.bin1EX=ex1.bin ex2.bin ex3.bin
2 2
3LDFLAGS=-L../3LDFLAGS=-L../
4CFLAGS=-I../ -I../patchwerk -I../nodes4CFLAGS=-I../ -I../patchwerk -I../nodes
examples/ex2.c+4−5
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#include "wavout/wavout.h"5#include "wavout/wavout.h"
6#include "sine/sine.h"6#include "sine/sine.h"
7#include "scale/scale.h"7#include "scale/scale.h"
8#include "arith/arith.h"
8 9
9int patch(sk_core *core)10int patch(sk_core *core)
10{11{
@@ -14,16 +15,14 @@ int patch(sk_core *core) · 3 unmodified lines
14 15
15 rc = sk_core_constant(core, 5);16 rc = sk_core_constant(core, 5);
16 SK_ERROR_CHECK(rc);17 SK_ERROR_CHECK(rc);
17 rc = sk_core_constant(core, 1);18 rc = sk_core_constant(core, 40);
18 SK_ERROR_CHECK(rc);19 SK_ERROR_CHECK(rc);
19 rc = sk_node_sine(core);20 rc = sk_node_sine(core);
20 SK_ERROR_CHECK(rc);21 SK_ERROR_CHECK(rc);
21 22
22 rc = sk_core_constant(core, 200);23 rc = sk_core_constant(core, 440);
23 SK_ERROR_CHECK(rc);24 SK_ERROR_CHECK(rc);
24 rc = sk_core_constant(core, 300);25 rc = sk_node_add(core);
25 SK_ERROR_CHECK(rc);
26 rc = sk_node_biscale(core);
27 SK_ERROR_CHECK(rc);26 SK_ERROR_CHECK(rc);
28 27
29 rc = sk_core_constant(core, 0.1);28 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) \
13if (ARGC < NARGS) { \
14 lil_set_error(lil, NODE ": not enough args."); \
15 return NULL; \
16}
17
18const 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
25static 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
37static 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
51static 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
63static 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
75int 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
2sine 350 0.2
3sine [add [sine 0.1 100] 440] 0.2
4add zz zz
5wavout zz test.wav
examples/hello.lil+3−0
@@ -0,0 +1,3 @@
1sine 440 0.5
2wavout zz "sine.wav"
3computes 40
examples/phasor.lil+5−0
@@ -0,0 +1,5 @@
1phasor 1 0
2biscale zz 220 440
3sine zz 0.5
4wavout zz "phasor.wav"
5computes 10
lil/LICENSE+18−0
@@ -0,0 +1,18 @@
1LIL - Little Interpreted Language
2Copyright (C) 2010-2019 Kostas Michalopoulos
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any damages
6arising from the use of this software.
7
8Permission is granted to anyone to use this software for any purpose,
9including commercial applications, and to alter it and redistribute it
10freely, subject to the following restrictions:
11
121. 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.
162. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
183. 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
61struct hashentry_t
62{
63 char* k;
64 void* v;
65};
66
67struct hashcell_t
68{
69 struct hashentry_t* e;
70 size_t c;
71};
72
73typedef struct _hashmap_t
74{
75 struct hashcell_t cell[HASHMAP_CELLS];
76} hashmap_t;
77
78struct _lil_value_t
79{
80 size_t l;
81#ifdef LIL_ENABLE_POOLS
82 size_t c;
83#endif
84 char* d;
85};
86
87struct _lil_var_t
88{
89 char* n;
90 char* w;
91 struct _lil_env_t* env;
92 lil_value_t v;
93};
94
95struct _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
108struct _lil_list_t
109{
110 lil_value_t* v;
111 size_t c;
112 size_t cap;
113};
114
115struct _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
123struct _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
151typedef 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
161static lil_value_t next_word(lil_t lil);
162static void register_stdcmds(lil_t lil);
163
164#ifdef LIL_ENABLE_POOLS
165static lil_value_t* pool;
166static int poolsize, poolcap;
167static lil_list_t* listpool;
168static size_t listpoolsize, listpoolcap;
169static lil_env_t* envpool;
170static size_t envpoolsize, envpoolcap;
171#endif
172
173static 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
182static 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
190static void hm_init(hashmap_t* hm)
191{
192 memset(hm, 0, sizeof(hashmap_t));
193}
194
195static 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
205static 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
220static 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
230static 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
241static 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
252static 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
261static 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
270static 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
303static lil_value_t alloc_value(const char* str)
304{
305 return alloc_value_len(str, str ? strlen(str) : 0);
306}
307
308lil_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
341int 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
357int 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
376int lil_append_string(lil_value_t val, const char* s)
377{
378 return lil_append_string_len(val, s, strlen(s));
379}
380
381int 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
400void 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
411lil_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
423void 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
441void 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
453size_t lil_list_size(lil_list_t list)
454{
455 return list->c;
456}
457
458lil_value_t lil_list_get(lil_list_t list, size_t index)
459{
460 return index >= list->c ? NULL : list->v[index];
461}
462
463static 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
472lil_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
494lil_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
522void 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
553static 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
570static 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
576static 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
593static 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
619static 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
637int 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
645lil_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
694lil_value_t lil_get_var(lil_t lil, const char* name)
695{
696 return lil_get_var_or(lil, name, lil->empty);
697}
698
699lil_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
712lil_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
719void 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
728lil_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
739static int islilspecial(char ch)
740{
741 return ch == '$' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '"' || ch == '\'' || ch == ';';
742}
743
744static int eolchar(char ch)
745{
746 return ch == '\n' || ch == '\r' || ch == ';';
747}
748
749static int ateol(lil_t lil)
750{
751 return !(lil->ignoreeol) && eolchar(lil->code[lil->head]);
752}
753
754static 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
782static 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
808static 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
821static 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
889static 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
916lil_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
936lil_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
945lil_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 }
1039cleanup:
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
1059lil_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
1065LILAPI 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
1096void 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
1102void 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
1111void 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
1120int 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
1137static void ee_expr(expreval_t* ee);
1138
1139static int ee_invalidpunct(int ch)
1140{
1141 return ispunct(ch) && ch != '!' && ch != '~' && ch != '(' && ch != ')' && ch != '-' && ch != '+';
1142}
1143
1144static void ee_skip_spaces(expreval_t* ee)
1145{
1146 while (ee->head < ee->len && isspace(ee->code[ee->head])) ee->head++;
1147}
1148
1149static 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
1174static 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
1189static 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
1201static 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
1262static 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
1487static 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
1586static 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
1686static 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
1867static 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
1964static 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
2016static 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
2068static 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
2120static 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
2172static 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
2183lil_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
2223lil_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
2239lil_value_t lil_arg(lil_value_t* argv, size_t index)
2240{
2241 return argv ? argv[index] : NULL;
2242}
2243
2244const char* lil_to_string(lil_value_t val)
2245{
2246 return (val && val->l) ? val->d : "";
2247}
2248
2249double lil_to_double(lil_value_t val)
2250{
2251 return atof(lil_to_string(val));
2252}
2253
2254lilint_t lil_to_integer(lil_value_t val)
2255{
2256 return (lilint_t)atoll(lil_to_string(val));
2257}
2258
2259int 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
2274lil_value_t lil_alloc_string(const char* str)
2275{
2276 return alloc_value(str);
2277}
2278
2279lil_value_t lil_alloc_string_len(const char* str, size_t len)
2280{
2281 return alloc_value_len(str, len);
2282}
2283
2284lil_value_t lil_alloc_double(double num)
2285{
2286 char buff[128];
2287 sprintf(buff, "%f", num);
2288 return alloc_value(buff);
2289}
2290
2291lil_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
2298void 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
2323LILAPI void lil_set_data(lil_t lil, void* data)
2324{
2325 lil->data = data;
2326}
2327
2328LILAPI void* lil_get_data(lil_t lil)
2329{
2330 return lil->data;
2331}
2332
2333static 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
2341char* 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
2428void lil_freemem(void* ptr)
2429{
2430 free(ptr);
2431}
2432
2433void 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
2441static 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
2548static 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
2579static 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
2608static 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
2613static 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
2626static 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
2644static 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
2655static 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
2668static 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
2675static 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
2692static 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
2705static 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
2719static 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
2733static 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
2793static 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
2817static 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
2828static 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
2844static 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
2860static 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
2884static 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
2907static 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
2935static 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
2947static 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
2953static 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
2970static 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
2998static 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
3007static 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
3017static 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
3034static 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
3046static 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
3052static 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
3058static 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
3084static 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
3102static 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
3122static 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
3145static 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
3166static 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
3175static 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
3189static 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
3200static 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
3219static 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
3235static 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
3245static 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
3266static 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
3272static 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
3278static 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
3284static 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
3290static 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
3296static 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
3332static 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
3361static 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
3376static 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
3382static 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
3391static 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
3420static 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
3432static 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
3437static 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
3449static 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
3467static 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
58typedef long long int lilint_t;
59#define LILINT_PRINTF "%lli"
60#else
61#ifdef LILINT_INT64
62typedef __int64 lilint_t;
63#define LILINT_PRINTF "%I64i"
64#else
65#ifndef LILINT_CUSTOM
66#include <stdint.h>
67#include <inttypes.h>
68typedef int64_t lilint_t;
69#define LILINT_PRINTF "%"PRIi64
70#endif
71#endif
72#endif
73
74typedef struct _lil_value_t* lil_value_t;
75typedef struct _lil_func_t* lil_func_t;
76typedef struct _lil_var_t* lil_var_t;
77typedef struct _lil_env_t* lil_env_t;
78typedef struct _lil_list_t* lil_list_t;
79typedef struct _lil_t* lil_t;
80typedef LILCALLBACK lil_value_t (*lil_func_proc_t)(lil_t lil, size_t argc, lil_value_t* argv);
81typedef LILCALLBACK void (*lil_exit_callback_proc_t)(lil_t lil, lil_value_t arg);
82typedef LILCALLBACK void (*lil_write_callback_proc_t)(lil_t lil, const char* msg);
83typedef LILCALLBACK char* (*lil_read_callback_proc_t)(lil_t lil, const char* name);
84typedef LILCALLBACK char* (*lil_source_callback_proc_t)(lil_t lil, const char* name);
85typedef LILCALLBACK void (*lil_store_callback_proc_t)(lil_t lil, const char* name, const char* data);
86typedef LILCALLBACK void (*lil_error_callback_proc_t)(lil_t lil, size_t pos, const char* msg);
87typedef LILCALLBACK int (*lil_setvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value);
88typedef LILCALLBACK int (*lil_getvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value);
89typedef LILCALLBACK void (*lil_callback_proc_t)(void);
90
91LILAPI lil_t lil_new(void);
92LILAPI void lil_free(lil_t lil);
93
94LILAPI int lil_register(lil_t lil, const char* name, lil_func_proc_t proc);
95
96LILAPI lil_value_t lil_parse(lil_t lil, const char* code, size_t codelen, int funclevel);
97LILAPI lil_value_t lil_parse_value(lil_t lil, lil_value_t val, int funclevel);
98LILAPI lil_value_t lil_call(lil_t lil, const char* funcname, size_t argc, lil_value_t* argv);
99
100LILAPI void lil_callback(lil_t lil, int cb, lil_callback_proc_t proc);
101
102LILAPI void lil_set_error(lil_t lil, const char* msg);
103LILAPI void lil_set_error_at(lil_t lil, size_t pos, const char* msg);
104LILAPI int lil_error(lil_t lil, const char** msg, size_t* pos);
105
106LILAPI const char* lil_to_string(lil_value_t val);
107LILAPI double lil_to_double(lil_value_t val);
108LILAPI lilint_t lil_to_integer(lil_value_t val);
109LILAPI int lil_to_boolean(lil_value_t val);
110
111LILAPI lil_value_t lil_alloc_string(const char* str);
112LILAPI lil_value_t lil_alloc_double(double num);
113LILAPI lil_value_t lil_alloc_integer(lilint_t num);
114LILAPI void lil_free_value(lil_value_t val);
115
116LILAPI lil_value_t lil_clone_value(lil_value_t src);
117LILAPI int lil_append_char(lil_value_t val, char ch);
118LILAPI int lil_append_string(lil_value_t val, const char* s);
119LILAPI int lil_append_val(lil_value_t val, lil_value_t v);
120
121LILAPI lil_list_t lil_alloc_list(void);
122LILAPI void lil_free_list(lil_list_t list);
123LILAPI void lil_list_append(lil_list_t list, lil_value_t val);
124LILAPI size_t lil_list_size(lil_list_t list);
125LILAPI lil_value_t lil_list_get(lil_list_t list, size_t index);
126LILAPI lil_value_t lil_list_to_value(lil_list_t list, int do_escape);
127
128LILAPI lil_list_t lil_subst_to_list(lil_t lil, lil_value_t code);
129LILAPI lil_value_t lil_subst_to_value(lil_t lil, lil_value_t code);
130
131LILAPI lil_env_t lil_alloc_env(lil_env_t parent);
132LILAPI void lil_free_env(lil_env_t env);
133LILAPI lil_env_t lil_push_env(lil_t lil);
134LILAPI void lil_pop_env(lil_t lil);
135
136LILAPI lil_var_t lil_set_var(lil_t lil, const char* name, lil_value_t val, int local);
137LILAPI lil_value_t lil_get_var(lil_t lil, const char* name);
138LILAPI lil_value_t lil_get_var_or(lil_t lil, const char* name, lil_value_t defvalue);
139
140LILAPI lil_value_t lil_eval_expr(lil_t lil, lil_value_t code);
141LILAPI lil_value_t lil_unused_name(lil_t lil, const char* part);
142
143LILAPI lil_value_t lil_arg(lil_value_t* argv, size_t index);
144
145LILAPI void lil_set_data(lil_t lil, void* data);
146LILAPI void* lil_get_data(lil_t lil);
147
148LILAPI char* lil_embedded(lil_t lil, const char* code, unsigned int flags);
149LILAPI void lil_freemem(void* ptr);
150
151LILAPI void lil_write(lil_t lil, const char* msg);
152
153#endif
mkdb.janet+20−20
@@ -9,31 +9,31 @@ · 8 unmodified lines
9# linked pages9# linked pages
10 10
11(ww-add-link "index" "index.org")11(ww-add-link "index" "index.org")
12(ww-add-link "bigverb" "bigverb.org")12(ww-add-link "bigverb" "dsp/bigverb.org")
13(ww-add-link "osc" "osc.org")13(ww-add-link "osc" "dsp/osc.org")
14(ww-add-link "dcblocker" "dcblocker.org")14(ww-add-link "dcblocker" "dsp/dcblocker.org")
15(ww-add-link "fmpair" "fmpair.org")15(ww-add-link "fmpair" "dsp/fmpair.org")
16(ww-add-link "vardelay" "vardelay.org")16(ww-add-link "vardelay" "dsp/vardelay.org")
17(ww-add-link "rline" "rline.org")17(ww-add-link "rline" "dsp/rline.org")
18(ww-add-link "peakeq" "peakeq.org")18(ww-add-link "peakeq" "dsp/peakeq.org")
19(ww-add-link "modalres" "modalres.org")19(ww-add-link "modalres" "dsp/modalres.org")
20(ww-add-link "phasewarp" "phasewarp.org")20(ww-add-link "phasewarp" "dsp/phasewarp.org")
21(ww-add-link "curated" "curated.org")21(ww-add-link "curated" "curated.org")
22(ww-add-link "wiki_index" "wiki_index.org")22(ww-add-link "wiki_index" "wiki_index.org")
23(ww-add-link "algos" "algos.org")23(ww-add-link "algos" "algos.org")
24(ww-add-link "bitnoise" "bitnoise.org")24(ww-add-link "bitnoise" "dsp/bitnoise.org")
25(ww-add-link "keywords" "keywords.org")25(ww-add-link "keywords" "keywords.org")
26(ww-add-link "valp1" "valp1.org")26(ww-add-link "valp1" "dsp/valp1.org")
27(ww-add-link "chaosnoise" "chaosnoise.org")27(ww-add-link "chaosnoise" "dsp/chaosnoise.org")
28(ww-add-link "oscf" "oscf.org")28(ww-add-link "oscf" "dsp/oscf.org")
29(ww-add-link "bezier" "bezier.org")29(ww-add-link "bezier" "dsp/bezier.org")
30(ww-add-link "expmap" "expmap.org")30(ww-add-link "expmap" "dsp/expmap.org")
31(ww-add-link "phsclk" "phsclk.org")31(ww-add-link "phsclk" "dsp/phsclk.org")
32(ww-add-link "phasor" "phasor.org")32(ww-add-link "phasor" "dsp/phasor.org")
33(ww-add-link "swell" "swell.org")33(ww-add-link "swell" "dsp/swell.org")
34(ww-add-link "biramp" "biramp.org")34(ww-add-link "biramp" "dsp/biramp.org")
35(ww-add-link "core" "core.org")35(ww-add-link "core" "core.org")
36(ww-add-link "scale" "scale.org")36(ww-add-link "scale" "dsp/scale.org")
37 37
38# sync and close38# sync and close
39 39
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
8struct arith_n {
9 pw_cable *a;
10 pw_cable *b;
11 pw_cable *out;
12};
13
14static 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
35static 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
47int 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
3int sk_node_add(sk_core *core);
4int sk_node_mul(sk_core *core);
5int sk_node_sub(sk_core *core);
6int sk_node_div(sk_core *core);
7#endif
nodes/arith/config.mk+2−0
@@ -0,0 +1,2 @@
1OBJ+=nodes/arith/arith.o
2OBJ+=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
10static 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
24void sklil_load_arith(lil_t lil)
25{
26 lil_register(lil, "add", add);
27}
nodes/config.mk+3−0
@@ -1,3 +1,6 @@
1include nodes/sine/config.mk1include nodes/sine/config.mk
2include nodes/wavout/config.mk2include nodes/wavout/config.mk
3include nodes/scale/config.mk3include nodes/scale/config.mk
4include nodes/arith/config.mk
5include nodes/phasor/config.mk
6include 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
8void sklil_load_sine(lil_t lil);
9void sklil_load_wavout(lil_t lil);
10void sklil_load_arith(lil_t lil);
11void sklil_load_scale(lil_t lil);
12void sklil_load_phasor(lil_t lil);
13void sklil_load_rephasor(lil_t lil);
14
15void 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
25static 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
36void 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
45void 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 @@
1OBJ+=nodes/phasor/phasor.o
2OBJ+=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
10static 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
23void 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
9struct phasor_n {
10 pw_cable *freq;
11 pw_cable *out;
12 sk_phasor phasor;
13};
14
15static 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
36static 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
48int 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
3int sk_node_phasor(sk_core *core, SKFLT iphs);
4#endif
nodes/rephasor/config.mk+2−0
@@ -0,0 +1,2 @@
1OBJ+=nodes/rephasor/rephasor.o
2OBJ+=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
10static 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
24void 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
9struct rephasor_n {
10 pw_cable *ext;
11 pw_cable *scale;
12 pw_cable *out;
13 sk_rephasor rephasor;
14};
15
16static 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
38static 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
50int 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
3int 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
2scale [phasor 1 0] 220 440
3sine zz 0.2
4
5# same thing, but with a slightly slower phasor
6# cable management coming soon
7scale [rephasor [phasor 1 0] 0.75] 220 440
8sine zz 0.2
9add zz zz
10
11wavout zz "test.wav"
12computes 10
nodes/scale/config.mk+1−0
@@ -1 +1,2 @@
1OBJ+=nodes/scale/scale.o1OBJ+=nodes/scale/scale.o
2OBJ+=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
10static 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
25static 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
40void 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
3#include <stdint.h>3#include <stdint.h>
4#include "patchwerk.h"4#include "patchwerk.h"
5#include "core.h"5#include "core.h"
6#include "../../scale.h"6#include "dsp/scale.h"
7 7
8struct scale_n {8struct scale_n {
9 pw_cable *in;9 pw_cable *in;
@@ -34,6 +34,28 @@ static void biscale_compute(pw_node *node) · 24 unmodified lines
34 }34 }
35}35}
36 36
37static 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
37static void destroy(pw_node *node)59static void destroy(pw_node *node)
38{60{
39 pw_patch *patch;61 pw_patch *patch;
@@ -46,7 +68,7 @@ static void destroy(pw_node *node) · 6 unmodified lines
46 pw_memory_free(patch, &ud);68 pw_memory_free(patch, &ud);
47}69}
48 70
49int sk_node_biscale(sk_core *core)71static int node_scale(sk_core *core, pw_function compute)
50{72{
51 pw_patch *patch;73 pw_patch *patch;
52 pw_node *node;74 pw_node *node;
@@ -84,7 +106,7 @@ int sk_node_biscale(sk_core *core) · 31 unmodified lines
84 pw_node_get_cable(node, 3, &scale->out);106 pw_node_get_cable(node, 3, &scale->out);
85 107
86 pw_node_set_data(node, scale);108 pw_node_set_data(node, scale);
87 pw_node_set_compute(node, biscale_compute);109 pw_node_set_compute(node, compute);
88 pw_node_set_destroy(node, destroy);110 pw_node_set_destroy(node, destroy);
89 111
90 sk_param_set(core, node, &in, 0);112 sk_param_set(core, node, &in, 0);
@@ -93,3 +115,13 @@ int sk_node_biscale(sk_core *core) · 2 unmodified lines
93 sk_param_out(core, node, 3);115 sk_param_out(core, node, 3);
94 return 0;116 return 0;
95}117}
118
119int sk_node_biscale(sk_core *core)
120{
121 return node_scale(core, biscale_compute);
122}
123
124int 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 @@
1#ifndef SK_NODE_SCALE_H1#ifndef SK_NODE_SCALE_H
2#define SK_NODE_SCALE_H2#define SK_NODE_SCALE_H
3int sk_node_biscale(sk_core *core);3int sk_node_biscale(sk_core *core);
4int sk_node_scale(sk_core *core);
4#endif5#endif
nodes/sine/config.mk+1−0
@@ -1 +1,2 @@
1OBJ+=nodes/sine/sine.o1OBJ+=nodes/sine/sine.o
2OBJ+=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
10static 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
24void 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
5#include "core.h"5#include "core.h"
6#define SK_OSC_PRIV6#define SK_OSC_PRIV
7#include "sine.h"7#include "sine.h"
8#include "osc.h"8#include "dsp/osc.h"
9 9
10#ifndef M_PI10#ifndef M_PI
11#define M_PI 3.1415926535897932384611#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
8void 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) \
4if (ARGC < NARGS) { \
5 lil_set_error(LIL, NODE ": not enough args."); \
6 return NULL; \
7}
8
9void sklil_param(sk_core *core, lil_value_t arg);
10#endif
nodes/wavout/config.mk+1−0
@@ -1 +1,2 @@
1OBJ+=nodes/wavout/wavout.c991OBJ+=nodes/wavout/wavout.c99
2OBJ+=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
10static 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
23void 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