| 
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -514,7 +514,7 @@ int ink_make_routine(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					int new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					void* renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					new_count = (ctx->routines_capacity + ctx->routines_capacity/2); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					renewed = ctx->inner_realloc(ctx->routines, sizeof(struct stack_frame) * new_count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					renewed = ctx->inner_realloc(ctx->routines, sizeof(struct ink_routine) * new_count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						return -99; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -770,7 +770,7 @@ int ink_step(struct context *pContext) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ink_compile(struct context *pContext, char* buffer) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ink_compile(struct context *pContext, ">const char* buffer) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int routine, saved, executable_buffer_top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				/* Main function has a size limit of 256 (need to know that for REPL */ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem executable_buffer[256]; | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1012,6 +1012,8 @@ void ink_gc(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				/* TODO: Mark objects contained within function code */ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				/* Mark the rest of the data */ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				do { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					marked = 0; | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1171,6 +1173,46 @@ static void div_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void is_equal(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem ret; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ret.type = INK_INTEGER; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ret.value = a.value == b.value && a.type == b.type; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void is_different(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem ret; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ret.type = INK_INTEGER; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ret.value = !(a.value == b.value && a.type == b.type); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#ifndef NOEXTRAARITHMETIC | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void rem_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -1190,6 +1232,84 @@ static void rem_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void gt_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value > a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void gte_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value >= a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void lte_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value <= a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#endif // NOEXTRAARITHMETIC | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void lt_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(currentRoutine->top < 2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a =  currentRoutine->stack[currentRoutine->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				b =  currentRoutine->stack[currentRoutine->top-2]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine->stack[currentRoutine->top-1].value = b.value < a.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void dupe_elem(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1348,12 +1468,6 @@ static void print_as_utf8(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			struct ink_array { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int capacity; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    struct elem* elements; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static int get_type_by_name(struct context* ctx, const char* name) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    for(i = 0; i < ctx->types_top; ++i) { | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -1364,20 +1478,50 @@ static int get_type_by_name(struct context* ctx, const char* name) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    return -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void run_gc(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_gc(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void clear_stack(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				while (currentRoutine->top >= 1) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void collect_noop(struct context* _1, void* _2) {} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static struct ink_collection_list gc_noop(struct context* _1, void* _2) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_collection_list c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.elements = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.count = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#ifndef NOARRAYLIB | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			struct ink_array { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int capacity; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem* elements; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void collect_array(struct context* ctx, void* array) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    struct ink_array* ary; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_array* ary; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ary = array; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if(ary->elements != NULL) ctx->free(ary->elements); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ary->elements != NULL) ctx->free(ary->elements); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static struct ink_collection_list gc_array(struct context* ctx, void* array) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    struct ink_array* ary; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    struct ink_collection_list c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_array* ary; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_collection_list c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ary = array; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    c.count = ary->top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    return c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.count = ary->top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void new_array(struct context* ctx) { | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1527,6 +1671,33 @@ static void index_array(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_push(ctx, ary->elements[idx.value]); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void get_size_array(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int tid; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine *currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_array *ary; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem sz; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				tid = get_type_by_name(ctx, "array"); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top - 1].type != tid) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				a = currentRoutine->stack[currentRoutine->top - 1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ary = ink_get_value(ctx, a); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (ary == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					currentRoutine->panic = -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				sz.type = INK_INTEGER; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				sz.value = ary->top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_push(ctx, sz); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void print_array_of_codepoints(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int tid, i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine *currentRoutine; | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1556,19 +1727,6 @@ static void print_array_of_codepoints(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void run_gc(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_gc(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void clear_stack(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				currentRoutine = ctx->routines + ctx->routine_current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				while (currentRoutine->top >= 1) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void arrayify_stack(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_routine* currentRoutine; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem array_ref; | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -1594,27 +1752,11 @@ static void arrayify_stack(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void collect_noop(struct context*, void*) {} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static struct ink_collection_list gc_noop(struct context*, void*) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct ink_collection_list c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.elements = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				c.count = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return c; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#endif // NOARRAYLIB | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			int ink_std_library(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int v; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "[", push_array_stack_delim); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "]", push_delimited_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.new", new_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.push", push_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.index", index_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "sys.trace", print_stacktrace); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "sys.gc", run_gc); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "print_int", print_int); | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -1623,14 +1765,35 @@ int ink_std_library(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "-", sub_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "*", mult_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "/", div_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "%", rem_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "==", is_equal); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "!=", is_different); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "<", lt_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "swap", swap_elem); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "dup", dupe_elem); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "drop", drop_elem); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "stack.clear", clear_stack); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "stack.to_array", arrayify_stack); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "pluck", pluck_elem); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "return_if", return_if); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "jump_if", jump_if); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#ifndef NOEXTRAARITHMETIC | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, ">", gt_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, ">=", gte_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "=<", lte_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "%", rem_int); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#endif // NOEXTRAARITHMETIC | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#ifndef NOARRAYLIB | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "[", push_array_stack_delim); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "]", push_delimited_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.new", new_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.push", push_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.index", index_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.size", get_size_array); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				v += ink_add_native(ctx, "stack.to_array", arrayify_stack); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#endif // NOARRAYLIB | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return v; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 |