浏览代码

Version 0.5.4

- load_file callback now can report if the file is static (and does not need to be freed) or not
- VM can now reports at runtime the exact line number of the reported error
- fixed a negative double/float optimization issue
- fixed an incorrect assert
- NULL is now an alias to null
- VM delegate can now report when a message is sent to null (instead of silently ignore the message)
- others fixes and improvements
Marco Bambini 7 年之前
父节点
当前提交
5a466d1699

+ 7 - 4
src/cli/gravity.c

@@ -60,7 +60,7 @@ static void report_error (gravity_vm *vm, error_type_t error_type, const char *m
 	printf("%s\n", message);
 	printf("%s\n", message);
 }
 }
 
 
-static const char *load_file (const char *file, size_t *size, uint32_t *fileid, void *xdata) {
+static const char *load_file (const char *file, size_t *size, uint32_t *fileid, void *xdata, bool *is_static) {
     (void) fileid, (void) xdata;
     (void) fileid, (void) xdata;
 
 
 	// this callback is called each time an import statement is parsed
 	// this callback is called each time an import statement is parsed
@@ -86,6 +86,7 @@ static const char *load_file (const char *file, size_t *size, uint32_t *fileid,
 	// please note than in this simple example the imported file must be
 	// please note than in this simple example the imported file must be
 	// in the same folder as the main input file
 	// in the same folder as the main input file
 
 
+    if (is_static) *is_static = false;
 	if (!file_exists(file)) return NULL;
 	if (!file_exists(file)) return NULL;
 	return file_read(file, size);
 	return file_read(file, size);
 }
 }
@@ -150,8 +151,10 @@ static void unittest_error (gravity_vm *vm, error_type_t error_type, const char
     }
     }
 }
 }
 
 
-static const char *unittest_read (const char *path, size_t *size, uint32_t *fileid, void *xdata) {
+static const char *unittest_read (const char *path, size_t *size, uint32_t *fileid, void *xdata, bool *is_static) {
     (void) fileid, (void) xdata;
     (void) fileid, (void) xdata;
+    if (is_static) *is_static = false;
+    
     if (file_exists(path)) return file_read(path, size);
     if (file_exists(path)) return file_read(path, size);
     
     
     // this unittest is able to resolve path only next to main test folder (not in nested folders)
     // this unittest is able to resolve path only next to main test folder (not in nested folders)
@@ -212,7 +215,7 @@ static void unittest_scan (const char *folder_path, unittest_data *data) {
         };
         };
         
         
         gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
         gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
-        gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, size, 0, false);
+        gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, size, 0, false, false);
         gravity_vm *vm = gravity_vm_new(&delegate);
         gravity_vm *vm = gravity_vm_new(&delegate);
         gravity_compiler_transfer(compiler, vm);
         gravity_compiler_transfer(compiler, vm);
         gravity_compiler_free(compiler);
         gravity_compiler_free(compiler);
@@ -446,7 +449,7 @@ int main (int argc, const char* argv[]) {
         compiler = gravity_compiler_create(&delegate);
         compiler = gravity_compiler_create(&delegate);
 
 
         // compile source code into a closure
         // compile source code into a closure
-        closure = gravity_compiler_run(compiler, source_code, size, 0, false);
+        closure = gravity_compiler_run(compiler, source_code, size, 0, false, true);
         if (!closure) goto cleanup;
         if (!closure) goto cleanup;
 
 
         // check if closure needs to be serialized
         // check if closure needs to be serialized

+ 12 - 12
src/compiler/debug_macros.h

@@ -55,72 +55,72 @@
 #endif
 #endif
 
 
 #if GRAVITY_PARSER_DEBUG
 #if GRAVITY_PARSER_DEBUG
-#define DEBUG_PARSER(...)           PRINT_LINE(__VA_ARGS__)
+#define DEBUG_PARSER(...)               PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define gravity_parser_debug(p)
 #define gravity_parser_debug(p)
 #define DEBUG_PARSER(...)
 #define DEBUG_PARSER(...)
 #endif
 #endif
 
 
 #if GRAVITY_SEMA1_DEBUG
 #if GRAVITY_SEMA1_DEBUG
-#define DEBUG_SEMA1(...)            PRINT_LINE(__VA_ARGS__)
+#define DEBUG_SEMA1(...)                PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_SEMA1(...)
 #define DEBUG_SEMA1(...)
 #endif
 #endif
 
 
 #if GRAVITY_SEMA2_DEBUG
 #if GRAVITY_SEMA2_DEBUG
-#define DEBUG_SEMA2(...)            PRINT_LINE(__VA_ARGS__)
+#define DEBUG_SEMA2(...)                PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_SEMA2(...)
 #define DEBUG_SEMA2(...)
 #endif
 #endif
 
 
 #if GRAVITY_LOOKUP_DEBUG
 #if GRAVITY_LOOKUP_DEBUG
-#define DEBUG_LOOKUP(...)            PRINT_LINE(__VA_ARGS__)
+#define DEBUG_LOOKUP(...)               PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_LOOKUP(...)
 #define DEBUG_LOOKUP(...)
 #endif
 #endif
 
 
 #if GRAVITY_SYMTABLE_DEBUG
 #if GRAVITY_SYMTABLE_DEBUG
-#define DEBUG_SYMTABLE(...)         printf("%*s",ident*4," ");PRINT_LINE(__VA_ARGS__)
+#define DEBUG_SYMTABLE(...)             printf("%*s",ident*4," ");PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_SYMTABLE(...)
 #define DEBUG_SYMTABLE(...)
 #endif
 #endif
 
 
 #if GRAVITY_CODEGEN_DEBUG
 #if GRAVITY_CODEGEN_DEBUG
-#define DEBUG_CODEGEN(...)          PRINT_LINE(__VA_ARGS__)
+#define DEBUG_CODEGEN(...)              PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_CODEGEN(...)
 #define DEBUG_CODEGEN(...)
 #endif
 #endif
 
 
 #if GRAVITY_OPCODE_DEBUG
 #if GRAVITY_OPCODE_DEBUG
-#define DEBUG_OPCODE(...)           PRINT_LINE(__VA_ARGS__)
+#define DEBUG_OPCODE(...)               PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_OPCODE(...)
 #define DEBUG_OPCODE(...)
 #endif
 #endif
 
 
 #if GRAVITY_BYTECODE_DEBUG
 #if GRAVITY_BYTECODE_DEBUG
-#define DEBUG_BYTECODE(...)         PRINT_LINE(__VA_ARGS__)
+#define DEBUG_BYTECODE(...)             PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_BYTECODE(...)
 #define DEBUG_BYTECODE(...)
 #endif
 #endif
 
 
 #if GRAVITY_REGISTER_DEBUG
 #if GRAVITY_REGISTER_DEBUG
-#define DEBUG_REGISTER(...)         PRINT_LINE(__VA_ARGS__)
+#define DEBUG_REGISTER(...)             PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_REGISTER(...)
 #define DEBUG_REGISTER(...)
 #endif
 #endif
 
 
 #if GRAVITY_FREE_DEBUG
 #if GRAVITY_FREE_DEBUG
-#define DEBUG_FREE(...)             PRINT_LINE(__VA_ARGS__)
+#define DEBUG_FREE(...)                 PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_FREE(...)
 #define DEBUG_FREE(...)
 #endif
 #endif
 
 
 #if GRAVITY_DESERIALIZE_DEBUG
 #if GRAVITY_DESERIALIZE_DEBUG
-#define DEBUG_DESERIALIZE(...)      PRINT_LINE(__VA_ARGS__)
+#define DEBUG_DESERIALIZE(...)          PRINT_LINE(__VA_ARGS__)
 #else
 #else
 #define DEBUG_DESERIALIZE(...)
 #define DEBUG_DESERIALIZE(...)
 #endif
 #endif
 
 
-#define DEBUG_ALWAYS(...)           PRINT_LINE(__VA_ARGS__)
+#define DEBUG_ALWAYS(...)               PRINT_LINE(__VA_ARGS__)
 
 
 #endif
 #endif

+ 1 - 1
src/compiler/gravity_ast.h

@@ -312,7 +312,7 @@ void    *meta_from_node (gnode_t *node);
 #define gnode_array_free(r)                 do {marray_destroy(*r); mem_free((void*)r);} while (0)
 #define gnode_array_free(r)                 do {marray_destroy(*r); mem_free((void*)r);} while (0)
 #define gtype_array_each(r, block, type)    {   size_t _len = gnode_array_size(r);                \
 #define gtype_array_each(r, block, type)    {   size_t _len = gnode_array_size(r);                \
                                                 for (size_t _i=0; _i<_len; ++_i) {                \
                                                 for (size_t _i=0; _i<_len; ++_i) {                \
-                                                    type val = (type)gnode_array_get(r, _i);    \
+                                                    type val = (type)gnode_array_get(r, _i);      \
                                                     block;} \
                                                     block;} \
                                             }
                                             }
 #define gnode_array_each(r, block)          gtype_array_each(r, block, gnode_t*)
 #define gnode_array_each(r, block)          gtype_array_each(r, block, gnode_t*)

+ 121 - 120
src/compiler/gravity_codegen.c

@@ -49,6 +49,7 @@ typedef struct codegen_t codegen_t;
 #define GET_VM()                        ((codegen_t *)self->data)->vm
 #define GET_VM()                        ((codegen_t *)self->data)->vm
 
 
 #define IS_LAST_LOOP(n1,n2)             (n1+1==n2)
 #define IS_LAST_LOOP(n1,n2)             (n1+1==n2)
+#define LINE_NUMBER(__node)             ((node) ? ((gnode_t*)__node)->token.lineno : 0)
 
 
 #if 0
 #if 0
 #define CODEGEN_COUNT_REGISTERS(_n)                     uint32_t _n = ircode_register_count(code)
 #define CODEGEN_COUNT_REGISTERS(_n)                     uint32_t _n = ircode_register_count(code)
@@ -309,7 +310,7 @@ static uint32_t compute_self_register (gvisitor_t *self, ircode_t *code, gnode_t
         uint32_t target = 0;
         uint32_t target = 0;
 
 
         for (uint16_t i=0; i<expr->location.nup; ++i) {
         for (uint16_t i=0; i<expr->location.nup; ++i) {
-            ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS);
+			ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS, LINE_NUMBER(expr));
             target = dest;
             target = dest;
         }
         }
 
 
@@ -360,7 +361,7 @@ static void visit_compound_stmt (gvisitor_t *self, gnode_compound_stmt_t *node)
 
 
     if (node->nclose != UINT32_MAX) {
     if (node->nclose != UINT32_MAX) {
         DECLARE_CODE();
         DECLARE_CODE();
-        ircode_add(code, CLOSE, node->nclose, 0, 0);
+		ircode_add(code, CLOSE, node->nclose, 0, 0, LINE_NUMBER(node));
     }
     }
 }
 }
 
 
@@ -404,15 +405,15 @@ static void visit_flow_if_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
     visit(node->cond);
     visit(node->cond);
     uint32_t reg = ircode_register_pop(code);
     uint32_t reg = ircode_register_pop(code);
     if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid if condition expression.");
     if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid if condition expression.");
-    ircode_add(code, JUMPF, reg, labelFalse, 0);
+	ircode_add(code, JUMPF, reg, labelFalse, 0, LINE_NUMBER(node));
 
 
     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, LINE_NUMBER(node));
 
 
-    ircode_marklabel(code, labelFalse);
+	ircode_marklabel(code, labelFalse, LINE_NUMBER(node));
     if (node->elsestmt) {
     if (node->elsestmt) {
         visit(node->elsestmt);
         visit(node->elsestmt);
-        ircode_marklabel(code, labelTrue);
+		ircode_marklabel(code, labelTrue, LINE_NUMBER(node));
     }
     }
 }
 }
 
 
@@ -465,16 +466,16 @@ static void visit_loop_while_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_false(code, labelFalse);
     ircode_setlabel_false(code, labelFalse);
 
 
