Browse Source

Multiple fixes for fuzzy unit test reported at https://github.com/rwhitworth/gravity-fuzz/tree/master/2017-04-05. Added a way to check expression correctness. Completed disassemble function.

Marco Bambini 8 years ago
parent
commit
aee9746bac

+ 143 - 55
src/compiler/gravity_codegen.c

@@ -272,7 +272,9 @@ static uint32_t compute_self_register (gvisitor_t *self, gnode_t *node, uint32_t
 			target = dest;
 			target = dest;
 		}
 		}
 		
 		
-		return ircode_register_pop_context_protect(code, true);
+		uint32_t reg = ircode_register_pop_context_protect(code, true);
+		DEBUG_ASSERT(reg != REGISTER_ERROR, "Unexpected register error.");
+		return reg;
 	}
 	}
 	
 	
 	// no special register found, so just return the target
 	// no special register found, so just return the target
@@ -347,7 +349,9 @@ static void visit_flow_if_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
 	uint32_t labelFalse = ircode_newlabel(code);
 	uint32_t labelFalse = ircode_newlabel(code);
 	
 	
 	visit(node->cond);
 	visit(node->cond);
-	ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
+	uint32_t reg = ircode_register_pop(code);
+	if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid if condition expression.");
+	ircode_add(code, JUMPF, reg, labelFalse, 0);
 	
 	
 	visit(node->stmt);
 	visit(node->stmt);
 	if (node->elsestmt) ircode_add(code, JUMP, labelTrue, 0, 0);
 	if (node->elsestmt) ircode_add(code, JUMP, labelTrue, 0, 0);
@@ -370,12 +374,14 @@ static void visit_flow_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
 	DEBUG_CODEGEN("visit_flow_stmt");
 	DEBUG_CODEGEN("visit_flow_stmt");
 	
 	
 	gtoken_t type = NODE_TOKEN_TYPE(node);
 	gtoken_t type = NODE_TOKEN_TYPE(node);
-	assert((type == TOK_KEY_IF) || (type == TOK_KEY_SWITCH));
+	assert((type == TOK_KEY_IF) || (type == TOK_KEY_SWITCH) || (type == TOK_OP_TERNARY));
 	
 	
 	if (type == TOK_KEY_IF) {
 	if (type == TOK_KEY_IF) {
 		visit_flow_if_stmt(self, node);
 		visit_flow_if_stmt(self, node);
 	} else if (type == TOK_KEY_SWITCH) {
 	} else if (type == TOK_KEY_SWITCH) {
 		visit_flow_switch_stmt(self, node);
 		visit_flow_switch_stmt(self, node);
+	} else if (type == TOK_OP_TERNARY) {
+		report_error(self, (gnode_t *)node, "Ternary operator not yet supported.");
 	}
 	}
 }
 }
 
 
@@ -407,7 +413,9 @@ static void visit_loop_while_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	
 	
 	ircode_marklabel(code, labelTrue);
 	ircode_marklabel(code, labelTrue);
 	visit(node->cond);
 	visit(node->cond);
-	ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
+	uint32_t reg = ircode_register_pop(code);
+	if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid while condition expression.");
+	ircode_add(code, JUMPF, reg, labelFalse, 0);
 	
 	
 	visit(node->stmt);
 	visit(node->stmt);
 	ircode_add(code, JUMP, labelTrue, 0, 0);
 	ircode_add(code, JUMP, labelTrue, 0, 0);
@@ -437,7 +445,9 @@ static void visit_loop_repeat_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	ircode_marklabel(code, labelTrue);
 	ircode_marklabel(code, labelTrue);
 	visit(node->stmt);
 	visit(node->stmt);
 	visit(node->expr);
 	visit(node->expr);
-	ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
+	uint32_t reg = ircode_register_pop(code);
+	if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid repeat condition expression.");
+	ircode_add(code, JUMPF, reg, labelFalse, 0);
 	ircode_add(code, JUMP, labelTrue, 0, 0);
 	ircode_add(code, JUMP, labelTrue, 0, 0);
 	
 	
 	ircode_marklabel(code, labelFalse);
 	ircode_marklabel(code, labelFalse);
@@ -485,6 +495,7 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	// generate code for $expr = expr (so expr is only evaluated once)
 	// generate code for $expr = expr (so expr is only evaluated once)
 	visit(node->expr);
 	visit(node->expr);
 	uint32_t once_expr = ircode_register_pop(code);
 	uint32_t once_expr = ircode_register_pop(code);
