Browse Source

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

...with all due respect to Gary Bernhardt!
Graham Northup 4 years ago
parent
commit
60b45ddcda
Signed by: Grissess <grissess@nexusg.org> GPG Key ID: 5D000E6F539376FB
9 changed files with 1145 additions and 804 deletions
  1. 3
    1
      ast.h
  2. 19
    1
      builtins.c
  3. 613
    410
      parser.output
  4. 395
    361
      parser.tab.c
  5. 29
    9
      parser.y
  6. 1
    3
      programs/dump.sol
  7. 36
    15
      runtime.c
  8. 9
    4
      sol.h
  9. 40
    0
      tests/lang_anno.sol

+ 3
- 1
ast.h View File

@@ -131,6 +131,7 @@ typedef struct tag_identlist_node {
131 131
 
132 132
 typedef struct {
133 133
 	identlist_node *args;
134
+	exprlist_node *annos;
134 135
 	identlist_node *clkeys;
135 136
 	exprlist_node *clvalues;
136 137
 	char *rest;
@@ -139,6 +140,7 @@ typedef struct {
139 140
 typedef struct {
140 141
 	char *name;
141 142
 	paramlist_node *params;
143
+	expr_node *anno;
142 144
 	stmt_node *body;
143 145
 } funcdecl_node;
144 146
 
@@ -248,7 +250,7 @@ typedef struct tag_stmt_node {
248 250
 		res;\
249 251
 })
250 252
 
251
-sol_object_t *sol_new_func(sol_state_t *, identlist_node *, stmt_node *, char *);
253
+sol_object_t *sol_new_func(sol_state_t *, identlist_node *, stmt_node *, char *, paramlist_node *, expr_node *);
252 254
 sol_object_t *sol_new_stmtnode(sol_state_t *, stmt_node *);
253 255
 sol_object_t *sol_new_exprnode(sol_state_t *, expr_node *);
254 256
 

+ 19
- 1
builtins.c View File

@@ -1489,7 +1489,11 @@ sol_object_t *sol_f_func_index(sol_state_t *state, sol_object_t *args) {
1489 1489
 		res = sol_map_get(state, func->udata, key);
1490 1490
 	} else {
1491 1491
 		if(sol_string_eq(state, key, "name")) {
1492
-			res = sol_new_string(state, func->fname);
1492
+			if(func->fname) {
1493
+				res = sol_new_string(state, func->fname);
1494
+			} else {
1495
+				res = sol_incref(state->None);
1496
+			}
1493 1497
 		} else if(sol_string_eq(state, key, "closure")) {
1494 1498
 			res = sol_incref(func->closure);
1495 1499
 		} 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) {
1503 1507
 				sol_list_insert(state, res, i++, sol_new_string(state, curi->ident));
1504 1508
 				curi = curi->next;
1505 1509
 			}
1510
+		} else if(sol_string_eq(state, key, "rest")) {
1511
+			if(func->rest) {
1512
+				res = sol_new_string(state, func->rest);
1513
+			} else {
1514
+				res = sol_incref(state->None);
1515
+			}
1516
+		} else if(sol_string_eq(state, key, "annos")) {
1517
+			res = sol_incref(func->annos);
1506 1518
 		} else {
1507 1519
 			res = sol_map_get(state, func->udata, key);
1508 1520
 		}
@@ -1549,6 +1561,12 @@ sol_object_t *sol_f_func_setindex(sol_state_t *state, sol_object_t *args) {
1549 1561
 		prev->next = NULL;
1550 1562
 		if(cur == func->args) func->args = NULL;
1551 1563
 		free(cur);
1564
+	} else if(sol_string_eq(state, key, "rest") && sol_is_string(val)) {
1565
+		free(func->rest);
1566
+		func->rest = strdup(val->str);
1567
+	} else if(sol_string_eq(state, key, "annos") && sol_is_map(val)) {
1568
+		sol_obj_free(func->annos);
1569
+		func->annos = sol_incref(val);
1552 1570
 	} else {
1553 1571
 		sol_map_set(state, func->udata, key, val);
1554 1572
 	}

+ 613
- 410
parser.output
File diff suppressed because it is too large
View File


+ 395
- 361
parser.tab.c
File diff suppressed because it is too large
View File


+ 29
- 9
parser.y View File

@@ -59,9 +59,9 @@ stmt:
59 59
   expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_EXPR; AS_ST($$)->expr = $1; }