-    ircode_marklabel(code, labelTrue);
+	ircode_marklabel(code, labelTrue, LINE_NUMBER(node));
     visit(node->cond);
     visit(node->cond);
     uint32_t reg = ircode_register_pop(code);
     uint32_t reg = ircode_register_pop(code);
     if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid while condition expression.");
     if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid while condition expression.");
-    ircode_add(code, JUMPF, reg, labelFalse, 0);
+	ircode_add(code, JUMPF, reg, labelFalse, 0, LINE_NUMBER(node));
 
 
     visit(node->stmt);
     visit(node->stmt);
-    ircode_add(code, JUMP, labelTrue, 0, 0);
+	ircode_add(code, JUMP, labelTrue, 0, 0, LINE_NUMBER(node));
 
 
-    ircode_marklabel(code, labelFalse);
+	ircode_marklabel(code, labelFalse, LINE_NUMBER(node));
 
 
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_false(code);
     ircode_unsetlabel_false(code);
@@ -496,15 +497,15 @@ static void visit_loop_repeat_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_false(code, labelFalse);
     ircode_setlabel_false(code, labelFalse);
 
 
-    ircode_marklabel(code, labelTrue);
+	ircode_marklabel(code, labelTrue, LINE_NUMBER(node));
     visit(node->stmt);
     visit(node->stmt);
     visit(node->expr);
     visit(node->expr);
     uint32_t reg = ircode_register_pop(code);
     uint32_t reg = ircode_register_pop(code);
     if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid repeat condition expression.");
     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, JUMPF, reg, labelFalse, 0, LINE_NUMBER(node));
+	ircode_add(code, JUMP, labelTrue, 0, 0, LINE_NUMBER(node));
 
 
-    ircode_marklabel(code, labelFalse);
+	ircode_marklabel(code, labelFalse, LINE_NUMBER(node));
 
 
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_false(code);
     ircode_unsetlabel_false(code);
@@ -550,26 +551,26 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     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.");
     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, LINE_NUMBER(node));
 
 
     // generate code for $value = $expr.iterate(null);
     // generate code for $value = $expr.iterate(null);
     uint32_t iterate_fn = ircode_register_push_temp(code);        // ++TEMP => 3
     uint32_t iterate_fn = ircode_register_push_temp(code);        // ++TEMP => 3
-    ircode_add(code, LOADK, iterate_fn, iterate_idx, 0);
-    ircode_add(code, LOAD, iterate_fn, $expr, iterate_fn);
+	ircode_add(code, LOADK, iterate_fn, iterate_idx, 0, LINE_NUMBER(node));
+	ircode_add(code, LOAD, iterate_fn, $expr, iterate_fn, LINE_NUMBER(node));
     ircode_register_set_skip_clear(code, iterate_fn);
     ircode_register_set_skip_clear(code, iterate_fn);
 
 
     uint32_t next_fn = ircode_register_push_temp(code);            // ++TEMP => 4
     uint32_t next_fn = ircode_register_push_temp(code);            // ++TEMP => 4
-    ircode_add(code, LOADK, next_fn, next_idx, 0);
-    ircode_add(code, LOAD, next_fn, $expr, next_fn);
+	ircode_add(code, LOADK, next_fn, next_idx, 0, LINE_NUMBER(node));
+	ircode_add(code, LOAD, next_fn, $expr, next_fn, LINE_NUMBER(node));
     ircode_register_set_skip_clear(code, next_fn);
     ircode_register_set_skip_clear(code, next_fn);
 
 
     uint32_t temp1 = ircode_register_push_temp(code);            // ++TEMP => 5
     uint32_t temp1 = ircode_register_push_temp(code);            // ++TEMP => 5
-    ircode_add(code, MOVE, temp1, iterate_fn, 0);
+	ircode_add(code, MOVE, temp1, iterate_fn, 0, LINE_NUMBER(node));
     uint32_t temp2 = ircode_register_push_temp(code);            // ++TEMP => 6
     uint32_t temp2 = ircode_register_push_temp(code);            // ++TEMP => 6
-    ircode_add(code, MOVE, temp2, $expr, 0);
+	ircode_add(code, MOVE, temp2, $expr, 0, LINE_NUMBER(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, CALL, $value, temp1, 2);
+	ircode_add(code, LOADK, temp2, CPOOL_VALUE_NULL, 0, LINE_NUMBER(node));
+	ircode_add(code, CALL, $value, temp1, 2, LINE_NUMBER(node));
     uint32_t temp = ircode_register_pop(code);                    // --TEMP => 6
     uint32_t temp = ircode_register_pop(code);                    // --TEMP => 6
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
     temp = ircode_register_pop(code);                            // --TEMP => 5
     temp = ircode_register_pop(code);                            // --TEMP => 5
@@ -583,18 +584,18 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_true(code, labelTrue);
     ircode_setlabel_false(code, labelFalse);
     ircode_setlabel_false(code, labelFalse);
 
 
-    ircode_marklabel(code, labelTrue);
-    ircode_add(code, JUMPF, $value, labelFalse, 1);                // flag JUMPF instruction to check ONLY BOOL values
+	ircode_marklabel(code, labelTrue, LINE_NUMBER(node));
+	ircode_add(code, JUMPF, $value, labelFalse, 1, LINE_NUMBER(node));				// flag JUMPF instruction to check ONLY BOOL values
 
 
     // cond = $expr.next($value);
     // cond = $expr.next($value);
     // cond is a local variable
     // cond is a local variable
     temp1 = ircode_register_push_temp(code);                    // ++TEMP => 5
     temp1 = ircode_register_push_temp(code);                    // ++TEMP => 5
-    ircode_add(code, MOVE, temp1, next_fn, 0);
+	ircode_add(code, MOVE, temp1, next_fn, 0, LINE_NUMBER(node));
     temp2 = ircode_register_push_temp(code);                    // ++TEMP => 6
     temp2 = ircode_register_push_temp(code);                    // ++TEMP => 6
-    ircode_add(code, MOVE, temp2, $expr, 0);
+	ircode_add(code, MOVE, temp2, $expr, 0, LINE_NUMBER(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, CALL, cond_idx, temp1, 2);
+	ircode_add(code, MOVE, temp2, $value, 0, LINE_NUMBER(node));
+	ircode_add(code, CALL, cond_idx, temp1, 2, LINE_NUMBER(node));
 
 
     // process statement
     // process statement
     visit(node->stmt);
     visit(node->stmt);
@@ -610,12 +611,12 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     // update $value for the next check
     // update $value for the next check
     // $value = $expr.iterate($value);
     // $value = $expr.iterate($value);
     temp1 = ircode_register_push_temp(code);                    // ++TEMP => 5
     temp1 = ircode_register_push_temp(code);                    // ++TEMP => 5
-    ircode_add(code, MOVE, temp1, iterate_fn, 0);
+	ircode_add(code, MOVE, temp1, iterate_fn, 0, LINE_NUMBER(node));
     temp2 = ircode_register_push_temp(code);                    // ++TEMP => 6
     temp2 = ircode_register_push_temp(code);                    // ++TEMP => 6
-    ircode_add(code, MOVE, temp2, $expr, 0);
+	ircode_add(code, MOVE, temp2, $expr, 0, LINE_NUMBER(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, CALL, $value, temp1, 2);
+	ircode_add(code, MOVE, temp2, $value, 0, LINE_NUMBER(node));
+	ircode_add(code, CALL, $value, temp1, 2, LINE_NUMBER(node));
     temp = ircode_register_pop(code);                            // --TEMP => 6
     temp = ircode_register_pop(code);                            // --TEMP => 6
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
     temp = ircode_register_pop(code);                            // --TEMP => 5
     temp = ircode_register_pop(code);                            // --TEMP => 5
@@ -623,9 +624,9 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     temp = ircode_register_pop(code);                            // --TEMP => 4
     temp = ircode_register_pop(code);                            // --TEMP => 4
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
     DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
 
 
-    ircode_add(code, JUMP, labelTrue, 0, 0);
+	ircode_add(code, JUMP, labelTrue, 0, 0, LINE_NUMBER(node));
 
 
-    ircode_marklabel(code, labelFalse);
+	ircode_marklabel(code, labelFalse, LINE_NUMBER(node));
 
 
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_true(code);
     ircode_unsetlabel_false(code);
     ircode_unsetlabel_false(code);
@@ -645,7 +646,7 @@ static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
     ircode_register_unset_skip_clear(code, next_fn);
     ircode_register_unset_skip_clear(code, next_fn);
 
 
     if (node->nclose != UINT32_MAX) {
     if (node->nclose != UINT32_MAX) {
-        ircode_add(code, CLOSE, node->nclose, 0, 0);
+		ircode_add(code, CLOSE, node->nclose, 0, 0, LINE_NUMBER(node));
     }
     }
 }
 }
 
 
@@ -673,18 +674,18 @@ static void visit_jump_stmt (gvisitor_t *self, gnode_jump_stmt_t *node) {
 
 
     if (type == TOK_KEY_BREAK) {
     if (type == TOK_KEY_BREAK) {
         uint32_t label = ircode_getlabel_false(code);
         uint32_t label = ircode_getlabel_false(code);
-        ircode_add(code, JUMP, label, 0, 0); // goto $end;
+		ircode_add(code, JUMP, label, 0, 0, LINE_NUMBER(node)); // goto $end;
     } else if (type == TOK_KEY_CONTINUE) {
     } else if (type == TOK_KEY_CONTINUE) {
         uint32_t label = ircode_getlabel_true(code);
         uint32_t label = ircode_getlabel_true(code);
-        ircode_add(code, JUMP, label, 0, 0); // goto $start;
+		ircode_add(code, JUMP, label, 0, 0, LINE_NUMBER(node)); // goto $start;
     } else if (type == TOK_KEY_RETURN) {
     } else if (type == TOK_KEY_RETURN) {
         if (node->expr) {
         if (node->expr) {
             visit(node->expr);
             visit(node->expr);
             uint32_t reg = ircode_register_pop(code);
             uint32_t reg = ircode_register_pop(code);
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid return expression.");
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid return expression.");
-            ircode_add(code, RET, reg, 0, 0);
+			ircode_add(code, RET, reg, 0, 0, LINE_NUMBER(node));
         } else {
         } else {
-            ircode_add(code, RET0, 0, 0, 0);
+			ircode_add(code, RET0, 0, 0, 0, LINE_NUMBER(node));
         }
         }
     }
     }
 }
 }
@@ -694,7 +695,7 @@ static void visit_empty_stmt (gvisitor_t *self, gnode_empty_stmt_t *node) {
     DEBUG_CODEGEN("visit_empty_stmt");
     DEBUG_CODEGEN("visit_empty_stmt");
 
 
     DECLARE_CODE();
     DECLARE_CODE();
-    ircode_add(code, NOP, 0, 0, 0);
+	ircode_add(code, NOP, 0, 0, 0, LINE_NUMBER(node));
 }
 }
 
 
 // MARK: - Declarations -
 // MARK: - Declarations -
@@ -726,22 +727,22 @@ static void store_declaration (gvisitor_t *self, gravity_object_t *obj, bool is_
 
 
             gravity_function_t *f = (gravity_function_t *)obj;
             gravity_function_t *f = (gravity_function_t *)obj;
             uint32_t regnum = ircode_register_push_temp(code);
             uint32_t regnum = ircode_register_push_temp(code);
-            ircode_add(code, CLOSURE, regnum, index, 0);
+			ircode_add(code, CLOSURE, regnum, index, 0, LINE_NUMBER(node));
             uint32_t upindex = 0;
             uint32_t upindex = 0;
             for (uint16_t i=0; i<f->nupvalues; ++i) {
             for (uint16_t i=0; i<f->nupvalues; ++i) {
                 gupvalue_t *upvalue = (gupvalue_t *)gnode_array_get(node->uplist, i);
                 gupvalue_t *upvalue = (gupvalue_t *)gnode_array_get(node->uplist, i);
                 uint32_t opindex = (upvalue->is_direct) ? upvalue->index : upindex++;
                 uint32_t opindex = (upvalue->is_direct) ? upvalue->index : upindex++;
-                ircode_add(code, MOVE, opindex, (upvalue->is_direct) ? 1 : 0, 0);
+				ircode_add(code, MOVE, opindex, (upvalue->is_direct) ? 1 : 0, 0, LINE_NUMBER(node));
             }
             }
         } else {
         } else {
-            ircode_add_constant(code, index);
+			ircode_add_constant(code, index, LINE_NUMBER(node));
         }
         }
 
 
         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));
             uint32_t reg = ircode_register_pop(code);
             uint32_t reg = ircode_register_pop(code);
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid declaration expression.");
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid declaration expression.");
-            ircode_add(code, STOREG, reg, index, 0);
+			ircode_add(code, STOREG, reg, index, 0, LINE_NUMBER(node));
         }
         }
 
 
         return;
         return;
