瀏覽代碼

Sol Part 56: Asymptotically equivalent to a unicorn!

https://derpicdn.net/img/download/2014/7/6/668821.png
master
Graham Northup 5 年之前
父節點
當前提交
e6f565383f
簽署人: grissess GPG Key ID: 5D000E6F539376FB
  1. 48
      README.md
  2. 11
      ast.h
  3. 28
      astprint.c
  4. 36
      builtins.c
  5. 247
      lex.yy.c
  6. 5570
      parser.output
  7. 871
      parser.tab.c
  8. 21
      parser.tab.h
  9. 97
      parser.y
  10. 52
      runtime.c
  11. 24
      sol.h
  12. 10
      state.c
  13. 3
      tests/_lib.sol
  14. 10
      tests/lang_bparen.sol
  15. 17
      tests/lang_variadic.sol
  16. 4
      tokenizer.lex

48
README.md

@ -21,31 +21,30 @@ while a < 10 do
end
-- "Pythonic" for loops; any expression can be used, so long as it
-- returns a function that will be called until it returns StopIteration
-- returns a function that will be called until it returns None
for i in range(10) do print(i) end -- Note Lua-ish keyword delimiting
-- "func" seems like a good compromise between "def" and "function" :D
-- (This is a currying add function)
func outer(a)
func inner(b)
return func inner(b, a=a)
return a+b
end
inner.closure.a = a
return inner
end
-- Alternatively...
outer = lambda(a) lambda(b, a=a) a + b end end
-- (...and this is an iterator)
func count(j)
inner = func () -- Note: function definitions are expressions, like in Lua
inner = func (i = 0, max = j) -- Function definitions are expressions, like in Lua
if i >= max then
return StopIteration
return -- If no value is given, None is implied
else
i += 1
return i - 1
end
end
inner.closure.i = 0
inner.closure.max = j
return inner
end
@ -59,7 +58,7 @@ print({a=1, b=2, ["c"]=3, [4]=5, ["with more spaces"]={health=100, speed=2}})
object = {__index = func(obj, idx) print("Index", obj, "with", idx); return idx end,
__setindex = func(obj, idx, val) print("Set index", idx, "of", obj, "to", val) end,
__call = func(obj, arg1, arg2) print("Called", obj, "with args", arg1, arg2); return arg1+arg2 end}
-- No metatables, but __index can be assigned to another map, which has nearly the same effect :D
-- No metatables, but __index can be assigned to another map, which has nearly the same effect
-- Lua-ish error handling
func bad(x)
@ -68,10 +67,11 @@ func bad(x)
end
res = try(bad, {}) -- Returns 1 (or true), "thing"
res = try(bad, None) -- Reurns 0 (or false), "Undefined method" -- you can't index None :P
res = try(bad, None) -- Reurns 0 (or false), "Undefined method" -- you can't index None
res = try(bad) -- Also fails; unbound arguments are assigned to None by default
res = try(error, 1234) -- Fails, returning [0, 1234] -- errors can be any object
-- Full suppport for self-modifying code, and invoking the compiler :D
-- Full suppport for self-modifying code, and invoking the compiler
func a() return 0 end
func b() return 2 end
@ -83,7 +83,7 @@ b.stmt = temp
code = parse('print("Hi!"); return 4')
a.stmt = code
b.stmt = code
-- a and b now return 4
-- a and b now return 4 (and print "Hi!")
parse('print("Good day!")')() -- Does the thing; shortcut is "exec"
q = parse('8 + 13 * 2').stmtlist[0].expr() -- Returns the value (should be...34?); shortcut "eval"
@ -97,7 +97,7 @@ That's a really brief taste; you can look at the `test.sol` file for a larger co
Buiding/Installation
--------------------
First off, *you should clone this repository with --recurive* if you want to get the submodules in one go. If you've already cloned it, don't worry; just run this:
First off, *you should clone this repository with --recursive* if you want to get the submodules in one go. If you've already cloned it, don't worry; just run this:
```
git submodule init
@ -106,13 +106,7 @@ git submodule update
This should pull in the requisite build dependencies. (For more on this, see git's documentation on [Cloning a Project with Submodules](http://git-scm.com/book/en/v2/Git-Tools-Submodules#Cloning-a-Project-with-Submodules).)
Because makefiles aren't hipster enough, the build system for Sol presently consists of exclusively .sh files, and it's presently hardcoded to use gcc, and include debugging symbols (this will be fixed eventually). If you're on any POSIX-y platform, you should be able to clone this repo and run:
./build.sh
This should build the executable runtime `sol` in the working directory (it is explicitly ignored, and won't be committed to the repo).
If, at any time, you change the grammar definitions (`tokenizer.lex`, `parser.y`), you will need to run `./buildgrammar.sh` first. This will build the appropriate parser and tokenizer C files, which will be built into the executable. (Building these files will require Flex and Bison; consult your platform's documentation on acquiring them.)
A typical `make` should suffice to build the project. There is no `make install` yet, as there's no agreed-upon location for its support files. The executable runtime `sol` should be in the working directory (it is explicitly ignored, and won't be committed to the repo).
Running
-------
@ -138,7 +132,9 @@ Todo
Most of what needs to be done is addressing these issues:
**Sol is a mess.** At present, there are numerous memory leaks (as checked with valgrind) due to some particularly relaxed refcount handling, as well as problems with the parse trees containing pointer clones, causing double frees when trying to free the trees proper (which I don't do because crashes--there goes several kilobytes of memory already...). The objects themselves are a bit non-optimal, just as well; a new integer is created every time one needs to be returned, such as during every arithmetic operation, even if they're transient (such as partial evaluations of large expressions). The map is especially abhorrent--indexing it does a linear scan and calls the `cmp` operation on each key. A `hash` operation will probably be implemented to help with this.
**Sol leaks memory.** As confirmed with Valgrind (running memcheck), a normal Sol run loses some objects. A great deal of work has been invested in finding and fixing these bugs, but they remain elusive. If you have any insight into something which causes Sol to leak, please file an issue!
**Sol is slow.** Sol pressures the heap pretty heavily by creating a new object ("returning a new reference") for most operations. At least one bottleneck was addressed with the "icache" (integer cache), which speeds up comparisons significantly, but Sol nonetheless rapidly creates, destroys, and copies strings in very critical execution paths. The map implementation is particularly egregious, and is currently an associative array.
**The API is unstable.** There will definitely be some changes to the API, mostly to *help* with integration. At present, some operations on behalf of Sol embedders are a little messy and require intrinsic knowledge of the language specifics. The refcounting scheme, as mentioned previously, requires about four lines of code per function that should be a one-liner, for example.
@ -154,16 +150,6 @@ After those (but more practically, with them), the following will be coming:
**Code consolidation and refactoring.** There are quite a few instances of repetitive code that need to be addressed, and can be refactored out into functions in their own right. This should also improve usability.
**Redefinition of print.** `ob_print` is a debug utility meant to be used from GDB, so it intentionally was not designed with state access in mind. `sol_ops_t.tostring` was always intended to be what generated object representations, and these need to be updated to match how `ob_print` does it (but better).
**Proper stream/file support.** Currently, printing happens to `stdout` implicitly through `printf`. By adding an object abstraction layer, Sol code can redirect output (like Python's `sys.stdout`). This will be especially useful in environments where `stdout` is invisible or obscured, like Windows GUI applications.
**Optimization.** As mentioned above, a few critical operations are quite slow. This will probably require some higher-caliber data structures than the ones I have now, most of which will probably be relegated to DSL for code reuse.
**Makefiles.** Being a non-conformist is fun, but will probably hurt in the long run :P
**Documentation.** More thorough documentation will be coming soon, I promise.
Contributing
------------

11
ast.h

@ -129,8 +129,15 @@ typedef struct tag_identlist_node {
} identlist_node;
typedef struct {
char *name;
identlist_node *args;
identlist_node *clkeys;
exprlist_node *clvalues;
char *rest;
} paramlist_node;
typedef struct {
char *name;
paramlist_node *params;
stmt_node *body;
} funcdecl_node;
@ -257,6 +264,7 @@ stmtlist_node *stl_copy(stmtlist_node *);
exprlist_node *exl_copy(exprlist_node *);
assoclist_node *asl_copy(assoclist_node *);
identlist_node *idl_copy(identlist_node *);
paramlist_node *pl_copy(paramlist_node *);
void st_free(stmt_node *);
void ex_free(expr_node *);
@ -264,6 +272,7 @@ void stl_free(stmtlist_node *);
void exl_free(exprlist_node *);
void asl_free(assoclist_node *);
void idl_free(identlist_node *);
void pl_free(paramlist_node *);
void st_print(sol_state_t *, stmt_node *);
void ex_print(sol_state_t *, expr_node *);

28
astprint.c

@ -273,11 +273,29 @@ void prex(sol_state_t *state, expr_node *node, int lev) {
prlev(state, lev, "FuncDecl:");
lev++;
prlev(state, lev, "Name: %s", node->funcdecl->name);
prlev(state, lev, "Args:");
curi = node->funcdecl->args;
while(curi && curi->ident) {
prlev(state, lev + 1, curi->ident);
curi = curi->next;
prlev(state, lev, "Params:");
if(!node->funcdecl->params) {
prlev(state, lev + 1, "<NULL>");
} else {
prlev(state, lev + 1, "Args:");
curi = node->funcdecl->params->args;
while(curi && curi->ident) {
prlev(state, lev + 2, curi->ident);
curi = curi->next;
}
prlev(state, lev + 1, "ClKeys:");
curi = node->funcdecl->params->clkeys;
while(curi && curi->ident) {
prlev(state, lev + 2, curi->ident);
curi = curi->next;
}
prlev(state, lev + 1, "ClValues:");
cure = node->funcdecl->params->clvalues;
while(cure && cure->expr) {
prex(state, cure->expr, lev + 2);
cure = cure->next;
}
prlev(state, lev + 1, "Rest: %s", node->funcdecl->params->rest);
}
prlev(state, lev, "Body:");
prst(state, node->funcdecl->body, lev + 1);

36
builtins.c

@ -126,6 +126,17 @@ sol_object_t *sol_f_try(sol_state_t *state, sol_object_t *args) {
return ls;
}
sol_object_t *sol_f_apply(sol_state_t *state, sol_object_t *args) {
sol_object_t *func = sol_list_get_index(state, args, 0), *arglist = sol_list_get_index(state, args, 1), *rest = sol_list_sublist(state, args, 2);
sol_list_append(state, rest, arglist);
sol_obj_free(arglist);
sol_list_insert(state, rest, 0, func);
sol_object_t *res = CALL_METHOD(state, func, call, rest);
sol_obj_free(rest);
sol_obj_free(func);
return res;
}
sol_object_t *sol_f_error(sol_state_t *state, sol_object_t *args) {
sol_object_t *arg = sol_list_get_index(state, args, 0), *res;
res = sol_set_error(state, arg);
@ -522,7 +533,7 @@ sol_object_t *sol_f_iter_str(sol_state_t *state, sol_object_t *args) {
sol_obj_free(index);
sol_obj_free(obj);
sol_obj_free(local);
return sol_incref(state->StopIteration);
return sol_incref(state->None);
}
temp[0] = obj->str[((size_t) index->buffer)];
res = sol_new_string(state, temp);
@ -546,7 +557,7 @@ sol_object_t *sol_f_iter_list(sol_state_t *state, sol_object_t *args) {
sol_obj_free(index);
sol_obj_free(obj);
sol_obj_free(local);
return sol_incref(state->StopIteration);
return sol_incref(state->None);
}
res = sol_incref(AS_OBJ(dsl_seq_iter_at(index->buffer)));
dsl_seq_iter_next(index->buffer);
@ -568,7 +579,7 @@ sol_object_t *sol_f_iter_map(sol_state_t *state, sol_object_t *args) {
sol_obj_free(index);
sol_obj_free(obj);
sol_obj_free(local);
return sol_incref(state->StopIteration);
return sol_incref(state->None);
}
res = sol_incref(AS_OBJ(dsl_seq_iter_at(index->buffer))->key);
dsl_seq_iter_next(index->buffer);
@ -1773,7 +1784,7 @@ sol_object_t *sol_f_astnode_index(sol_state_t *state, sol_object_t *args) {
res = sol_new_string(state, (expr->funcdecl->name ? expr->funcdecl->name : ""));
} else if(sol_string_eq(state, str, "args")) {
res = sol_new_list(state);
curi = expr->funcdecl->args;
curi = expr->funcdecl->params ? expr->funcdecl->params->args : NULL;
while(curi) {
sol_list_insert(state, res, i++, sol_new_string(state, curi->ident));
curi = curi->next;
@ -2117,11 +2128,18 @@ sol_object_t *sol_f_astnode_setindex(sol_state_t *state, sol_object_t *args) {
expr->funcdecl->name = strdup(sval->str);
sol_obj_free(sval);
} else if(sol_string_eq(state, str, "args") && sol_is_list(val)) {
idl_free(expr->funcdecl->args);
if(!expr->funcdecl->params) {
expr->funcdecl->params = malloc(sizeof(paramlist_node));
expr->funcdecl->params->args = NULL;
expr->funcdecl->params->clkeys = NULL;
expr->funcdecl->params->clvalues = NULL;
expr->funcdecl->params->rest = NULL;
}
idl_free(expr->funcdecl->params->args);
len = sol_list_len(state, val);
if(len > 0) {
curi = malloc(sizeof(identlist_node));
expr->funcdecl->args = curi;
expr->funcdecl->params->args = curi;
for(i = 0; i < len; i++) {
sval = sol_cast_string(state, sol_list_get_index(state, val, i));
curi->ident = strdup(sval->str);
@ -2130,15 +2148,15 @@ sol_object_t *sol_f_astnode_setindex(sol_state_t *state, sol_object_t *args) {
curi = malloc(sizeof(identlist_node));
previ->next = curi;
}
if(expr->funcdecl->args == curi) {
expr->funcdecl->args = NULL;
if(expr->funcdecl->params->args == curi) {
expr->funcdecl->params->args = NULL;
}
free(curi);
if(previ) {
previ->next = NULL;
}
} else {
expr->funcdecl->args = NULL;
expr->funcdecl->params->args = NULL;
}
} else if(sol_string_eq(state, str, "body") && sol_is_aststmt(val)) {
st_free(expr->funcdecl->body);

247
lex.yy.c

@ -360,8 +360,8 @@ static void yynoreturn yy_fatal_error (yyconst char* msg );
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
#define YY_NUM_RULES 72
#define YY_END_OF_BUFFER 73
#define YY_NUM_RULES 73
#define YY_END_OF_BUFFER 74
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@ -369,24 +369,25 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_accept[148] =
static yyconst flex_int16_t yy_accept[152] =
{ 0,
0, 0, 73, 72, 71, 34, 72, 67, 23, 26,
72, 61, 62, 21, 19, 66, 20, 63, 22, 2,
64, 65, 51, 40, 52, 69, 69, 69, 69, 59,
60, 28, 69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 57, 27, 58, 29,
71, 0, 50, 0, 3, 30, 46, 0, 4, 25,
43, 41, 0, 42, 44, 1, 2, 56, 53, 49,
54, 55, 69, 69, 69, 69, 48, 69, 69, 69,
11, 69, 69, 69, 69, 69, 5, 10, 69, 69,
69, 33, 69, 69, 69, 69, 47, 32, 68, 45,
0, 70, 1, 69, 69, 69, 31, 69, 69, 69,
17, 69, 9, 69, 69, 24, 35, 69, 69, 69,
69, 69, 18, 37, 69, 69, 7, 69, 12, 69,
69, 6, 36, 69, 39, 15, 69, 38, 69, 69,
8, 69, 13, 14, 69, 16, 0
0, 0, 74, 73, 72, 34, 73, 68, 23, 26,
73, 62, 63, 21, 19, 67, 20, 64, 22, 2,
65, 66, 51, 40, 52, 70, 70, 70, 70, 59,
60, 28, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 57, 27, 58, 29,
72, 61, 72, 0, 50, 0, 3, 30, 46, 0,
4, 25, 43, 41, 0, 42, 44, 1, 2, 56,
53, 49, 54, 55, 70, 70, 70, 70, 48, 70,
70, 70, 11, 70, 70, 70, 70, 70, 5, 10,
70, 70, 70, 33, 70, 70, 70, 70, 47, 32,
72, 61, 69, 45, 0, 71, 1, 70, 70, 70,
31, 70, 70, 70, 17, 70, 9, 70, 70, 24,
35, 70, 70, 70, 70, 70, 18, 37, 70, 70,
7, 70, 12, 70, 70, 6, 36, 70, 39, 15,
70, 38, 70, 70, 8, 70, 13, 14, 70, 16,
0
} ;
static yyconst YY_CHAR yy_ec[256] =
@ -431,102 +432,104 @@ static yyconst YY_CHAR yy_meta[53] =
1, 1
} ;
static yyconst flex_uint16_t yy_base[152] =
static yyconst flex_uint16_t yy_base[156] =
{ 0,
0, 0, 161, 162, 51, 51, 155, 162, 162, 48,
150, 162, 162, 45, 136, 162, 43, 162, 135, 43,
162, 162, 41, 134, 46, 0, 124, 111, 109, 162,
162, 130, 109, 106, 106, 105, 24, 29, 35, 116,
103, 102, 100, 108, 37, 105, 162, 53, 162, 162,
76, 137, 162, 135, 162, 162, 162, 130, 162, 116,
162, 162, 134, 162, 162, 118, 64, 162, 162, 162,
162, 162, 0, 95, 92, 86, 162, 98, 96, 88,
0, 84, 94, 87, 82, 83, 0, 0, 83, 89,
76, 0, 75, 85, 72, 80, 162, 162, 162, 162,
114, 162, 98, 70, 79, 78, 0, 81, 65, 75,
0, 57, 0, 68, 68, 0, 0, 52, 56, 62,
56, 60, 0, 0, 55, 55, 0, 57, 0, 57,
46, 0, 0, 54, 0, 0, 46, 0, 56, 44,
0, 38, 0, 0, 49, 0, 162, 103, 105, 81,
107
0, 51, 169, 170, 52, 52, 163, 170, 170, 49,
158, 170, 170, 46, 144, 170, 44, 170, 143, 44,
170, 170, 42, 142, 47, 0, 132, 119, 117, 170,
170, 138, 117, 114, 114, 113, 25, 41, 37, 124,
111, 110, 108, 116, 38, 113, 170, 54, 170, 170,
75, 170, 78, 145, 170, 143, 170, 170, 170, 138,
170, 124, 170, 170, 142, 170, 170, 126, 71, 170,
170, 170, 170, 170, 0, 103, 100, 94, 170, 106,
104, 96, 0, 92, 102, 95, 90, 91, 0, 0,
91, 97, 84, 0, 83, 93, 80, 88, 170, 170,
88, 170, 170, 170, 122, 170, 106, 78, 87, 86,
0, 89, 73, 83, 0, 72, 0, 83, 83, 0,
0, 67, 71, 77, 71, 68, 0, 0, 63, 63,
0, 65, 0, 65, 53, 0, 0, 61, 0, 0,
53, 0, 63, 51, 0, 45, 0, 0, 51, 0,
170, 104, 106, 81, 108
} ;
static yyconst flex_int16_t yy_def[152] =
static yyconst flex_int16_t yy_def[156] =
{ 0,
147, 1, 147, 147, 147, 147, 148, 147, 147, 147,
149, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 150, 150, 150, 150, 147,
147, 147, 150, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 147, 147, 147, 147,
147, 147, 147, 148, 147, 147, 147, 149, 147, 147,
147, 147, 151, 147, 147, 147, 147, 147, 147, 147,
147, 147, 150, 150, 150, 150, 147, 150, 150, 150,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 147, 147, 147, 147,
151, 147, 147, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
150, 150, 150, 150, 150, 150, 0, 147, 147, 147,
147
151, 1, 151, 151, 151, 151, 152, 151, 151, 151,
153, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 154, 154, 154, 154, 151,
151, 151, 154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 151, 151, 151, 151,
151, 151, 151, 151, 151, 152, 151, 151, 151, 153,
151, 151, 151, 151, 155, 151, 151, 151, 151, 151,
151, 151, 151, 151, 154, 154, 154, 154, 151, 154,
154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154, 151, 151,
151, 151, 151, 151, 155, 151, 151, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
0, 151, 151, 151, 151
} ;
static yyconst flex_uint16_t yy_nxt[215] =
static yyconst flex_uint16_t yy_nxt[223] =
{ 0,
4, 5, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 26, 39, 26, 40,
41, 42, 43, 44, 26, 45, 26, 46, 47, 48,
49, 50, 51, 51, 52, 56, 60, 63, 66, 84,
67, 68, 69, 82, 64, 83, 61, 71, 72, 57,
87, 85, 53, 94, 97, 86, 88, 51, 51, 66,
95, 67, 73, 146, 145, 144, 143, 142, 141, 140,
139, 138, 137, 136, 135, 134, 133, 132, 131, 130,
129, 128, 98, 54, 54, 58, 58, 101, 101, 127,
126, 125, 124, 123, 122, 103, 102, 121, 120, 119,
118, 117, 116, 115, 114, 113, 112, 111, 110, 109,
108, 107, 106, 105, 104, 103, 102, 100, 59, 55,
99, 96, 93, 92, 91, 90, 89, 81, 80, 79,
78, 77, 76, 75, 74, 70, 65, 62, 59, 55,
147, 3, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147
49, 50, 51, 53, 53, 54, 58, 62, 65, 68,
52, 69, 70, 71, 84, 66, 85, 63, 73, 74,
59, 86, 89, 55, 96, 99, 101, 53, 90, 53,
53, 97, 75, 87, 102, 150, 68, 88, 69, 101,
53, 149, 148, 147, 146, 145, 144, 102, 143, 142,
141, 140, 139, 100, 56, 56, 60, 60, 105, 105,
138, 137, 136, 135, 134, 133, 132, 131, 130, 129,
128, 127, 126, 107, 106, 125, 124, 123, 122, 121,
120, 119, 118, 117, 116, 115, 114, 113, 112, 111,
110, 109, 108, 107, 106, 104, 61, 57, 103, 98,
95, 94, 93, 92, 91, 83, 82, 81, 80, 79,
78, 77, 76, 72, 67, 64, 61, 57, 151, 3,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151
} ;
static yyconst flex_int16_t yy_chk[215] =
static yyconst flex_int16_t yy_chk[223] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 5, 5, 6, 10, 14, 17, 20, 38,
20, 23, 23, 37, 17, 37, 14, 25, 25, 10,
39, 38, 6, 45, 48, 38, 39, 51, 51, 67,
45, 67, 150, 145, 142, 140, 139, 137, 134, 131,
130, 128, 126, 125, 122, 121, 120, 119, 118, 115,
114, 112, 48, 148, 148, 149, 149, 151, 151, 110,
109, 108, 106, 105, 104, 103, 101, 96, 95, 94,
93, 91, 90, 89, 86, 85, 84, 83, 82, 80,
79, 78, 76, 75, 74, 66, 63, 60, 58, 54,
52, 46, 44, 43, 42, 41, 40, 36, 35, 34,
33, 32, 29, 28, 27, 24, 19, 15, 11, 7,
3, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147
1, 1, 2, 5, 5, 6, 10, 14, 17, 20,
2, 20, 23, 23, 37, 17, 37, 14, 25, 25,
10, 38, 39, 6, 45, 48, 51, 51, 39, 53,
53, 45, 154, 38, 51, 149, 69, 38, 69, 101,
101, 146, 144, 143, 141, 138, 135, 101, 134, 132,
130, 129, 126, 48, 152, 152, 153, 153, 155, 155,
125, 124, 123, 122, 119, 118, 116, 114, 113, 112,
110, 109, 108, 107, 105, 98, 97, 96, 95, 93,
92, 91, 88, 87, 86, 85, 84, 82, 81, 80,
78, 77, 76, 68, 65, 62, 60, 56, 54, 46,
44, 43, 42, 41, 40, 36, 35, 34, 33, 32,
29, 28, 27, 24, 19, 15, 11, 7, 3, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
151, 151
} ;
static yy_state_type yy_last_accepting_state;
@ -618,7 +621,7 @@ static void update_loc(YYLTYPE *yylloc, char *yytext){
<STRING>. { str_putc(*yytext); }
*/
#line 622 "lex.yy.c"
#line 625 "lex.yy.c"
#define INITIAL 0
@ -809,6 +812,9 @@ extern int yylex \
#endif
#define YY_RULE_SETUP \
if ( yyleng > 0 ) \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
(yytext[yyleng - 1] == '\n'); \
YY_USER_ACTION
/** The main scanner function which does all the work.
@ -857,7 +863,7 @@ YY_DECL
#line 85 "tokenizer.lex"
#line 861 "lex.yy.c"
#line 867 "lex.yy.c"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@ -872,6 +878,7 @@ YY_DECL
yy_bp = yy_cp;
yy_current_state = (yy_start);
yy_current_state += YY_AT_BOL();
yy_match:
do
{
@ -884,13 +891,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 148 )
if ( yy_current_state >= 152 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
++yy_cp;
}
while ( yy_base[yy_current_state] != 162 );
while ( yy_base[yy_current_state] != 170 );
yy_find_action:
yy_act = yy_accept[yy_current_state];
@ -1219,66 +1226,71 @@ YY_RULE_SETUP
case 61:
YY_RULE_SETUP
#line 207 "tokenizer.lex"
{ return LPAREN; }
{ return BLPAREN; } /* "Breaking" paren, not allowed to introduce a call_expr */
YY_BREAK
case 62:
YY_RULE_SETUP
#line 209 "tokenizer.lex"
{ return RPAREN; }
{ return LPAREN; }
YY_BREAK
case 63:
YY_RULE_SETUP
#line 211 "tokenizer.lex"
{ return DOT; }
{ return RPAREN; }
YY_BREAK
case 64:
YY_RULE_SETUP
#line 213 "tokenizer.lex"
{ return COLON; }
{ return DOT; }
YY_BREAK
case 65:
YY_RULE_SETUP
#line 215 "tokenizer.lex"
{ return SEMICOLON; }
{ return COLON; }
YY_BREAK
case 66:
YY_RULE_SETUP
#line 217 "tokenizer.lex"
{ return COMMA; }
{ return SEMICOLON; }
YY_BREAK
case 67:
YY_RULE_SETUP
#line 219 "tokenizer.lex"
{ return POUND; }
{ return COMMA; }
YY_BREAK
case 68:
YY_RULE_SETUP
#line 221 "tokenizer.lex"
{ return TBANG; }
{ return POUND; }
YY_BREAK
case 69:
YY_RULE_SETUP
#line 223 "tokenizer.lex"
{ *yylval = (void *) strdup(yytext); return IDENT; }
{ return TBANG; }
YY_BREAK
case 70:
/* rule 70 can match eol */
YY_RULE_SETUP
#line 225 "tokenizer.lex"
/* Skip comments */
{ *yylval = (void *) strdup(yytext); return IDENT; }
YY_BREAK
case 71:
/* rule 71 can match eol */
YY_RULE_SETUP
#line 227 "tokenizer.lex"
/* Skip whitespace */
/* Skip comments */
YY_BREAK
case 72:
/* rule 72 can match eol */
YY_RULE_SETUP
#line 229 "tokenizer.lex"
/* Skip whitespace */
YY_BREAK
case 73:
YY_RULE_SETUP
#line 231 "tokenizer.lex"
ECHO;
YY_BREAK
#line 1282 "lex.yy.c"
#line 1294 "lex.yy.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
@ -1559,6 +1571,7 @@ static int yy_get_next_buffer (void)
char *yy_cp;
yy_current_state = (yy_start);
yy_current_state += YY_AT_BOL();
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
@ -1571,7 +1584,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 148 )
if ( yy_current_state >= 152 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
@ -1599,11 +1612,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 148 )
if ( yy_current_state >= 152 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
yy_is_jam = (yy_current_state == 147);
yy_is_jam = (yy_current_state == 151);
return yy_is_jam ? 0 : yy_current_state;
}
@ -1719,6 +1732,8 @@ static int yy_get_next_buffer (void)
*(yy_c_buf_p) = '\0'; /* preserve yytext */
(yy_hold_char) = *++(yy_c_buf_p);
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
return c;
}
#endif /* ifndef YY_NO_INPUT */
@ -2279,7 +2294,7 @@ void yyfree (void * ptr )
#define YYTABLES_NAME "yytables"
#line 229 "tokenizer.lex"
#line 231 "tokenizer.lex"

5570
parser.output
文件差異過大導致無法顯示
查看文件

871
parser.tab.c
文件差異過大導致無法顯示
查看文件

21
parser.tab.h

@ -95,16 +95,17 @@ extern int yydebug;
LSHIFT = 305,
LBRACE = 306,
RBRACE = 307,
LPAREN = 308,
RPAREN = 309,
LBRACKET = 310,
RBRACKET = 311,
DOT = 312,
COLON = 313,
SEMICOLON = 314,
COMMA = 315,
POUND = 316,
TBANG = 317
BLPAREN = 308,
LPAREN = 309,
RPAREN = 310,
LBRACKET = 311,
RBRACKET = 312,
DOT = 313,
COLON = 314,
SEMICOLON = 315,
COMMA = 316,
POUND = 317,
TBANG = 318
};
#endif

97
parser.y

@ -20,7 +20,7 @@
%token PLUS MINUS STAR SLASH PERCENT DSTAR BAND BOR BXOR BNOT LAND LOR LNOT
%token ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNSTAR ASSIGNSLASH ASSIGNDSTAR ASSIGNBAND ASSIGNBOR ASSIGNBXOR
%token EQUAL NEQUAL LESS GREATER LESSEQ GREATEREQ RSHIFT LSHIFT
%token LBRACE RBRACE LPAREN RPAREN LBRACKET RBRACKET DOT COLON SEMICOLON COMMA POUND
%token LBRACE RBRACE BLPAREN LPAREN RPAREN LBRACKET RBRACKET DOT COLON SEMICOLON COMMA POUND
%token TBANG
%parse-param {stmt_node **program}
@ -370,28 +370,28 @@ call_expr:
;
funcdecl_expr:
FUNC IDENT LPAREN ident_list RPAREN stmt_list END {
FUNC IDENT any_lparen param_list RPAREN stmt_list END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = $2;
AS_EX($$)->funcdecl->args = $4;
AS_EX($$)->funcdecl->params = $4;
AS_EX($$)->funcdecl->body = $6;
}
| FUNC LPAREN ident_list RPAREN stmt_list END {
| FUNC any_lparen param_list RPAREN stmt_list END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = NULL;
AS_EX($$)->funcdecl->args = $3;
AS_EX($$)->funcdecl->params = $3;
AS_EX($$)->funcdecl->body = $5;
}
| LAMBDA LPAREN ident_list RPAREN expr END {
| LAMBDA any_lparen param_list RPAREN expr END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = NULL;
AS_EX($$)->funcdecl->args = $3;
AS_EX($$)->funcdecl->params = $3;
AS_EX($$)->funcdecl->body = NEW_ST();
AS_EX($$)->funcdecl->body->type = ST_RET;
AS_EX($$)->funcdecl->body->ret = NEW(ret_node);
@ -452,7 +452,7 @@ gen_expr:
;
paren_expr:
LPAREN expr RPAREN { $$ = $2; }
any_lparen expr RPAREN { $$ = $2; }
;
expr_list:
@ -493,6 +493,82 @@ ident_list:
}
;
param_list:
/*empty*/ { $$ = NULL; }
| param_list IDENT ASSIGN expr {
paramlist_node *pl = $1;
identlist_node *curk;
exprlist_node *curv;
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
}
if(!pl->clkeys) {
pl->clkeys = NEW(identlist_node);
curk = pl->clkeys;
pl->clvalues = NEW(exprlist_node);
curv = pl->clvalues;
} else {
curk = pl->clkeys;
curv = pl->clvalues;
while(curk->next) {
curk = curk->next;
curv = curv->next;
}
curk->next = NEW(identlist_node);
curk = curk->next;
curv->next = NEW(exprlist_node);
curv = curv->next;
}
curk->ident = $2;
curk->next = NULL;
curv->expr = $4;
curv->next = NULL;
$$ = pl;
}
| param_list STAR IDENT {
paramlist_node *pl = $1;
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
}
pl-> rest = $3;
$$ = pl;
}
| param_list IDENT {
paramlist_node *pl = $1;
identlist_node *cura;
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
}
if(!pl->args) {
pl->args = NEW(identlist_node);
cura = pl->args;
} else {
cura = pl->args;
while(cura->next) {
cura = cura->next;
}
cura->next = NEW(identlist_node);
cura = cura->next;
}
cura->ident = $2;
cura->next = NULL;
$$ = pl;
}
| param_list COMMA { $$ = $1; }
;
assoc_list:
/*empty*/ { $$ = NULL; }
| assoc_item {
@ -529,6 +605,11 @@ assoc_item:
}
;
any_lparen:
LPAREN
| BLPAREN
;
%%
// TODO

52
runtime.c

@ -177,7 +177,7 @@ expr_node *ex_copy(expr_node *old) {
} else {
new->funcdecl->name = NULL;
}
new->funcdecl->args = idl_copy(old->funcdecl->args);
new->funcdecl->params = pl_copy(old->funcdecl->params);
new->funcdecl->body = st_copy(old->funcdecl->body);
break;
@ -288,6 +288,17 @@ identlist_node *idl_copy(identlist_node *old) {
return new;
}
paramlist_node *pl_copy(paramlist_node *old) {
paramlist_node *new;
if(!old) return NULL;
new = NEW(paramlist_node);
new->args = idl_copy(old->args);
new->clkeys = idl_copy(old->clkeys);
new->clvalues = exl_copy(old->clvalues);
new->rest = old->rest ? strdup(old->rest) : NULL;
return new;
}
void ex_free(expr_node *);
void st_free(stmt_node *stmt) {
@ -401,7 +412,7 @@ void ex_free(expr_node *expr) {
case EX_FUNCDECL:
free(expr->funcdecl->name);
st_free(expr->funcdecl->body);
idl_free(expr->funcdecl->args);
pl_free(expr->funcdecl->params);
free(expr->funcdecl);
break;
@ -466,11 +477,20 @@ void idl_free(identlist_node *list) {
}
}
void pl_free(paramlist_node *list) {
if(!list) return;
idl_free(list->args);
idl_free(list->clkeys);
exl_free(list->clvalues);
if(list->rest) free(list->rest);
}
#define ERR_CHECK(state) do { if(sol_has_error(state)) longjmp(jmp, 1); } while(0)
sol_object_t *sol_eval_inner(sol_state_t *state, expr_node *expr, jmp_buf jmp) {
sol_object_t *res, *left, *right, *lint, *rint, *value, *list, *vint, *iter, *item;
exprlist_node *cure;
assoclist_node *cura;
identlist_node *curi;
if(!expr) {
return sol_set_error_string(state, "Evaluate NULL expression");
}
@ -761,8 +781,19 @@ sol_object_t *sol_eval_inner(sol_state_t *state, expr_node *expr, jmp_buf jmp) {
break;
case EX_FUNCDECL:
res = sol_new_func(state, expr->funcdecl->args, expr->funcdecl->body, expr->funcdecl->name);
res = sol_new_func(state, expr->funcdecl->params ? expr->funcdecl->params->args : NULL, expr->funcdecl->body, expr->funcdecl->name);
ERR_CHECK(state);
if(expr->funcdecl->params) {
res->rest = expr->funcdecl->params->rest ? strdup(expr->funcdecl->params->rest) : NULL;
curi = expr->funcdecl->params->clkeys;
cure = expr->funcdecl->params->clvalues;
while(curi) {
sol_map_borrow_name(state, res->closure, curi->ident, sol_eval_inner(state, cure->expr, jmp));
ERR_CHECK(state);
curi = curi->next;
cure = cure->next;
}
}
if(expr->funcdecl->name) {
sol_state_assign_l_name(state, expr->funcdecl->name, res);
ERR_CHECK(state);
@ -821,7 +852,7 @@ sol_object_t *sol_eval_inner(sol_state_t *state, expr_node *expr, jmp_buf jmp) {
iter = CALL_METHOD(state, value, iter, list);
sol_obj_free(list);
} else {
iter = value;
iter = sol_incref(value);
}
if(!iter->ops->call || iter->ops->call == sol_f_not_impl) {
sol_obj_free(sol_set_error_string(state, "Iterate over non-iterable"));
@ -832,12 +863,12 @@ sol_object_t *sol_eval_inner(sol_state_t *state, expr_node *expr, jmp_buf jmp) {
sol_list_insert(state, list, 1, value);
sol_list_insert(state, list, 2, sol_new_map(state));
item = CALL_METHOD(state, iter, call, list);
while(item != state->StopIteration) {
while(item != state->None) {
sol_state_assign_l_name(state, expr->iter->var, item);
sol_exec(state, expr->iter->loop);
sol_obj_free(item);
if(state->ret || state->sflag == SF_BREAKING || sol_has_error(state)) {
item = sol_incref(state->StopIteration);
item = sol_incref(state->None);
continue;
}
state->sflag = SF_NORMAL;
@ -937,6 +968,7 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
sol_object_t *res, *scope, *value, *key;
identlist_node *curi;
dsl_seq_iter *iter;
int argcnt = 0;
iter = dsl_new_seq_iter(args->seq);
if(!args || dsl_seq_iter_is_invalid(iter) || sol_is_none(state, args)) {
printf("WARNING: No parameters to function call (expecting function)\n");
@ -964,6 +996,14 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
}
sol_obj_free(key);
curi = curi->next;
argcnt++;
}
}
if(value->rest) {
if(argcnt < sol_list_len(state, args) - 1) {
sol_map_borrow_name(state, scope, value->rest, sol_list_sublist(state, args, argcnt + 1));
} else {
sol_map_borrow_name(state, scope, value->rest, sol_new_list(state));
}
}
if(value->fname) {

24
sol.h

@ -10,7 +10,7 @@
#include "dsl/dsl.h"
/** The version of the project, as made available through `debug.version`. */
#define VERSION "0.2a3"
#define VERSION "0.3a0"
/** The hexadecimal version of the project, formatted 0xAAIIRPP where:
*
* - AA is the two-digit major version
@ -20,7 +20,7 @@
*
* This value is guaranteed to only monotonically increase by revision.
*/
#define HEXVER 0x0002A03
#define HEXVER 0x0003A00
#ifndef SOL_ICACHE_MIN
/** The smallest integer to cache. */
@ -156,7 +156,7 @@ typedef struct {
*/
typedef enum {
/** The singlet type--the type of None, as well as StopIteration and OutOfMemory. It is also the "default" type. */
/** The singlet type--the type of None, as well as OutOfMemory. It is also the "default" type. */
SOL_SINGLET,
/** The integer type, implemented as a long. */
SOL_INTEGER,
@ -332,6 +332,8 @@ typedef struct sol_tag_object_t {
struct sol_tag_object_t *udata;
/** For `SOL_FUNCTION`, the name of the function if it was not declared anonymously (otherwise NULL). */
char *fname;
/* For `SOL_FUNCTION`, the name of an argument that receives extra parameters as a list (otherwise NULL). */
char *rest;
};
/** For `SOL_CFUNCTION`, the C function pointer. */
sol_cfunc_t cfunc;
@ -390,9 +392,8 @@ typedef struct sol_tag_state_t {
sol_object_t *stderr; ///< Standard error stream object (type `SOL_STREAM`)
sol_object_t *None; ///< The all-important `None` object
sol_object_t *OutOfMemory; ///< The semi-important `OutOfMemory` object
sol_object_t *StopIteration; ///< The somewhat-important `StopIteration` object
sol_ops_t NullOps; ///< Basic, initialized operations. Not used by any extant object type.
sol_ops_t SingletOps; ///< Operations on singlets (`None`, `OutOfMemory`, `StopIteration`, etc.)
sol_ops_t SingletOps; ///< Operations on singlets (`None`, `OutOfMemory`, etc.)
sol_ops_t IntOps; ///< Operations on integers
sol_ops_t FloatOps; ///< Operations on floats
sol_ops_t StringOps; ///< Operations on strings
@ -426,7 +427,7 @@ typedef struct sol_tag_state_t {
* This should be called once (and only once!) for every state; it does the important
* work of ensuring that the state is ready to execute code, including:
*
* - Creating the initial singlet values `None`, `OutOfMemory`, and `StopIteration`,
* - Creating the initial singlet values `None` and `OutOfMemory`,
* - Creating and populating the operations on all internally-defined object types.
* - Initializing all built-in modules and methods.
* - Running any "init.sol" files.
@ -676,6 +677,8 @@ sol_object_t *sol_f_tofloat(sol_state_t *, sol_object_t *);
sol_object_t *sol_f_tostring(sol_state_t *, sol_object_t *);
/// Built-in function try
sol_object_t *sol_f_try(sol_state_t *, sol_object_t *);
/// Built-in function apply
sol_object_t *sol_f_apply(sol_state_t *, sol_object_t *);
/// Built-in function error
sol_object_t *sol_f_error(sol_state_t *, sol_object_t *);
/// Built-in function type
@ -871,7 +874,12 @@ sol_object_t *sol_f_stream_open(sol_state_t *, sol_object_t *);
* internal routines are special-cased for certain singlets.
*/
sol_object_t *sol_new_singlet(sol_state_t *, const char *);
/** Creates a new integer object with the specified value. */
/** Creates a new integer object with the specified value.
*
* If `icache_bypass` is off and this value is within [`SOL_ICACHE_MIN`,
* `SOL_ICACHE_MAX`] (as set at compile time), a new reference to a cached
* integer in the state is returned instead.
*/
sol_object_t *sol_new_int(sol_state_t *, long);
/** Creates a new float object with the specified value. */
sol_object_t *sol_new_float(sol_state_t *, double);
@ -924,7 +932,7 @@ sol_object_t *sol_list_copy(sol_state_t *, sol_object_t *);
/** Internal routine to return a new Sol list equivalent to its input up to the
* first n elements. */
sol_object_t *sol_list_truncate(sol_state_t *, sol_object_t *, int);
/** Utility routine to insert at the end of a Sol list. */
/** Utility routine to concatenate Sol lists. */
void sol_list_append(sol_state_t *, sol_object_t *, sol_object_t *);
/** Utility macro to insert an object at the beginning of a Sol list. */
#define sol_list_push(st, ls, obj) sol_list_insert(st, ls, 0, obj);

10
state.c

@ -52,9 +52,6 @@ int sol_state_init(sol_state_t *state) {
if(!(state->OutOfMemory = sol_new_singlet(state, "OutOfMemory"))) {
goto cleanup;
}
if(!(state->StopIteration = sol_new_singlet(state, "StopIteration"))) {
goto cleanup;
}
// We can now use the normal error reporting mechanism, now
// that errors are distinguishable. Set that up now.
@ -234,13 +231,14 @@ int sol_state_init(sol_state_t *state) {
state->stdout = sol_new_stream(state, stdout, MODE_WRITE);
state->stderr = sol_new_stream(state, stderr, MODE_WRITE);
// I'm going to buffer all of these together because I can.
// NB: None is actually a keyword in the language--it doesn't need to be a
// global (see parser.y)
sol_map_borrow_name(state, globals, "OutOfMemory", state->OutOfMemory);
sol_map_borrow_name(state, globals, "StopIteration", state->StopIteration);
sol_map_borrow_name(state, globals, "toint", sol_new_cfunc(state, sol_f_toint));
sol_map_borrow_name(state, globals, "tofloat", sol_new_cfunc(state, sol_f_tofloat));
sol_map_borrow_name(state, globals, "tostring", sol_new_cfunc(state, sol_f_tostring));
sol_map_borrow_name(state, globals, "try", sol_new_cfunc(state, sol_f_try));
sol_map_borrow_name(state, globals, "apply", sol_new_cfunc(state, sol_f_apply));
sol_map_borrow_name(state, globals, "error", sol_new_cfunc(state, sol_f_error));
sol_map_borrow_name(state, globals, "type", sol_new_cfunc(state, sol_f_type));
sol_map_borrow_name(state, globals, "prepr", sol_new_cfunc(state, sol_f_prepr));
@ -507,7 +505,6 @@ int sol_state_init(sol_state_t *state) {
cleanup:
sol_obj_free(state->None);
sol_obj_free(state->OutOfMemory);
sol_obj_free(state->StopIteration);
return 0;
}
@ -517,7 +514,6 @@ void sol_state_cleanup(sol_state_t *state) {
sol_obj_free(state->error);
sol_obj_free(state->None);
sol_obj_free(state->OutOfMemory);
sol_obj_free(state->StopIteration);
sol_obj_free(state->stdin);
sol_obj_free(state->stdout);
sol_obj_free(state->stderr);

3
tests/_lib.sol

@ -1,4 +1,4 @@
func assert(x, msg)
func assert(x, msg, _test_count = 0)
_test_count += 1
io.stdout:write('Test ' + tostring(_test_count) + ': ' + msg)
if !x then
@ -6,7 +6,6 @@ func assert(x, msg)
end
print("...passed")
end
assert.closure._test_count = 0
func assert_eq(x, y, msg)
assert(x == y, "equality: " + tostring(x) + " == " + tostring(y) + ": " + msg)

10
tests/lang_bparen.sol

@ -0,0 +1,10 @@
execfile("tests/_lib.sol")
func dont_call_me(a) error("dont_call_me was called: " + tostring(a)) end
('after func_decl') -- SHOULD be just a ST_EXPR
assert(1, "After funcdecl")
dont_call_me
('after st_expr')
assert(1, "After st_expr")

17
tests/lang_variadic.sol

@ -0,0 +1,17 @@
execfile("tests/_lib.sol")
func pop2(a, b, *l) return l end
assert_eq(pop2(1, 2, 3, 4, 5), [3, 4, 5], "rest param")
assert_eq(pop2(1, 2), [], "rest param (at affinity)")
assert_eq(pop2(), [], "rest param, (below affinity)")
func count(i = 0) i += 1; return i end
assert_eq(count(), 1, "count")
assert_eq(count(), 2, "count")
assert_eq(count(), 3, "count")
func rg(start, stop) return func(i=start, stop=stop) if i >= stop then return end; i += 1; return i - 1 end end
assert_eq(for i in rg(3, 10) do continue i end, [3, 4, 5, 6, 7, 8, 9], "iter over count")

4
tokenizer.lex

@ -204,7 +204,9 @@ None { return NONE; }
"]" { return RBRACKET; }
"(" { return LPAREN; }
^[ \t]*"(" { return BLPAREN; } /* "Breaking" paren, not allowed to introduce a call_expr */
"(" { return LPAREN; }
")" { return RPAREN; }

Loading…
取消
儲存