60 60
 | RETURN expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_RET; AS_ST($$)->ret = NEW(ret_node); AS_ST($$)->ret->ret = $2; }
61 61
 | RETURN { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_RET; AS_ST($$)->ret = NEW(ret_node); AS_ST($$)->ret->ret = NULL; }
62
-| BREAK { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); }
62
+| BREAK { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); AS_ST($$)->brk->val = NULL;}
63 63
 | BREAK expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_BREAK; AS_ST($$)->brk = NEW(break_node); AS_ST($$)->brk->val = $2; }
64
-| CONTINUE { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); }
64
+| CONTINUE { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); AS_ST($$)->cont->val = NULL; }
65 65
 | CONTINUE expr { $$ = NEW_ST(); SET_LOC(AS_ST($$), @$); AS_ST($$)->type = ST_CONT; AS_ST($$)->cont = NEW(cont_node); AS_ST($$)->cont->val = $2; }
66 66
 | stmt SEMICOLON { $$ = $1; }
67 67
 ;
@@ -361,32 +361,35 @@ call_expr:
361 361
 ;
362 362
 
363 363
 funcdecl_expr:
364
-  FUNC IDENT any_lparen param_list RPAREN stmt_list END {
364
+  FUNC IDENT any_lparen param_list RPAREN maybe_anno stmt_list END {
365 365
 	$$ = NEW_EX();
366 366
 	AS_EX($$)->type = EX_FUNCDECL;
367 367
 	AS_EX($$)->funcdecl = NEW(funcdecl_node);
368 368
 	AS_EX($$)->funcdecl->name = $2;
369 369
 	AS_EX($$)->funcdecl->params = $4;
370
-	AS_EX($$)->funcdecl->body = $6;
370
+	AS_EX($$)->funcdecl->anno = $6;
371
+	AS_EX($$)->funcdecl->body = $7;
371 372
 }
372
-| FUNC any_lparen param_list RPAREN stmt_list END {
373
+| FUNC any_lparen param_list RPAREN maybe_anno stmt_list END {
373 374
 	$$ = NEW_EX();
374 375
 	AS_EX($$)->type = EX_FUNCDECL;
375 376
 	AS_EX($$)->funcdecl = NEW(funcdecl_node);
376 377
 	AS_EX($$)->funcdecl->name = NULL;
377 378
 	AS_EX($$)->funcdecl->params = $3;
378
-	AS_EX($$)->funcdecl->body = $5;
379
+	AS_EX($$)->funcdecl->anno = $5;
380
+	AS_EX($$)->funcdecl->body = $6;
379 381
 }
380
-| LAMBDA any_lparen param_list RPAREN expr END {
382
+| LAMBDA any_lparen param_list RPAREN maybe_anno expr END {
381 383
 	$$ = NEW_EX();
382 384
 	AS_EX($$)->type = EX_FUNCDECL;
383 385
 	AS_EX($$)->funcdecl = NEW(funcdecl_node);
384 386
 	AS_EX($$)->funcdecl->name = NULL;
385 387
 	AS_EX($$)->funcdecl->params = $3;
388
+	AS_EX($$)->funcdecl->anno = $5;
386 389
 	AS_EX($$)->funcdecl->body = NEW_ST();
387 390
 	AS_EX($$)->funcdecl->body->type = ST_RET;
388 391
 	AS_EX($$)->funcdecl->body->ret = NEW(ret_node);
389
-	AS_EX($$)->funcdecl->body->ret->ret = $5;
392
+	AS_EX($$)->funcdecl->body->ret->ret = $6;
390 393
 }
391 394
 | index_expr { $$ = $1; }
392 395
 ;
@@ -493,6 +496,7 @@ param_list:
493 496
 	if(!pl) {
494 497
 		pl = NEW(paramlist_node);
495 498
 		pl->args = NULL;
499
+		pl->annos = NULL;
496 500
 		pl->clkeys = NULL;
497 501
 		pl->clvalues = NULL;
498 502
 		pl->rest = NULL;
@@ -525,6 +529,7 @@ param_list:
525 529
 	if(!pl) {
526 530
 		pl = NEW(paramlist_node);
527 531
 		pl->args = NULL;
532
+		pl->annos = NULL;
528 533
 		pl->clkeys = NULL;
529 534
 		pl->clvalues = NULL;
530 535
 		pl->rest = NULL;
@@ -532,12 +537,14 @@ param_list:
532 537
 	pl-> rest = $3;
533 538
 	$$ = pl;
534 539
 }
535
-| param_list IDENT {
540
+| param_list IDENT maybe_anno {
536 541
 	paramlist_node *pl = $1;
537 542
 	identlist_node *cura;
543
+	exprlist_node *curn;
538 544
 	if(!pl) {
539 545
 		pl = NEW(paramlist_node);
540 546
 		pl->args = NULL;
547
+		pl->annos = NULL;
541 548
 		pl->clkeys = NULL;
542 549
 		pl->clvalues = NULL;
543 550
 		pl->rest = NULL;
@@ -545,16 +552,24 @@ param_list:
545 552
 	if(!pl->args) {
546 553
 		pl->args = NEW(identlist_node);
547 554
 		cura = pl->args;
555
+		pl->annos = NEW(exprlist_node);
556
+		curn = pl->annos;
548 557
 	} else {
549 558
 		cura = pl->args;
559
+		curn = pl->annos;
550 560
 		while(cura->next) {
551 561
 			cura = cura->next;
562
+			curn = curn->next;
552 563
 		}
553 564
 		cura->next = NEW(identlist_node);
554 565
 		cura = cura->next;
566
+		curn->next = NEW(exprlist_node);
567
+		curn = curn->next;
555 568
 	}
556 569
 	cura->ident = $2;
557 570
 	cura->next = NULL;
571
+	curn->expr = $3;
572
+	curn->next = NULL;
558 573
 	$$ = pl;
559 574
 }
560 575
 | param_list COMMA { $$ = $1; }
@@ -601,6 +616,11 @@ any_lparen:
601 616
 | BLPAREN
602 617
 ;
603 618
 
619
+maybe_anno:
620
+  COLON expr { $$ = $2; }
621
+| /* empty */ { $$ = NULL; }
622
+;
623
+
604 624
 %%
605 625
 
606 626
 // TODO

+ 1
- 3
programs/dump.sol View File

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

+ 36
- 15
runtime.c View File

@@ -179,6 +179,7 @@ expr_node *ex_copy(expr_node *old) {
179 179
 				new->funcdecl->name = NULL;
180 180
 			}
181 181
 			new->funcdecl->params = pl_copy(old->funcdecl->params);
182
+			new->funcdecl->anno = ex_copy(old->funcdecl->anno);
182 183
 			new->funcdecl->body = st_copy(old->funcdecl->body);
183 184
 			break;
184 185
 
@@ -294,6 +295,7 @@ paramlist_node *pl_copy(paramlist_node *old) {
294 295
 	if(!old) return NULL;
295 296
 	new = NEW(paramlist_node);
296 297
 	new->args = idl_copy(old->args);
298
+	new->annos = exl_copy(old->annos);
297 299
 	new->clkeys = idl_copy(old->clkeys);
298 300
 	new->clvalues = exl_copy(old->clvalues);
299 301
 	new->rest = old->rest ? strdup(old->rest) : NULL;
@@ -415,6 +417,7 @@ void ex_free(expr_node *expr) {
415 417
 			free(expr->funcdecl->name);
416 418
 			st_free(expr->funcdecl->body);
417 419
 			pl_free(expr->funcdecl->params);
420
+			ex_free(expr->funcdecl->anno);
418 421
 			free(expr->funcdecl);
419 422
 			break;
420 423
 
@@ -482,6 +485,7 @@ void idl_free(identlist_node *list) {
482 485
 void pl_free(paramlist_node *list) {
483 486
 	if(!list) return;
484 487
 	idl_free(list->args);
488
+	exl_free(list->annos);
485 489
 	idl_free(list->clkeys);
486 490
 	exl_free(list->clvalues);
487 491
 	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) {
801 805
 			break;
802 806
 
803 807
 		case EX_FUNCDECL:
804
-			res = sol_new_func(state, expr->funcdecl->params ? expr->funcdecl->params->args : NULL, expr->funcdecl->body, expr->funcdecl->name);
808
+			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);
805 809
 			ERR_CHECK(state);
806
-			if(expr->funcdecl->params) {
807
-				res->rest = expr->funcdecl->params->rest ? strdup(expr->funcdecl->params->rest) : NULL;
808
-				curi = expr->funcdecl->params->clkeys;
809
-				cure = expr->funcdecl->params->clvalues;
810
-				while(curi) {
811
-					sol_map_borrow_name(state, res->closure, curi->ident, sol_eval_inner(state, cure->expr, jmp));
812
-					ERR_CHECK(state);
813
-					curi = curi->next;
814
-					cure = cure->next;
815
-				}
816
-			} else {
817
-				res->rest = NULL;
818
-			}
819 810
 			if(expr->funcdecl->name) {
820 811
 				sol_state_assign_l_name(state, expr->funcdecl->name, res);
821 812
 				ERR_CHECK(state);
@@ -1047,15 +1038,45 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
1047 1038
 	return res;
1048 1039
 }
1049 1040
 
1050
-sol_object_t *sol_new_func(sol_state_t *state, identlist_node *identlist, stmt_node *body, char *name) {
1041
+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) {
1042
+	identlist_node *cura;
1043
+	exprlist_node *cure;
1051 1044
 	sol_object_t *obj = sol_alloc_object(state);
1052 1045
 	obj->func = st_copy(body);
1053 1046
 	obj->args = idl_copy(identlist);
1054 1047
 	obj->fname = (name ? strdup(name) : NULL);
1055 1048
 	obj->closure = sol_new_map(state);
1056 1049
 	obj->udata = sol_new_map(state);
1050
+	obj->rest = NULL;
1051
+	obj->annos = sol_new_map(state);
1057 1052
 	obj->type = SOL_FUNCTION;
1058 1053
 	obj->ops = &(state->FuncOps);
1054
+	if(params) {
1055
+		obj->rest = params->rest ? strdup(params->rest) : NULL;
1056
+		cura = params->clkeys;
1057
+		cure = params->clvalues;
1058
+		while(cura) {
1059
+			sol_map_borrow_name(state, obj->closure, cura->ident, sol_eval(state, cure->expr));
1060
+			if(sol_has_error(state)) {
1061
+				sol_obj_free(obj);
1062
+				return sol_incref(state->None);
1063
+			}
1064
+			cura = cura->next;
1065
+			cure = cure->next;
1066
+		}
1067
+		cura = params->args;
1068
+		cure = params->annos;
1069
+		while(cura) {
1070
+			if(cure->expr) {
1071
+				sol_map_borrow_name(state, obj->annos, cura->ident, sol_eval(state, cure->expr));
1072
+			}
1073
+			cura = cura->next;
1074
+			cure = cure->next;
1075
+		}
1076
+	}
1077
+	if(func_anno) {
1078
+		sol_map_borrow(state, obj->annos, obj, sol_eval(state, func_anno));
1079
+	}
1059 1080
 	return obj;
1060 1081
 }
1061 1082
 

+ 9
- 4
sol.h View File

@@ -10,7 +10,7 @@
10 10
 #include "dsl/dsl.h"
11 11
 
12 12
 /** The version of the project, as made available through `debug.version`. */
13
-#define SOL_VERSION "0.3a1"
13
+#define SOL_VERSION "0.3a2"
14 14
 /** The hexadecimal version of the project, formatted 0xAAIIRPP where:
15 15
  * 
16 16
  * - AA is the two-digit major version
@@ -18,9 +18,12 @@
18 18
  * - R is 'A' for alpha, 'B' for beta, 'C' for candidate, and 'F' for final
19 19
  * - PP is the two-digit patch
20 20
  *
21
- * This value is guaranteed to only monotonically increase by revision.
21
+ * This value is guaranteed to only monotonically increase by revision, within
22
+ * the same line of development. In particular, features introduced in some
23
+ * version shall be available in all versions numerically greater than it
24
+ * (unless they are later deprecated or removed).
22 25
  */
23
-#define SOL_HEXVER 0x0003A01
26
+#define SOL_HEXVER 0x0003A02
24 27
 
25 28
 #ifndef SOL_ICACHE_MIN
26 29
 /** The smallest integer to cache. */
@@ -332,8 +335,10 @@ typedef struct sol_tag_object_t {
332 335
 			struct sol_tag_object_t *udata;
333 336
 			/** For `SOL_FUNCTION`, the name of the function if it was not declared anonymously (otherwise NULL). */
334 337
 			char *fname;
335
-			/* For `SOL_FUNCTION`, the name of an argument that receives extra parameters as a list (otherwise NULL). */
338
+			/** For `SOL_FUNCTION`, the name of an argument that receives extra parameters as a list (otherwise NULL). */
336 339
 			char *rest;
340
+			/** For `SOL_FUNCTION`, the map of annotations, with arguments by name, and the function itself by object. */
341
+			struct sol_tag_object_t *annos;
337 342
 		};
338 343
 		struct {
339 344
 			/** For `SOL_CFUNCTION`, the C function pointer. */

+ 40
- 0
tests/lang_anno.sol View File

@@ -0,0 +1,40 @@
1
+execfile("tests/_lib.sol")
2
+
3
+func f() end
4
+assert_eq(0, #(f.annos), "no annotations")
5
+
6
+func f(a: 12): -37 end
7
+assert_eq(12, f.annos.a, "arg annotation (int)")
8
+assert_eq(-37, f.annos[f], "func annotation (int)")
9
+
10
+func f(a: "herp"): "derp" end
11
+assert_eq("herp", f.annos.a, "arg annotation (str)")
12
+assert_eq("derp", f.annos[f], "func annotation (str)")
13
+
14
+func f(a: [1, 2], b: {c = [3, 4]}): {d = [12, "herps"]} return "asdfghjkl" end
15
+assert_eq([1, 2], f.annos.a, "composite anno a")
16
+assert_eq([3, 4], f.annos.b.c, "composite anno b")
17
+assert_eq([12, "herps"], f.annos[f].d, "composite func anno")
18
+assert_eq("asdfghjkl", f(), "correct call to anno func")
19
+
20
+func tc(f)
21
+	return func(*args, f=f)
22
+		for idx in range(#args) do
23
+			argn = f.args[idx]
24
+			if None == argn then continue end
25
+			tspec = f.annos[argn]
26
+			if None == tspec then continue end
27
+			if type(args[idx]) != tspec then
28
+				error("Calling " + tostring(f.name)+ ": arg " + argn + " should be " + tspec)
29
+			end
30
+		end
31
+		return apply(f, args)
32
+	end
33
+end
34
+
35
+iadd = tc(lambda(a: 'int', b: 'int'): 'int' a + b end)
36
+
37
+assert_eq(5, iadd(2, 3), "conformance")
38
+assert_eq(0, try(iadd, 2.2, 3)[0], "float a")
39
+assert_eq(0, try(iadd, 3, "string")[0], "str b")
40
+assert_eq(0, try(iadd, [], {})[0], "composite a/b")

Loading…
Cancel
Save