@@ -822,15 +823,15 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c, gnode_t *
         // 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;}
         if (!code) {report_error(self, node, "Invalid code context."); return;}
-        ircode_add(code, RET0, 0, 0, 0);
+		ircode_add(code, RET0, 0, 0, 0, LINE_NUMBER(node));
 
 
         if (constructor_function == NULL) {
         if (constructor_function == NULL) {
             constructor_function = gravity_function_new(NULL, CLASS_CONSTRUCTOR_NAME, 1, 0, 2, ircode_create(1));
             constructor_function = gravity_function_new(NULL, CLASS_CONSTRUCTOR_NAME, 1, 0, 2, ircode_create(1));
             ircode_t *code2 = (ircode_t *)constructor_function->bytecode;
             ircode_t *code2 = (ircode_t *)constructor_function->bytecode;
-            ircode_add_skip(code2);    // LOADK
-            ircode_add_skip(code2);    // LOAD
-            ircode_add_skip(code2);    // MOVE
-            ircode_add_skip(code2);    // CALL
+			ircode_add_skip(code2, LINE_NUMBER(node));	// LOADK
+			ircode_add_skip(code2, LINE_NUMBER(node));	// LOAD
+			ircode_add_skip(code2, LINE_NUMBER(node));	// MOVE
+			ircode_add_skip(code2, LINE_NUMBER(node));	// CALL
             gravity_class_bind(c, CLASS_CONSTRUCTOR_NAME, VALUE_FROM_OBJECT(constructor_function));
             gravity_class_bind(c, CLASS_CONSTRUCTOR_NAME, VALUE_FROM_OBJECT(constructor_function));
         }
         }
     }
     }
@@ -840,7 +841,7 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c, gnode_t *
         // 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;}
         if (!code) {report_error(self, node, "Invalid code context."); return;}
-        ircode_add(code, RET, 0, 0, 0);
+		ircode_add(code, RET, 0, 0, 0, LINE_NUMBER(node));
 
 
         if (internal_init_function) {
         if (internal_init_function) {
             // if an internal init function is present ($init) then add a call to it as a first instruction
             // if an internal init function is present ($init) then add a call to it as a first instruction
@@ -864,8 +865,8 @@ static void process_constructor (gvisitor_t *self, gravity_class_t *c, gnode_t *
         }
         }
     }
     }
 
 
-    if (internal_init_function) gravity_optimizer(internal_init_function);
-    if (constructor_function) gravity_optimizer(constructor_function);
+	if (internal_init_function) gravity_optimizer(internal_init_function, false);
+	if (constructor_function) gravity_optimizer(constructor_function, false);
 
 
 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
@@ -894,7 +895,7 @@ static void process_getter_setter (gvisitor_t *self, gnode_var_t *p, gravity_cla
         if (block) {gnode_array_each(block->stmts, {visit(val);});}
         if (block) {gnode_array_each(block->stmts, {visit(val);});}
         CONTEXT_POP();
         CONTEXT_POP();
 
 
-        gravity_optimizer(f2[i]);
+		gravity_optimizer(f2[i], self->bflag);
     }
     }
 
 
     // getter and setter NULL means default
     // getter and setter NULL means default
@@ -945,10 +946,10 @@ static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node)
         // 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;}
         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, LINE_NUMBER(node));
+		ircode_add_skip(code, LINE_NUMBER(node));
+		ircode_add_skip(code, LINE_NUMBER(node));
+		ircode_add_skip(code, LINE_NUMBER(node));
     }
     }
 
 
     // process inner block
     // process inner block
@@ -976,7 +977,7 @@ static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node)
     store_declaration(self, (gravity_object_t *)f, (node->storage == TOK_KEY_STATIC), node);
     store_declaration(self, (gravity_object_t *)f, (node->storage == TOK_KEY_STATIC), node);
 
 
     // convert ircode to bytecode (postpone optimization of the constructor)
     // convert ircode to bytecode (postpone optimization of the constructor)
-    if (!is_constructor) gravity_optimizer(f);
+	if (!is_constructor) gravity_optimizer(f, self->bflag);
 }
 }
 
 
 static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
 static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
@@ -1024,10 +1025,10 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
                 // assign to variable result of the expression
                 // assign to variable result of the expression
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
-                ircode_add(code, MOVE, p->index, reg, 0);
+				ircode_add(code, MOVE, p->index, reg, 0, LINE_NUMBER(node));
             } 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, LINE_NUMBER(node));
             }
             }
             continue;
             continue;
         }
         }
@@ -1056,11 +1057,11 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
             if (p->expr) {
             if (p->expr) {
                 visit(p->expr); // context is a function
                 visit(p->expr); // context is a function
             } else {
             } else {
-                ircode_add_constant(code, CPOOL_VALUE_NULL);
+				ircode_add_constant(code, CPOOL_VALUE_NULL, LINE_NUMBER(node));
             }
             }
             uint32_t reg = ircode_register_pop(code);
             uint32_t reg = ircode_register_pop(code);
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
-            ircode_add(code, STOREG, reg, index, 0);
+			ircode_add(code, STOREG, reg, index, 0, LINE_NUMBER(node));
             continue;
             continue;
         }
         }
 
 
@@ -1115,7 +1116,7 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
                 visit(p->expr);
                 visit(p->expr);
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
-                ircode_add(code, STORE, reg, 0, p->index + MAX_REGISTERS);
+				ircode_add(code, STORE, reg, 0, p->index + MAX_REGISTERS, LINE_NUMBER(node));
                 CONTEXT_POP();
                 CONTEXT_POP();
             }
             }
 
 
@@ -1243,13 +1244,13 @@ static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
 
 
     // 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
     if ((node->op == TOK_OP_RANGE_INCLUDED) || (node->op == TOK_OP_RANGE_EXCLUDED)) {
     if ((node->op == TOK_OP_RANGE_INCLUDED) || (node->op == TOK_OP_RANGE_EXCLUDED)) {
-        ircode_add_tag(code, RANGENEW, r1, r2, r3, (node->op == TOK_OP_RANGE_INCLUDED) ? RANGE_INCLUDE_TAG : RANGE_EXCLUDE_TAG);
+		ircode_add_tag(code, RANGENEW, r1, r2, r3, (node->op == TOK_OP_RANGE_INCLUDED) ? RANGE_INCLUDE_TAG : RANGE_EXCLUDE_TAG, LINE_NUMBER(node));
         return;
         return;
     }
     }
 
 
     // generate code for binary OP
     // generate code for binary OP
     opcode_t op = token2opcode(node->op);
     opcode_t op = token2opcode(node->op);
-    ircode_add(code, op, r1, r2, r3);
+	ircode_add(code, op, r1, r2, r3, LINE_NUMBER(node));
 
 
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
@@ -1278,7 +1279,7 @@ static void visit_unary_expr (gvisitor_t *self, gnode_unary_expr_t *node) {
     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);
-    ircode_add(code, op, r1, r2, 0);
+	ircode_add(code, op, r1, r2, 0, LINE_NUMBER(node));
 
 
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
@@ -1298,7 +1299,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
     ircode_push_context(code);
     ircode_push_context(code);
 
 
     // disable MOVE optimization
     // disable MOVE optimization
-    ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
+	ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0, LINE_NUMBER(node));
 
 
     // generate code for the common id node
     // generate code for the common id node
     visit(node->id);
     visit(node->id);
@@ -1357,7 +1358,7 @@ 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, LINE_NUMBER(node));
             uint32_t treg = ircode_register_pop_context_protect(code, true);
             uint32_t treg = ircode_register_pop_context_protect(code, true);
             if (treg == REGISTER_ERROR) {
             if (treg == REGISTER_ERROR) {
                 report_error(self, (gnode_t *)subnode, "Unexpected register error.");
                 report_error(self, (gnode_t *)subnode, "Unexpected register error.");
@@ -1367,7 +1368,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
             // 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, LINE_NUMBER(node));
             treg = ircode_register_pop_context_protect(code, true);
             treg = ircode_register_pop_context_protect(code, true);
             if (treg == REGISTER_ERROR) {
             if (treg == REGISTER_ERROR) {
                 report_error(self, (gnode_t *)subnode, "Unexpected register error.");
                 report_error(self, (gnode_t *)subnode, "Unexpected register error.");
@@ -1380,9 +1381,9 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
             for (size_t j=0; j<n; ++j) {
             for (size_t j=0; j<n; ++j) {
                 // process each argument
                 // process each argument
                 gnode_t *arg = (gnode_t *)gnode_array_get(subnode->args, j);
                 gnode_t *arg = (gnode_t *)gnode_array_get(subnode->args, j);
-                ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1);
+				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1, LINE_NUMBER(node));
                 visit(arg);
                 visit(arg);
-                ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
+				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0, LINE_NUMBER(node));
                 uint32_t nreg = ircode_register_pop_context_protect(code, true);
                 uint32_t nreg = ircode_register_pop_context_protect(code, true);
                 if (nreg == REGISTER_ERROR) {
                 if (nreg == REGISTER_ERROR) {
                     report_error(self, (gnode_t *)arg, "Invalid argument expression at index %d.", j+1);
                     report_error(self, (gnode_t *)arg, "Invalid argument expression at index %d.", j+1);
@@ -1393,7 +1394,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
                 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);
                     if (temp == 0) return; // temp value == 0 means codegen error (error will be automatically reported later in visit_function_decl
                     if (temp == 0) return; // temp value == 0 means codegen error (error will be automatically reported later in visit_function_decl
-                    ircode_add(code, MOVE, temp, nreg, 0);
+					ircode_add(code, MOVE, temp, nreg, 0, LINE_NUMBER(node));
                     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) {
                     if (nreg == REGISTER_ERROR) {
@@ -1409,7 +1410,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
             }
             }
 
 
             // generate instruction CALL with count parameters (taking in account self)
             // generate instruction CALL with count parameters (taking in account self)
-            ircode_add(code, CALL, dest_register, temp_target_register, (uint32_t)n+1);
+			ircode_add(code, CALL, dest_register, temp_target_register, (uint32_t)n+1, LINE_NUMBER(node));
 
 
             // cleanup temp registers
             // cleanup temp registers
             ircode_register_clear(code, temp_target_register);
             ircode_register_clear(code, temp_target_register);
@@ -1450,7 +1451,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
             gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)subnode->expr;
             gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)subnode->expr;
             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, LINE_NUMBER(expr));
             uint32_t temp = ircode_register_pop(code);
             uint32_t temp = ircode_register_pop(code);
             if (temp == REGISTER_ERROR) {
             if (temp == REGISTER_ERROR) {
                 report_error(self, (gnode_t *)expr, "Invalid access expression.");
                 report_error(self, (gnode_t *)expr, "Invalid access expression.");
@@ -1464,8 +1465,8 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
                 return;
                 return;
             }
             }
 
 