+	if (once_expr == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid for expression.");
 	ircode_add(code, MOVE, $expr, once_expr, 0);
 	ircode_add(code, MOVE, $expr, once_expr, 0);
 	
 	
 	// generate code for $value = $expr.iterate(null);
 	// generate code for $value = $expr.iterate(null);
@@ -505,9 +516,12 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	temp2 = ircode_register_push_temp(code);					// ++TEMP => 7
 	temp2 = ircode_register_push_temp(code);					// ++TEMP => 7
 	ircode_add(code, LOADK, temp2, CPOOL_VALUE_NULL, 0);
 	ircode_add(code, LOADK, temp2, CPOOL_VALUE_NULL, 0);
 	ircode_add(code, CALL, $value, temp1, 2);
 	ircode_add(code, CALL, $value, temp1, 2);
-	ircode_register_pop(code);									// --TEMP => 6
-	ircode_register_pop(code);									// --TEMP => 5
-	ircode_register_pop(code);									// --TEMP => 4
+	uint32_t temp = ircode_register_pop(code);					// --TEMP => 6
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 5
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 4
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 	
 	
 	// while code
 	// while code
 	uint32_t labelTrue  = ircode_newlabel(code);
 	uint32_t labelTrue  = ircode_newlabel(code);
@@ -532,9 +546,12 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	visit(node->stmt);
 	visit(node->stmt);
 	
 	
 	// pop next_fn temp register AFTER user code because function ptr must be protected inside loop
 	// pop next_fn temp register AFTER user code because function ptr must be protected inside loop
-	ircode_register_pop(code);									// --TEMP => 6
-	ircode_register_pop(code);									// --TEMP => 5
-	ircode_register_pop(code);									// --TEMP => 4
+	temp = ircode_register_pop(code);							// --TEMP => 6
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 5
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 4
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 	
 	
 	// update $value for the next check
 	// update $value for the next check
 	// $value = $expr.iterate($value);
 	// $value = $expr.iterate($value);
@@ -545,9 +562,12 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	temp2 = ircode_register_push_temp(code);					// ++TEMP => 7
 	temp2 = ircode_register_push_temp(code);					// ++TEMP => 7
 	ircode_add(code, MOVE, temp2, $value, 0);
 	ircode_add(code, MOVE, temp2, $value, 0);
 	ircode_add(code, CALL, $value, temp1, 2);
 	ircode_add(code, CALL, $value, temp1, 2);
-	ircode_register_pop(code);									// --TEMP => 6
-	ircode_register_pop(code);									// --TEMP => 5
-	ircode_register_pop(code);									// --TEMP => 4
+	temp = ircode_register_pop(code);							// --TEMP => 6
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 5
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 4
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 	
 	
 	ircode_add(code, JUMP, labelTrue, 0, 0);
 	ircode_add(code, JUMP, labelTrue, 0, 0);
 	
 	
@@ -556,10 +576,14 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
 	ircode_unsetlabel_true(code);
 	ircode_unsetlabel_true(code);
 	ircode_unsetlabel_false(code);
 	ircode_unsetlabel_false(code);
 	
 	
-	ircode_register_pop(code);									// --TEMP => 3
-	ircode_register_pop(code);									// --TEMP => 2
-	ircode_register_pop(code);									// --TEMP => 1
-	ircode_register_pop(code);									// --TEMP => 0
+	temp = ircode_register_pop(code);							// --TEMP => 3
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 2
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 1
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+	temp = ircode_register_pop(code);							// --TEMP => 0
+	DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 	
 	
 	ircode_register_unset_skip_clear(code, $expr);
 	ircode_register_unset_skip_clear(code, $expr);
 	ircode_register_unset_skip_clear(code, $value);
 	ircode_register_unset_skip_clear(code, $value);
@@ -602,7 +626,9 @@ static void visit_jump_stmt (gvisitor_t *self, gnode_jump_stmt_t *node) {
 	} else if (type == TOK_KEY_RETURN) {
 	} else if (type == TOK_KEY_RETURN) {
 		if (node->expr) {
 		if (node->expr) {
 			visit(node->expr);
 			visit(node->expr);
-			ircode_add(code, RET, ircode_register_pop(code), 0, 0);
+			uint32_t reg = ircode_register_pop(code);
+			if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid return expression.");
+			ircode_add(code, RET, reg, 0, 0);
 		} else {
 		} else {
 			ircode_add(code, RET0, 0, 0, 0);
 			ircode_add(code, RET0, 0, 0, 0);
 		}
 		}
@@ -655,7 +681,9 @@ static void store_declaration (gvisitor_t *self, gravity_object_t *obj, bool is_
 			
 			
 		if (is_module && obj->identifier) {
 		if (is_module && obj->identifier) {
 			index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, obj->identifier));
 			index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, obj->identifier));
-			ircode_add(code, STOREG, ircode_register_pop(code), index, 0);
+			uint32_t reg = ircode_register_pop(code);
+			if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid declaration expression.");
+			ircode_add(code, STOREG, reg, index, 0);
 		}
 		}
 			
 			
 		return;
 		return;
@@ -679,7 +707,7 @@ static gravity_function_t *class_lookup_nosuper (gravity_class_t *c, const char
 	return (v) ? (gravity_function_t*)v->p : NULL;
 	return (v) ? (gravity_function_t*)v->p : NULL;
 }
 }
 
 
