diff --git a/src/pk_compiler.c b/src/pk_compiler.c index 1ef65ae..a5b0d7a 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -224,7 +224,6 @@ typedef enum { PREC_TERM, // + - PREC_FACTOR, // * / % PREC_UNARY, // - ! ~ not - PREC_CHAIN_CALL, // -> PREC_CALL, // () PREC_SUBSCRIPT, // [] PREC_ATTRIB, // .index @@ -1126,7 +1125,6 @@ static void exprName(Compiler* compiler); static void exprOr(Compiler* compiler); static void exprAnd(Compiler* compiler); -static void exprChainCall(Compiler* compiler); static void exprBinaryOp(Compiler* compiler); static void exprUnaryOp(Compiler* compiler); @@ -1165,7 +1163,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence /* TK_AMP */ { NULL, exprBinaryOp, PREC_BITWISE_AND }, /* TK_PIPE */ { NULL, exprBinaryOp, PREC_BITWISE_OR }, /* TK_CARET */ { NULL, exprBinaryOp, PREC_BITWISE_XOR }, - /* TK_ARROW */ { NULL, exprChainCall, PREC_CHAIN_CALL }, + /* TK_ARROW */ NO_RULE, /* TK_PLUS */ { NULL, exprBinaryOp, PREC_TERM }, /* TK_MINUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM }, /* TK_STAR */ { NULL, exprBinaryOp, PREC_FACTOR }, @@ -1300,7 +1298,9 @@ static void exprName(Compiler* compiler) { compiler->new_local = true; // Ensure the local variable's index is equals to the stack top index. - ASSERT((compiler->stack_size - 1) == index, OOPS); + // If the compiler has errors, we cannot and don't have to assert. + ASSERT(compiler->has_errors || (compiler->stack_size - 1) == index, + OOPS); // We don't need to call emitStoreVariable (which emit STORE_LOCAL) // because the local is already at it's location in the stack, we just @@ -1408,34 +1408,6 @@ void exprAnd(Compiler* compiler) { compiler->is_last_call = false; } -static void exprChainCall(Compiler* compiler) { - skipNewLines(compiler); - parsePrecedence(compiler, (Precedence)(PREC_CHAIN_CALL + 1)); - emitOpcode(compiler, OP_SWAP); // Swap the data with the function. - - int argc = 1; // The initial data. - - if (match(compiler, TK_LBRACE)) { - if (!match(compiler, TK_RBRACE)) { - do { - skipNewLines(compiler); - compileExpression(compiler); - skipNewLines(compiler); - argc++; - } while (match(compiler, TK_COMMA)); - consume(compiler, TK_RBRACE, "Expected '}' after chain call " - "parameter list."); - } - } - - // TODO: ensure argc < 256 (MAX_ARGC) 1byte. - - emitOpcode(compiler, OP_CALL); - emitByte(compiler, argc); - - compiler->is_last_call = false; -} - static void exprBinaryOp(Compiler* compiler) { TokenType op = compiler->previous.type; skipNewLines(compiler); @@ -2102,16 +2074,6 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) { if (fn_type != FN_NATIVE) { compileBlockBody(compiler, BLOCK_FUNC); - // Tail call optimization disabled at debug mode. - if (compiler->options && !compiler->options->debug) { - if (compiler->is_last_call) { - ASSERT(_FN->opcodes.count >= 3, OOPS); // OP_CALL, argc, OP_POP - ASSERT(_FN->opcodes.data[_FN->opcodes.count - 1] == OP_POP, OOPS); - ASSERT(_FN->opcodes.data[_FN->opcodes.count - 3] == OP_CALL, OOPS); - _FN->opcodes.data[_FN->opcodes.count - 3] = OP_TAIL_CALL; - } - } - consume(compiler, TK_END, "Expected 'end' after function definition end."); compilerExitBlock(compiler); // Parameter depth. emitFunctionEnd(compiler); diff --git a/src/pk_vm.c b/src/pk_vm.c index b2d6c74..3b5726c 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -439,32 +439,6 @@ static void* defaultRealloc(void* memory, size_t new_size, void* user_data) { return realloc(memory, new_size); } -// If failed to resolve it'll return false. Parameter [result] should be points -// to the string which is the path that has to be resolved and once it resolved -// the provided result's string's on_done() will be called and, it's string -// will be updated with the new resolved path string. -static inline bool resolveScriptPath(PKVM* vm, PkStringPtr* path_string) { - if (vm->config.resolve_path_fn == NULL) return true; - - const char* path = path_string->string; - PkStringPtr resolved; - - Fiber* fiber = vm->fiber; - if (fiber == NULL || fiber->frame_count <= 0) { - // fiber == NULL => vm haven't started yet and it's a root script. - resolved = vm->config.resolve_path_fn(vm, NULL, path); - } else { - const Function* fn = fiber->frames[fiber->frame_count - 1].fn; - resolved = vm->config.resolve_path_fn(vm, fn->owner->path->data, path); - } - - // Done with the last string and update it with the new string. - if (path_string->on_done != NULL) path_string->on_done(vm, *path_string); - *path_string = resolved; - - return path_string->string != NULL; -} - // Import and return Script object as Var. If the script is imported and // compiled here it'll set [is_new_script] to true otherwise (using the cached // script) set to false. diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index ccb7d05..5a52241 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -50,6 +50,15 @@ if a and b then assert(false) end if a or b then val = 42 else assert(false) end assert(val == 42) if get_true() or false then val = 12 end assert(val == 12) +## Newer logical or implementation. +## a or b === if (a) return a else return b +## a and b === if (!a) return a else return b +a = null; b = [1, 2, 3] +assert((a or b) == [1, 2, 3]) ## Note == has higher precedence than and/or. +assert((a and b) == null) +assert((b or a) == [1, 2, 3]) +assert((a or b) == b or a) + ## Recursive to_string list/map l = [1] list_append(l, l) diff --git a/tests/lang/functions.pk b/tests/lang/functions.pk index a817b60..3bc2efc 100644 --- a/tests/lang/functions.pk +++ b/tests/lang/functions.pk @@ -14,14 +14,12 @@ end assert(val == 'defined after the call') ## Chain call tests. (concatenative programming) - -def fn1(data) return '[fn1:' + data + ']' end -def fn2(data, suffix) return '[fn2:' + data + '|' + suffix + ']' end -def fn3(data) return '[fn3:' + data + ']' end - -result = 'data' -> fn1 -> fn2{'suff'} -> fn3 -assert(result == '[fn3:[fn2:[fn1:data]|suff]]') - +## Chain call no more supported (unnecessary feature). +#def fn1(data) return '[fn1:' + data + ']' end +#def fn2(data, suffix) return '[fn2:' + data + '|' + suffix + ']' end +#def fn3(data) return '[fn3:' + data + ']' end +#result = 'data' -> fn1 -> fn2{'suff'} -> fn3 +#assert(result == '[fn3:[fn2:[fn1:data]|suff]]') # str_lower(s) function refactored to s.lower attribute. #result = ' tEST+InG ' -> str_strip -> str_lower #assert(result == 'test+ing') diff --git a/tests/lang/import.pk b/tests/lang/import.pk index a784eab..d023488 100644 --- a/tests/lang/import.pk +++ b/tests/lang/import.pk @@ -11,7 +11,7 @@ from path import * import "basics.pk" ## will import all import "controlflow.pk" as if_test -from "functions.pk" import fn1, fn2 as f2, fn3 +from "functions.pk" import f1, f2 as fn2, f3 import "class.pk" as class_ assert(class_.Vec(42, 3.14).y == 3.14) diff --git a/tests/lang/toc.pk b/tests/lang/toc.pk index ef852d9..05e9cd4 100644 --- a/tests/lang/toc.pk +++ b/tests/lang/toc.pk @@ -71,6 +71,11 @@ for i in 0..100 assert(i%2 == f(i)) end +## The below function caused a bug after compile time stack size calculation +## bug fixed. Added here to check for regression. +def h() + f() ## <-- Not tail called here (anymore) because it's not returned. +end # If we got here, that means all test were passed. print('All TESTS PASSED')