-            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);
+			if (is_super) ircode_add(code, LOADS, dest_register, target_register, index_register, LINE_NUMBER(node));
+			else ircode_add(code, (is_real_assigment) ? STORE : LOAD, dest_register, target_register, index_register, LINE_NUMBER(node));
             if (!is_real_assigment) {
             if (!is_real_assigment) {
                 if (i+1<count) {
                 if (i+1<count) {
                 uint32_t rtemp = ircode_register_pop_context_protect(code, true);
                 uint32_t rtemp = ircode_register_pop_context_protect(code, true);
@@ -1489,9 +1490,9 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 
 
         } else if (tag == NODE_SUBSCRIPT_EXPR) {
         } else if (tag == NODE_SUBSCRIPT_EXPR) {
             // process index
             // process index
-            ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1);
+			ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1, LINE_NUMBER(node));
             visit(subnode->expr);
             visit(subnode->expr);
-            ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
+			ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0, LINE_NUMBER(node));
             uint32_t index = ircode_register_pop(code);
             uint32_t index = ircode_register_pop(code);
             if (index == REGISTER_ERROR) {
             if (index == REGISTER_ERROR) {
                 report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
                 report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
@@ -1504,7 +1505,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
                 report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
                 report_error(self, (gnode_t *)subnode->expr, "Invalid subscript expression.");
                 return;
                 return;
             }
             }
-            ircode_add(code, (is_assignment) ? STOREAT : LOADAT, dest_register, target_register, index);
+			ircode_add(code, (is_assignment) ? STOREAT : LOADAT, dest_register, target_register, index, LINE_NUMBER(node));
             if ((!is_real_assigment) && (i+1<count)) {
             if ((!is_real_assigment) && (i+1<count)) {
                 uint32_t rtemp = ircode_register_pop_context_protect(code, true);
                 uint32_t rtemp = ircode_register_pop_context_protect(code, true);
                 if (rtemp == REGISTER_ERROR) {
                 if (rtemp == REGISTER_ERROR) {
@@ -1531,7 +1532,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
         ircode_register_pop(code);
         ircode_register_pop(code);
         // allocate a new register (that I am now sure does not have holes)
         // allocate a new register (that I am now sure does not have holes)
         temp_register = ircode_register_push_temp(code);
         temp_register = ircode_register_push_temp(code);
-        ircode_add(code, MOVE, temp_register, dest_register, 0);
+        ircode_add(code, MOVE, temp_register, dest_register, 0, LINE_NUMBER(node));
         ircode_register_clear(code, dest_register);
         ircode_register_clear(code, dest_register);
     }
     }
     
     
@@ -1539,7 +1540,7 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
     CODEGEN_ASSERT_REGISTERS(n1, n2, (is_assignment) ? -1 : 1);
     CODEGEN_ASSERT_REGISTERS(n1, n2, (is_assignment) ? -1 : 1);
 
 
     // re-enable MOVE optimization
     // re-enable MOVE optimization
-    ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1);
+	ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1, LINE_NUMBER(node));
 }
 }
 
 
 static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
 static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
@@ -1559,9 +1560,9 @@ static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
         if ((is_assignment) && (IS_LAST_LOOP(i, count))) {
         if ((is_assignment) && (IS_LAST_LOOP(i, count))) {
             uint32_t reg = ircode_register_pop(code);
             uint32_t reg = ircode_register_pop(code);
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid file expression.");
             if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid file expression.");
-            ircode_add(code, STOREG, reg, kindex, 0);
+			ircode_add(code, STOREG, reg, kindex, 0, LINE_NUMBER(node));
         } else {
         } else {
-            ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
+			ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0, LINE_NUMBER(node));
         }
         }
     }
     }
 
 
@@ -1590,25 +1591,25 @@ static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
         case LITERAL_STRING: {
         case LITERAL_STRING: {
             // LOADK temp, s
             // LOADK temp, s
             uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_STRING(NULL, node->value.str, node->len));
             uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_STRING(NULL, node->value.str, node->len));
-            ircode_add_constant(code, index);
+			ircode_add_constant(code, index, LINE_NUMBER(node));
             DEBUG_CODEGEN("visit_literal_expr (string) %s", node->value.str);
             DEBUG_CODEGEN("visit_literal_expr (string) %s", node->value.str);
         } break;
         } break;
 
 
         case LITERAL_FLOAT:
         case LITERAL_FLOAT:
             // LOADI temp, d
             // LOADI temp, d
-            ircode_add_double(code, node->value.d);
-            DEBUG_CODEGEN("visit_literal_expr (float) %.2f", node->value.d);
+			ircode_add_double(code, node->value.d, LINE_NUMBER(node));
+			DEBUG_CODEGEN("visit_literal_expr (float) %.5f", node->value.d);
             break;
             break;
 
 
         case LITERAL_INT:
         case LITERAL_INT:
             // LOADI temp, n
             // LOADI temp, n
-            ircode_add_int(code, node->value.n64);
+			ircode_add_int(code, node->value.n64, LINE_NUMBER(node));
             DEBUG_CODEGEN("visit_literal_expr (int) %lld", node->value.n64);
             DEBUG_CODEGEN("visit_literal_expr (int) %lld", node->value.n64);
             break;
             break;
 
 
         case LITERAL_BOOL: {
         case LITERAL_BOOL: {
             uint32_t value = (node->value.n64 == 0) ? CPOOL_VALUE_FALSE : CPOOL_VALUE_TRUE;
             uint32_t value = (node->value.n64 == 0) ? CPOOL_VALUE_FALSE : CPOOL_VALUE_TRUE;
-            ircode_add_constant(code, value);
+			ircode_add_constant(code, value, LINE_NUMBER(node));
             DEBUG_CODEGEN("visit_literal_expr (bool) %lld", node->value.n64);
             DEBUG_CODEGEN("visit_literal_expr (bool) %lld", node->value.n64);
         } break;
         } break;
 
 
@@ -1624,21 +1625,21 @@ static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
 
 
             // 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, LINE_NUMBER(node));
             uint32_t temp1 = ircode_register_last(code);
             uint32_t temp1 = ircode_register_last(code);
             DEBUG_ASSERT(temp1 != REGISTER_ERROR, "Unexpected register error.");
             DEBUG_ASSERT(temp1 != REGISTER_ERROR, "Unexpected register error.");
 
 
             // LOAD
             // LOAD
-            ircode_add(code, LOAD, temp1, listreg, temp1);
+			ircode_add(code, LOAD, temp1, listreg, temp1, LINE_NUMBER(node));
 
 
             // temp1+1 register used for parameter passing
             // temp1+1 register used for parameter passing
             uint32_t temp2 = ircode_register_push_temp(code);
             uint32_t temp2 = ircode_register_push_temp(code);
 
 
             // MOVE
             // MOVE
-            ircode_add(code, MOVE, temp2, listreg, 0);
+			ircode_add(code, MOVE, temp2, listreg, 0, LINE_NUMBER(node));
 
 
             // CALL
             // CALL
-            ircode_add(code, CALL, listreg, temp1, 1);
+			ircode_add(code, CALL, listreg, temp1, 1, LINE_NUMBER(node));
 
 
             // cleanup
             // cleanup
             mem_free(list);
             mem_free(list);
@@ -1688,7 +1689,7 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
             if (is_assignment) {
             if (is_assignment) {
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
-                ircode_add(code, MOVE, index, reg, 0);
+				ircode_add(code, MOVE, index, reg, 0, LINE_NUMBER(node));
             } else {
             } else {
                 ircode_register_push(code, index);
                 ircode_register_push(code, index);
             }
             }
@@ -1700,9 +1701,9 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
             if (is_assignment) {
             if (is_assignment) {
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
-                ircode_add(code, STOREG, reg, kindex, 0);
+				ircode_add(code, STOREG, reg, kindex, 0, LINE_NUMBER(node));
             } else {
             } else {
-                ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
+				ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0, LINE_NUMBER(node));
             }
             }
         } break;
         } break;
 
 
@@ -1712,9 +1713,9 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
             if (is_assignment) {
             if (is_assignment) {
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid identifier expression.");
-                ircode_add(code, STOREU, reg, upvalue->selfindex, 0);
+				ircode_add(code, STOREU, reg, upvalue->selfindex, 0, LINE_NUMBER(node));
             } else {
             } 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, LINE_NUMBER(node));
             }
             }
         } break;
         } break;
 
 
@@ -1729,7 +1730,7 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
             if (type == LOCATION_CLASS_IVAR_OUTER) {
             if (type == LOCATION_CLASS_IVAR_OUTER) {
                 dest = ircode_register_push_temp(code);
                 dest = ircode_register_push_temp(code);
                 for (uint16_t i=0; i<nup; ++i) {
                 for (uint16_t i=0; i<nup; ++i) {
-                    ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS);
+					ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS, LINE_NUMBER(node));
                     target = dest;
                     target = dest;
                 }
                 }
                 if (is_assignment) {
                 if (is_assignment) {
@@ -1748,7 +1749,7 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
                 // first class citizen at runtime too)
                 // first class citizen at runtime too)
                 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, LINE_NUMBER(node));
                 uint32_t temp = ircode_register_pop(code);
                 uint32_t temp = ircode_register_pop(code);
                 DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
                 DEBUG_ASSERT(temp != REGISTER_ERROR, "Unexpected register error.");
             }
             }
@@ -1757,10 +1758,10 @@ static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *no
                 // 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.");
                 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, LINE_NUMBER(node));
             } 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);
-                ircode_add(code, LOAD, dest , target, index_register);
+				ircode_add(code, LOAD, dest , target, index_register, LINE_NUMBER(node));
             }
             }
         } break;
         } break;
     }
     }