-static void process_constructor (gvisitor_t *self, gravity_class_t *c) {
+static void process_constructor (gvisitor_t *self, gravity_class_t *c, gnode_t *node) {
 	DEBUG_CODEGEN("process_constructor");
 	DEBUG_CODEGEN("process_constructor");
 	
 	
 	// $init is an internal function used to initialize instance variables to a default value
 	// $init is an internal function used to initialize instance variables to a default value
@@ -735,6 +763,7 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c) {
 	if (internal_init_function) {
 	if (internal_init_function) {
 		// convert ircode to bytecode for $init special function and add a RET0 command
 		// convert ircode to bytecode for $init special function and add a RET0 command
 		ircode_t *code = (ircode_t *)internal_init_function->bytecode;
 		ircode_t *code = (ircode_t *)internal_init_function->bytecode;
+		if (!code) {report_error(self, node, "Invalid code context."); return;}
 		ircode_add(code, RET0, 0, 0, 0);
 		ircode_add(code, RET0, 0, 0, 0);
 		
 		
 		if (constructor_function == NULL) {
 		if (constructor_function == NULL) {
@@ -752,6 +781,7 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c) {
 	if (constructor_function) {
 	if (constructor_function) {
 		// add an implicit RET 0 (RET self) to the end of the constructor
 		// add an implicit RET 0 (RET self) to the end of the constructor
 		ircode_t *code = (ircode_t *)constructor_function->bytecode;
 		ircode_t *code = (ircode_t *)constructor_function->bytecode;
+		if (!code) {report_error(self, node, "Invalid code context."); return;}
 		ircode_add(code, RET, 0, 0, 0);
 		ircode_add(code, RET, 0, 0, 0);
 		
 		
 		if (internal_init_function) {
 		if (internal_init_function) {
@@ -768,20 +798,20 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c) {
 			// prepare parameters
 			// prepare parameters
 			uint32_t dest2 = ircode_register_push_temp(code);
 			uint32_t dest2 = ircode_register_push_temp(code);
 			ircode_set_index(2, code, MOVE, dest2, 0, 0);
 			ircode_set_index(2, code, MOVE, dest2, 0, 0);
-			ircode_register_pop(code);
+			uint32_t temp = ircode_register_pop(code);
+			DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 			
 			
 			// execute call
 			// execute call
 			ircode_set_index(3, code, CALL, dest, dest, 1);
 			ircode_set_index(3, code, CALL, dest, dest, 1);
 		}
 		}
 	}
 	}
 	
 	
-//process_funcs:
 	if (internal_init_function) gravity_optimizer(internal_init_function);
 	if (internal_init_function) gravity_optimizer(internal_init_function);
 	if (constructor_function) gravity_optimizer(constructor_function);
 	if (constructor_function) gravity_optimizer(constructor_function);
 	
 	
 check_meta:
 check_meta:
 	// recursively process constructor but stop when object or class class is found, otherwise an infinite loop is triggered
 	// recursively process constructor but stop when object or class class is found, otherwise an infinite loop is triggered
-	if ((c->objclass) && (c->objclass->isa) && (c->objclass->isa != c->objclass->objclass)) process_constructor(self, c->objclass);
+	if ((c->objclass) && (c->objclass->isa) && (c->objclass->isa != c->objclass->objclass)) process_constructor(self, c->objclass, node);
 }
 }
 
 
 static void process_getter_setter (gvisitor_t *self, gnode_var_t *p, gravity_class_t *c) {
 static void process_getter_setter (gvisitor_t *self, gnode_var_t *p, gravity_class_t *c) {
@@ -839,6 +869,7 @@ static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node)
 		// reserve first four instructions that could be later filled with a CALL to $init
 		// reserve first four instructions that could be later filled with a CALL to $init
 		// see process_constructor for more information
 		// see process_constructor for more information
 		ircode_t *code = (ircode_t *)f->bytecode;
 		ircode_t *code = (ircode_t *)f->bytecode;
+		if (!code) {report_error(self, (gnode_t *)node, "Invalid code context."); return;}
 		ircode_add_skip(code);
 		ircode_add_skip(code);
 		ircode_add_skip(code);
 		ircode_add_skip(code);
 		ircode_add_skip(code);
 		ircode_add_skip(code);
@@ -916,7 +947,9 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
 			ircode_t *code = (ircode_t *)context_function->bytecode;
 			ircode_t *code = (ircode_t *)context_function->bytecode;
 			if (p->expr) {
 			if (p->expr) {
 				// assign to variable result of the expression
 				// assign to variable result of the expression
-				ircode_add(code, MOVE, p->index, ircode_register_pop(code), 0);
+				uint32_t reg = ircode_register_pop(code);
+				if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
+				ircode_add(code, MOVE, p->index, reg, 0);
 			} else {
 			} else {
 				// no default assignment expression found so initialize to NULL
 				// no default assignment expression found so initialize to NULL
 				ircode_add(code, LOADK, p->index, CPOOL_VALUE_NULL, 0);
 				ircode_add(code, LOADK, p->index, CPOOL_VALUE_NULL, 0);
@@ -950,7 +983,9 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
 			} else {
 			} else {
 				ircode_add_constant(code, CPOOL_VALUE_NULL);
 				ircode_add_constant(code, CPOOL_VALUE_NULL);
 			}
 			}
-			ircode_add(code, STOREG, ircode_register_pop(code), index, 0);
+			uint32_t reg = ircode_register_pop(code);
+			if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
+			ircode_add(code, STOREG, reg, index, 0);
 			continue;
 			continue;
 		}
 		}
 		
 		
@@ -1003,8 +1038,9 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
 				CONTEXT_PUSH(init_function);
 				CONTEXT_PUSH(init_function);
 				ircode_t *code = (ircode_t *)init_function->bytecode;
 				ircode_t *code = (ircode_t *)init_function->bytecode;
 				visit(p->expr);
 				visit(p->expr);
-				uint32_t dest = ircode_register_pop(code);
-				ircode_add(code, STORE, dest, 0, p->index + MAX_REGISTERS);
+				uint32_t reg = ircode_register_pop(code);
+				if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
+				ircode_add(code, STORE, reg, 0, p->index + MAX_REGISTERS);
 				CONTEXT_POP();
 				CONTEXT_POP();
 			}
 			}
 			
 			
@@ -1064,7 +1100,7 @@ static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
 	CONTEXT_POP();
 	CONTEXT_POP();
 	
 	
 	// fix constructor chain
 	// fix constructor chain
-	process_constructor(self, c);
+	process_constructor(self, c, (gnode_t *)node);
 	
 	
 	// store class declaration in current context
 	// store class declaration in current context
 	store_declaration(self, (gravity_object_t *)c, (node->storage == TOK_KEY_STATIC), NULL);
 	store_declaration(self, (gravity_object_t *)c, (node->storage == TOK_KEY_STATIC), NULL);
@@ -1125,7 +1161,9 @@ static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
 	visit(node->right);
 	visit(node->right);
 	
 	
 	uint32_t r3 = ircode_register_pop(code);
 	uint32_t r3 = ircode_register_pop(code);
+	if (r3 == REGISTER_ERROR) report_error(self, (gnode_t *)node->right, "Invalid right expression.");
 	uint32_t r2 = ircode_register_pop(code);
 	uint32_t r2 = ircode_register_pop(code);
+	if (r2 == REGISTER_ERROR) report_error(self, (gnode_t *)node->left, "Invalid left expression.");
 	uint32_t r1 = ircode_register_push_temp(code);
 	uint32_t r1 = ircode_register_push_temp(code);
 	
 	
 	// a special instruction needs to be generated for a binary expression of type RANGE
 	// a special instruction needs to be generated for a binary expression of type RANGE
@@ -1161,6 +1199,7 @@ static void visit_unary_expr (gvisitor_t *self, gnode_unary_expr_t *node) {
 	}
 	}
 	
 	
 	uint32_t r2 = ircode_register_pop(code);
 	uint32_t r2 = ircode_register_pop(code);
+	if (r2 == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid unary expression.");
 	uint32_t r1 = ircode_register_push_temp(code);
 	uint32_t r1 = ircode_register_push_temp(code);
 	
 	
 	opcode_t op = (node->op == TOK_OP_SUB) ? NEG : token2opcode(node->op);
 	opcode_t op = (node->op == TOK_OP_SUB) ? NEG : token2opcode(node->op);
@@ -1193,6 +1232,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 	
 	
 	// register that contains callable object
 	// register that contains callable object
 	uint32_t target_register = ircode_register_pop_context_protect(code, true);
 	uint32_t target_register = ircode_register_pop_context_protect(code, true);
+	if (target_register == REGISTER_ERROR) report_error(self, (gnode_t *)node->id, "Invalid postfix expression.");
 	
 	
 	// register where to store final result
 	// register where to store final result
 	uint32_t dest_register = target_register;
 	uint32_t dest_register = target_register;
@@ -1239,13 +1279,15 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 			// add target register (must be temp)
 			// add target register (must be temp)
 			uint32_t temp_target_register = ircode_register_push_temp(code);
 			uint32_t temp_target_register = ircode_register_push_temp(code);
 			ircode_add(code, MOVE, temp_target_register, target_register, 0);
 			ircode_add(code, MOVE, temp_target_register, target_register, 0);
-			ircode_register_pop_context_protect(code, true);
+			uint32_t treg = ircode_register_pop_context_protect(code, true);
+			DEBUG_ASSERT(treg != REGISTER_ERROR, "Unexpected register error.");
 			
 			
 			// always add SELF parameter (must be temp+1)
 			// always add SELF parameter (must be temp+1)
 			uint32_t self_register = marray_pop(self_list);
 			uint32_t self_register = marray_pop(self_list);
 			uint32_t temp_self_register = ircode_register_push_temp(code);
 			uint32_t temp_self_register = ircode_register_push_temp(code);
 			ircode_add(code, MOVE, temp_self_register, self_register, 0);
 			ircode_add(code, MOVE, temp_self_register, self_register, 0);
-			ircode_register_pop_context_protect(code, true);
+			treg = ircode_register_pop_context_protect(code, true);
+			DEBUG_ASSERT(treg != REGISTER_ERROR, "Unexpected register error.");
 			
 			
 			// process each parameter (each must be temp+2 ... temp+n)
 			// process each parameter (each must be temp+2 ... temp+n)
 			marray_decl_init(uint32_r, args);
 			marray_decl_init(uint32_r, args);
@@ -1257,6 +1299,8 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 				visit(arg);
 				visit(arg);
 				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 				uint32_t nreg = ircode_register_pop_context_protect(code, true);
 				uint32_t nreg = ircode_register_pop_context_protect(code, true);
+				if (nreg == REGISTER_ERROR) report_error(self, (gnode_t *)arg, "Invalid argument expression at index %d.", j+1);
+				
 				// make sure args are in consecutive register locations (from temp_target_register + 1 to temp_target_register + n)
 				// make sure args are in consecutive register locations (from temp_target_register + 1 to temp_target_register + n)
 				if (nreg != temp_target_register + j + 2) {
 				if (nreg != temp_target_register + j + 2) {
 					uint32_t temp = ircode_register_push_temp(code);
 					uint32_t temp = ircode_register_push_temp(code);
@@ -1264,8 +1308,9 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 					ircode_add(code, MOVE, temp, nreg, 0);
 					ircode_add(code, MOVE, temp, nreg, 0);
 					ircode_register_clear(code, nreg);
 					ircode_register_clear(code, nreg);
 					nreg = ircode_register_pop_context_protect(code, true);
 					nreg = ircode_register_pop_context_protect(code, true);
+					if (nreg == REGISTER_ERROR) report_error(self, (gnode_t *)arg, "Invalid argument expression");
 				}
 				}
-				assert(nreg == temp_target_register + j + 2);
+				DEBUG_ASSERT(nreg == temp_target_register + j + 2, "Invalid register computation in call expression.");
 				marray_push(uint32_t, args, nreg);
 				marray_push(uint32_t, args, nreg);
 			}
 			}
 			
 			
