Explorar el Código

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

...with all due respect to Gary Bernhardt!
master
Graham Northup hace 5 años
padre
commit
60b45ddcda
Firmado por: grissess ID de clave GPG: 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
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero

756
parser.tab.c
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero

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")
Cargando…
Cancelar
Guardar