@@ -1778,38 +1779,37 @@ static void visit_keyword_expr (gvisitor_t *self, gnode_keyword_expr_t *node) {
     gtoken_t type = NODE_TOKEN_TYPE(node);
     gtoken_t type = NODE_TOKEN_TYPE(node);
     switch (type) {
     switch (type) {
         case TOK_KEY_CURRFUNC:
         case TOK_KEY_CURRFUNC:
-            ircode_add_constant(code, CPOOL_VALUE_FUNC);
+			ircode_add_constant(code, CPOOL_VALUE_FUNC, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_NULL:
         case TOK_KEY_NULL:
-            ircode_add_constant(code, CPOOL_VALUE_NULL);
+			ircode_add_constant(code, CPOOL_VALUE_NULL, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_SUPER:
         case TOK_KEY_SUPER:
-            ircode_add_constant(code, CPOOL_VALUE_SUPER);
+			ircode_add_constant(code, CPOOL_VALUE_SUPER, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_CURRARGS:
         case TOK_KEY_CURRARGS:
             // compiler can know in advance if arguments special array is used
             // compiler can know in advance if arguments special array is used
             context_function->useargs = true;
             context_function->useargs = true;
-            ircode_add_constant(code, CPOOL_VALUE_ARGUMENTS);
+			ircode_add_constant(code, CPOOL_VALUE_ARGUMENTS, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_UNDEFINED:
         case TOK_KEY_UNDEFINED:
-            ircode_add_constant(code, CPOOL_VALUE_UNDEFINED);
+			ircode_add_constant(code, CPOOL_VALUE_UNDEFINED, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_TRUE:
         case TOK_KEY_TRUE:
-            ircode_add_constant(code, CPOOL_VALUE_TRUE);
+			ircode_add_constant(code, CPOOL_VALUE_TRUE, LINE_NUMBER(node));
             break;
             break;
 
 
         case TOK_KEY_FALSE:
         case TOK_KEY_FALSE:
-            ircode_add_constant(code, CPOOL_VALUE_FALSE);
+			ircode_add_constant(code, CPOOL_VALUE_FALSE, LINE_NUMBER(node));
             break;
             break;
 
 
         default:
         default:
-            // should never reach this point
-            assert(0);
+            report_error(self, (gnode_t *)node, "Invalid keyword expression.");
             break;
             break;
     }
     }
 
 
@@ -1832,7 +1832,7 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
     // destination register of a new instruction is ALWAYS a temp register
     // destination register of a new instruction is ALWAYS a temp register
     // then the optimizer could decide to optimize and merge the step
     // then the optimizer could decide to optimize and merge the step
     uint32_t dest = ircode_register_push_temp(code);
     uint32_t dest = ircode_register_push_temp(code);
-    ircode_add(code, (ismap) ? MAPNEW : LISTNEW, dest, n, 0);
+	ircode_add(code, (ismap) ? MAPNEW : LISTNEW, dest, n, 0, LINE_NUMBER(node));
     if (n == 0) return;
     if (n == 0) return;
 
 
     // this is just like Lua "fields per flush"
     // this is just like Lua "fields per flush"
@@ -1842,7 +1842,7 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
     if (n % max_fields != 0) ++nloops;
     if (n % max_fields != 0) ++nloops;
     uint32_t nprocessed = 0;
     uint32_t nprocessed = 0;
 
 
-    ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
+	ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0, LINE_NUMBER(node));
     while (nprocessed < n) {
     while (nprocessed < n) {
         size_t k = (n - nprocessed > max_fields) ? max_fields : (n - nprocessed);
         size_t k = (n - nprocessed > max_fields) ? max_fields : (n - nprocessed);
         size_t idxstart = nprocessed;
         size_t idxstart = nprocessed;
@@ -1867,7 +1867,7 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 
 
             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, LINE_NUMBER(node));
                 ircode_register_clear(code, nreg);
                 ircode_register_clear(code, nreg);
                 uint32_t temp = ircode_register_pop_context_protect(code, true);
                 uint32_t temp = ircode_register_pop_context_protect(code, true);
                 if (temp == REGISTER_ERROR) {report_error(self, (gnode_t *)e, "Unexpected register error."); continue;}
                 if (temp == REGISTER_ERROR) {report_error(self, (gnode_t *)e, "Unexpected register error."); continue;}
@@ -1876,9 +1876,9 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 
 
             if (ismap) {
             if (ismap) {
                 e = gnode_array_get(node->list2, j);
                 e = gnode_array_get(node->list2, j);
-                ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1);
+				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1, LINE_NUMBER(node));
                 visit(e);
                 visit(e);
-                ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0);
+				ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 0, LINE_NUMBER(node));
                 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)))) {
                 if ((nreg == REGISTER_ERROR) || ((nreg <= dest) && (ircode_register_istemp(code, nreg)))) {
                     report_error(self, (gnode_t *)e, "Invalid map expression.");
                     report_error(self, (gnode_t *)e, "Invalid map expression.");
@@ -1887,7 +1887,7 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 
 
                 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, LINE_NUMBER(node));
                     ircode_register_clear(code, nreg);
                     ircode_register_clear(code, nreg);
                     uint32_t temp = ircode_register_pop_context_protect(code, true);
                     uint32_t temp = ircode_register_pop_context_protect(code, true);
                     if (temp == REGISTER_ERROR) {report_error(self, (gnode_t *)e, "Unexpected register error."); continue;}
                     if (temp == REGISTER_ERROR) {report_error(self, (gnode_t *)e, "Unexpected register error."); continue;}
@@ -1901,20 +1901,20 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
         // emit proper SETLIST instruction
         // emit proper SETLIST instruction
         // since in a map registers are always used in pairs (key, value) it is
         // since in a map registers are always used in pairs (key, value) it is
         // extremely easier to just set reg1 to be always 0 and use r in a loop
         // extremely easier to just set reg1 to be always 0 and use r in a loop
-        ircode_add(code, SETLIST, dest, (uint32_t)(idxend-idxstart), 0);
+		ircode_add(code, SETLIST, dest, (uint32_t)(idxend-idxstart), 0, LINE_NUMBER(node));
 
 
         // restore register context
         // restore register context
         ircode_pop_context(code);
         ircode_pop_context(code);
     }
     }
 
 
-    ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1);
+	ircode_pragma(code, PRAGMA_MOVE_OPTIMIZATION, 1, LINE_NUMBER(node));
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_COUNT_REGISTERS(n2);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
     CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
 }
 }
 
 
 // MARK: -
 // MARK: -
 
 
-gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate, gravity_vm *vm) {
+gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate, gravity_vm *vm, bool add_debug) {
     codegen_t data;
     codegen_t data;
     data.vm = vm;
     data.vm = vm;
     marray_init(data.context);
     marray_init(data.context);
@@ -1927,6 +1927,7 @@ gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate,
     gvisitor_t visitor = {
     gvisitor_t visitor = {
         .nerr = 0,                        // used for internal codegen errors
         .nerr = 0,                        // used for internal codegen errors
         .data = &data,                    // used to store a pointer to codegen struct
         .data = &data,                    // used to store a pointer to codegen struct
+        .bflag = add_debug,             // flag used to decide if bytecode must include debug info
         .delegate = (void *)delegate,    // compiler delegate to report errors
         .delegate = (void *)delegate,    // compiler delegate to report errors
 
 
         // COMMON
         // COMMON

+ 1 - 1
src/compiler/gravity_codegen.h

@@ -13,6 +13,6 @@
 #include "gravity_value.h"
 #include "gravity_value.h"
 #include "gravity_delegate.h"
 #include "gravity_delegate.h"
 
 
-gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate, gravity_vm *vm);
+gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate, gravity_vm *vm, bool add_debug);
 
 
 #endif
 #endif

+ 3 - 3
src/compiler/gravity_compiler.c

@@ -140,7 +140,7 @@ void gravity_compiler_transfer(gravity_compiler_t *compiler, gravity_vm *vm) {
 
 
 // MARK: -
 // MARK: -
 
 
-gravity_closure_t *gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static) {
+gravity_closure_t *gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static, bool add_debug) {
     if ((source == NULL) || (len == 0)) return NULL;
     if ((source == NULL) || (len == 0)) return NULL;
 
 
     // CHECK cleanup first
     // CHECK cleanup first
@@ -172,11 +172,11 @@ gravity_closure_t *gravity_compiler_run (gravity_compiler_t *compiler, const cha
     if (!b2) goto abort_compilation;
     if (!b2) goto abort_compilation;
 
 
     // STEP 3: INTERMEDIATE CODE GENERATION (stack based VM)
     // STEP 3: INTERMEDIATE CODE GENERATION (stack based VM)
-    gravity_function_t *f = gravity_codegen(compiler->ast, compiler->delegate, compiler->vm);
+	gravity_function_t *f = gravity_codegen(compiler->ast, compiler->delegate, compiler->vm, add_debug);
     if (!f) goto abort_compilation;
     if (!f) goto abort_compilation;
 
 
     // STEP 4: CODE GENERATION (register based VM)
     // STEP 4: CODE GENERATION (register based VM)
-    f = gravity_optimizer(f);
+	f = gravity_optimizer(f, add_debug);
     if (f) return gravity_closure_new(compiler->vm, f);
     if (f) return gravity_closure_new(compiler->vm, f);
 
 
 abort_compilation:
 abort_compilation:

+ 1 - 1
src/compiler/gravity_compiler.h

@@ -23,7 +23,7 @@ extern "C" {
 typedef struct gravity_compiler_t   gravity_compiler_t;
 typedef struct gravity_compiler_t   gravity_compiler_t;
 
 
 GRAVITY_API gravity_compiler_t  *gravity_compiler_create (gravity_delegate_t *delegate);
 GRAVITY_API gravity_compiler_t  *gravity_compiler_create (gravity_delegate_t *delegate);
-GRAVITY_API gravity_closure_t   *gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static);
+GRAVITY_API gravity_closure_t	*gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static, bool add_debug);
 GRAVITY_API json_t  *gravity_compiler_serialize (gravity_compiler_t *compiler, gravity_closure_t *closure);
 GRAVITY_API json_t  *gravity_compiler_serialize (gravity_compiler_t *compiler, gravity_closure_t *closure);
 GRAVITY_API bool    gravity_compiler_serialize_infile (gravity_compiler_t *compiler, gravity_closure_t *closure, const char *path);
 GRAVITY_API bool    gravity_compiler_serialize_infile (gravity_compiler_t *compiler, gravity_closure_t *closure, const char *path);
 GRAVITY_API void    gravity_compiler_transfer (gravity_compiler_t *compiler, gravity_vm *vm);
 GRAVITY_API void    gravity_compiler_transfer (gravity_compiler_t *compiler, gravity_vm *vm);

+ 22 - 21
src/compiler/gravity_ircode.c

@@ -92,7 +92,7 @@ bool ircode_iserror (ircode_t *code) {
 }
 }
 // MARK: -
 // MARK: -
 
 
-static inst_t *inst_new (opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag, int64_t n, double d) {
+static inst_t *inst_new (opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag, int64_t n, double d, uint32_t lineno) {
 
 
     // debug code
     // debug code
     #if GRAVITY_OPCODE_DEBUG
     #if GRAVITY_OPCODE_DEBUG
@@ -127,6 +127,7 @@ static inst_t *inst_new (opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, opt
     inst->p1 = p1;
     inst->p1 = p1;
     inst->p2 = p2;
     inst->p2 = p2;
     inst->p3 = p3;
     inst->p3 = p3;
+    inst->lineno = lineno;
 
 
     if (tag == DOUBLE_TAG) inst->d = d;
     if (tag == DOUBLE_TAG) inst->d = d;
     else if (tag == INT_TAG) inst->n = n;
     else if (tag == INT_TAG) inst->n = n;
@@ -148,18 +149,18 @@ void ircode_patch_init (ircode_t *code, uint16_t index) {
 
 
     // load constant
     // load constant
     uint32_t dest = ircode_register_push_temp(code);
     uint32_t dest = ircode_register_push_temp(code);
-    inst_t *inst1 = inst_new(LOADK, dest, index, 0, NO_TAG, 0, 0.0);
+	inst_t *inst1 = inst_new(LOADK, dest, index, 0, NO_TAG, 0, 0.0, 0);
 
 
     // load from lookup
     // load from lookup
-    inst_t *inst2 = inst_new(LOAD, dest, 0, dest, NO_TAG, 0, 0.0);
+	inst_t *inst2 = inst_new(LOAD, dest, 0, dest, NO_TAG, 0, 0.0, 0);
 
 
     // prepare parameter
     // prepare parameter
     uint32_t dest2 = ircode_register_push_temp(code);
     uint32_t dest2 = ircode_register_push_temp(code);
-    inst_t *inst3 = inst_new(MOVE, dest2, 0, 0, NO_TAG, 0, 0.0);
+	inst_t *inst3 = inst_new(MOVE, dest2, 0, 0, NO_TAG, 0, 0.0, 0);
     ircode_register_pop(code);
     ircode_register_pop(code);
 
 
     // execute call
     // execute call
-    inst_t *inst4 = inst_new(CALL, dest, dest, 1, NO_TAG, 0, 0.0);
+	inst_t *inst4 = inst_new(CALL, dest, dest, 1, NO_TAG, 0, 0.0, 0);
 
 
     // pop temps used
     // pop temps used
     ircode_register_pop(code);
     ircode_register_pop(code);
@@ -347,14 +348,14 @@ uint32_t ircode_getlabel_false (ircode_t *code) {
     return v;
     return v;
 }
 }
 
 
-void ircode_marklabel (ircode_t *code, uint32_t nlabel) {
-    inst_t *inst = inst_new(0, nlabel, 0, 0, LABEL_TAG, 0, 0.0);
+void ircode_marklabel (ircode_t *code, uint32_t nlabel, uint32_t lineno) {
+	inst_t *inst = inst_new(0, nlabel, 0, 0, LABEL_TAG, 0, 0.0, lineno);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
 // MARK: -
 // MARK: -
-void ircode_pragma (ircode_t *code, optag_t tag, uint32_t value) {
-    ircode_add_tag(code, 0, value, 0, 0, tag);
+void ircode_pragma (ircode_t *code, optag_t tag, uint32_t value, uint32_t lineno) {
+	ircode_add_tag(code, 0, value, 0, 0, tag, lineno);
 }
 }
 
 
 // MARK: -
 // MARK: -
@@ -368,35 +369,35 @@ void ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1,
     inst->tag = NO_TAG;
     inst->tag = NO_TAG;
 }
 }
 
 
-void ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3) {
-    ircode_add_tag(code, op, p1, p2, p3, 0);
+void ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t lineno) {
+	ircode_add_tag(code, op, p1, p2, p3, 0, lineno);
 }
 }
 
 
-void ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag) {
-    inst_t *inst = inst_new(op, p1, p2, p3, tag, 0, 0.0);
+void ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag, uint32_t lineno) {
+	inst_t *inst = inst_new(op, p1, p2, p3, tag, 0, 0.0, lineno);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
-void ircode_add_double (ircode_t *code, double d) {
+void ircode_add_double (ircode_t *code, double d, uint32_t lineno) {
     uint32_t regnum = ircode_register_push_temp(code);
     uint32_t regnum = ircode_register_push_temp(code);
-    inst_t *inst = inst_new(LOADI, regnum, 0, 0, DOUBLE_TAG, 0, d);
+	inst_t *inst = inst_new(LOADI, regnum, 0, 0, DOUBLE_TAG, 0, d, lineno);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
-void ircode_add_constant (ircode_t *code, uint32_t index) {
+void ircode_add_constant (ircode_t *code, uint32_t index, uint32_t lineno) {
     uint32_t regnum = ircode_register_push_temp(code);
     uint32_t regnum = ircode_register_push_temp(code);
-    inst_t *inst = inst_new(LOADK, regnum, index, 0, NO_TAG, 0, 0);
+	inst_t *inst = inst_new(LOADK, regnum, index, 0, NO_TAG, 0, 0, lineno);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
-void ircode_add_int (ircode_t *code, int64_t n) {
+void ircode_add_int (ircode_t *code, int64_t n, uint32_t lineno) {
     uint32_t regnum = ircode_register_push_temp(code);
     uint32_t regnum = ircode_register_push_temp(code);
-    inst_t *inst = inst_new(LOADI, regnum, 0, 0, INT_TAG, n, 0);
+	inst_t *inst = inst_new(LOADI, regnum, 0, 0, INT_TAG, n, 0, lineno);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
-void ircode_add_skip (ircode_t *code) {
-    inst_t *inst = inst_new(0, 0, 0, 0, NO_TAG, 0, 0);
+void ircode_add_skip (ircode_t *code, uint32_t lineno) {
+	inst_t *inst = inst_new(0, 0, 0, 0, NO_TAG, 0, 0, lineno);
     inst_setskip(inst);
     inst_setskip(inst);
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }

+ 10 - 10
src/compiler/gravity_ircode.h

@@ -50,6 +50,7 @@ typedef struct {
         double      d;  //    tag is DOUBLE_TAG
         double      d;  //    tag is DOUBLE_TAG
         int64_t     n;  //    tag is INT_TAG
         int64_t     n;  //    tag is INT_TAG
     };
     };
+    uint32_t    lineno;     //  debug info
 } inst_t;
 } inst_t;
 
 
 typedef struct ircode_t ircode_t;
 typedef struct ircode_t ircode_t;
@@ -72,21 +73,20 @@ void        ircode_unsetlabel_true (ircode_t *code);
 void        ircode_unsetlabel_false (ircode_t *code);
 void        ircode_unsetlabel_false (ircode_t *code);
 uint32_t    ircode_getlabel_true (ircode_t *code);
 uint32_t    ircode_getlabel_true (ircode_t *code);
 uint32_t    ircode_getlabel_false (ircode_t *code);
 uint32_t    ircode_getlabel_false (ircode_t *code);
-void        ircode_marklabel (ircode_t *code, uint32_t nlabel);
+void		ircode_marklabel (ircode_t *code, uint32_t nlabel, uint32_t lineno);
 
 
 void        inst_setskip (inst_t *inst);
 void        inst_setskip (inst_t *inst);
 uint8_t     opcode_numop (opcode_t op);
 uint8_t     opcode_numop (opcode_t op);
 
 
-void        ircode_pragma (ircode_t *code, optag_t tag, uint32_t value);
-void        ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3);
-void        ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag);
-void        ircode_add_array (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_r r);
-void        ircode_add_double (ircode_t *code, double d);
-void        ircode_add_int (ircode_t *code, int64_t n);
-void        ircode_add_constant (ircode_t *code, uint32_t index);
-void        ircode_add_skip (ircode_t *code);
+void		ircode_pragma (ircode_t *code, optag_t tag, uint32_t value, uint32_t lineno);
+void		ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t lineno);
+void		ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag, uint32_t lineno);
+void		ircode_add_array (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, uint32_r r, uint32_t lineno);
+void		ircode_add_double (ircode_t *code, double d, uint32_t lineno);
+void		ircode_add_int (ircode_t *code, int64_t n, uint32_t lineno);
+void		ircode_add_constant (ircode_t *code, uint32_t index, uint32_t lineno);
+void		ircode_add_skip (ircode_t *code, uint32_t lineno);
 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);
 
 
 // IMPORTANT NOTE
 // IMPORTANT NOTE
 //
 //

+ 4 - 2
src/compiler/gravity_lexer.c

@@ -647,7 +647,9 @@ void gravity_lexer_debug (gravity_lexer_t *lexer) {
     if (offset == token.position) return;
     if (offset == token.position) return;
     offset = token.position;
     offset = token.position;
     
     
-    printf("(%02d, %02d) %s: ", token.lineno, token.colno, token_name(token.type));
-    printf("%.*s\t(offset: %d)\n", token.bytes, token.value, token.position);
+    printf("(%02d, %02d) %.*s\n", token.lineno, token.colno, token.bytes, token.value);
+    
+    //printf("(%02d, %02d) %s: ", token.lineno, token.colno, token_name(token.type));
+	//printf("%.*s\t(offset: %d)\n", token.bytes, token.value, token.position);
 }
 }
 #endif
 #endif