@@ -1290,6 +1335,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 					// code added in order to protect the extra register pushed in case
 					// code added in order to protect the extra register pushed in case
 					// of code like: f(20)(30)
 					// of code like: f(20)(30)
 					uint32_t last_register = ircode_register_last(code);
 					uint32_t last_register = ircode_register_last(code);
+					if (last_register == REGISTER_ERROR) report_error(self, (gnode_t *)subnode, "Invalid call expression.");
 					if (dest_is_temp && last_register == dest_register) dest_is_temp = false;
 					if (dest_is_temp && last_register == dest_register) dest_is_temp = false;
 				}
 				}
 				if (dest_is_temp) ircode_register_push(code, dest_register);
 				if (dest_is_temp) ircode_register_push(code, dest_register);
@@ -1305,13 +1351,19 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 			uint32_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, expr->value));
 			uint32_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, expr->value));
 			uint32_t index_register = ircode_register_push_temp(code);
 			uint32_t index_register = ircode_register_push_temp(code);
 			ircode_add(code, LOADK, index_register, index, 0);
 			ircode_add(code, LOADK, index_register, index, 0);
-			ircode_register_pop(code);
+			uint32_t temp = ircode_register_pop(code);
+			if (temp == REGISTER_ERROR) report_error(self, (gnode_t *)expr, "Invalid access expression.");
 			
 			
 			// generate LOAD/STORE instruction
 			// generate LOAD/STORE instruction
 			dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
 			dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
+			if (dest_register == REGISTER_ERROR) report_error(self, (gnode_t *)expr, "Invalid access expression.");
+			
 			if (is_super) ircode_add(code, LOADS, dest_register, target_register, index_register);
 			if (is_super) ircode_add(code, LOADS, dest_register, target_register, index_register);
 			else ircode_add(code, (is_real_assigment) ? STORE : LOAD, dest_register, target_register, index_register);
 			else ircode_add(code, (is_real_assigment) ? STORE : LOAD, dest_register, target_register, index_register);
-			if ((!is_real_assigment) && (i+1<count)) ircode_register_pop_context_protect(code, true);
+			if ((!is_real_assigment) && (i+1<count)) {
+				uint32_t rtemp = ircode_register_pop_context_protect(code, true);
+				DEBUG_ASSERT(rtemp != REGISTER_ERROR, "Unexpected register error.");
+			}
 			
 			
 			// update self list (if latest instruction)
 			// update self list (if latest instruction)
 			// this was added in order to properly emit instructions for nested_class.gravity unit test
 			// this was added in order to properly emit instructions for nested_class.gravity unit test
@@ -1326,11 +1378,16 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 			visit(subnode->expr);
 			visit(subnode->expr);
 			ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 			ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 			uint32_t index = ircode_register_pop(code);
 			uint32_t index = ircode_register_pop(code);
+			if (index == REGISTER_ERROR) report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
 			
 			
 			// generate LOADAT/STOREAT instruction
 			// generate LOADAT/STOREAT instruction
 			dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
 			dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
+			if (dest_register == REGISTER_ERROR) report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
 			ircode_add(code, (is_assignment) ? STOREAT : LOADAT, dest_register, target_register, index);
 			ircode_add(code, (is_assignment) ? STOREAT : LOADAT, dest_register, target_register, index);
-			if ((!is_real_assigment) && (i+1<count)) ircode_register_pop_context_protect(code, true);
+			if ((!is_real_assigment) && (i+1<count)) {
+				uint32_t rtemp = ircode_register_pop_context_protect(code, true);
+				DEBUG_ASSERT(rtemp != REGISTER_ERROR, "Unexpected register error.");
+			}
 		}
 		}
 		
 		
 		// reset is_super flag
 		// reset is_super flag
@@ -1364,10 +1421,13 @@ static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
 		const char *identifier = gnode_array_get(node->identifiers, i);
 		const char *identifier = gnode_array_get(node->identifiers, i);
 		uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
 		uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
 		
 		
-		if ((is_assignment) && (IS_LAST_LOOP(i, count)))
-			ircode_add(code, STOREG, ircode_register_pop(code), kindex, 0);
-		else
+		if ((is_assignment) && (IS_LAST_LOOP(i, count))) {
+			uint32_t reg = ircode_register_pop(code);
+			if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid file expression.");
+			ircode_add(code, STOREG, reg, kindex, 0);
+		} else {
 			ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
 			ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
+		}
 	}
 	}
 	
 	
 	CODEGEN_COUNT_REGISTERS(n2);
 	CODEGEN_COUNT_REGISTERS(n2);
@@ -1425,11 +1485,13 @@ static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
 			
 			
 			// list
 			// list
 			uint32_t listreg = ircode_register_last(code);
 			uint32_t listreg = ircode_register_last(code);
+			if (listreg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid string interpolated expression.");
 			
 			
 			// LOADK
 			// LOADK
 			uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, "join"));
 			uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, "join"));
 			ircode_add_constant(code, index);
 			ircode_add_constant(code, index);
 			uint32_t temp1 = ircode_register_last(code);
 			uint32_t temp1 = ircode_register_last(code);
