Quellcode durchsuchen

Sol Part 59: Now Useing You're Type's Good!

...with all due respect to Gary Bernhardt!
master
Graham Northup vor 5 Jahren
Ursprung
Commit
60b45ddcda
Signiert von: grissess GPG-Schlüssel-ID: 5D000E6F539376FB
  1. 4
      ast.h
  2. 20
      builtins.c
  3. 1023
      parser.output
  4. 756
      parser.tab.c
  5. 38
      parser.y
  6. 4
      programs/dump.sol
  7. 51
      runtime.c
  8. 13
      sol.h
  9. 40
      tests/lang_anno.sol

4
ast.h

@ -131,6 +131,7 @@ typedef struct tag_identlist_node {
typedef struct {
identlist_node *args;
exprlist_node *annos;
identlist_node *clkeys;
exprlist_node *clvalues;
char *rest;
@ -139,6 +140,7 @@ typedef struct {
typedef struct {
char *name;
paramlist_node *params;
expr_node *anno;
stmt_node *body;
} funcdecl_node;
@ -248,7 +250,7 @@ typedef struct tag_stmt_node {
res;\
})
sol_object_t *sol_new_func(sol_state_t *, identlist_node *, stmt_node *, char *);
sol_object_t *sol_new_func(sol_state_t *, identlist_node *, stmt_node *, char *, paramlist_node *, expr_node *);
sol_object_t *sol_new_stmtnode(sol_state_t *, stmt_node *);
sol_object_t *sol_new_exprnode(sol_state_t *, expr_node *);

20
builtins.c

@ -1489,7 +1489,11 @@ sol_object_t *sol_f_func_index(sol_state_t *state, sol_object_t *args) {
res = sol_map_get(state, func->udata, key);
} else {
if(sol_string_eq(state, key, "name")) {
res = sol_new_string(state, func->fname);
if(func->fname) {
res = sol_new_string(state, func->fname);
} else {
res = sol_incref(state->None);
}
} else if(sol_string_eq(state, key, "closure")) {
res = sol_incref(func->closure);
} else if(sol_string_eq(state, key, "udata")) {
@ -1503,6 +1507,14 @@ sol_object_t *sol_f_func_index(sol_state_t *state, sol_object_t *args) {
sol_list_insert(state, res, i++, sol_new_string(state, curi->ident));
curi = curi->next;
}
} else if(sol_string_eq(state, key, "rest")) {
if(func->rest) {
res = sol_new_string(state, func->rest);
} else {
res = sol_incref(state->None);
}
} else if(sol_string_eq(state, key, "annos")) {
res = sol_incref(func->annos);
} else {
res = sol_map_get(state, func->udata, key);
}
@ -1549,6 +1561,12 @@ sol_object_t *sol_f_func_setindex(sol_state_t *state, sol_object_t *args) {
prev->next = NULL;
if(cur == func->args) func->args = NULL;
free(cur);
} else if(sol_string_eq(state, key, "rest") && sol_is_string(val)) {
free(func->rest);
func->rest = strdup(val->str);
} else if(sol_string_eq(state, key, "annos") && sol_is_map(val)) {
sol_obj_free(func->annos);
func->annos = sol_incref(val);
} else {
sol_map_set(state, func->udata, key, val);
}

1023
parser.output
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen

756
parser.tab.c
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen

38
parser.y

@ -59,9 +59,9 @@ stmt:
expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_EXPR; AS_ST($$)->expr = $1; }
| RETURN expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_RET; AS_ST($$)->ret = NEW(ret_node); AS_ST($$)->ret->ret = $2; }
| RETURN { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_RET; AS_ST($$)->ret = NEW(ret_node); AS_ST($$)->ret->ret = NULL; }
| BREAK { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); }
| BREAK { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); AS_ST($$)->brk->val = NULL;}
| BREAK expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); AS_ST($$)->brk->val = $2; }
| CONTINUE { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); }
| CONTINUE { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); AS_ST($$)->cont->val = NULL; }
| CONTINUE expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); AS_ST($$)->cont->val = $2; }
| stmt SEMICOLON { $$ = $1; }
;
@ -361,32 +361,35 @@ call_expr:
;
funcdecl_expr:
FUNC IDENT any_lparen param_list RPAREN stmt_list END {
FUNC IDENT any_lparen param_list RPAREN maybe_anno stmt_list END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = $2;
AS_EX($$)->funcdecl->params = $4;
AS_EX($$)->funcdecl->body = $6;
AS_EX($$)->funcdecl->anno = $6;
AS_EX($$)->funcdecl->body = $7;
}
| FUNC any_lparen param_list RPAREN stmt_list END {
| FUNC any_lparen param_list RPAREN maybe_anno stmt_list END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = NULL;
AS_EX($$)->funcdecl->params = $3;
AS_EX($$)->funcdecl->body = $5;
AS_EX($$)->funcdecl->anno = $5;
AS_EX($$)->funcdecl->body = $6;
}
| LAMBDA any_lparen param_list RPAREN expr END {
| LAMBDA any_lparen param_list RPAREN maybe_anno expr END {
$$ = NEW_EX();
AS_EX($$)->type = EX_FUNCDECL;
AS_EX($$)->funcdecl = NEW(funcdecl_node);
AS_EX($$)->funcdecl->name = NULL;
AS_EX($$)->funcdecl->params = $3;
AS_EX($$)->funcdecl->anno = $5;
AS_EX($$)->funcdecl->body = NEW_ST();
AS_EX($$)->funcdecl->body->type = ST_RET;
AS_EX($$)->funcdecl->body->ret = NEW(ret_node);
AS_EX($$)->funcdecl->body->ret->ret = $5;
AS_EX($$)->funcdecl->body->ret->ret = $6;
}
| index_expr { $$ = $1; }
;
@ -493,6 +496,7 @@ param_list:
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->annos = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
@ -525,6 +529,7 @@ param_list:
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->annos = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
@ -532,12 +537,14 @@ param_list:
pl-> rest = $3;
$$ = pl;
}
| param_list IDENT {
| param_list IDENT maybe_anno {
paramlist_node *pl = $1;
identlist_node *cura;
exprlist_node *curn;
if(!pl) {
pl = NEW(paramlist_node);
pl->args = NULL;
pl->annos = NULL;
pl->clkeys = NULL;
pl->clvalues = NULL;
pl->rest = NULL;
@ -545,16 +552,24 @@ param_list:
if(!pl->args) {
pl->args = NEW(identlist_node);
cura = pl->args;
pl->annos = NEW(exprlist_node);
curn = pl->annos;
} else {
cura = pl->args;
curn = pl->annos;
while(cura->next) {
cura = cura->next;
curn = curn->next;
}
cura->next = NEW(identlist_node);
cura = cura->next;
curn->next = NEW(exprlist_node);
curn = curn->next;
}
cura->ident = $2;
cura->next = NULL;
curn->expr = $3;
curn->next = NULL;
$$ = pl;
}
| param_list COMMA { $$ = $1; }
@ -601,6 +616,11 @@ any_lparen:
| BLPAREN
;
maybe_anno:
COLON expr { $$ = $2; }
| /* empty */ { $$ = NULL; }
;
%%
// TODO

4
programs/dump.sol

@ -1,4 +1,4 @@
func dump(obj, indent)
func dump(obj, indent, seen = {})
if None == indent then
indent = 0
seen = {}
@ -38,5 +38,3 @@ func dump(obj, indent)
end
prepr(obj)
end
dump.closure.seen = {}

51
runtime.c

@ -179,6 +179,7 @@ expr_node *ex_copy(expr_node *old) {
new->funcdecl->name = NULL;
}
new->funcdecl->params = pl_copy(old->funcdecl->params);
new->funcdecl->anno = ex_copy(old->funcdecl->anno);
new->funcdecl->body = st_copy(old->funcdecl->body);
break;
@ -294,6 +295,7 @@ paramlist_node *pl_copy(paramlist_node *old) {
if(!old) return NULL;
new = NEW(paramlist_node);
new->args = idl_copy(old->args);
new->annos = exl_copy(old->annos);
new->clkeys = idl_copy(old->clkeys);
new->clvalues = exl_copy(old->clvalues);
new->rest = old->rest ? strdup(old->rest) : NULL;
@ -415,6 +417,7 @@ void ex_free(expr_node *expr) {
free(expr->funcdecl->name);
st_free(expr->funcdecl->body);
pl_free(expr->funcdecl->params);
ex_free(expr->funcdecl->anno);
free(expr->funcdecl);
break;
@ -482,6 +485,7 @@ void idl_free(identlist_node *list) {
void pl_free(paramlist_node *list) {
if(!list) return;
idl_free(list->args);
exl_free(list->annos);
idl_free(list->clkeys);
exl_free(list->clvalues);
if(list->rest) free(list->rest);
@ -801,21 +805,8 @@ 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->params ? expr->funcdecl->params->args : NULL, 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, expr->funcdecl->params, expr->funcdecl->anno);
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;
}
} else {
res->rest = NULL;
}
if(expr->funcdecl->name) {
sol_state_assign_l_name(state, expr->funcdecl->name, res);
ERR_CHECK(state);
@ -1047,15 +1038,45 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
return res;
}
sol_object_t *sol_new_func(sol_state_t *state, identlist_node *identlist, stmt_node *body, char *name) {
sol_object_t *sol_new_func(sol_state_t *state, identlist_node *identlist, stmt_node *body, char *name, paramlist_node *params, expr_node *func_anno) {
identlist_node *cura;
exprlist_node *cure;
sol_object_t *obj = sol_alloc_object(state);
obj->func = st_copy(body);
obj->args = idl_copy(identlist);
obj->fname = (name ? strdup(name) : NULL);
obj->closure = sol_new_map(state);
obj->udata = sol_new_map(state);
obj->rest = NULL;
obj->annos = sol_new_map(state);
obj->type = SOL_FUNCTION;
obj->ops = &(state->FuncOps);
if(params) {
obj->rest = params->rest ? strdup(params->rest) : NULL;
cura = params->clkeys;
cure = params->clvalues;
while(cura) {
sol_map_borrow_name(state, obj->closure, cura->ident, sol_eval(state, cure->expr));
if(sol_has_error(state)) {
sol_obj_free(obj);
return sol_incref(state->None);
}
cura = cura->next;
cure = cure->next;
}
cura = params->args;
cure = params->annos;
while(cura) {
if(cure->expr) {
sol_map_borrow_name(state, obj->annos, cura->ident, sol_eval(state, cure->expr));
}
cura = cura->next;
cure = cure->next;
}
}
if(func_anno) {
sol_map_borrow(state, obj->annos, obj, sol_eval(state, func_anno));
}
return obj;
}

13
sol.h

@ -10,7 +10,7 @@
#include "dsl/dsl.h"
/** The version of the project, as made available through `debug.version`. */
#define SOL_VERSION "0.3a1"
#define SOL_VERSION "0.3a2"
/** The hexadecimal version of the project, formatted 0xAAIIRPP where:
*
* - AA is the two-digit major version
@ -18,9 +18,12 @@
* - R is 'A' for alpha, 'B' for beta, 'C' for candidate, and 'F' for final
* - PP is the two-digit patch
*
* This value is guaranteed to only monotonically increase by revision.
* This value is guaranteed to only monotonically increase by revision, within
* the same line of development. In particular, features introduced in some
* version shall be available in all versions numerically greater than it
* (unless they are later deprecated or removed).
*/
#define SOL_HEXVER 0x0003A01
#define SOL_HEXVER 0x0003A02
#ifndef SOL_ICACHE_MIN
/** The smallest integer to cache. */
@ -332,8 +335,10 @@ 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). */
/** For `SOL_FUNCTION`, the name of an argument that receives extra parameters as a list (otherwise NULL). */
char *rest;
/** For `SOL_FUNCTION`, the map of annotations, with arguments by name, and the function itself by object. */
struct sol_tag_object_t *annos;
};
struct {
/** For `SOL_CFUNCTION`, the C function pointer. */

40
tests/lang_anno.sol

@ -0,0 +1,40 @@
execfile("tests/_lib.sol")
func f() end
assert_eq(0, #(f.annos), "no annotations")
func f(a: 12): -37 end
assert_eq(12, f.annos.a, "arg annotation (int)")
assert_eq(-37, f.annos[f], "func annotation (int)")
func f(a: "herp"): "derp" end
assert_eq("herp", f.annos.a, "arg annotation (str)")
assert_eq("derp", f.annos[f], "func annotation (str)")
func f(a: [1, 2], b: {c = [3, 4]}): {d = [12, "herps"]} return "asdfghjkl" end
assert_eq([1, 2], f.annos.a, "composite anno a")
assert_eq([3, 4], f.annos.b.c, "composite anno b")
assert_eq([12, "herps"], f.annos[f].d, "composite func anno")
assert_eq("asdfghjkl", f(), "correct call to anno func")
func tc(f)
return func(*args, f=f)
for idx in range(#args) do
argn = f.args[idx]
if None == argn then continue end
tspec = f.annos[argn]
if None == tspec then continue end
if type(args[idx]) != tspec then
error("Calling " + tostring(f.name)+ ": arg " + argn + " should be " + tspec)
end
end
return apply(f, args)
end
end
iadd = tc(lambda(a: 'int', b: 'int'): 'int' a + b end)
assert_eq(5, iadd(2, 3), "conformance")
assert_eq(0, try(iadd, 2.2, 3)[0], "float a")
assert_eq(0, try(iadd, 3, "string")[0], "str b")
assert_eq(0, try(iadd, [], {})[0], "composite a/b")
Laden…
Abbrechen
Speichern