+ 22 - 7
src/compiler/gravity_optimizer.c

@@ -48,11 +48,12 @@ static uint32_t hash_compute (gravity_value_t v) {
     return gravity_hash_compute_int(v.n);
     return gravity_hash_compute_int(v.n);
 }
 }
 
 
-static void finalize_function (gravity_function_t *f) {
+static void finalize_function (gravity_function_t *f, bool add_debug) {
     ircode_t        *code = (ircode_t *)f->bytecode;
     ircode_t        *code = (ircode_t *)f->bytecode;
     uint32_t        ninst = 0, count = ircode_count(code);
     uint32_t        ninst = 0, count = ircode_count(code);
     uint32_t        notpure = 0;
     uint32_t        notpure = 0;
     uint32_t        *bytecode = NULL;
     uint32_t        *bytecode = NULL;
+    uint32_t        *lineno = NULL;
     gravity_hash_t    *labels = gravity_hash_create(0, hash_compute, hash_isequal, NULL, NULL);
     gravity_hash_t    *labels = gravity_hash_create(0, hash_compute, hash_isequal, NULL, NULL);
 
 
     // determine how big bytecode buffer must be
     // determine how big bytecode buffer must be
@@ -72,6 +73,7 @@ static void finalize_function (gravity_function_t *f) {
     // +1 is just a trick so the VM switch loop terminates with an implicit RET0 instruction (RET0 has opcode 0)
     // +1 is just a trick so the VM switch loop terminates with an implicit RET0 instruction (RET0 has opcode 0)
     f->ninsts = ninst;
     f->ninsts = ninst;
     bytecode = (uint32_t *)mem_alloc(NULL, (ninst+1) * sizeof(uint32_t));
     bytecode = (uint32_t *)mem_alloc(NULL, (ninst+1) * sizeof(uint32_t));
+    if (add_debug) lineno = (uint32_t *)mem_alloc(NULL, (ninst+1) * sizeof(uint32_t));
     assert(bytecode);
     assert(bytecode);
 
 
     uint32_t j=0;
     uint32_t j=0;
@@ -200,6 +202,9 @@ static void finalize_function (gravity_function_t *f) {
                 break;
                 break;
         }
         }
 
 
+        // add debug information
+        if (add_debug) lineno[j] = inst->lineno;
+        
         // store encoded instruction
         // store encoded instruction
         bytecode[j++] = op;
         bytecode[j++] = op;
     }
     }
@@ -208,6 +213,7 @@ static void finalize_function (gravity_function_t *f) {
     gravity_hash_free(labels);
     gravity_hash_free(labels);
 
 
     f->bytecode = bytecode;
     f->bytecode = bytecode;
+    f->lineno = lineno;
     f->purity = (notpure == 0) ? 1.0f : ((float)(notpure * 100) / (float)ninst) / 100.0f;
     f->purity = (notpure == 0) ? 1.0f : ((float)(notpure * 100) / (float)ninst) / 100.0f;
 }
 }
 
 
@@ -355,10 +361,19 @@ static bool optimize_neg_instruction (ircode_t *code, inst_t *inst, uint32_t i)
     if (inst1->p1 != inst->p2) return false;
     if (inst1->p1 != inst->p2) return false;
     if (!ircode_register_istemp(code, inst1->p1)) return false;
     if (!ircode_register_istemp(code, inst1->p1)) return false;
 
 
-    uint64_t n = inst1->n;
-    if (n>131072) return false;
-    inst1->p1 = inst->p2;
-    inst1->n = -(int64_t)n;
+    if (inst1->tag == INT_TAG) {
+        uint64_t n = inst1->n;
+        if (n>131072) return false;
+        inst1->p1 = inst->p2;
+        inst1->n = -(int64_t)n;
+    } else if (inst1->tag == DOUBLE_TAG) {
+        double d = inst1->d;
+        inst1->p1 = inst->p2;
+        inst1->d = -d;
+    } else {
+        return false;
+    }
+	
     inst_setskip(inst);
     inst_setskip(inst);
     return true;
     return true;
 }
 }
