Browse Source

Sol Part 69: They told me I couldn't ship this! THEY WERE WRONG!

Graham Northup 2 years ago
parent
commit
84aed45860
6 changed files with 75 additions and 16 deletions
  1. 4
    0
      builtins.c
  2. 49
    1
      runtime.c
  3. 6
    2
      sol.h
  4. 1
    0
      state.c
  5. 0
    13
      tests/_crasher_tco.sol
  6. 15
    0
      tests/crasher_tco.sol

+ 4
- 0
builtins.c View File

@@ -567,6 +567,10 @@ sol_object_t *sol_f_debug_getops(sol_state_t *state, sol_object_t *args) {
567 567
 	return res;
568 568
 }
569 569
 
570
+sol_object_t *sol_f_debug_fnstack(sol_state_t *state, sol_object_t *args) {
571
+	return sol_incref(state->fnstack);
572
+}
573
+
570 574
 #ifndef NO_READLINE
571 575
 sol_object_t *sol_f_readline_readline(sol_state_t *state, sol_object_t *args) {
572 576
 	sol_object_t *obj, *objstr, *res;

+ 49
- 1
runtime.c View File

@@ -939,6 +939,7 @@ sol_object_t *sol_eval(sol_state_t *state, expr_node *expr) {
939 939
 void sol_exec(sol_state_t *state, stmt_node *stmt) {
940 940
 	sol_object_t *value = NULL, *vint = NULL, *list, *iter, *item;
941 941
 	stmtlist_node *curs;
942
+	exprlist_node *cure;
942 943
 	if(!stmt) {
943 944
 		sol_obj_free(sol_set_error_string(state, "Execute NULL statement"));
944 945
 		return;
@@ -969,7 +970,47 @@ void sol_exec(sol_state_t *state, stmt_node *stmt) {
969 970
 
970 971
 		case ST_RET:
971 972
 			if(stmt->ret->ret) {
972
-				state->ret = sol_eval(state, stmt->ret->ret);
973
+				if(stmt->ret->ret->type == EX_CALL) {
974
+					value = sol_eval(state, stmt->ret->ret->call->expr);
975
+					iter = sol_new_list(state);
976
+					if(stmt->ret->ret->call->method) {
977
+						list = sol_new_list(state);
978
+						sol_list_insert(state, list, 0, value);
979
+						item = sol_new_string(state, stmt->ret->ret->call->method);
980
+						sol_list_insert(state, list, 1, item);
981
+						sol_obj_free(item);
982
+						item = CALL_METHOD(state, value, index, list);
983
+						sol_obj_free(value);
984
+						sol_list_insert(state, iter, 0, value);
985
+						value = item;
986
+					}
987
+					cure = stmt->ret->ret->call->args;
988
+					while(cure) {
989
+						if(cure->expr) {
990
+							if(value->ops->tflags & SOL_TF_NO_EVAL_CALL_ARGS) {
991
+								sol_list_insert(state, iter, sol_list_len(state, iter), sol_new_exprnode(state, cure->expr));
992
+							} else {
993
+								sol_list_insert(state, iter, sol_list_len(state, iter), sol_eval(state, cure->expr));
994
+							}
995
+						}
996
+						cure = cure->next;
997
+					}
998
+					sol_list_insert(state, iter, 0, value);
999
+					vint = sol_list_get_index(state, state->fnstack, 0);
1000
+					if(vint == value) {
1001
+						sol_obj_free(vint);
1002
+						sol_obj_free(value);
1003
+						state->topargs = iter;
1004
+						longjmp(state->topfunc, 1);
1005
+					}
1006
+					sol_obj_free(vint);
1007
+					vint = CALL_METHOD(state, value, call, iter);
1008
+					sol_obj_free(value);
1009
+					sol_obj_free(iter);
1010
+					state->ret = vint;
1011
+				} else {
1012
+					state->ret = sol_eval(state, stmt->ret->ret);
1013
+				}
973 1014
 			} else {
974 1015
 				state->ret = sol_incref(state->None);
975 1016
 			}
@@ -1010,6 +1051,12 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
1010 1051
 	identlist_node *curi;
1011 1052
 	dsl_seq_iter *iter;
1012 1053
 	int argcnt = 0;
1054
+	char was_jumped = 0;
1055
+	if(setjmp(state->topfunc)) {
1056
+		//sol_obj_free(args);
1057
+		args = state->topargs;
1058
+		was_jumped = 1;
1059
+	}
1013 1060
 	iter = dsl_new_seq_iter(args->seq);
1014 1061
 	if(!args || dsl_seq_iter_is_invalid(iter) || sol_is_none(state, args)) {
1015 1062
 		printf("WARNING: No parameters to function call (expecting function)\n");
@@ -1018,6 +1065,7 @@ sol_object_t *sol_f_func_call(sol_state_t *state, sol_object_t *args) {
1018 1065
 	value = dsl_seq_iter_at(iter);
1019 1066
 	if(!value || !(sol_is_func(value) || sol_is_macro(value))) {
1020 1067
 		printf("WARNING: Function call without function as first parameter\n");
1068
+		ob_print(value);
1021 1069
 		return sol_incref(state->None);
1022 1070
 	}
1023 1071
 	if(!value->func) {

+ 6
- 2
sol.h View File

@@ -7,10 +7,11 @@
7 7
 
8 8
 #include <stdio.h>
9 9
 #include <stdarg.h>
10
+#include <setjmp.h>
10 11
 #include "dsl/dsl.h"
11 12
 
12 13
 /** The version of the project, as made available through `debug.version`. */
13
-#define SOL_VERSION "0.5a3"
14
+#define SOL_VERSION "0.5a4"
14 15
 /** The hexadecimal version of the project, formatted 0xAAIIRPP where:
15 16
  * 
16 17
  * - AA is the two-digit major version
@@ -23,7 +24,7 @@
23 24
  * version shall be available in all versions numerically greater than it
24 25
  * (unless they are later deprecated or removed).
25 26
  */
26
-#define SOL_HEXVER 0x0005A03
27
+#define SOL_HEXVER 0x0005A04
27 28
 
28 29
 #ifndef SOL_BUILD_HOST
29 30
 #define SOL_BUILD_HOST "(unknown host)"
@@ -426,6 +427,8 @@ typedef struct sol_tag_state_t {
426 427
 	sol_object_t *ret; ///< Return value of this function, for early return
427 428
 	sol_object_t *traceback; ///< The last stack of statement (nodes) in the last error, or NULL
428 429
 	sol_object_t *fnstack; ///< The stack of function objects (`SOL_FUNCTION`, `SOL_CFUNCTION`) in the current call stack
430
+	jmp_buf topfunc; ///< A jump buffer pointing to the most recent `SOL_FUNCTION` call, used for tail calls
431
+	sol_object_t *topargs; ///< The new arguments passed before jumping in a tail call
429 432
 	sol_state_flag_t sflag; ///< Used to implement break/continue
430 433
 	sol_object_t *error; ///< Some arbitrary error descriptor, `None` if no error
431 434
 	sol_object_t *_stdout; ///< Standard output stream object (for print(), type `SOL_STREAM`)
@@ -775,6 +778,7 @@ sol_object_t *sol_f_debug_globals(sol_state_t *, sol_object_t *);
775 778
 sol_object_t *sol_f_debug_locals(sol_state_t *, sol_object_t *);
776 779
 sol_object_t *sol_f_debug_scopes(sol_state_t *, sol_object_t *);
777 780
 sol_object_t *sol_f_debug_getops(sol_state_t *, sol_object_t *);
781
+sol_object_t *sol_f_debug_fnstack(sol_state_t *, sol_object_t *);
778 782
 
779 783
 sol_object_t *sol_f_iter_str(sol_state_t *, sol_object_t *);
780 784
 sol_object_t *sol_f_iter_buffer(sol_state_t *, sol_object_t *);

+ 1
- 0
state.c View File

@@ -286,6 +286,7 @@ int sol_state_init(sol_state_t *state) {
286 286
 	sol_map_borrow_name(state, mod, "globals", sol_new_cfunc(state, sol_f_debug_globals, "debug.globals"));
287 287
 	sol_map_borrow_name(state, mod, "locals", sol_new_cfunc(state, sol_f_debug_locals, "debug.locals"));
288 288
 	sol_map_borrow_name(state, mod, "scopes", sol_new_cfunc(state, sol_f_debug_scopes, "debug.scopes"));
289
+	sol_map_borrow_name(state, mod, "fnstack", sol_new_cfunc(state, sol_f_debug_fnstack, "debug.fnstack"));
289 290
 	sol_map_borrow_name(state, mod, "version", sol_new_buffer(state, SOL_VERSION, strlen(SOL_VERSION), OWN_NONE, NULL, NULL));
290 291
 	sol_map_borrow_name(state, mod, "hexversion", sol_new_int(state, SOL_HEXVER));
291 292
 #ifdef SOL_ICACHE

+ 0
- 13
tests/_crasher_tco.sol View File

@@ -1,13 +0,0 @@
1
-execfile("tests/_lib.sol")
2
-
3
-func blow_up_stack(n)
4
-	return if n > 0 then
5
-		1 + blow_up_stack(n - 1)
6
-	else
7
-		0
8
-	end
9
-end
10
-
11
-assert_eq(blow_up_stack(5), 5, "blow_up_stack 5 deep")
12
-assert_eq(blow_up_stack(5000), 5000, "blow_up_stack 5000 deep")
13
-assert_eq(blow_up_stack(5000000), 5000000, "blow_up_stack 5000000 deep")

+ 15
- 0
tests/crasher_tco.sol View File

@@ -0,0 +1,15 @@
1
+execfile("tests/_lib.sol")
2
+
3
+func blow_up_stack(n, accum)
4
+	if n > 0 then
5
+		return blow_up_stack(n - 1, accum + 1)
6
+	else
7
+		return accum
8
+	end
9
+end
10
+
11
+print('TCO test (will take a long time, sorry)')
12
+assert_eq(blow_up_stack(5, 0), 5, "blow_up_stack 5 deep")
13
+assert_eq(blow_up_stack(5000, 0), 5000, "blow_up_stack 5000 deep")
14
+assert_eq(blow_up_stack(50000, 0), 50000, "blow_up_stack 50000 deep")
15
+assert_eq(assert.closure._test_count, 3, "ran three tests")

Loading…
Cancel
Save