+			DEBUG_ASSERT(temp1 != REGISTER_ERROR, "Unexpected register error.");
 			
 			
 			// LOAD
 			// LOAD
 			ircode_add(code, LOAD, temp1, listreg, temp1);
 			ircode_add(code, LOAD, temp1, listreg, temp1);
@@ -1445,8 +1507,10 @@ static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
 			
 			
 			// cleanup
 			// cleanup
 			mem_free(list);
 			mem_free(list);
-			ircode_register_pop(code);	// temp2
-			ircode_register_pop(code);	// temp1
+			uint32_t temp = ircode_register_pop(code);	// temp2
+			DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+			temp = ircode_register_pop(code);			// temp1
+			DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 			
 			
 			/*
 			/*
 			 
 			 
@@ -1486,28 +1550,37 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
 			
 			
 		// local variable
 		// local variable
 		case LOCATION_LOCAL: {
 		case LOCATION_LOCAL: {
-			if (is_assignment)
-				ircode_add(code, MOVE, index, ircode_register_pop(code), 0);
-			else
+			if (is_assignment) {
+				uint32_t reg = ircode_register_pop(code);
+				if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
+				ircode_add(code, MOVE, index, reg, 0);
+			} else {
 				ircode_register_push(code, index);
 				ircode_register_push(code, index);
+			}
 		} break;
 		} break;
 		
 		
 		// module (global) variable
 		// module (global) variable
 		case LOCATION_GLOBAL: {
 		case LOCATION_GLOBAL: {
 			uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
 			uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
-			if (is_assignment)
-				ircode_add(code, STOREG, ircode_register_pop(code), kindex, 0);
-			else
+			if (is_assignment) {
+				uint32_t reg = ircode_register_pop(code);
+				if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
+				ircode_add(code, STOREG, reg, kindex, 0);
+			} else {
 				ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
 				ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
+			}
 		} break;
 		} break;
 		
 		
 		// upvalue access
 		// upvalue access
 		case LOCATION_UPVALUE: {
 		case LOCATION_UPVALUE: {
 			gupvalue_t *upvalue = node->upvalue;
 			gupvalue_t *upvalue = node->upvalue;
-			if (is_assignment)
-				ircode_add(code, STOREU, ircode_register_pop(code), upvalue->selfindex, 0);
-			else
+			if (is_assignment) {
+				uint32_t reg = ircode_register_pop(code);
+				if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
+				ircode_add(code, STOREU, reg, upvalue->selfindex, 0);
+			} else {
 				ircode_add(code, LOADU, ircode_register_push_temp(code), upvalue->selfindex, 0);
 				ircode_add(code, LOADU, ircode_register_push_temp(code), upvalue->selfindex, 0);
+			}
 		} break;
 		} break;
 			
 			
 		// class ivar case (outer case just need a loop lookup before)
 		// class ivar case (outer case just need a loop lookup before)
@@ -1524,7 +1597,10 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
 					ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS);
 					ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS);
 					target = dest;
 					target = dest;
 				}
 				}
-				if (is_assignment) ircode_register_pop(code);
+				if (is_assignment) {
+					uint32_t temp = ircode_register_pop(code);
+					DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+				}
 			}
 			}
 			
 			
 			uint32_t index_register;
 			uint32_t index_register;
@@ -1538,12 +1614,14 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
 				uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
 				uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
 				index_register = ircode_register_push_temp(code);
 				index_register = ircode_register_push_temp(code);
 				ircode_add(code, LOADK, index_register, kindex, 0);
 				ircode_add(code, LOADK, index_register, kindex, 0);
-				ircode_register_pop(code);
+				uint32_t temp = ircode_register_pop(code);
+				DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 			}
 			}
 			
 			
 			if (is_assignment) {
 			if (is_assignment) {
 				// should be prohibited by semantic to store something into a non ivar slot?
 				// should be prohibited by semantic to store something into a non ivar slot?
 				dest = ircode_register_pop(code); // consume temp register
 				dest = ircode_register_pop(code); // consume temp register
+				if (dest == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
 				ircode_add(code, STORE, dest, target, index_register);
 				ircode_add(code, STORE, dest, target, index_register);
 			} else {
 			} else {
 				dest = (type == LOCATION_CLASS_IVAR_OUTER) ? target : ircode_register_push_temp(code);
 				dest = (type == LOCATION_CLASS_IVAR_OUTER) ? target : ircode_register_push_temp(code);
@@ -1647,13 +1725,18 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 			gnode_t *e = gnode_array_get(node->list1, j);
 			gnode_t *e = gnode_array_get(node->list1, j);
 			visit(e);
 			visit(e);
 			uint32_t nreg = ircode_register_pop_context_protect(code, true);
 			uint32_t nreg = ircode_register_pop_context_protect(code, true);
+			if ((nreg == REGISTER_ERROR) || ((nreg <= dest) && (ircode_register_istemp(code, nreg)))) {
+				report_error(self, (gnode_t *)e, "Invalid list expression.");
+				continue;
+			}
 			
 			
 			if (nreg != dest + i) {
 			if (nreg != dest + i) {
 				uint32_t temp_register = ircode_register_push_temp(code);
 				uint32_t temp_register = ircode_register_push_temp(code);
 				ircode_add(code, MOVE, temp_register, nreg, 0);
 				ircode_add(code, MOVE, temp_register, nreg, 0);
 				ircode_register_clear(code, nreg);
 				ircode_register_clear(code, nreg);
-				ircode_register_pop_context_protect(code, true);
-				assert(temp_register == dest + i);
+				uint32_t temp = ircode_register_pop_context_protect(code, true);
+				DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+				DEBUG_ASSERT(temp_register == dest + i, "Unexpected register computation.");
 			}
 			}
 			
 			
 			if (ismap) {
 			if (ismap) {
@@ -1662,13 +1745,18 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 				visit(e);
 				visit(e);
 				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
 				nreg = ircode_register_pop_context_protect(code, true);
 				nreg = ircode_register_pop_context_protect(code, true);
+				if ((nreg == REGISTER_ERROR) || ((nreg <= dest) && (ircode_register_istemp(code, nreg)))) {
+					report_error(self, (gnode_t *)e, "Invalid map expression.");
+					continue;
+				}
 				
 				
 				if (nreg != dest + i + 1) {
 				if (nreg != dest + i + 1) {
 					uint32_t temp_register = ircode_register_push_temp(code);
 					uint32_t temp_register = ircode_register_push_temp(code);
 					ircode_add(code, MOVE, temp_register, nreg, 0);
 					ircode_add(code, MOVE, temp_register, nreg, 0);
 					ircode_register_clear(code, nreg);
 					ircode_register_clear(code, nreg);
-					ircode_register_pop_context_protect(code, true);
-					assert(temp_register == dest + i + 1);
+					uint32_t temp = ircode_register_pop_context_protect(code, true);
+					DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
+					DEBUG_ASSERT(temp_register == dest + i + 1, "Unexpected register computation.");
 				}
 				}
 			}
 			}
 			
 			

+ 5 - 7
src/compiler/gravity_ircode.c

@@ -80,7 +80,6 @@ uint32_t ircode_count (ircode_t *code) {
 
 
 inst_t *ircode_get (ircode_t *code, uint32_t index) {
 inst_t *ircode_get (ircode_t *code, uint32_t index) {
 	uint32_t n = (uint32_t)marray_size(*code->list);
 	uint32_t n = (uint32_t)marray_size(*code->list);
-	if (index == IRCODE_LATEST) index = n-1;
 	return (index >= n) ? NULL : marray_get(*code->list, index);
 	return (index >= n) ? NULL : marray_get(*code->list, index);
 }
 }
 
 
@@ -287,7 +286,7 @@ void ircode_dump  (void *_code) {
 			case 2: {
 			case 2: {
 				if (op == LOADI) {
 				if (op == LOADI) {
 					if (inst->tag == DOUBLE_TAG) printf("%05d\t%s %d %.2f\n", line, opcode_name(op), p1, inst->d);
 					if (inst->tag == DOUBLE_TAG) printf("%05d\t%s %d %.2f\n", line, opcode_name(op), p1, inst->d);
-					else printf("%05d\t%s %d %lld\n", line, opcode_name(op), p1, inst->n);
+					else printf("%05d\t%s %d %"PRId64"\n", line, opcode_name(op), p1, inst->n);
 				} else if (op == LOADK) {
 				} else if (op == LOADK) {
 					if (p2 < CPOOL_INDEX_MAX) printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
 					if (p2 < CPOOL_INDEX_MAX) printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
 					else printf("%05d\t%s %d %s\n", line, opcode_name(op), p1, opcode_constname(p2));
 					else printf("%05d\t%s %d %s\n", line, opcode_name(op), p1, opcode_constname(p2));
@@ -420,7 +419,7 @@ void ircode_pop_context (ircode_t *code) {
 }
 }
 
 
 uint32_t ircode_register_pop_context_protect (ircode_t *code, bool protect) {
 uint32_t ircode_register_pop_context_protect (ircode_t *code, bool protect) {
-	assert(marray_size(code->registers) != 0);
+	if (marray_size(code->registers) == 0) return REGISTER_ERROR;
 	uint32_t value = (uint32_t)marray_pop(code->registers);
 	uint32_t value = (uint32_t)marray_pop(code->registers);
 	
 	
 	if (protect) code->state[value] = true;
 	if (protect) code->state[value] = true;
@@ -484,15 +483,14 @@ uint32_t ircode_register_pop (ircode_t *code) {
 }
 }
 
 
 void ircode_register_clear (ircode_t *code, uint32_t nreg) {
 void ircode_register_clear (ircode_t *code, uint32_t nreg) {
+	if (nreg == REGISTER_ERROR) return;
 	// cleanup busy mask only if it is a temp register
 	// cleanup busy mask only if it is a temp register
 	if (nreg >= code->nlocals) code->state[nreg] = false;
 	if (nreg >= code->nlocals) code->state[nreg] = false;
 }
 }
 
 
 uint32_t ircode_register_last (ircode_t *code) {
 uint32_t ircode_register_last (ircode_t *code) {
-	assert(marray_size(code->registers) != 0);
-	uint32_t value = (uint32_t)marray_last(code->registers);
-	
-	return value;
+	if (marray_size(code->registers) == 0) return REGISTER_ERROR;
+	return (uint32_t)marray_last(code->registers);
 }
 }
 
 
 bool ircode_register_istemp (ircode_t *code, uint32_t nreg) {
 bool ircode_register_istemp (ircode_t *code, uint32_t nreg) {

+ 12 - 1
src/compiler/gravity_ircode.h

@@ -27,7 +27,7 @@
 #include "gravity_opcodes.h"
 #include "gravity_opcodes.h"
 #include "gravity_array.h"
 #include "gravity_array.h"
 
 
-#define IRCODE_LATEST	UINT32_MAX
+#define REGISTER_ERROR	UINT32_MAX
 
 
 typedef enum {
 typedef enum {
 		NO_TAG = 0,
 		NO_TAG = 0,
@@ -88,6 +88,17 @@ void		ircode_add_skip (ircode_t *code);
 void		ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3);
 void		ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3);
 void		ircode_setarray_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_r r);
 void		ircode_setarray_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_r r);
 
 
+// IMPORTANT NOTE
+//
+// The following functions can return REGISTER_ERROR and so an error check is mandatory
+// ircode_register_pop
+// ircode_register_pop_context_protect
+// ircode_register_last
+//
+// The following functions can return 0 if no temp registers are available
+// ircode_register_push_temp
+//
+
 bool		ircode_register_istemp (ircode_t *code, uint32_t n);
 bool		ircode_register_istemp (ircode_t *code, uint32_t n);
 uint32_t	ircode_register_push_temp (ircode_t *code);
 uint32_t	ircode_register_push_temp (ircode_t *code);
 uint32_t	ircode_register_push (ircode_t *code, uint32_t nreg);
 uint32_t	ircode_register_push (ircode_t *code, uint32_t nreg);

+ 2 - 2
src/compiler/gravity_lexer.c

@@ -198,10 +198,10 @@ static gtoken_t lexer_scan_comment(gravity_lexer_t *lexer) {
 	// because I already scanned /* or //
 	// because I already scanned /* or //
 	lexer->token.bytes = lexer->token.length = 2;
 	lexer->token.bytes = lexer->token.length = 2;
 	
 	
-	// count necessary only to support nested comments
+	// count variable used only to support nested comments
 	int count = 1;
 	int count = 1;
 	while (!IS_EOF) {
 	while (!IS_EOF) {
-		int c;
+		int c = 0;
 		next_utf8(lexer, &c);
 		next_utf8(lexer, &c);
 		
 		
 		if (isLineComment){
 		if (isLineComment){

+ 10 - 2
src/compiler/gravity_parser.c

@@ -218,7 +218,10 @@ gnode_t *parse_function (gravity_parser_t *parser, bool is_declaration, gtoken_t
 	if (!is_implicit) {
 	if (!is_implicit) {
 		gtoken_t type = gravity_lexer_next(lexer);
 		gtoken_t type = gravity_lexer_next(lexer);
 		token = gravity_lexer_token(lexer);
 		token = gravity_lexer_token(lexer);
-		assert(type == TOK_KEY_FUNC);
+		if (type != TOK_KEY_FUNC) {
+			REPORT_ERROR(token, "Invalid function expression.");
+			return NULL;
+		}
 	}
 	}
 	
 	
 	// parse IDENTIFIER
 	// parse IDENTIFIER
@@ -1393,7 +1396,12 @@ static gnode_t *parse_event_declaration (gravity_parser_t *parser, gtoken_t acce
 	// 'event' IDENTIFIER '(' parameter_declaration_clause? ')' ';'
 	// 'event' IDENTIFIER '(' parameter_declaration_clause? ')' ';'
 	
 	
 	// NODE_EVENT_DECL
 	// NODE_EVENT_DECL
-	assert(0);
+	DECLARE_LEXER;
+	gtoken_t type = gravity_lexer_next(lexer);
+	gtoken_s token = gravity_lexer_token(lexer);
+	assert(type == TOK_KEY_EVENT);
+	
+	REPORT_ERROR(token, "Event declarations not yet supported.");
 	return NULL;
 	return NULL;
 }
 }
 
 

+ 1 - 0
src/compiler/gravity_semacheck2.c

@@ -107,6 +107,7 @@ static symboltable_t *symtable_from_node (gnode_t *node) {
 // lookup identifier into node
 // lookup identifier into node
 static gnode_t *lookup_node (gnode_t *node, const char *identifier) {
 static gnode_t *lookup_node (gnode_t *node, const char *identifier) {
 	symboltable_t *symtable = symtable_from_node(node);
 	symboltable_t *symtable = symtable_from_node(node);
+	if (!symtable) return NULL;
 	return symboltable_lookup(symtable, identifier);
 	return symboltable_lookup(symtable, identifier);
 }
 }
 
 

+ 3 - 2
src/runtime/gravity_core.c

@@ -592,17 +592,18 @@ static bool object_bind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 	gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
 	gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
 	
 	
 	// check if instance has already an anonymous class added to its hierarchy
 	// check if instance has already an anonymous class added to its hierarchy
-	if (string_nocasencmp(c->identifier, GRAVITY_VM_ANONYMOUS_PREFIX, strlen(GRAVITY_VM_ANONYMOUS_PREFIX) != 0)) {
+	if (string_casencmp(c->identifier, GRAVITY_VM_ANONYMOUS_PREFIX, strlen(GRAVITY_VM_ANONYMOUS_PREFIX) != 0)) {
 		// no super anonymous class found so create a new one, set its super as c, and add it to the hierarchy
 		// no super anonymous class found so create a new one, set its super as c, and add it to the hierarchy
 		char *name = gravity_vm_anonymous(vm);
 		char *name = gravity_vm_anonymous(vm);
 		gravity_class_t *anon = gravity_class_new_pair(NULL, name, c, 0, 0);
 		gravity_class_t *anon = gravity_class_new_pair(NULL, name, c, 0, 0);
+		gravity_class_t *anon_meta = gravity_class_get_meta(anon);
 		object->objclass = anon;
 		object->objclass = anon;
 		c = anon;
 		c = anon;
 		
 		
 		// store anonymous class (and its meta) into VM special GC stack
 		// store anonymous class (and its meta) into VM special GC stack
 		// manually retains anonymous class that will retain its bound functions
 		// manually retains anonymous class that will retain its bound functions
 		gravity_gc_push(vm, (gravity_object_t *)anon);
 		gravity_gc_push(vm, (gravity_object_t *)anon);
-		gravity_gc_push(vm, (gravity_object_t *)gravity_class_get_meta(anon));
+		gravity_gc_push(vm, (gravity_object_t *)anon_meta);
 	}
 	}
 	
 	
 	// add closure to anonymous class
 	// add closure to anonymous class

+ 7 - 7
src/runtime/gravity_vm.c

@@ -362,7 +362,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					} break;
 					} break;
 						
 						
 					case EXEC_TYPE_BRIDGED: {
 					case EXEC_TYPE_BRIDGED: {
-						ASSERT(delegate->bridge_getvalue, "bridge_getvalue delegate callback is mandatory");
+						DEBUG_ASSERT(delegate->bridge_getvalue, "bridge_getvalue delegate callback is mandatory");
 						if (!delegate->bridge_getvalue(vm, closure->f->xdata, v2, VALUE_AS_CSTRING(v3), r1)) {
 						if (!delegate->bridge_getvalue(vm, closure->f->xdata, v2, VALUE_AS_CSTRING(v3), r1)) {
 							if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 							if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 						}
 						}
@@ -489,7 +489,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					} break;
 					} break;
 					
 					
 					case EXEC_TYPE_BRIDGED: {
 					case EXEC_TYPE_BRIDGED: {
-						ASSERT(delegate->bridge_setvalue, "bridge_setvalue delegate callback is mandatory");
+						DEBUG_ASSERT(delegate->bridge_setvalue, "bridge_setvalue delegate callback is mandatory");
 						if (!delegate->bridge_setvalue(vm, closure->f->xdata, v2, VALUE_AS_CSTRING(v3), v1)) {
 						if (!delegate->bridge_setvalue(vm, closure->f->xdata, v2, VALUE_AS_CSTRING(v3), v1)) {
 							if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 							if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 						}
 						}
@@ -1046,12 +1046,12 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					case EXEC_TYPE_BRIDGED: {
 					case EXEC_TYPE_BRIDGED: {
 						bool result;
 						bool result;
 						if (VALUE_ISA_CLASS(v)) {
 						if (VALUE_ISA_CLASS(v)) {
-							ASSERT(delegate->bridge_initinstance, "bridge_initinstance delegate callback is mandatory");
+							DEBUG_ASSERT(delegate->bridge_initinstance, "bridge_initinstance delegate callback is mandatory");
 							gravity_instance_t *instance = (gravity_instance_t *)VALUE_AS_OBJECT(stackstart[rwin]);
 							gravity_instance_t *instance = (gravity_instance_t *)VALUE_AS_OBJECT(stackstart[rwin]);
 							result = delegate->bridge_initinstance(vm, closure->f->xdata, instance, &stackstart[rwin], r3);
 							result = delegate->bridge_initinstance(vm, closure->f->xdata, instance, &stackstart[rwin], r3);
 							SETVALUE(r1, VALUE_FROM_OBJECT(instance));
 							SETVALUE(r1, VALUE_FROM_OBJECT(instance));
 						} else {
 						} else {
-							ASSERT(delegate->bridge_execute, "bridge_execute delegate callback is mandatory");
+							DEBUG_ASSERT(delegate->bridge_execute, "bridge_execute delegate callback is mandatory");
 							result = delegate->bridge_execute(vm, closure->f->xdata, &stackstart[rwin], r3, r1);
 							result = delegate->bridge_execute(vm, closure->f->xdata, &stackstart[rwin], r3, r1);
 						}
 						}
 						if (!result && fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 						if (!result && fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
@@ -1083,7 +1083,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 				}
 				}
 				
 				
 				// sanity check
 				// sanity check
-				ASSERT(fiber->nframes > 0, "Number of active frames cannot be 0.");
+				DEBUG_ASSERT(fiber->nframes > 0, "Number of active frames cannot be 0.");
 				
 				
 				// POP frame
 				// POP frame
 				--fiber->nframes;
 				--fiber->nframes;
@@ -1122,7 +1122,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 			
 			
 			// MARK: SWITCH
 			// MARK: SWITCH
 			CASE_CODE(SWITCH): {
 			CASE_CODE(SWITCH): {
-				ASSERT(0, "To be implemented");
+				DEBUG_ASSERT(0, "To be implemented");
 				DISPATCH();
 				DISPATCH();
 			}
 			}
 			
 			
@@ -1225,7 +1225,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t p1, const uint32_t p2);
 					OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t p1, const uint32_t p2);
 					
 					
 					// p2 can be 1 (means that upvalue is in the current call frame) or 0 (means that upvalue is in the upvalue list of the caller)
 					// p2 can be 1 (means that upvalue is in the current call frame) or 0 (means that upvalue is in the upvalue list of the caller)
-					ASSERT(op == MOVE, "Wrong OPCODE in CLOSURE statement");
+					DEBUG_ASSERT(op == MOVE, "Wrong OPCODE in CLOSURE statement");
 					closure->upvalue[i] = (p2) ? gravity_capture_upvalue (vm, fiber, &stackstart[p1]) : frame->closure->upvalue[p1];
 					closure->upvalue[i] = (p2) ? gravity_capture_upvalue (vm, fiber, &stackstart[p1]) : frame->closure->upvalue[p1];
 				}
 				}
 				
 				

+ 1 - 15
src/runtime/gravity_vmmacros.h

@@ -9,20 +9,6 @@
 #ifndef __GRAVITY_VMMACROS__
 #ifndef __GRAVITY_VMMACROS__
 #define __GRAVITY_VMMACROS__
 #define __GRAVITY_VMMACROS__
 
 
-// Assertions add significant overhead, so are only enabled in debug builds.
-#if 1
-#define ASSERT(condition, message)						do { \
-															if (!(condition)) { \
-																fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \
-																__FILE__, __LINE__, __func__, message); \
-																abort(); \
-															} \
-														} \
-														while(0)
-#else
-#define ASSERT(condition, message)
-#endif
-
 #if 0
 #if 0
 #define DEBUG_CALL(s, f)								printf("%s %s\n", s, f->identifier)
 #define DEBUG_CALL(s, f)								printf("%s %s\n", s, f->identifier)
 #else
 #else
@@ -262,7 +248,7 @@
 														}																					\
 														}																					\
 													} break;																				\
 													} break;																				\
 													case EXEC_TYPE_BRIDGED:	{																\
 													case EXEC_TYPE_BRIDGED:	{																\
-														ASSERT(delegate->bridge_execute, "bridge_execute delegate callback is mandatory");	\
+														DEBUG_ASSERT(delegate->bridge_execute, "bridge_execute delegate callback is mandatory");	\
 														if (!delegate->bridge_execute(vm, _c->f->xdata, &stackstart[rwin], nargs, r1)) {	\
 														if (!delegate->bridge_execute(vm, _c->f->xdata, &stackstart[rwin], nargs, r1)) {	\
 															if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);							\
 															if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);							\
 														}																					\
 														}																					\

+ 14 - 0
src/shared/gravity_macros.h

@@ -131,5 +131,19 @@
 
 
 #define GRAVITY_VM_ANONYMOUS_PREFIX			"$$"
 #define GRAVITY_VM_ANONYMOUS_PREFIX			"$$"
 
 
+// MARK: -
+
+#if 1
+#define DEBUG_ASSERT(condition, message)	do { \
+												if (!(condition)) { \
+													fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \
+													__FILE__, __LINE__, __func__, message); \
+													abort(); \
+												} \
+											} \
+											while(0)
+#else
+#define DEBUG_ASSERT(condition, message)
+#endif
 
 
 #endif
 #endif

+ 7 - 7
src/utils/gravity_debug.c

@@ -8,8 +8,8 @@
 
 
 #include <assert.h>
 #include <assert.h>
 #include "gravity_value.h"
 #include "gravity_value.h"
-#include "gravity_vmmacros.h"
 #include "gravity_debug.h"
 #include "gravity_debug.h"
+#include "gravity_vmmacros.h"
 
 
 const char *opcode_constname (int n) {
 const char *opcode_constname (int n) {
 	switch (n) {
 	switch (n) {
@@ -21,8 +21,6 @@ const char *opcode_constname (int n) {
 		case CPOOL_VALUE_FALSE: return "FALSE";
 		case CPOOL_VALUE_FALSE: return "FALSE";
 		case CPOOL_VALUE_FUNC: return "FUNC";
 		case CPOOL_VALUE_FUNC: return "FUNC";
 	}
 	}
-	
-	assert(0);
 	return "N/A";
 	return "N/A";
 }
 }
 
 
@@ -111,7 +109,7 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
 						case CPOOL_VALUE_TRUE: special = "TRUE"; break;
 						case CPOOL_VALUE_TRUE: special = "TRUE"; break;
 						case CPOOL_VALUE_FALSE: special = "FALSE"; break;
 						case CPOOL_VALUE_FALSE: special = "FALSE"; break;
 						case CPOOL_VALUE_FUNC: special = "_FUNC"; break;
 						case CPOOL_VALUE_FUNC: special = "_FUNC"; break;
-						default: ASSERT(0, "Invalid index in LOADK opcode"); break;
+						default: special = "Invalid index in LOADK opcode"; break;
 					}
 					}
 					DUMP_VM(buffer, bindex, "LOADK %d %s", r1, special);
 					DUMP_VM(buffer, bindex, "LOADK %d %s", r1, special);
 				}
 				}
@@ -133,7 +131,8 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
 			}
 			}
 				
 				
 			case LOADU: {
 			case LOADU: {
-				ASSERT(0, "To be implemented");
+				OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
+				DUMP_VM(buffer, bindex, "LOADU %d %d", r1, r2);
 				break;
 				break;
 			}
 			}
 				
 				
@@ -144,7 +143,8 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
 			}
 			}
 				
 				
 			case STOREU: {
 			case STOREU: {
-				ASSERT(0, "To be implemented");
+				OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
+				DUMP_VM(buffer, bindex, "STOREU %d %d", r1, r2);
 				break;
 				break;
 			}
 			}
 				
 				
@@ -240,7 +240,7 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
 			}
 			}
 				
 				
 			case SWITCH: {
 			case SWITCH: {
-				ASSERT(0, "To be implemented");
+				DUMP_VM(buffer, bindex, "SWITCH instruction not yet implemented");
 				break;
 				break;
 			}
 			}