@@ -471,7 +486,7 @@ static bool optimize_num_instruction (inst_t *inst, gravity_function_t *f) {
 
 
 // MARK: -
 // MARK: -
 
 
-gravity_function_t *gravity_optimizer(gravity_function_t *f) {
+gravity_function_t *gravity_optimizer(gravity_function_t *f, bool add_debug) {
     if (f->bytecode == NULL) return f;
     if (f->bytecode == NULL) return f;
 
 
     ircode_t    *code = (ircode_t *)f->bytecode;
     ircode_t    *code = (ircode_t *)f->bytecode;
@@ -529,7 +544,7 @@ gravity_function_t *gravity_optimizer(gravity_function_t *f) {
     #endif
     #endif
 
 
     // finalize function
     // finalize function
-    finalize_function(f);
+	finalize_function(f, add_debug);
 
 
     return f;
     return f;
 }
 }

+ 1 - 1
src/compiler/gravity_optimizer.h

@@ -12,6 +12,6 @@
 #include "gravity_macros.h"
 #include "gravity_macros.h"
 #include "gravity_value.h"
 #include "gravity_value.h"
 
 
-gravity_function_t *gravity_optimizer(gravity_function_t *f);
+gravity_function_t *gravity_optimizer(gravity_function_t *f, bool add_debug);
 
 
 #endif
 #endif

+ 37 - 4
src/compiler/gravity_parser.c

@@ -48,7 +48,7 @@ struct gravity_parser_t {
 // http://nshipster.com/swift-operators/
 // http://nshipster.com/swift-operators/
 typedef enum {
 typedef enum {
     PREC_LOWEST,
     PREC_LOWEST,
-    PREC_ASSIGN      = 90,    // = *= /= %= += -= <<= >>= &= ^= |=      (11 cases)
+    PREC_ASSIGN      = 90,     // = *= /= %= += -= <<= >>= &= ^= |=     (11 cases)
     PREC_TERNARY     = 100,    // ?:                                      (1 case)
     PREC_TERNARY     = 100,    // ?:                                      (1 case)
     PREC_LOGICAL_OR  = 110,    // ||                                      (1 case)
     PREC_LOGICAL_OR  = 110,    // ||                                      (1 case)
     PREC_LOGICAL_AND = 120,    // &&                                      (1 case)
     PREC_LOGICAL_AND = 120,    // &&                                      (1 case)
@@ -59,7 +59,7 @@ typedef enum {
     PREC_FACTOR      = 150,    // * / % &                                (4 cases)
     PREC_FACTOR      = 150,    // * / % &                                (4 cases)
     PREC_SHIFT       = 160,    // << >>                                  (2 cases)
     PREC_SHIFT       = 160,    // << >>                                  (2 cases)
     PREC_UNARY       = 170,    // + - ! ~                                (4 cases)
     PREC_UNARY       = 170,    // + - ! ~                                (4 cases)
-    PREC_CALL        = 200  // . ( [                                     (3 cases)
+    PREC_CALL        = 200     // . ( [                                  (3 cases)
 } prec_level;
 } prec_level;
 
 
 typedef gnode_t* (*parse_func) (gravity_parser_t *parser);
 typedef gnode_t* (*parse_func) (gravity_parser_t *parser);
@@ -149,6 +149,21 @@ static gravity_hash_t *parser_getmeta (gravity_parser_t *parser, bool consume) {
     return htable;
     return htable;
 }
 }
 
 
+static void patch_token_node (gnode_t *node, gtoken_s token) {
+    node->token = token;
+    
+    if (node->tag == NODE_POSTFIX_EXPR) {
+        gnode_postfix_expr_t *expr = (gnode_postfix_expr_t *)node;
+        if (expr->id) expr->id->token = token;
+        
+        size_t count = gnode_array_size(expr->list);
+        for (size_t i=0; i<count; ++i) {
+            gnode_t *subnode = (gnode_t *)gnode_array_get(expr->list, i);
+            if (subnode) subnode->token = token;
+        }
+    }
+}
+
 static void report_error (gravity_parser_t *parser, error_type_t error_type, gtoken_s token, const char *format, ...) {
 static void report_error (gravity_parser_t *parser, error_type_t error_type, gtoken_s token, const char *format, ...) {
     // consider just one error for each line;
     // consider just one error for each line;
     if (parser->last_error_lineno == token.lineno) return;
     if (parser->last_error_lineno == token.lineno) return;
@@ -825,6 +840,9 @@ static gnode_t *parse_analyze_literal_string (gravity_parser_t *parser, gtoken_s
 
 
                     // add expression to r
                     // add expression to r
                     if (subnode) {
                     if (subnode) {
+                        // subnode contains information from a temp lexer so let's fix it
+                        patch_token_node(subnode, token);
+                        
                         if (!r) r = gnode_array_create();
                         if (!r) r = gnode_array_create();
                         if (length) gnode_array_push(r, gnode_literal_string_expr_create(token, buffer, length, true, LAST_DECLARATION()));
                         if (length) gnode_array_push(r, gnode_literal_string_expr_create(token, buffer, length, true, LAST_DECLARATION()));
                         gnode_array_push(r, subnode);
                         gnode_array_push(r, subnode);
@@ -904,9 +922,21 @@ static gnode_r *parse_arguments_expression (gravity_parser_t *parser) {
     // it's OK for a call_expression_list to be empty
     // it's OK for a call_expression_list to be empty
     if (gravity_lexer_peek(lexer) == TOK_OP_CLOSED_PARENTHESIS) return NULL;
     if (gravity_lexer_peek(lexer) == TOK_OP_CLOSED_PARENTHESIS) return NULL;
 
 
+    // https://en.wikipedia.org/wiki/Named_parameter
+    // with the introduction of named parameters there are a lot
+    // of sub-cases to handle here, for example I cannot know in
+    // advance if a call has named parameters or not from the
+    // beginning because we also support mixed calls (both position
+    // and named parameters)
+    // so basically I collect two arrays here
+    // one for names (or positions) and one for values
+    // if the call is not a named call then the useless
+    // array is discarded
+    
     bool arg_expected = true;
     bool arg_expected = true;
     gnode_r *list = gnode_array_create();
     gnode_r *list = gnode_array_create();
 
 
+    uint32_t index = 0;
     while (1) {
     while (1) {
         gtoken_t peek = gravity_lexer_peek(lexer);
         gtoken_t peek = gravity_lexer_peek(lexer);
 
 
@@ -947,6 +977,8 @@ static gnode_r *parse_arguments_expression (gravity_parser_t *parser) {
             // this fixes syntax errors like System.print("Hello" " World")
             // this fixes syntax errors like System.print("Hello" " World")
             arg_expected = (peek == TOK_OP_COMMA);
             arg_expected = (peek == TOK_OP_COMMA);
         }
         }
+        
+        ++index;
     }
     }
 
 
     return list;
     return list;
@@ -2074,8 +2106,9 @@ loop:
     // tokens are then stored inside AST nodes in order to locate errors into source code
     // tokens are then stored inside AST nodes in order to locate errors into source code
     // AST can live a lot longer than both lexer and parser so we need a way to persistent
     // AST can live a lot longer than both lexer and parser so we need a way to persistent
     // store these chuncks of memory
     // store these chuncks of memory
-    const char *source = parser->delegate->loadfile_callback(module_name, &size, &fileid, parser->delegate->xdata);
-    if (source) newlexer = gravity_lexer_create(source, size, fileid, false);
+    bool is_static = false;
+	const char *source = parser->delegate->loadfile_callback(module_name, &size, &fileid, parser->delegate->xdata, &is_static);
+	if (source) newlexer = gravity_lexer_create(source, size, fileid, is_static);
 
 
     if (newlexer) {
     if (newlexer) {
         // push new lexer into lexer stack
         // push new lexer into lexer stack

+ 15 - 1
src/compiler/gravity_semacheck2.c

@@ -793,6 +793,20 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
         // variable with a initial value (or with a getter/setter)
         // variable with a initial value (or with a getter/setter)
         if (p->expr) visit(p->expr);
         if (p->expr) visit(p->expr);
 
 
+//        // check for manifest type
+//        if (p->annotation_type) {
+//            // struct gnode_var_t was modified with
+//            // // untagged union, if no type is declared then this union is NULL otherwise
+//            // union {
+//            //     const char          *annotation_type;   // optional annotation type
+//            //     gnode_class_decl_t  *class_type;        // class type (set in semacheck2 if annotation_type is not NULL)
+//            // };
+//            gnode_t *class_type = lookup_identifier(self, p->annotation_type, NULL);
+//            if (!class_type) {REPORT_WARNING(p, "Unable to find type %s.", p->annotation_type);}
+//        //     if (!NODE_ISA(class_type, NODE_CLASS_DECL)) {REPORT_ERROR(p, "Unable to set non class type %s.", p->annotation_type); continue;}
+//        //     p->class_type = (gnode_class_decl_t *)class_type;
+//        }
+        
         if (env_is_function) {
         if (env_is_function) {
             // local variable defined inside a function
             // local variable defined inside a function
             if (!symboltable_insert(symtable, p->identifier, (void *)p)) {
             if (!symboltable_insert(symtable, p->identifier, (void *)p)) {
@@ -1172,7 +1186,7 @@ static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 // MARK: -
 // MARK: -
 
 
 bool gravity_semacheck2 (gnode_t *node, gravity_delegate_t *delegate) {
 bool gravity_semacheck2 (gnode_t *node, gravity_delegate_t *delegate) {
-    semacheck_t    data = {.declarations = gnode_array_create(), .lasterror = 0};
+    semacheck_t data = {.declarations = gnode_array_create(), .lasterror = 0};
     marray_init(data.statements);
     marray_init(data.statements);
 
 
     gvisitor_t visitor = {
     gvisitor_t visitor = {

+ 1 - 0
src/compiler/gravity_token.c

@@ -189,6 +189,7 @@ gtoken_t token_keyword (const char *buffer, int32_t len) {
             if (string_casencmp(buffer, "enum", len) == 0) return TOK_KEY_ENUM;
             if (string_casencmp(buffer, "enum", len) == 0) return TOK_KEY_ENUM;
             if (string_casencmp(buffer, "case", len) == 0) return TOK_KEY_CASE;
             if (string_casencmp(buffer, "case", len) == 0) return TOK_KEY_CASE;
             if (string_casencmp(buffer, "null", len) == 0) return TOK_KEY_NULL;
             if (string_casencmp(buffer, "null", len) == 0) return TOK_KEY_NULL;
+            if (string_casencmp(buffer, "NULL", len) == 0) return TOK_KEY_NULL;
             if (string_casencmp(buffer, "file", len) == 0) return TOK_KEY_FILE;
             if (string_casencmp(buffer, "file", len) == 0) return TOK_KEY_FILE;
             if (string_casencmp(buffer, "lazy", len) == 0) return TOK_KEY_LAZY;
             if (string_casencmp(buffer, "lazy", len) == 0) return TOK_KEY_LAZY;
             break;
             break;

+ 4 - 3
src/compiler/gravity_visitor.h

@@ -14,9 +14,10 @@
 #define visit(node) gvisit(self, node)
 #define visit(node) gvisit(self, node)
 
 
 typedef struct gvisitor {
 typedef struct gvisitor {
-    uint32_t    nerr;            // to store err counter state
-    void        *data;            // to store a ptr state
-    void        *delegate;        // delegate callback
+    uint32_t    nerr;           // to store err counter state
+    void        *data;          // to store a ptr state
+    bool        bflag;          // to store a bool flag
+    void        *delegate;      // delegate callback
 
 
     // COMMON
     // COMMON
     void (* visit_pre)(struct gvisitor *self, gnode_t *node);
     void (* visit_pre)(struct gvisitor *self, gnode_t *node);

+ 18 - 0
src/runtime/gravity_core.c

@@ -785,6 +785,13 @@ static bool object_exec (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
     RETURN_ERROR("Forbidden Object execution.");
     RETURN_ERROR("Forbidden Object execution.");
 }
 }
 
 
+//static bool object_methods (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+//    #pragma unused(vm, nargs)
+//    gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
+//    
+//    
+//}
+
 // MARK: - List Class -
 // MARK: - List Class -
 
 
 static bool list_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 static bool list_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
@@ -2671,12 +2678,23 @@ static bool operator_null_silent (gravity_vm *vm, gravity_value_t *args, uint16_
         if (obj) RETURN_VALUE(VALUE_FROM_OBJECT(obj), rindex);
         if (obj) RETURN_VALUE(VALUE_FROM_OBJECT(obj), rindex);
     }
     }
     
     
+    gravity_delegate_t *delegate = gravity_vm_delegate(vm);
+    if (delegate->report_null_errors) {
+        RETURN_ERROR("Unable to find %s into null object", VALUE_ISA_STRING(key) ? VALUE_AS_CSTRING(key) : "N/A");
+    }
+    
     // every operation on NULL returns NULL
     // every operation on NULL returns NULL
     RETURN_VALUE(VALUE_FROM_NULL, rindex);
     RETURN_VALUE(VALUE_FROM_NULL, rindex);
 }
 }
 
 
 static bool operator_store_null_silent (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 static bool operator_store_null_silent (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
     #pragma unused(vm,args,nargs,rindex)
     #pragma unused(vm,args,nargs,rindex)
+    gravity_delegate_t *delegate = gravity_vm_delegate(vm);
+    if (delegate->report_null_errors) {
+        gravity_value_t key = GET_VALUE(1);
+        RETURN_ERROR("Unable to find %s into null object", VALUE_ISA_STRING(key) ? VALUE_AS_CSTRING(key) : "N/A");
+    }
+        
     // do not touch any register, a store op on NULL is a NOP operation
     // do not touch any register, a store op on NULL is a NOP operation
     return true;
     return true;
 }
 }

+ 31 - 1
src/runtime/gravity_vm.c

@@ -105,6 +105,34 @@ static void gravity_callframe_dump (gravity_fiber_t *fiber) {
         printf("[%03d]\t%s\t(%s)\n", i, fname, buffer);
         printf("[%03d]\t%s\t(%s)\n", i, fname, buffer);
     }
     }
 }
 }
+
+static uint32_t gravity_vm_lineno (gravity_vm *vm) {
+    // get current fiber
+    gravity_fiber_t *fiber = vm->fiber;
+    
+    // get current call frame
+    gravity_callframe_t *frame = (fiber->nframes) ? &fiber->frames[fiber->nframes-1] : NULL;
+    if (!frame) return 0;
+    
+    // get current executing function
+    gravity_function_t *func = (frame->closure) ? frame->closure->f : NULL;
+    if (!func) return 0;
+    
+    // sanity check about function type and included debug information
+    if (func->tag == EXEC_TYPE_NATIVE && func->lineno) {
+        uint32_t nindex = 0;
+        if (frame->ip > func->bytecode) {
+            // -1 because frame->ip points to the next instruction to execute
+            nindex = (uint32_t)(frame->ip - func->bytecode) - 1;
+        }
+        
+        return func->lineno[nindex];
+    }
+    
+    return 0;
+}
+
+
 #pragma clang diagnostic pop
 #pragma clang diagnostic pop
 
 
 // MARK: -
 // MARK: -
@@ -124,8 +152,10 @@ static void report_runtime_error (gravity_vm *vm, error_type_t error_type, const
 
 
     gravity_error_callback error_cb = ((gravity_delegate_t *)vm->delegate)->error_callback;
     gravity_error_callback error_cb = ((gravity_delegate_t *)vm->delegate)->error_callback;
     if (error_cb) {
     if (error_cb) {
+        uint32_t lineno = gravity_vm_lineno(vm);
+        error_desc_t edesc = (error_desc_t){lineno, 0, 0, 0, NULL};
         void *data = ((gravity_delegate_t *)vm->delegate)->xdata;
         void *data = ((gravity_delegate_t *)vm->delegate)->xdata;
-        error_cb(vm, error_type, buffer, ERROR_DESC_NONE, data);
+		error_cb(vm, error_type, buffer, edesc, data);
     } else {
     } else {
         printf("%s\n", buffer);
         printf("%s\n", buffer);
         fflush(stdout);
         fflush(stdout);

+ 2 - 1
src/shared/gravity_delegate.h

@@ -39,7 +39,7 @@ typedef void                (*gravity_unittest_callback) (gravity_vm *vm, error_
 typedef void                (*gravity_parser_callback) (void *token, void *xdata);
 typedef void                (*gravity_parser_callback) (void *token, void *xdata);
 typedef void                (*gravity_type_callback) (void *token, const char *type, void *xdata);
 typedef void                (*gravity_type_callback) (void *token, const char *type, void *xdata);
 typedef const char*         (*gravity_precode_callback) (void *xdata);
 typedef const char*         (*gravity_precode_callback) (void *xdata);
-typedef const char*         (*gravity_loadfile_callback) (const char *file, size_t *size, uint32_t *fileid, void *xdata);
+typedef const char*			(*gravity_loadfile_callback) (const char *file, size_t *size, uint32_t *fileid, void *xdata, bool *is_static);
 typedef const char*         (*gravity_filename_callback) (uint32_t fileid, void *xdata);
 typedef const char*         (*gravity_filename_callback) (uint32_t fileid, void *xdata);
 typedef const char**        (*gravity_optclass_callback) (void);
 typedef const char**        (*gravity_optclass_callback) (void);
 
 
@@ -58,6 +58,7 @@ typedef void                (*gravity_bridge_free) (gravity_vm *vm, gravity_obje
 typedef struct {
 typedef struct {
     // user data
     // user data
     void                        *xdata;                 // optional user data transparently passed between callbacks
     void                        *xdata;                 // optional user data transparently passed between callbacks
+    bool                        report_null_errors;     // by default messages sent to null objects are silently ignored (if this flag is false)
 
 
     // callbacks
     // callbacks
     gravity_log_callback        log_callback;           // log reporting callback
     gravity_log_callback        log_callback;           // log reporting callback

+ 2 - 1
src/shared/gravity_macros.h

@@ -9,7 +9,7 @@
 #ifndef __GRAVITY_MACROS__
 #ifndef __GRAVITY_MACROS__
 #define __GRAVITY_MACROS__
 #define __GRAVITY_MACROS__
 
 
-#define AUTOLENGTH                            UINT32_MAX
+#define AUTOLENGTH                          UINT32_MAX
 
 
 // MARK: -
 // MARK: -
 // pragma unused is not recognized by VC
 // pragma unused is not recognized by VC
@@ -115,6 +115,7 @@
 #define GRAVITY_JSON_LABELPNAMES            "pnames"
 #define GRAVITY_JSON_LABELPNAMES            "pnames"
 #define GRAVITY_JSON_LABELMETA              "meta"
 #define GRAVITY_JSON_LABELMETA              "meta"
 #define GRAVITY_JSON_LABELBYTECODE          "bytecode"
 #define GRAVITY_JSON_LABELBYTECODE          "bytecode"
+#define GRAVITY_JSON_LABELLINENO            "lineno"
 #define GRAVITY_JSON_LABELNPARAM            "nparam"
 #define GRAVITY_JSON_LABELNPARAM            "nparam"
 #define GRAVITY_JSON_LABELNLOCAL            "nlocal"
 #define GRAVITY_JSON_LABELNLOCAL            "nlocal"
 #define GRAVITY_JSON_LABELNTEMP             "ntemp"
 #define GRAVITY_JSON_LABELNTEMP             "ntemp"

+ 2 - 2
src/shared/gravity_memory.h

@@ -53,8 +53,8 @@ void    *memdebug_malloc0 (gravity_vm *vm, size_t size);
 void    *memdebug_calloc (gravity_vm *vm, size_t num, size_t size);
 void    *memdebug_calloc (gravity_vm *vm, size_t num, size_t size);
 void    *memdebug_realloc (gravity_vm *vm, void *ptr, size_t new_size);
 void    *memdebug_realloc (gravity_vm *vm, void *ptr, size_t new_size);
 void    memdebug_free (void *ptr);
 void    memdebug_free (void *ptr);
-size_t    memdebug_leaks (void);
-size_t    memdebug_status (void);
+size_t  memdebug_leaks (void);
+size_t  memdebug_status (void);
 void    memdebug_setcheck (bool flag);
 void    memdebug_setcheck (bool flag);
 void    memdebug_stat (void);
 void    memdebug_stat (void);
 bool    memdebug_remove (void *ptr);
 bool    memdebug_remove (void *ptr);

+ 26 - 0
src/shared/gravity_value.c

@@ -632,6 +632,7 @@ static void gravity_function_bytecode_serialize (gravity_function_t *f, json_t *
         return;
         return;
     }
     }
 
 
+    // bytecode
     uint32_t ninst = f->ninsts;
     uint32_t ninst = f->ninsts;
     uint32_t length = ninst * 2 * sizeof(uint32_t);
     uint32_t length = ninst * 2 * sizeof(uint32_t);
     uint8_t *hexchar = (uint8_t*) mem_alloc(NULL, sizeof(uint8_t) * length);
     uint8_t *hexchar = (uint8_t*) mem_alloc(NULL, sizeof(uint8_t) * length);
@@ -647,6 +648,25 @@ static void gravity_function_bytecode_serialize (gravity_function_t *f, json_t *
 
 
     json_add_string(json, GRAVITY_JSON_LABELBYTECODE, (const char *)hexchar, length);
     json_add_string(json, GRAVITY_JSON_LABELBYTECODE, (const char *)hexchar, length);
     mem_free(hexchar);
     mem_free(hexchar);
+    
+    // debug lineno
+    if (!f->lineno) return;
+    
+    ninst = f->ninsts;
+    length = ninst * 2 * sizeof(uint32_t);
+    hexchar = (uint8_t*) mem_alloc(NULL, sizeof(uint8_t) * length);
+    
+    for (uint32_t k=0, i=0; i < ninst; ++i) {
+        uint32_t value = f->lineno[i];
+        
+        for (int32_t j=2*sizeof(value)-1; j>=0; --j) {
+            uint8_t c = "0123456789ABCDEF"[((value >> (j*4)) & 0xF)];
+            hexchar[k++] = c;
+        }
+    }
+    
+    json_add_string(json, GRAVITY_JSON_LABELLINENO, (const char *)hexchar, length);
+    mem_free(hexchar);
 }
 }
 
 
 uint32_t *gravity_bytecode_deserialize (const char *buffer, size_t len, uint32_t *n) {
 uint32_t *gravity_bytecode_deserialize (const char *buffer, size_t len, uint32_t *n) {
@@ -932,6 +952,11 @@ gravity_function_t *gravity_function_deserialize (gravity_vm *vm, json_value *js
             continue;
             continue;
         }
         }
 
 
+        // lineno debug info
+        if (string_casencmp(label, GRAVITY_JSON_LABELLINENO, label_size) == 0) {
+            if (value->type == json_string) f->lineno = gravity_bytecode_deserialize(value->u.string.ptr, value->u.string.length, &f->ninsts);
+        }
+        
         // arguments names
         // arguments names
         if (string_casencmp(label, GRAVITY_JSON_LABELPNAMES, label_size) == 0) {
         if (string_casencmp(label, GRAVITY_JSON_LABELPNAMES, label_size) == 0) {
             if (value->type != json_array) goto abort_load;
             if (value->type != json_array) goto abort_load;
@@ -1073,6 +1098,7 @@ void gravity_function_free (gravity_vm *vm, gravity_function_t *f) {
     if (f->identifier) mem_free((void *)f->identifier);
     if (f->identifier) mem_free((void *)f->identifier);
     if (f->tag == EXEC_TYPE_NATIVE) {
     if (f->tag == EXEC_TYPE_NATIVE) {
         if (f->bytecode) mem_free((void *)f->bytecode);
         if (f->bytecode) mem_free((void *)f->bytecode);
+        if (f->lineno) mem_free((void *)f->lineno);
         
         
         // FREE EACH DEFAULT value
         // FREE EACH DEFAULT value
         size_t n = marray_size(f->pvalue);
         size_t n = marray_size(f->pvalue);

+ 4 - 3
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define GRAVITY_VERSION                     "0.5.1"     // git tag 0.5.1
-#define GRAVITY_VERSION_NUMBER              0x000501    // git push --tags
+#define GRAVITY_VERSION						"0.5.4"     // git tag 0.5.4
+#define GRAVITY_VERSION_NUMBER				0x000504    // git push --tags
 #define GRAVITY_BUILD_DATE                  __DATE__
 #define GRAVITY_BUILD_DATE                  __DATE__
 
 
 #ifndef GRAVITY_ENABLE_DOUBLE
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -257,6 +257,7 @@ typedef struct {
             gravity_value_r pname;          // param names
             gravity_value_r pname;          // param names
             uint32_t        ninsts;         // number of instructions in the bytecode
             uint32_t        ninsts;         // number of instructions in the bytecode
             uint32_t        *bytecode;      // bytecode as array of 32bit values
             uint32_t        *bytecode;      // bytecode as array of 32bit values
+            uint32_t        *lineno;            // debug: line number <-> current instruction relation
             float           purity;         // experimental value
             float           purity;         // experimental value
             bool            useargs;        // flag set by the compiler to optimize the creation of the arguments array only if needed
             bool            useargs;        // flag set by the compiler to optimize the creation of the arguments array only if needed
         };
         };
@@ -363,7 +364,7 @@ typedef struct gravity_class_s {
     struct gravity_class_s  *superclass;    // reference to the super class
     struct gravity_class_s  *superclass;    // reference to the super class
     gravity_hash_t          *htable;        // hash table
     gravity_hash_t          *htable;        // hash table
     uint32_t                nivars;         // number of instance variables
     uint32_t                nivars;         // number of instance variables
-    //cstring_r             debug;          // ivar index to name debug info
+	//gravity_value_r			inames;			    // ivar names
     gravity_value_t         *ivars;         // static variables
     gravity_value_t         *ivars;         // static variables
 } gravity_class_s;
 } gravity_class_s;