|
@@ -6132,7 +6132,7 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
char buffer[4096], with_slash[4096];
|
|
char buffer[4096], with_slash[4096];
|
|
size_t n;
|
|
size_t n;
|
|
|
|
|
|
- #ifdef _MSC_VER
|
|
|
|
|
|
+ #ifdef WIN32
|
|
stb__wchar *ws;
|
|
stb__wchar *ws;
|
|
struct _wfinddata_t data;
|
|
struct _wfinddata_t data;
|
|
#ifdef _WIN64
|
|
#ifdef _WIN64
|
|
@@ -6142,7 +6142,7 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
const long none = -1;
|
|
const long none = -1;
|
|
long z;
|
|
long z;
|
|
#endif
|
|
#endif
|
|
- #else // !_MSC_VER
|
|
|
|
|
|
+ #else // !WIN32
|
|
const DIR *none = NULL;
|
|
const DIR *none = NULL;
|
|
DIR *z;
|
|
DIR *z;
|
|
#endif
|
|
#endif
|
|
@@ -6159,7 +6159,7 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
|
|
if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- #ifdef _MSC_VER
|
|
|
|
|
|
+ #ifdef WIN32
|
|
if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
|
|
if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
|
|
return NULL;
|
|
return NULL;
|
|
ws = stb__from_utf8(buffer);
|
|
ws = stb__from_utf8(buffer);
|
|
@@ -6170,7 +6170,7 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
|
|
|
|
if (z != none) {
|
|
if (z != none) {
|
|
int nonempty = STB_TRUE;
|
|
int nonempty = STB_TRUE;
|
|
- #ifndef _MSC_VER
|
|
|
|
|
|
+ #ifndef WIN32
|
|
struct dirent *data = readdir(z);
|
|
struct dirent *data = readdir(z);
|
|
nonempty = (data != NULL);
|
|
nonempty = (data != NULL);
|
|
#endif
|
|
#endif
|
|
@@ -6179,7 +6179,7 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
|
|
|
|
do {
|
|
do {
|
|
int is_subdir;
|
|
int is_subdir;
|
|
- #ifdef _MSC_VER
|
|
|
|
|
|
+ #ifdef WIN32
|
|
char *name = stb__to_utf8((stb__wchar *)data.name);
|
|
char *name = stb__to_utf8((stb__wchar *)data.name);
|
|
if (name == NULL) {
|
|
if (name == NULL) {
|
|
fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8");
|
|
fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8");
|
|
@@ -6207,13 +6207,13 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- #ifdef _MSC_VER
|
|
|
|
|
|
+ #ifdef WIN32
|
|
while (0 == _wfindnext(z, &data));
|
|
while (0 == _wfindnext(z, &data));
|
|
#else
|
|
#else
|
|
while ((data = readdir(z)) != NULL);
|
|
while ((data = readdir(z)) != NULL);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
- #ifdef _MSC_VER
|
|
|
|
|
|
+ #ifdef WIN32
|
|
_findclose(z);
|
|
_findclose(z);
|
|
#else
|
|
#else
|
|
closedir(z);
|
|
closedir(z);
|
|
@@ -13059,1356 +13059,6 @@ char * stb__string_constant(char *file, int line, char *x)
|
|
#endif // STB_DEFINE
|
|
#endif // STB_DEFINE
|
|
#endif // !STB_DEBUG && !STB_ALWAYS_H
|
|
#endif // !STB_DEBUG && !STB_ALWAYS_H
|
|
|
|
|
|
-
|
|
|
|
-#ifdef STB_STUA
|
|
|
|
-#error "STUA is no longer supported"
|
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
|
-//
|
|
|
|
-// stua: little scripting language
|
|
|
|
-//
|
|
|
|
-// define STB_STUA to compile it
|
|
|
|
-//
|
|
|
|
-// see http://nothings.org/stb/stb_stua.html for documentation
|
|
|
|
-//
|
|
|
|
-// basic parsing model:
|
|
|
|
-//
|
|
|
|
-// lexical analysis
|
|
|
|
-// use stb_lex() to parse tokens; keywords get their own tokens
|
|
|
|
-//
|
|
|
|
-// parsing:
|
|
|
|
-// recursive descent parser. too much of a hassle to make an unambiguous
|
|
|
|
-// LR(1) grammar, and one-pass generation is clumsier (recursive descent
|
|
|
|
-// makes it easier to e.g. compile nested functions). on the other hand,
|
|
|
|
-// dictionary syntax required hackery to get extra lookahead.
|
|
|
|
-//
|
|
|
|
-// codegen:
|
|
|
|
-// output into an evaluation tree, using array indices as 'pointers'
|
|
|
|
-//
|
|
|
|
-// run:
|
|
|
|
-// traverse the tree; support for 'break/continue/return' is tricky
|
|
|
|
-//
|
|
|
|
-// garbage collection:
|
|
|
|
-// stu__mark and sweep; explicit stack with non-stu__compile_global_scope roots
|
|
|
|
-
|
|
|
|
-typedef stb_int32 stua_obj;
|
|
|
|
-
|
|
|
|
-typedef stb_idict stua_dict;
|
|
|
|
-
|
|
|
|
-STB_EXTERN void stua_run_script(char *s);
|
|
|
|
-STB_EXTERN void stua_uninit(void);
|
|
|
|
-
|
|
|
|
-extern stua_obj stua_globals;
|
|
|
|
-
|
|
|
|
-STB_EXTERN double stua_number(stua_obj z);
|
|
|
|
-
|
|
|
|
-STB_EXTERN stua_obj stua_getnil(void);
|
|
|
|
-STB_EXTERN stua_obj stua_getfalse(void);
|
|
|
|
-STB_EXTERN stua_obj stua_gettrue(void);
|
|
|
|
-STB_EXTERN stua_obj stua_string(char *z);
|
|
|
|
-STB_EXTERN stua_obj stua_make_number(double d);
|
|
|
|
-STB_EXTERN stua_obj stua_box(int type, void *data, int size);
|
|
|
|
-
|
|
|
|
-enum
|
|
|
|
-{
|
|
|
|
- STUA_op_negate=129,
|
|
|
|
- STUA_op_shl, STUA_op_ge,
|
|
|
|
- STUA_op_shr, STUA_op_le,
|
|
|
|
- STUA_op_shru,
|
|
|
|
- STUA_op_last
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-#define STUA_NO_VALUE 2 // equivalent to a tagged NULL
|
|
|
|
-STB_EXTERN stua_obj (*stua_overload)(int op, stua_obj a, stua_obj b, stua_obj c);
|
|
|
|
-
|
|
|
|
-STB_EXTERN stua_obj stua_error(char *err, ...);
|
|
|
|
-
|
|
|
|
-STB_EXTERN stua_obj stua_pushroot(stua_obj o);
|
|
|
|
-STB_EXTERN void stua_poproot ( void );
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-#ifdef STB_DEFINE
|
|
|
|
-// INTERPRETER
|
|
|
|
-
|
|
|
|
-// 31-bit floating point implementation
|
|
|
|
-// force the (1 << 30) bit (2nd highest bit) to be zero by re-biasing the exponent;
|
|
|
|
-// then shift and set the bottom bit
|
|
|
|
-
|
|
|
|
-static stua_obj stu__floatp(float *f)
|
|
|
|
-{
|
|
|
|
- unsigned int n = *(unsigned int *) f;
|
|
|
|
- unsigned int e = n & (0xff << 23);
|
|
|
|
-
|
|
|
|
- assert(sizeof(int) == 4 && sizeof(float) == 4);
|
|
|
|
-
|
|
|
|
- if (!e) // zero?
|
|
|
|
- n = n; // no change
|
|
|
|
- else if (e < (64 << 23)) // underflow of the packed encoding?
|
|
|
|
- n = (n & 0x80000000); // signed 0
|
|
|
|
- else if (e > (190 << 23)) // overflow of the encoding? (or INF or NAN)
|
|
|
|
- n = (n & 0x80000000) + (127 << 23); // new INF encoding
|
|
|
|
- else
|
|
|
|
- n -= 0x20000000;
|
|
|
|
-
|
|
|
|
- // now we need to shuffle the bits so that the spare bit is at the bottom
|
|
|
|
- assert((n & 0x40000000) == 0);
|
|
|
|
- return (n & 0x80000000) + (n << 1) + 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static unsigned char stu__getfloat_addend[256];
|
|
|
|
-static float stu__getfloat(stua_obj v)
|
|
|
|
-{
|
|
|
|
- unsigned int n;
|
|
|
|
- unsigned int e = ((unsigned int) v) >> 24;
|
|
|
|
-
|
|
|
|
- n = (int) v >> 1; // preserve high bit
|
|
|
|
- n += stu__getfloat_addend[e] << 24;
|
|
|
|
- return *(float *) &n;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-stua_obj stua_float(float f)
|
|
|
|
-{
|
|
|
|
- return stu__floatp(&f);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stu__float_init(void)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- stu__getfloat_addend[0] = 0; // do nothing to biased exponent of 0
|
|
|
|
- for (i=1; i < 127; ++i)
|
|
|
|
- stu__getfloat_addend[i] = 32; // undo the -0x20000000
|
|
|
|
- stu__getfloat_addend[127] = 64; // convert packed INF to INF (0x3f -> 0x7f)
|
|
|
|
-
|
|
|
|
- for (i=0; i < 128; ++i) // for signed floats, remove the bit we just shifted down
|
|
|
|
- stu__getfloat_addend[128+i] = stu__getfloat_addend[i] - 64;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// Tagged data type implementation
|
|
|
|
-
|
|
|
|
- // TAGS:
|
|
|
|
-#define stu__int_tag 0 // of 2 bits // 00 int
|
|
|
|
-#define stu__float_tag 1 // of 1 bit // 01 float
|
|
|
|
-#define stu__ptr_tag 2 // of 2 bits // 10 boxed
|
|
|
|
- // 11 float
|
|
|
|
-
|
|
|
|
-#define stu__tag(x) ((x) & 3)
|
|
|
|
-#define stu__number(x) (stu__tag(x) != stu__ptr_tag)
|
|
|
|
-#define stu__isint(x) (stu__tag(x) == stu__int_tag)
|
|
|
|
-
|
|
|
|
-#define stu__int(x) ((x) >> 2)
|
|
|
|
-#define stu__float(x) (stu__getfloat(x))
|
|
|
|
-
|
|
|
|
-#define stu__makeint(v) ((v)*4+stu__int_tag)
|
|
|
|
-
|
|
|
|
-// boxed data, and tag support for boxed data
|
|
|
|
-
|
|
|
|
-enum
|
|
|
|
-{
|
|
|
|
- STU___float = 1, STU___int = 2,
|
|
|
|
- STU___number = 3, STU___string = 4,
|
|
|
|
- STU___function = 5, STU___dict = 6,
|
|
|
|
- STU___boolean = 7, STU___error = 8,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// boxed data
|
|
|
|
-#define STU__BOX short type, stua_gc
|
|
|
|
-typedef struct stu__box { STU__BOX; } stu__box;
|
|
|
|
-
|
|
|
|
-stu__box stu__nil = { 0, 1 };
|
|
|
|
-stu__box stu__true = { STU___boolean, 1, };
|
|
|
|
-stu__box stu__false = { STU___boolean, 1, };
|
|
|
|
-
|
|
|
|
-#define stu__makeptr(v) ((stua_obj) (v) + stu__ptr_tag)
|
|
|
|
-
|
|
|
|
-#define stua_nil stu__makeptr(&stu__nil)
|
|
|
|
-#define stua_true stu__makeptr(&stu__true)
|
|
|
|
-#define stua_false stu__makeptr(&stu__false)
|
|
|
|
-
|
|
|
|
-stua_obj stua_getnil(void) { return stua_nil; }
|
|
|
|
-stua_obj stua_getfalse(void) { return stua_false; }
|
|
|
|
-stua_obj stua_gettrue(void) { return stua_true; }
|
|
|
|
-
|
|
|
|
-#define stu__ptr(x) ((stu__box *) ((x) - stu__ptr_tag))
|
|
|
|
-
|
|
|
|
-#define stu__checkt(t,x) ((t) == STU___float ? ((x) & 1) == stu__float_tag : \
|
|
|
|
- (t) == STU___int ? stu__isint(x) : \
|
|
|
|
- (t) == STU___number ? stu__number(x) : \
|
|
|
|
- stu__tag(x) == stu__ptr_tag && stu__ptr(x)->type == (t))
|
|
|
|
-
|
|
|
|
-typedef struct
|
|
|
|
-{
|
|
|
|
- STU__BOX;
|
|
|
|
- void *ptr;
|
|
|
|
-} stu__wrapper;
|
|
|
|
-
|
|
|
|
-// implementation of a 'function' or function + closure
|
|
|
|
-
|
|
|
|
-typedef struct stu__func
|
|
|
|
-{
|
|
|
|
- STU__BOX;
|
|
|
|
- stua_obj closure_source; // 0 - regular function; 4 - C function
|
|
|
|
- // if closure, pointer to source function
|
|
|
|
- union {
|
|
|
|
- stua_obj closure_data; // partial-application data
|
|
|
|
- void *store; // pointer to free that holds 'code'
|
|
|
|
- stua_obj (*func)(stua_dict *context);
|
|
|
|
- } f;
|
|
|
|
- // closure ends here
|
|
|
|
- short *code;
|
|
|
|
- int num_param;
|
|
|
|
- stua_obj *param; // list of parameter strings
|
|
|
|
-} stu__func;
|
|
|
|
-
|
|
|
|
-// apply this to 'short *code' to get at data
|
|
|
|
-#define stu__const(f) ((stua_obj *) (f))
|
|
|
|
-
|
|
|
|
-static void stu__free_func(stu__func *f)
|
|
|
|
-{
|
|
|
|
- if (f->closure_source == 0) free(f->f.store);
|
|
|
|
- if ((stb_uint) f->closure_source <= 4) free(f->param);
|
|
|
|
- free(f);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#define stu__pd(x) ((stua_dict *) stu__ptr(x))
|
|
|
|
-#define stu__pw(x) ((stu__wrapper *) stu__ptr(x))
|
|
|
|
-#define stu__pf(x) ((stu__func *) stu__ptr(x))
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-// garbage-collection
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static stu__box ** stu__gc_ptrlist;
|
|
|
|
-static stua_obj * stu__gc_root_stack;
|
|
|
|
-
|
|
|
|
-stua_obj stua_pushroot(stua_obj o) { stb_arr_push(stu__gc_root_stack, o); return o; }
|
|
|
|
-void stua_poproot ( void ) { stb_arr_pop(stu__gc_root_stack); }
|
|
|
|
-
|
|
|
|
-static stb_sdict *stu__strings;
|
|
|
|
-static void stu__mark(stua_obj z)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- stu__box *p = stu__ptr(z);
|
|
|
|
- if (p->stua_gc == 1) return; // already marked
|
|
|
|
- assert(p->stua_gc == 0);
|
|
|
|
- p->stua_gc = 1;
|
|
|
|
- switch(p->type) {
|
|
|
|
- case STU___function: {
|
|
|
|
- stu__func *f = (stu__func *) p;
|
|
|
|
- if ((stb_uint) f->closure_source <= 4) {
|
|
|
|
- if (f->closure_source == 0) {
|
|
|
|
- for (i=1; i <= f->code[0]; ++i)
|
|
|
|
- if (!stu__number(((stua_obj *) f->code)[-i]))
|
|
|
|
- stu__mark(((stua_obj *) f->code)[-i]);
|
|
|
|
- }
|
|
|
|
- for (i=0; i < f->num_param; ++i)
|
|
|
|
- stu__mark(f->param[i]);
|
|
|
|
- } else {
|
|
|
|
- stu__mark(f->closure_source);
|
|
|
|
- stu__mark(f->f.closure_data);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case STU___dict: {
|
|
|
|
- stua_dict *e = (stua_dict *) p;
|
|
|
|
- for (i=0; i < e->limit; ++i)
|
|
|
|
- if (e->table[i].k != STB_IEMPTY && e->table[i].k != STB_IDEL) {
|
|
|
|
- if (!stu__number(e->table[i].k)) stu__mark((int) e->table[i].k);
|
|
|
|
- if (!stu__number(e->table[i].v)) stu__mark((int) e->table[i].v);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__num_allocs, stu__size_allocs;
|
|
|
|
-static stua_obj stu__flow_val = stua_nil; // used for break & return
|
|
|
|
-
|
|
|
|
-static void stua_gc(int force)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- if (!force && stu__num_allocs == 0 && stu__size_allocs == 0) return;
|
|
|
|
- stu__num_allocs = stu__size_allocs = 0;
|
|
|
|
- //printf("[gc]\n");
|
|
|
|
-
|
|
|
|
- // clear marks
|
|
|
|
- for (i=0; i < stb_arr_len(stu__gc_ptrlist); ++i)
|
|
|
|
- stu__gc_ptrlist[i]->stua_gc = 0;
|
|
|
|
-
|
|
|
|
- // stu__mark everything reachable
|
|
|
|
- stu__nil.stua_gc = stu__true.stua_gc = stu__false.stua_gc = 1;
|
|
|
|
- stu__mark(stua_globals);
|
|
|
|
- if (!stu__number(stu__flow_val))
|
|
|
|
- stu__mark(stu__flow_val);
|
|
|
|
- for (i=0; i < stb_arr_len(stu__gc_root_stack); ++i)
|
|
|
|
- if (!stu__number(stu__gc_root_stack[i]))
|
|
|
|
- stu__mark(stu__gc_root_stack[i]);
|
|
|
|
-
|
|
|
|
- // sweep unreachables
|
|
|
|
- for (i=0; i < stb_arr_len(stu__gc_ptrlist);) {
|
|
|
|
- stu__box *z = stu__gc_ptrlist[i];
|
|
|
|
- if (!z->stua_gc) {
|
|
|
|
- switch (z->type) {
|
|
|
|
- case STU___dict: stb_idict_destroy((stua_dict *) z); break;
|
|
|
|
- case STU___error: free(((stu__wrapper *) z)->ptr); break;
|
|
|
|
- case STU___string: stb_sdict_remove(stu__strings, (char*) ((stu__wrapper *) z)->ptr, NULL); free(z); break;
|
|
|
|
- case STU___function: stu__free_func((stu__func *) z); break;
|
|
|
|
- }
|
|
|
|
- // swap in the last item over this, and repeat
|
|
|
|
- z = stb_arr_pop(stu__gc_ptrlist);
|
|
|
|
- stu__gc_ptrlist[i] = z;
|
|
|
|
- } else
|
|
|
|
- ++i;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stu__consider_gc(stua_obj x)
|
|
|
|
-{
|
|
|
|
- if (stu__size_allocs < 100000) return;
|
|
|
|
- if (stu__num_allocs < 10 && stu__size_allocs < 1000000) return;
|
|
|
|
- stb_arr_push(stu__gc_root_stack, x);
|
|
|
|
- stua_gc(0);
|
|
|
|
- stb_arr_pop(stu__gc_root_stack);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static stua_obj stu__makeobj(int type, void *data, int size, int safe_to_gc)
|
|
|
|
-{
|
|
|
|
- stua_obj x = stu__makeptr(data);
|
|
|
|
- ((stu__box *) data)->type = type;
|
|
|
|
- stb_arr_push(stu__gc_ptrlist, (stu__box *) data);
|
|
|
|
- stu__num_allocs += 1;
|
|
|
|
- stu__size_allocs += size;
|
|
|
|
- if (safe_to_gc) stu__consider_gc(x);
|
|
|
|
- return x;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-stua_obj stua_box(int type, void *data, int size)
|
|
|
|
-{
|
|
|
|
- stu__wrapper *p = (stu__wrapper *) malloc(sizeof(*p));
|
|
|
|
- p->ptr = data;
|
|
|
|
- return stu__makeobj(type, p, size, 0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// a stu string can be directly compared for equality, because
|
|
|
|
-// they go into a hash table
|
|
|
|
-stua_obj stua_string(char *z)
|
|
|
|
-{
|
|
|
|
- stu__wrapper *b = (stu__wrapper *) stb_sdict_get(stu__strings, z);
|
|
|
|
- if (b == NULL) {
|
|
|
|
- int o = stua_box(STU___string, NULL, strlen(z) + sizeof(*b));
|
|
|
|
- b = stu__pw(o);
|
|
|
|
- stb_sdict_add(stu__strings, z, b);
|
|
|
|
- stb_sdict_getkey(stu__strings, z, (char **) &b->ptr);
|
|
|
|
- }
|
|
|
|
- return stu__makeptr(b);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// stb_obj dictionary is just an stb_idict
|
|
|
|
-static void stu__set(stua_dict *d, stua_obj k, stua_obj v)
|
|
|
|
-{ if (stb_idict_set(d, k, v)) stu__size_allocs += 8; }
|
|
|
|
-
|
|
|
|
-static stua_obj stu__get(stua_dict *d, stua_obj k, stua_obj res)
|
|
|
|
-{
|
|
|
|
- stb_idict_get_flag(d, k, &res);
|
|
|
|
- return res;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static stua_obj make_string(char *z, int len)
|
|
|
|
-{
|
|
|
|
- stua_obj s;
|
|
|
|
- char temp[256], *q = (char *) stb_temp(temp, len+1), *p = q;
|
|
|
|
- while (len > 0) {
|
|
|
|
- if (*z == '\\') {
|
|
|
|
- if (z[1] == 'n') *p = '\n';
|
|
|
|
- else if (z[1] == 'r') *p = '\r';
|
|
|
|
- else if (z[1] == 't') *p = '\t';
|
|
|
|
- else *p = z[1];
|
|
|
|
- p += 1; z += 2; len -= 2;
|
|
|
|
- } else {
|
|
|
|
- *p++ = *z++; len -= 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- *p = 0;
|
|
|
|
- s = stua_string(q);
|
|
|
|
- stb_tempfree(temp, q);
|
|
|
|
- return s;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-enum token_names
|
|
|
|
-{
|
|
|
|
- T__none=128,
|
|
|
|
- ST_shl = STUA_op_shl, ST_ge = STUA_op_ge,
|
|
|
|
- ST_shr = STUA_op_shr, ST_le = STUA_op_le,
|
|
|
|
- ST_shru = STUA_op_shru, STU__negate = STUA_op_negate,
|
|
|
|
- ST__reset_numbering = STUA_op_last,
|
|
|
|
- ST_white,
|
|
|
|
- ST_id, ST_float, ST_decimal, ST_hex, ST_char,ST_string, ST_number,
|
|
|
|
- // make sure the keywords come _AFTER_ ST_id, so stb_lex prefer them
|
|
|
|
- ST_if, ST_while, ST_for, ST_eq, ST_nil,
|
|
|
|
- ST_then, ST_do, ST_in, ST_ne, ST_true,
|
|
|
|
- ST_else, ST_break, ST_let, ST_and, ST_false,
|
|
|
|
- ST_elseif, ST_continue, ST_into, ST_or, ST_repeat,
|
|
|
|
- ST_end, ST_as, ST_return, ST_var, ST_func,
|
|
|
|
- ST_catch, ST__frame,
|
|
|
|
- ST__max_terminals,
|
|
|
|
-
|
|
|
|
- STU__defaultparm, STU__seq,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static stua_dict * stu__globaldict;
|
|
|
|
- stua_obj stua_globals;
|
|
|
|
-
|
|
|
|
-static enum
|
|
|
|
-{
|
|
|
|
- FLOW_normal, FLOW_continue, FLOW_break, FLOW_return, FLOW_error,
|
|
|
|
-} stu__flow;
|
|
|
|
-
|
|
|
|
-stua_obj stua_error(char *z, ...)
|
|
|
|
-{
|
|
|
|
- stua_obj a;
|
|
|
|
- char temp[4096], *x;
|
|
|
|
- va_list v; va_start(v,z); vsprintf(temp, z, v); va_end(v);
|
|
|
|
- x = stb_p_strdup(temp);
|
|
|
|
- a = stua_box(STU___error, x, strlen(x));
|
|
|
|
- stu__flow = FLOW_error;
|
|
|
|
- stu__flow_val = a;
|
|
|
|
- return stua_nil;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-double stua_number(stua_obj z)
|
|
|
|
-{
|
|
|
|
- return stu__tag(z) == stu__int_tag ? stu__int(z) : stu__float(z);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-stua_obj stua_make_number(double d)
|
|
|
|
-{
|
|
|
|
- double e = floor(d);
|
|
|
|
- if (e == d && e < (1 << 29) && e >= -(1 << 29))
|
|
|
|
- return stu__makeint((int) e);
|
|
|
|
- else
|
|
|
|
- return stua_float((float) d);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-stua_obj (*stua_overload)(int op, stua_obj a, stua_obj b, stua_obj c) = NULL;
|
|
|
|
-
|
|
|
|
-static stua_obj stu__op(int op, stua_obj a, stua_obj b, stua_obj c)
|
|
|
|
-{
|
|
|
|
- stua_obj r = STUA_NO_VALUE;
|
|
|
|
- if (op == '+') {
|
|
|
|
- if (stu__checkt(STU___string, a) && stu__checkt(STU___string, b)) {
|
|
|
|
- ;// @TODO: string concatenation
|
|
|
|
- } else if (stu__checkt(STU___function, a) && stu__checkt(STU___dict, b)) {
|
|
|
|
- stu__func *f = (stu__func *) malloc(12);
|
|
|
|
- assert(offsetof(stu__func, code)==12);
|
|
|
|
- f->closure_source = a;
|
|
|
|
- f->f.closure_data = b;
|
|
|
|
- return stu__makeobj(STU___function, f, 16, 1);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (stua_overload) r = stua_overload(op,a,b,c);
|
|
|
|
- if (stu__flow != FLOW_error && r == STUA_NO_VALUE)
|
|
|
|
- stua_error("Typecheck for operator %d", op), r=stua_nil;
|
|
|
|
- return r;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#define STU__EVAL2(a,b) \
|
|
|
|
- a = stu__eval(stu__f[n+1]); if (stu__flow) break; stua_pushroot(a); \
|
|
|
|
- b = stu__eval(stu__f[n+2]); stua_poproot(); if (stu__flow) break;
|
|
|
|
-
|
|
|
|
-#define STU__FB(op) \
|
|
|
|
- STU__EVAL2(a,b) \
|
|
|
|
- if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \
|
|
|
|
- return ((a) op (b)); \
|
|
|
|
- if (stu__number(a) && stu__number(b)) \
|
|
|
|
- return stua_make_number(stua_number(a) op stua_number(b)); \
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil)
|
|
|
|
-
|
|
|
|
-#define STU__F(op) \
|
|
|
|
- STU__EVAL2(a,b) \
|
|
|
|
- if (stu__number(a) && stu__number(b)) \
|
|
|
|
- return stua_make_number(stua_number(a) op stua_number(b)); \
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil)
|
|
|
|
-
|
|
|
|
-#define STU__I(op) \
|
|
|
|
- STU__EVAL2(a,b) \
|
|
|
|
- if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \
|
|
|
|
- return stu__makeint(stu__int(a) op stu__int(b)); \
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil)
|
|
|
|
-
|
|
|
|
-#define STU__C(op) \
|
|
|
|
- STU__EVAL2(a,b) \
|
|
|
|
- if (stu__number(a) && stu__number(b)) \
|
|
|
|
- return (stua_number(a) op stua_number(b)) ? stua_true : stua_false; \
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil)
|
|
|
|
-
|
|
|
|
-#define STU__CE(op) \
|
|
|
|
- STU__EVAL2(a,b) \
|
|
|
|
- return (a op b) ? stua_true : stua_false
|
|
|
|
-
|
|
|
|
-static short *stu__f;
|
|
|
|
-static stua_obj stu__f_obj;
|
|
|
|
-static stua_dict *stu__c;
|
|
|
|
-static stua_obj stu__funceval(stua_obj fo, stua_obj co);
|
|
|
|
-
|
|
|
|
-static int stu__cond(stua_obj x)
|
|
|
|
-{
|
|
|
|
- if (stu__flow) return 0;
|
|
|
|
- if (!stu__checkt(STU___boolean, x))
|
|
|
|
- x = stu__op('!', x, stua_nil, stua_nil);
|
|
|
|
- if (x == stua_true ) return 1;
|
|
|
|
- if (x == stua_false) return 0;
|
|
|
|
- stu__flow = FLOW_error;
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// had to manually eliminate tailcall recursion for debugging complex stuff
|
|
|
|
-#define TAILCALL(x) n = (x); goto top;
|
|
|
|
-static stua_obj stu__eval(int n)
|
|
|
|
-{
|
|
|
|
-top:
|
|
|
|
- if (stu__flow >= FLOW_return) return stua_nil; // is this needed?
|
|
|
|
- if (n < 0) return stu__const(stu__f)[n];
|
|
|
|
- assert(n != 0 && n != 1);
|
|
|
|
- switch (stu__f[n]) {
|
|
|
|
- stua_obj a,b,c;
|
|
|
|
- case ST_catch: a = stu__eval(stu__f[n+1]);
|
|
|
|
- if (stu__flow == FLOW_error) { a=stu__flow_val; stu__flow = FLOW_normal; }
|
|
|
|
- return a;
|
|
|
|
- case ST_var: b = stu__eval(stu__f[n+2]); if (stu__flow) break;
|
|
|
|
- stu__set(stu__c, stu__const(stu__f)[stu__f[n+1]], b);
|
|
|
|
- return b;
|
|
|
|
- case STU__seq: stu__eval(stu__f[n+1]); if (stu__flow) break;
|
|
|
|
- TAILCALL(stu__f[n+2]);
|
|
|
|
- case ST_if: if (!stu__cond(stu__eval(stu__f[n+1]))) return stua_nil;
|
|
|
|
- TAILCALL(stu__f[n+2]);
|
|
|
|
- case ST_else: a = stu__cond(stu__eval(stu__f[n+1]));
|
|
|
|
- TAILCALL(stu__f[n + 2 + !a]);
|
|
|
|
- #define STU__HANDLE_BREAK \
|
|
|
|
- if (stu__flow >= FLOW_break) { \
|
|
|
|
- if (stu__flow == FLOW_break) { \
|
|
|
|
- a = stu__flow_val; \
|
|
|
|
- stu__flow = FLOW_normal; \
|
|
|
|
- stu__flow_val = stua_nil; \
|
|
|
|
- return a; \
|
|
|
|
- } \
|
|
|
|
- return stua_nil; \
|
|
|
|
- }
|
|
|
|
- case ST_as: stu__eval(stu__f[n+3]);
|
|
|
|
- STU__HANDLE_BREAK
|
|
|
|
- // fallthrough!
|
|
|
|
- case ST_while: a = stua_nil; stua_pushroot(a);
|
|
|
|
- while (stu__cond(stu__eval(stu__f[n+1]))) {
|
|
|
|
- stua_poproot();
|
|
|
|
- a = stu__eval(stu__f[n+2]);
|
|
|
|
- STU__HANDLE_BREAK
|
|
|
|
- stu__flow = FLOW_normal; // clear 'continue' flag
|
|
|
|
- stua_pushroot(a);
|
|
|
|
- if (stu__f[n+3]) stu__eval(stu__f[n+3]);
|
|
|
|
- STU__HANDLE_BREAK
|
|
|
|
- stu__flow = FLOW_normal; // clear 'continue' flag
|
|
|
|
- }
|
|
|
|
- stua_poproot();
|
|
|
|
- return a;
|
|
|
|
- case ST_break: stu__flow = FLOW_break; stu__flow_val = stu__eval(stu__f[n+1]); break;
|
|
|
|
- case ST_continue:stu__flow = FLOW_continue; break;
|
|
|
|
- case ST_return: stu__flow = FLOW_return; stu__flow_val = stu__eval(stu__f[n+1]); break;
|
|
|
|
- case ST__frame: return stu__f_obj;
|
|
|
|
- case '[': STU__EVAL2(a,b);
|
|
|
|
- if (stu__checkt(STU___dict, a))
|
|
|
|
- return stu__get(stu__pd(a), b, stua_nil);
|
|
|
|
- return stu__op(stu__f[n], a, b, stua_nil);
|
|
|
|
- case '=': a = stu__eval(stu__f[n+2]); if (stu__flow) break;
|
|
|
|
- n = stu__f[n+1];
|
|
|
|
- if (stu__f[n] == ST_id) {
|
|
|
|
- if (!stb_idict_update(stu__c, stu__const(stu__f)[stu__f[n+1]], a))
|
|
|
|
- if (!stb_idict_update(stu__globaldict, stu__const(stu__f)[stu__f[n+1]], a))
|
|
|
|
- return stua_error("Assignment to undefined variable");
|
|
|
|
- } else if (stu__f[n] == '[') {
|
|
|
|
- stua_pushroot(a);
|
|
|
|
- b = stu__eval(stu__f[n+1]); if (stu__flow) { stua_poproot(); break; }
|
|
|
|
- stua_pushroot(b);
|
|
|
|
- c = stu__eval(stu__f[n+2]); stua_poproot(); stua_poproot();
|
|
|
|
- if (stu__flow) break;
|
|
|
|
- if (!stu__checkt(STU___dict, b)) return stua_nil;
|
|
|
|
- stu__set(stu__pd(b), c, a);
|
|
|
|
- } else {
|
|
|
|
- return stu__op(stu__f[n], stu__eval(n), a, stua_nil);
|
|
|
|
- }
|
|
|
|
- return a;
|
|
|
|
- case STU__defaultparm:
|
|
|
|
- a = stu__eval(stu__f[n+2]);
|
|
|
|
- stu__flow = FLOW_normal;
|
|
|
|
- if (stb_idict_add(stu__c, stu__const(stu__f)[stu__f[n+1]], a))
|
|
|
|
- stu__size_allocs += 8;
|
|
|
|
- return stua_nil;
|
|
|
|
- case ST_id: a = stu__get(stu__c, stu__const(stu__f)[stu__f[n+1]], STUA_NO_VALUE); // try local variable
|
|
|
|
- return a != STUA_NO_VALUE // else try stu__compile_global_scope variable
|
|
|
|
- ? a : stu__get(stu__globaldict, stu__const(stu__f)[stu__f[n+1]], stua_nil);
|
|
|
|
- case STU__negate:a = stu__eval(stu__f[n+1]); if (stu__flow) break;
|
|
|
|
- return stu__isint(a) ? -a : stu__op(stu__f[n], a, stua_nil, stua_nil);
|
|
|
|
- case '~': a = stu__eval(stu__f[n+1]); if (stu__flow) break;
|
|
|
|
- return stu__isint(a) ? (~a)&~3 : stu__op(stu__f[n], a, stua_nil, stua_nil);
|
|
|
|
- case '!': a = stu__eval(stu__f[n+1]); if (stu__flow) break;
|
|
|
|
- a = stu__cond(a); if (stu__flow) break;
|
|
|
|
- return a ? stua_true : stua_false;
|
|
|
|
- case ST_eq: STU__CE(==); case ST_le: STU__C(<=); case '<': STU__C(<);
|
|
|
|
- case ST_ne: STU__CE(!=); case ST_ge: STU__C(>=); case '>': STU__C(>);
|
|
|
|
- case '+' : STU__FB(+); case '*': STU__F(*); case '&': STU__I(&); case ST_shl: STU__I(<<);
|
|
|
|
- case '-' : STU__FB(-); case '/': STU__F(/); case '|': STU__I(|); case ST_shr: STU__I(>>);
|
|
|
|
- case '%': STU__I(%); case '^': STU__I(^);
|
|
|
|
- case ST_shru: STU__EVAL2(a,b);
|
|
|
|
- if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag)
|
|
|
|
- return stu__makeint((unsigned) stu__int(a) >> stu__int(b));
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil);
|
|
|
|
- case ST_and: a = stu__eval(stu__f[n+1]); b = stu__cond(a); if (stu__flow) break;
|
|
|
|
- return a ? stu__eval(stu__f[n+2]) : a;
|
|
|
|
- case ST_or : a = stu__eval(stu__f[n+1]); b = stu__cond(a); if (stu__flow) break;
|
|
|
|
- return a ? b : stu__eval(stu__f[n+2]);
|
|
|
|
- case'(':case':': STU__EVAL2(a,b);
|
|
|
|
- if (!stu__checkt(STU___function, a))
|
|
|
|
- return stu__op(stu__f[n], a,b, stua_nil);
|
|
|
|
- if (!stu__checkt(STU___dict, b))
|
|
|
|
- return stua_nil;
|
|
|
|
- if (stu__f[n] == ':')
|
|
|
|
- b = stu__makeobj(STU___dict, stb_idict_copy(stu__pd(b)), stb_idict_memory_usage(stu__pd(b)), 0);
|
|
|
|
- a = stu__funceval(a,b);
|
|
|
|
- return a;
|
|
|
|
- case '{' : {
|
|
|
|
- stua_dict *d;
|
|
|
|
- d = stb_idict_new_size(stu__f[n+1] > 40 ? 64 : 16);
|
|
|
|
- if (d == NULL)
|
|
|
|
- return stua_nil; // breakpoint fodder
|
|
|
|
- c = stu__makeobj(STU___dict, d, 32, 1);
|
|
|
|
- stua_pushroot(c);
|
|
|
|
- a = stu__f[n+1];
|
|
|
|
- for (b=0; b < a; ++b) {
|
|
|
|
- stua_obj x = stua_pushroot(stu__eval(stu__f[n+2 + b*2 + 0]));
|
|
|
|
- stua_obj y = stu__eval(stu__f[n+2 + b*2 + 1]);
|
|
|
|
- stua_poproot();
|
|
|
|
- if (stu__flow) { stua_poproot(); return stua_nil; }
|
|
|
|
- stu__set(d, x, y);
|
|
|
|
- }
|
|
|
|
- stua_poproot();
|
|
|
|
- return c;
|
|
|
|
- }
|
|
|
|
- default: if (stu__f[n] < 0) return stu__const(stu__f)[stu__f[n]];
|
|
|
|
- assert(0); /* NOTREACHED */ // internal error!
|
|
|
|
- }
|
|
|
|
- return stua_nil;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int stb__stua_nesting;
|
|
|
|
-static stua_obj stu__funceval(stua_obj fo, stua_obj co)
|
|
|
|
-{
|
|
|
|
- stu__func *f = stu__pf(fo);
|
|
|
|
- stua_dict *context = stu__pd(co);
|
|
|
|
- int i,j;
|
|
|
|
- stua_obj p;
|
|
|
|
- short *tf = stu__f; // save previous function
|
|
|
|
- stua_dict *tc = stu__c;
|
|
|
|
-
|
|
|
|
- if (stu__flow == FLOW_error) return stua_nil;
|
|
|
|
- assert(stu__flow == FLOW_normal);
|
|
|
|
-
|
|
|
|
- stua_pushroot(fo);
|
|
|
|
- stua_pushroot(co);
|
|
|
|
- stu__consider_gc(stua_nil);
|
|
|
|
-
|
|
|
|
- while ((stb_uint) f->closure_source > 4) {
|
|
|
|
- // add data from closure to context
|
|
|
|
- stua_dict *e = (stua_dict *) stu__pd(f->f.closure_data);
|
|
|
|
- for (i=0; i < e->limit; ++i)
|
|
|
|
- if (e->table[i].k != STB_IEMPTY && e->table[i].k != STB_IDEL)
|
|
|
|
- if (stb_idict_add(context, e->table[i].k, e->table[i].v))
|
|
|
|
- stu__size_allocs += 8;
|
|
|
|
- // use add so if it's already defined, we don't override it; that way
|
|
|
|
- // explicit parameters win over applied ones, and most recent applications
|
|
|
|
- // win over previous ones
|
|
|
|
- f = stu__pf(f->closure_source);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (j=0, i=0; i < f->num_param; ++i)
|
|
|
|
- // if it doesn't already exist, add it from the numbered parameters
|
|
|
|
- if (stb_idict_add(context, f->param[i], stu__get(context, stu__int(j), stua_nil)))
|
|
|
|
- ++j;
|
|
|
|
-
|
|
|
|
- // @TODO: if (stu__get(context, stu__int(f->num_param+1)) != STUA_NO_VALUE) // error: too many parameters
|
|
|
|
- // @TODO: ditto too few parameters
|
|
|
|
-
|
|
|
|
- if (f->closure_source == 4)
|
|
|
|
- p = f->f.func(context);
|
|
|
|
- else {
|
|
|
|
- stu__f = f->code, stu__c = context;
|
|
|
|
- stu__f_obj = co;
|
|
|
|
- ++stb__stua_nesting;
|
|
|
|
- if (stu__f[1])
|
|
|
|
- p = stu__eval(stu__f[1]);
|
|
|
|
- else
|
|
|
|
- p = stua_nil;
|
|
|
|
- --stb__stua_nesting;
|
|
|
|
- stu__f = tf, stu__c = tc; // restore previous function
|
|
|
|
- if (stu__flow == FLOW_return) {
|
|
|
|
- stu__flow = FLOW_normal;
|
|
|
|
- p = stu__flow_val;
|
|
|
|
- stu__flow_val = stua_nil;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stua_poproot();
|
|
|
|
- stua_poproot();
|
|
|
|
-
|
|
|
|
- return p;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// Parser
|
|
|
|
-
|
|
|
|
-static int stu__tok;
|
|
|
|
-static stua_obj stu__tokval;
|
|
|
|
-
|
|
|
|
-static char *stu__curbuf, *stu__bufstart;
|
|
|
|
-
|
|
|
|
-static stb_matcher *stu__lex_matcher;
|
|
|
|
-
|
|
|
|
-static unsigned char stu__prec[ST__max_terminals], stu__end[ST__max_terminals];
|
|
|
|
-
|
|
|
|
-static void stu__nexttoken(void)
|
|
|
|
-{
|
|
|
|
- int len;
|
|
|
|
-
|
|
|
|
-retry:
|
|
|
|
- stu__tok = stb_lex(stu__lex_matcher, stu__curbuf, &len);
|
|
|
|
- if (stu__tok == 0)
|
|
|
|
- return;
|
|
|
|
- switch(stu__tok) {
|
|
|
|
- case ST_white : stu__curbuf += len; goto retry;
|
|
|
|
- case T__none : stu__tok = *stu__curbuf; break;
|
|
|
|
- case ST_string: stu__tokval = make_string(stu__curbuf+1, len-2); break;
|
|
|
|
- case ST_id : stu__tokval = make_string(stu__curbuf, len); break;
|
|
|
|
- case ST_hex : stu__tokval = stu__makeint(strtol(stu__curbuf+2,NULL,16)); stu__tok = ST_number; break;
|
|
|
|
- case ST_decimal: stu__tokval = stu__makeint(strtol(stu__curbuf ,NULL,10)); stu__tok = ST_number; break;
|
|
|
|
- case ST_float : stu__tokval = stua_float((float) atof(stu__curbuf)) ; stu__tok = ST_number; break;
|
|
|
|
- case ST_char : stu__tokval = stu__curbuf[2] == '\\' ? stu__curbuf[3] : stu__curbuf[2];
|
|
|
|
- if (stu__curbuf[3] == 't') stu__tokval = '\t';
|
|
|
|
- if (stu__curbuf[3] == 'n') stu__tokval = '\n';
|
|
|
|
- if (stu__curbuf[3] == 'r') stu__tokval = '\r';
|
|
|
|
- stu__tokval = stu__makeint(stu__tokval);
|
|
|
|
- stu__tok = ST_number;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- stu__curbuf += len;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static struct { int stu__tok; char *regex; } stu__lexemes[] =
|
|
|
|
-{
|
|
|
|
- ST_white , "([ \t\n\r]|/\\*(.|\n)*\\*/|//[^\r\n]*([\r\n]|$))+",
|
|
|
|
- ST_id , "[_a-zA-Z][_a-zA-Z0-9]*",
|
|
|
|
- ST_hex , "0x[0-9a-fA-F]+",
|
|
|
|
- ST_decimal, "[0-9]+[0-9]*",
|
|
|
|
- ST_float , "[0-9]+\\.?[0-9]*([eE][-+]?[0-9]+)?",
|
|
|
|
- ST_float , "\\.[0-9]+([eE][-+]?[0-9]+)?",
|
|
|
|
- ST_char , "c'(\\\\.|[^\\'])'",
|
|
|
|
- ST_string , "\"(\\\\.|[^\\\"\n\r])*\"",
|
|
|
|
- ST_string , "\'(\\\\.|[^\\\'\n\r])*\'",
|
|
|
|
-
|
|
|
|
- #define stua_key4(a,b,c,d) ST_##a, #a, ST_##b, #b, ST_##c, #c, ST_##d, #d,
|
|
|
|
- stua_key4(if,then,else,elseif) stua_key4(while,do,for,in)
|
|
|
|
- stua_key4(func,var,let,break) stua_key4(nil,true,false,end)
|
|
|
|
- stua_key4(return,continue,as,repeat) stua_key4(_frame,catch,catch,catch)
|
|
|
|
-
|
|
|
|
- ST_shl, "<<", ST_and, "&&", ST_eq, "==", ST_ge, ">=",
|
|
|
|
- ST_shr, ">>", ST_or , "||", ST_ne, "!=", ST_le, "<=",
|
|
|
|
- ST_shru,">>>", ST_into, "=>",
|
|
|
|
- T__none, ".",
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-typedef struct
|
|
|
|
-{
|
|
|
|
- stua_obj *data; // constants being compiled
|
|
|
|
- short *code; // code being compiled
|
|
|
|
- stua_dict *locals;
|
|
|
|
- short *non_local_refs;
|
|
|
|
-} stu__comp_func;
|
|
|
|
-
|
|
|
|
-static stu__comp_func stu__pfunc;
|
|
|
|
-static stu__comp_func *func_stack = NULL;
|
|
|
|
-static void stu__push_func_comp(void)
|
|
|
|
-{
|
|
|
|
- stb_arr_push(func_stack, stu__pfunc);
|
|
|
|
- stu__pfunc.data = NULL;
|
|
|
|
- stu__pfunc.code = NULL;
|
|
|
|
- stu__pfunc.locals = stb_idict_new_size(16);
|
|
|
|
- stu__pfunc.non_local_refs = NULL;
|
|
|
|
- stb_arr_push(stu__pfunc.code, 0); // number of data items
|
|
|
|
- stb_arr_push(stu__pfunc.code, 1); // starting execution address
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stu__pop_func_comp(void)
|
|
|
|
-{
|
|
|
|
- stb_arr_free(stu__pfunc.code);
|
|
|
|
- stb_arr_free(stu__pfunc.data);
|
|
|
|
- stb_idict_destroy(stu__pfunc.locals);
|
|
|
|
- stb_arr_free(stu__pfunc.non_local_refs);
|
|
|
|
- stu__pfunc = stb_arr_pop(func_stack);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// if an id is a reference to an outer lexical scope, this
|
|
|
|
-// function returns the "name" of it, and updates the stack
|
|
|
|
-// structures to make sure the names are propagated in.
|
|
|
|
-static int stu__nonlocal_id(stua_obj var_obj)
|
|
|
|
-{
|
|
|
|
- stua_obj dummy, var = var_obj;
|
|
|
|
- int i, n = stb_arr_len(func_stack), j,k;
|
|
|
|
- if (stb_idict_get_flag(stu__pfunc.locals, var, &dummy)) return 0;
|
|
|
|
- for (i=n-1; i > 1; --i) {
|
|
|
|
- if (stb_idict_get_flag(func_stack[i].locals, var, &dummy))
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (i <= 1) return 0; // stu__compile_global_scope
|
|
|
|
- j = i; // need to access variable from j'th frame
|
|
|
|
- for (i=0; i < stb_arr_len(stu__pfunc.non_local_refs); ++i)
|
|
|
|
- if (stu__pfunc.non_local_refs[i] == j) return j-n;
|
|
|
|
- stb_arr_push(stu__pfunc.non_local_refs, j-n);
|
|
|
|
- // now make sure all the parents propagate it down
|
|
|
|
- for (k=n-1; k > 1; --k) {
|
|
|
|
- if (j-k >= 0) return j-n; // comes direct from this parent
|
|
|
|
- for(i=0; i < stb_arr_len(func_stack[k].non_local_refs); ++i)
|
|
|
|
- if (func_stack[k].non_local_refs[i] == j-k)
|
|
|
|
- return j-n;
|
|
|
|
- stb_arr_push(func_stack[k].non_local_refs, j-k);
|
|
|
|
- }
|
|
|
|
- assert (k != 1);
|
|
|
|
-
|
|
|
|
- return j-n;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__off(void) { return stb_arr_len(stu__pfunc.code); }
|
|
|
|
-static void stu__cc(int a)
|
|
|
|
-{
|
|
|
|
- assert(a >= -2000 && a < 5000);
|
|
|
|
- stb_arr_push(stu__pfunc.code, a);
|
|
|
|
-}
|
|
|
|
-static int stu__cc1(int a) { stu__cc(a); return stu__off()-1; }
|
|
|
|
-static int stu__cc2(int a, int b) { stu__cc(a); stu__cc(b); return stu__off()-2; }
|
|
|
|
-static int stu__cc3(int a, int b, int c) {
|
|
|
|
- if (a == '=') assert(c != 0);
|
|
|
|
- stu__cc(a); stu__cc(b); stu__cc(c); return stu__off()-3; }
|
|
|
|
-static int stu__cc4(int a, int b, int c, int d) { stu__cc(a); stu__cc(b); stu__cc(c); stu__cc(d); return stu__off()-4; }
|
|
|
|
-
|
|
|
|
-static int stu__cdv(stua_obj p)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- assert(p != STUA_NO_VALUE);
|
|
|
|
- for (i=0; i < stb_arr_len(stu__pfunc.data); ++i)
|
|
|
|
- if (stu__pfunc.data[i] == p)
|
|
|
|
- break;
|
|
|
|
- if (i == stb_arr_len(stu__pfunc.data))
|
|
|
|
- stb_arr_push(stu__pfunc.data, p);
|
|
|
|
- return ~i;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__cdt(void)
|
|
|
|
-{
|
|
|
|
- int z = stu__cdv(stu__tokval);
|
|
|
|
- stu__nexttoken();
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__seq(int a, int b)
|
|
|
|
-{
|
|
|
|
- return !a ? b : !b ? a : stu__cc3(STU__seq, a,b);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static char stu__comp_err_str[1024];
|
|
|
|
-static int stu__comp_err_line;
|
|
|
|
-static int stu__err(char *str, ...)
|
|
|
|
-{
|
|
|
|
- va_list v;
|
|
|
|
- char *s = stu__bufstart;
|
|
|
|
- stu__comp_err_line = 1;
|
|
|
|
- while (s < stu__curbuf) {
|
|
|
|
- if (s[0] == '\n' || s[0] == '\r') {
|
|
|
|
- if (s[0]+s[1] == '\n' + '\r') ++s;
|
|
|
|
- ++stu__comp_err_line;
|
|
|
|
- }
|
|
|
|
- ++s;
|
|
|
|
- }
|
|
|
|
- va_start(v, str);
|
|
|
|
- vsprintf(stu__comp_err_str, str, v);
|
|
|
|
- va_end(v);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__accept(int p)
|
|
|
|
-{
|
|
|
|
- if (stu__tok != p) return 0;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- return 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__demand(int p)
|
|
|
|
-{
|
|
|
|
- if (stu__accept(p)) return 1;
|
|
|
|
- return stu__err("Didn't find expected stu__tok");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__demandv(int p, stua_obj *val)
|
|
|
|
-{
|
|
|
|
- if (stu__tok == p || p==0) {
|
|
|
|
- *val = stu__tokval;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- return 1;
|
|
|
|
- } else
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__expr(int p);
|
|
|
|
-int stu__nexpr(int p) { stu__nexttoken(); return stu__expr(p); }
|
|
|
|
-static int stu__statements(int once, int as);
|
|
|
|
-
|
|
|
|
-static int stu__parse_if(void) // parse both ST_if and ST_elseif
|
|
|
|
-{
|
|
|
|
- int b,c,a;
|
|
|
|
- a = stu__nexpr(1); if (!a) return 0;
|
|
|
|
- if (!stu__demand(ST_then)) return stu__err("expecting THEN");
|
|
|
|
- b = stu__statements(0,0); if (!b) return 0;
|
|
|
|
- if (b == 1) b = -1;
|
|
|
|
-
|
|
|
|
- if (stu__tok == ST_elseif) {
|
|
|
|
- return stu__parse_if();
|
|
|
|
- } else if (stu__accept(ST_else)) {
|
|
|
|
- c = stu__statements(0,0); if (!c) return 0;
|
|
|
|
- if (!stu__demand(ST_end)) return stu__err("expecting END after else clause");
|
|
|
|
- return stu__cc4(ST_else, a, b, c);
|
|
|
|
- } else {
|
|
|
|
- if (!stu__demand(ST_end)) return stu__err("expecting END in if statement");
|
|
|
|
- return stu__cc3(ST_if, a, b);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int stu__varinit(int z, int in_globals)
|
|
|
|
-{
|
|
|
|
- int a,b;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- while (stu__demandv(ST_id, &b)) {
|
|
|
|
- if (!stb_idict_add(stu__pfunc.locals, b, 1))
|
|
|
|
- if (!in_globals) return stu__err("Redefined variable %s.", stu__pw(b)->ptr);
|
|
|
|
- if (stu__accept('=')) {
|
|
|
|
- a = stu__expr(1); if (!a) return 0;
|
|
|
|
- } else
|
|
|
|
- a = stu__cdv(stua_nil);
|
|
|
|
- z = stu__seq(z, stu__cc3(ST_var, stu__cdv(b), a));
|
|
|
|
- if (!stu__accept(',')) break;
|
|
|
|
- }
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__compile_unary(int z, int outparm, int require_inparm)
|
|
|
|
-{
|
|
|
|
- int op = stu__tok, a, b;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- if (outparm) {
|
|
|
|
- if (require_inparm || (stu__tok && stu__tok != ST_end && stu__tok != ST_else && stu__tok != ST_elseif && stu__tok !=';')) {
|
|
|
|
- a = stu__expr(1); if (!a) return 0;
|
|
|
|
- } else
|
|
|
|
- a = stu__cdv(stua_nil);
|
|
|
|
- b = stu__cc2(op, a);
|
|
|
|
- } else
|
|
|
|
- b = stu__cc1(op);
|
|
|
|
- return stu__seq(z,b);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__assign(void)
|
|
|
|
-{
|
|
|
|
- int z;
|
|
|
|
- stu__accept(ST_let);
|
|
|
|
- z = stu__expr(1); if (!z) return 0;
|
|
|
|
- if (stu__accept('=')) {
|
|
|
|
- int y,p = (z >= 0 ? stu__pfunc.code[z] : 0);
|
|
|
|
- if (z < 0 || (p != ST_id && p != '[')) return stu__err("Invalid lvalue in assignment");
|
|
|
|
- y = stu__assign(); if (!y) return 0;
|
|
|
|
- z = stu__cc3('=', z, y);
|
|
|
|
- }
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__statements(int once, int stop_while)
|
|
|
|
-{
|
|
|
|
- int a,b, c, z=0;
|
|
|
|
- for(;;) {
|
|
|
|
- switch (stu__tok) {
|
|
|
|
- case ST_if : a = stu__parse_if(); if (!a) return 0;
|
|
|
|
- z = stu__seq(z, a);
|
|
|
|
- break;
|
|
|
|
- case ST_while : if (stop_while) return (z ? z:1);
|
|
|
|
- a = stu__nexpr(1); if (!a) return 0;
|
|
|
|
- if (stu__accept(ST_as)) c = stu__statements(0,0); else c = 0;
|
|
|
|
- if (!stu__demand(ST_do)) return stu__err("expecting DO");
|
|
|
|
- b = stu__statements(0,0); if (!b) return 0;
|
|
|
|
- if (!stu__demand(ST_end)) return stu__err("expecting END");
|
|
|
|
- if (b == 1) b = -1;
|
|
|
|
- z = stu__seq(z, stu__cc4(ST_while, a, b, c));
|
|
|
|
- break;
|
|
|
|
- case ST_repeat : stu__nexttoken();
|
|
|
|
- c = stu__statements(0,1); if (!c) return 0;
|
|
|
|
- if (!stu__demand(ST_while)) return stu__err("expecting WHILE");
|
|
|
|
- a = stu__expr(1); if (!a) return 0;
|
|
|
|
- if (!stu__demand(ST_do)) return stu__err("expecting DO");
|
|
|
|
- b = stu__statements(0,0); if (!b) return 0;
|
|
|
|
- if (!stu__demand(ST_end)) return stu__err("expecting END");
|
|
|
|
- if (b == 1) b = -1;
|
|
|
|
- z = stu__seq(z, stu__cc4(ST_as, a, b, c));
|
|
|
|
- break;
|
|
|
|
- case ST_catch : a = stu__nexpr(1); if (!a) return 0;
|
|
|
|
- z = stu__seq(z, stu__cc2(ST_catch, a));
|
|
|
|
- break;
|
|
|
|
- case ST_var : z = stu__varinit(z,0); break;
|
|
|
|
- case ST_return : z = stu__compile_unary(z,1,1); break;
|
|
|
|
- case ST_continue:z = stu__compile_unary(z,0,0); break;
|
|
|
|
- case ST_break : z = stu__compile_unary(z,1,0); break;
|
|
|
|
- case ST_into : if (z == 0 && !once) return stu__err("=> cannot be first statement in block");
|
|
|
|
- a = stu__nexpr(99);
|
|
|
|
- b = (a >= 0? stu__pfunc.code[a] : 0);
|
|
|
|
- if (a < 0 || (b != ST_id && b != '[')) return stu__err("Invalid lvalue on right side of =>");
|
|
|
|
- z = stu__cc3('=', a, z);
|
|
|
|
- break;
|
|
|
|
- default : if (stu__end[stu__tok]) return once ? 0 : (z ? z:1);
|
|
|
|
- a = stu__assign(); if (!a) return 0;
|
|
|
|
- stu__accept(';');
|
|
|
|
- if (stu__tok && !stu__end[stu__tok]) {
|
|
|
|
- if (a < 0)
|
|
|
|
- return stu__err("Constant has no effect");
|
|
|
|
- if (stu__pfunc.code[a] != '(' && stu__pfunc.code[a] != '=')
|
|
|
|
- return stu__err("Expression has no effect");
|
|
|
|
- }
|
|
|
|
- z = stu__seq(z, a);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (!z) return 0;
|
|
|
|
- stu__accept(';');
|
|
|
|
- if (once && stu__tok != ST_into) return z;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__postexpr(int z, int p);
|
|
|
|
-static int stu__dictdef(int end, int *count)
|
|
|
|
-{
|
|
|
|
- int z,n=0,i,flags=0;
|
|
|
|
- short *dict=NULL;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- while (stu__tok != end) {
|
|
|
|
- if (stu__tok == ST_id) {
|
|
|
|
- stua_obj id = stu__tokval;
|
|
|
|
- stu__nexttoken();
|
|
|
|
- if (stu__tok == '=') {
|
|
|
|
- flags |= 1;
|
|
|
|
- stb_arr_push(dict, stu__cdv(id));
|
|
|
|
- z = stu__nexpr(1); if (!z) return 0;
|
|
|
|
- } else {
|
|
|
|
- z = stu__cc2(ST_id, stu__cdv(id));
|
|
|
|
- z = stu__postexpr(z,1); if (!z) return 0;
|
|
|
|
- flags |= 2;
|
|
|
|
- stb_arr_push(dict, stu__cdv(stu__makeint(n++)));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- z = stu__expr(1); if (!z) return 0;
|
|
|
|
- flags |= 2;
|
|
|
|
- stb_arr_push(dict, stu__cdv(stu__makeint(n++)));
|
|
|
|
- }
|
|
|
|
- if (end != ')' && flags == 3) { z=stu__err("can't mix initialized and uninitialized defs"); goto done;}
|
|
|
|
- stb_arr_push(dict, z);
|
|
|
|
- if (!stu__accept(',')) break;
|
|
|
|
- }
|
|
|
|
- if (!stu__demand(end))
|
|
|
|
- return stu__err(end == ')' ? "Expecting ) at end of function call"
|
|
|
|
- : "Expecting } at end of dictionary definition");
|
|
|
|
- z = stu__cc2('{', stb_arr_len(dict)/2);
|
|
|
|
- for (i=0; i < stb_arr_len(dict); ++i)
|
|
|
|
- stu__cc(dict[i]);
|
|
|
|
- if (count) *count = n;
|
|
|
|
-done:
|
|
|
|
- stb_arr_free(dict);
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__comp_id(void)
|
|
|
|
-{
|
|
|
|
- int z,d;
|
|
|
|
- d = stu__nonlocal_id(stu__tokval);
|
|
|
|
- if (d == 0)
|
|
|
|
- return z = stu__cc2(ST_id, stu__cdt());
|
|
|
|
- // access a non-local frame by naming it with the appropriate int
|
|
|
|
- assert(d < 0);
|
|
|
|
- z = stu__cdv(d); // relative frame # is the 'variable' in our local frame
|
|
|
|
- z = stu__cc2(ST_id, z); // now access that dictionary
|
|
|
|
- return stu__cc3('[', z, stu__cdt()); // now access the variable from that dir
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static stua_obj stu__funcdef(stua_obj *id, stua_obj *func);
|
|
|
|
-static int stu__expr(int p)
|
|
|
|
-{
|
|
|
|
- int z;
|
|
|
|
- // unary
|
|
|
|
- switch (stu__tok) {
|
|
|
|
- case ST_number: z = stu__cdt(); break;
|
|
|
|
- case ST_string: z = stu__cdt(); break; // @TODO - string concatenation like C
|
|
|
|
- case ST_id : z = stu__comp_id(); break;
|
|
|
|
- case ST__frame: z = stu__cc1(ST__frame); stu__nexttoken(); break;
|
|
|
|
- case ST_func : z = stu__funcdef(NULL,NULL); break;
|
|
|
|
- case ST_if : z = stu__parse_if(); break;
|
|
|
|
- case ST_nil : z = stu__cdv(stua_nil); stu__nexttoken(); break;
|
|
|
|
- case ST_true : z = stu__cdv(stua_true); stu__nexttoken(); break;
|
|
|
|
- case ST_false : z = stu__cdv(stua_false); stu__nexttoken(); break;
|
|
|
|
- case '-' : z = stu__nexpr(99); if (z) z=stu__cc2(STU__negate,z); else return z; break;
|
|
|
|
- case '!' : z = stu__nexpr(99); if (z) z=stu__cc2('!',z); else return z; break;
|
|
|
|
- case '~' : z = stu__nexpr(99); if (z) z=stu__cc2('~',z); else return z; break;
|
|
|
|
- case '{' : z = stu__dictdef('}', NULL); break;
|
|
|
|
- default : return stu__err("Unexpected token");
|
|
|
|
- case '(' : stu__nexttoken(); z = stu__statements(0,0); if (!stu__demand(')')) return stu__err("Expecting )");
|
|
|
|
- }
|
|
|
|
- return stu__postexpr(z,p);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__postexpr(int z, int p)
|
|
|
|
-{
|
|
|
|
- int q;
|
|
|
|
- // postfix
|
|
|
|
- while (stu__tok == '(' || stu__tok == '[' || stu__tok == '.') {
|
|
|
|
- if (stu__accept('.')) {
|
|
|
|
- // MUST be followed by a plain identifier! use [] for other stuff
|
|
|
|
- if (stu__tok != ST_id) return stu__err("Must follow . with plain name; try [] instead");
|
|
|
|
- z = stu__cc3('[', z, stu__cdv(stu__tokval));
|
|
|
|
- stu__nexttoken();
|
|
|
|
- } else if (stu__accept('[')) {
|
|
|
|
- while (stu__tok != ']') {
|
|
|
|
- int r = stu__expr(1); if (!r) return 0;
|
|
|
|
- z = stu__cc3('[', z, r);
|
|
|
|
- if (!stu__accept(',')) break;
|
|
|
|
- }
|
|
|
|
- if (!stu__demand(']')) return stu__err("Expecting ]");
|
|
|
|
- } else {
|
|
|
|
- int n, p = stu__dictdef(')', &n); if (!p) return 0;
|
|
|
|
- #if 0 // this is incorrect!
|
|
|
|
- if (z > 0 && stu__pfunc.code[z] == ST_id) {
|
|
|
|
- stua_obj q = stu__get(stu__globaldict, stu__pfunc.data[-stu__pfunc.code[z+1]-1], stua_nil);
|
|
|
|
- if (stu__checkt(STU___function, q))
|
|
|
|
- if ((stu__pf(q))->num_param != n)
|
|
|
|
- return stu__err("Incorrect number of parameters");
|
|
|
|
- }
|
|
|
|
- #endif
|
|
|
|
- z = stu__cc3('(', z, p);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // binop - this implementation taken from lcc
|
|
|
|
- for (q=stu__prec[stu__tok]; q >= p; --q) {
|
|
|
|
- while (stu__prec[stu__tok] == q) {
|
|
|
|
- int o = stu__tok, y = stu__nexpr(p+1); if (!y) return 0;
|
|
|
|
- z = stu__cc3(o,z,y);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static stua_obj stu__finish_func(stua_obj *param, int start)
|
|
|
|
-{
|
|
|
|
- int n, size;
|
|
|
|
- stu__func *f = (stu__func *) malloc(sizeof(*f));
|
|
|
|
- f->closure_source = 0;
|
|
|
|
- f->num_param = stb_arr_len(param);
|
|
|
|
- f->param = (int *) stb_copy(param, f->num_param * sizeof(*f->param));
|
|
|
|
- size = stb_arr_storage(stu__pfunc.code) + stb_arr_storage(stu__pfunc.data) + sizeof(*f) + 8;
|
|
|
|
- f->f.store = malloc(stb_arr_storage(stu__pfunc.code) + stb_arr_storage(stu__pfunc.data));
|
|
|
|
- f->code = (short *) ((char *) f->f.store + stb_arr_storage(stu__pfunc.data));
|
|
|
|
- memcpy(f->code, stu__pfunc.code, stb_arr_storage(stu__pfunc.code));
|
|
|
|
- f->code[1] = start;
|
|
|
|
- f->code[0] = stb_arr_len(stu__pfunc.data);
|
|
|
|
- for (n=0; n < f->code[0]; ++n)
|
|
|
|
- ((stua_obj *) f->code)[-1-n] = stu__pfunc.data[n];
|
|
|
|
- return stu__makeobj(STU___function, f, size, 0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__funcdef(stua_obj *id, stua_obj *result)
|
|
|
|
-{
|
|
|
|
- int n,z=0,i,q;
|
|
|
|
- stua_obj *param = NULL;
|
|
|
|
- short *nonlocal;
|
|
|
|
- stua_obj v,f=stua_nil;
|
|
|
|
- assert(stu__tok == ST_func);
|
|
|
|
- stu__nexttoken();
|
|
|
|
- if (id) {
|
|
|
|
- if (!stu__demandv(ST_id, id)) return stu__err("Expecting function name");
|
|
|
|
- } else
|
|
|
|
- stu__accept(ST_id);
|
|
|
|
- if (!stu__demand('(')) return stu__err("Expecting ( for function parameter");
|
|
|
|
- stu__push_func_comp();
|
|
|
|
- while (stu__tok != ')') {
|
|
|
|
- if (!stu__demandv(ST_id, &v)) { z=stu__err("Expecting parameter name"); goto done; }
|
|
|
|
- stb_idict_add(stu__pfunc.locals, v, 1);
|
|
|
|
- if (stu__tok == '=') {
|
|
|
|
- n = stu__nexpr(1); if (!n) { z=0; goto done; }
|
|
|
|
- z = stu__seq(z, stu__cc3(STU__defaultparm, stu__cdv(v), n));
|
|
|
|
- } else
|
|
|
|
- stb_arr_push(param, v);
|
|
|
|
- if (!stu__accept(',')) break;
|
|
|
|
- }
|
|
|
|
- if (!stu__demand(')')) { z=stu__err("Expecting ) at end of parameter list"); goto done; }
|
|
|
|
- n = stu__statements(0,0); if (!n) { z=0; goto done; }
|
|
|
|
- if (!stu__demand(ST_end)) { z=stu__err("Expecting END at end of function"); goto done; }
|
|
|
|
- if (n == 1) n = 0;
|
|
|
|
- n = stu__seq(z,n);
|
|
|
|
- f = stu__finish_func(param, n);
|
|
|
|
- if (result) { *result = f; z=1; stu__pop_func_comp(); }
|
|
|
|
- else {
|
|
|
|
- nonlocal = stu__pfunc.non_local_refs;
|
|
|
|
- stu__pfunc.non_local_refs = NULL;
|
|
|
|
- stu__pop_func_comp();
|
|
|
|
- z = stu__cdv(f);
|
|
|
|
- if (nonlocal) { // build a closure with references to the needed frames
|
|
|
|
- short *initcode = NULL;
|
|
|
|
- for (i=0; i < stb_arr_len(nonlocal); ++i) {
|
|
|
|
- int k = nonlocal[i], p;
|
|
|
|
- stb_arr_push(initcode, stu__cdv(k));
|
|
|
|
- if (k == -1) p = stu__cc1(ST__frame);
|
|
|
|
- else { p = stu__cdv(stu__makeint(k+1)); p = stu__cc2(ST_id, p); }
|
|
|
|
- stb_arr_push(initcode, p);
|
|
|
|
- }
|
|
|
|
- q = stu__cc2('{', stb_arr_len(nonlocal));
|
|
|
|
- for (i=0; i < stb_arr_len(initcode); ++i)
|
|
|
|
- stu__cc(initcode[i]);
|
|
|
|
- z = stu__cc3('+', z, q);
|
|
|
|
- stb_arr_free(initcode);
|
|
|
|
- }
|
|
|
|
- stb_arr_free(nonlocal);
|
|
|
|
- }
|
|
|
|
-done:
|
|
|
|
- stb_arr_free(param);
|
|
|
|
- if (!z) stu__pop_func_comp();
|
|
|
|
- return z;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stu__compile_global_scope(void)
|
|
|
|
-{
|
|
|
|
- stua_obj o;
|
|
|
|
- int z=0;
|
|
|
|
-
|
|
|
|
- stu__push_func_comp();
|
|
|
|
- while (stu__tok != 0) {
|
|
|
|
- if (stu__tok == ST_func) {
|
|
|
|
- stua_obj id, f;
|
|
|
|
- if (!stu__funcdef(&id,&f))
|
|
|
|
- goto error;
|
|
|
|
- stu__set(stu__globaldict, id, f);
|
|
|
|
- } else if (stu__tok == ST_var) {
|
|
|
|
- z = stu__varinit(z,1); if (!z) goto error;
|
|
|
|
- } else {
|
|
|
|
- int y = stu__statements(1,0); if (!y) goto error;
|
|
|
|
- z = stu__seq(z,y);
|
|
|
|
- }
|
|
|
|
- stu__accept(';');
|
|
|
|
- }
|
|
|
|
- o = stu__finish_func(NULL, z);
|
|
|
|
- stu__pop_func_comp();
|
|
|
|
-
|
|
|
|
- o = stu__funceval(o, stua_globals); // initialize stu__globaldict
|
|
|
|
- if (stu__flow == FLOW_error)
|
|
|
|
- printf("Error: %s\n", ((stu__wrapper *) stu__ptr(stu__flow_val))->ptr);
|
|
|
|
- return 1;
|
|
|
|
-error:
|
|
|
|
- stu__pop_func_comp();
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-stua_obj stu__myprint(stua_dict *context)
|
|
|
|
-{
|
|
|
|
- stua_obj x = stu__get(context, stua_string("x"), stua_nil);
|
|
|
|
- if ((x & 1) == stu__float_tag) printf("%f", stu__getfloat(x));
|
|
|
|
- else if (stu__tag(x) == stu__int_tag) printf("%d", stu__int(x));
|
|
|
|
- else {
|
|
|
|
- stu__wrapper *s = stu__pw(x);
|
|
|
|
- if (s->type == STU___string || s->type == STU___error)
|
|
|
|
- printf("%s", s->ptr);
|
|
|
|
- else if (s->type == STU___dict) printf("{{dictionary}}");
|
|
|
|
- else if (s->type == STU___function) printf("[[function]]");
|
|
|
|
- else
|
|
|
|
- printf("[[ERROR:%s]]", s->ptr);
|
|
|
|
- }
|
|
|
|
- return x;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void stua_init(void)
|
|
|
|
-{
|
|
|
|
- if (!stu__globaldict) {
|
|
|
|
- int i;
|
|
|
|
- stua_obj s;
|
|
|
|
- stu__func *f;
|
|
|
|
-
|
|
|
|
- stu__prec[ST_and] = stu__prec[ST_or] = 1;
|
|
|
|
- stu__prec[ST_eq ] = stu__prec[ST_ne] = stu__prec[ST_le] =
|
|
|
|
- stu__prec[ST_ge] = stu__prec['>' ] = stu__prec['<'] = 2;
|
|
|
|
- stu__prec[':'] = 3;
|
|
|
|
- stu__prec['&'] = stu__prec['|'] = stu__prec['^'] = 4;
|
|
|
|
- stu__prec['+'] = stu__prec['-'] = 5;
|
|
|
|
- stu__prec['*'] = stu__prec['/'] = stu__prec['%'] =
|
|
|
|
- stu__prec[ST_shl]= stu__prec[ST_shr]= stu__prec[ST_shru]= 6;
|
|
|
|
-
|
|
|
|
- stu__end[')'] = stu__end[ST_end] = stu__end[ST_else] = 1;
|
|
|
|
- stu__end[ST_do] = stu__end[ST_elseif] = 1;
|
|
|
|
-
|
|
|
|
- stu__float_init();
|
|
|
|
- stu__lex_matcher = stb_lex_matcher();
|
|
|
|
- for (i=0; i < sizeof(stu__lexemes)/sizeof(stu__lexemes[0]); ++i)
|
|
|
|
- stb_lex_item(stu__lex_matcher, stu__lexemes[i].regex, stu__lexemes[i].stu__tok);
|
|
|
|
-
|
|
|
|
- stu__globaldict = stb_idict_new_size(64);
|
|
|
|
- stua_globals = stu__makeobj(STU___dict, stu__globaldict, 0,0);
|
|
|
|
- stu__strings = stb_sdict_new(0);
|
|
|
|
-
|
|
|
|
- stu__curbuf = stu__bufstart = "func _print(x) end\n"
|
|
|
|
- "func print()\n var x=0 while _frame[x] != nil as x=x+1 do _print(_frame[x]) end end\n";
|
|
|
|
- stu__nexttoken();
|
|
|
|
- if (!stu__compile_global_scope())
|
|
|
|
- printf("Compile error in line %d: %s\n", stu__comp_err_line, stu__comp_err_str);
|
|
|
|
-
|
|
|
|
- s = stu__get(stu__globaldict, stua_string("_print"), stua_nil);
|
|
|
|
- if (stu__tag(s) == stu__ptr_tag && stu__ptr(s)->type == STU___function) {
|
|
|
|
- f = stu__pf(s);
|
|
|
|
- free(f->f.store);
|
|
|
|
- f->closure_source = 4;
|
|
|
|
- f->f.func = stu__myprint;
|
|
|
|
- f->code = NULL;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void stua_uninit(void)
|
|
|
|
-{
|
|
|
|
- if (stu__globaldict) {
|
|
|
|
- stb_idict_remove_all(stu__globaldict);
|
|
|
|
- stb_arr_setlen(stu__gc_root_stack, 0);
|
|
|
|
- stua_gc(1);
|
|
|
|
- stb_idict_destroy(stu__globaldict);
|
|
|
|
- stb_sdict_delete(stu__strings);
|
|
|
|
- stb_matcher_free(stu__lex_matcher);
|
|
|
|
- stb_arr_free(stu__gc_ptrlist);
|
|
|
|
- stb_arr_free(func_stack);
|
|
|
|
- stb_arr_free(stu__gc_root_stack);
|
|
|
|
- stu__globaldict = NULL;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void stua_run_script(char *s)
|
|
|
|
-{
|
|
|
|
- stua_init();
|
|
|
|
-
|
|
|
|
- stu__curbuf = stu__bufstart = s;
|
|
|
|
- stu__nexttoken();
|
|
|
|
-
|
|
|
|
- stu__flow = FLOW_normal;
|
|
|
|
-
|
|
|
|
- if (!stu__compile_global_scope())
|
|
|
|
- printf("Compile error in line %d: %s\n", stu__comp_err_line, stu__comp_err_str);
|
|
|
|
- stua_gc(1);
|
|
|
|
-}
|
|
|
|
-#endif // STB_DEFINE
|
|
|
|
-#endif // STB_STUA
|
|
|
|
-
|
|
|
|
#undef STB_EXTERN
|
|
#undef STB_EXTERN
|
|
#endif // STB_INCLUDE_STB_H
|
|
#endif // STB_INCLUDE_STB_H
|
|
|
|
|