diff --git a/src/pk_compiler.c b/src/pk_compiler.c index 2b9f4fd..13ee55a 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -218,10 +218,8 @@ typedef enum { PREC_LOWEST, PREC_LOGICAL_OR, // or PREC_LOGICAL_AND, // and - PREC_LOGICAL_NOT, // not PREC_EQUALITY, // == != - PREC_IN, // in - PREC_IS, // is + PREC_TEST, // in is PREC_COMPARISION, // < > <= >= PREC_BITWISE_OR, // | PREC_BITWISE_XOR, // ^ @@ -230,7 +228,7 @@ typedef enum { PREC_RANGE, // .. PREC_TERM, // + - PREC_FACTOR, // * / % - PREC_UNARY, // - ! ~ + PREC_UNARY, // - ! ~ not PREC_CHAIN_CALL, // -> PREC_CALL, // () PREC_SUBSCRIPT, // [] @@ -1192,10 +1190,10 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence /* TK_FUNC */ { exprFunc, NULL, NO_INFIX }, /* TK_END */ NO_RULE, /* TK_NULL */ { exprValue, NULL, NO_INFIX }, - /* TK_IN */ { NULL, exprBinaryOp, PREC_IN }, + /* TK_IN */ { NULL, exprBinaryOp, PREC_TEST }, /* TK_AND */ { NULL, exprAnd, PREC_LOGICAL_AND }, /* TK_OR */ { NULL, exprOr, PREC_LOGICAL_OR }, - /* TK_NOT */ { exprUnaryOp, NULL, PREC_LOGICAL_NOT }, + /* TK_NOT */ { exprUnaryOp, NULL, PREC_UNARY }, /* TK_TRUE */ { exprValue, NULL, NO_INFIX }, /* TK_FALSE */ { exprValue, NULL, NO_INFIX }, /* TK_DO */ NO_RULE, diff --git a/src/pk_core.c b/src/pk_core.c index 15da694..afb65a7 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -1243,9 +1243,7 @@ Var varBitRshift(PKVM* vm, Var v1, Var v2) { Var varBitNot(PKVM* vm, Var v) { int64_t i; - if (!validateInteger(vm, v, &i, "Unary operand")) return VAR_NULL; - return VAR_NUM((double)(~i)); } @@ -1274,6 +1272,48 @@ bool varLesser(Var v1, Var v2) { #undef RIGHT_OPERAND #undef UNSUPPORTED_OPERAND_TYPES +bool varContains(PKVM* vm, Var elem, Var container) { + if (!IS_OBJ(container)) { + VM_SET_ERROR(vm, stringFormat(vm, "'$' is not iterable.", + varTypeName(container))); + } + Object* obj = AS_OBJ(container); + + switch (obj->type) { + case OBJ_STRING: { + if (!IS_OBJ_TYPE(elem, OBJ_STRING)) { + VM_SET_ERROR(vm, stringFormat(vm, "Expected a string operand.")); + return false; + } + + String* sub = (String*)AS_OBJ(elem); + String* str = (String*)AS_OBJ(container); + if (sub->length > str->length) return false; + + TODO; + + } break; + + case OBJ_LIST: { + List* list = (List*)AS_OBJ(container); + for (uint32_t i = 0; i < list->elements.count; i++) { + if (isValuesEqual(elem, list->elements.data[i])) return true; + } + return false; + } break; + + case OBJ_MAP: + case OBJ_RANGE: + case OBJ_SCRIPT: + case OBJ_FUNC: + case OBJ_FIBER: + case OBJ_CLASS: + case OBJ_INST: + TODO; + } + +} + // Here we're switching the FNV-1a hash value of the name (cstring). Which is // an efficient way than having multiple if (attrib == "name"). From O(n) * k // to O(1) where n is the length of the string and k is the number of string diff --git a/src/pk_core.h b/src/pk_core.h index 03bfbb1..f5ff55f 100644 --- a/src/pk_core.h +++ b/src/pk_core.h @@ -46,6 +46,9 @@ Var varBitNot(PKVM* vm, Var v); // Returns ~v. bool varGreater(Var v1, Var v2); // Returns v1 > v2. bool varLesser(Var v1, Var v2); // Returns v1 < v2. +// Returns elem in container. +bool varContains(PKVM* vm, Var elem, Var container); + // Returns the attribute named [attrib] on the variable [on]. Var varGetAttrib(PKVM* vm, Var on, String* attrib); diff --git a/src/pk_vm.c b/src/pk_vm.c index 4815361..33ce8fc 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -1477,9 +1477,15 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber) { } OPCODE(IN): - // TODO: Implement bool varContaines(vm, on, value); - TODO; - UNREACHABLE(); + { + // Don't pop yet, we need the reference for gc. + Var container = PEEK(-1), elem = PEEK(-2); + bool contains = varContains(vm, elem, container); + DROP(); DROP(); // container, elem + PUSH(VAR_BOOL(contains)); + CHECK_ERROR(); + DISPATCH(); + } OPCODE(REPL_PRINT): { diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index 96bb08a..baf318b 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -27,6 +27,11 @@ l1 = [1] + []; assert(l1.length == 1); assert(l1[0] == 1) l2 = l1 + [1,2,3]; assert(l2.length == 4); assert(l2 == [1,1,2,3]) l3 = l2 + l1 + l2; assert(l3 == [1,1,2,3,1,1,1,2,3]) +## in tests. +assert(!('abc' in 'a')) +assert(42 in [12, 42, 3.14]) +assert(!('a' in ['abc'])) + ## Builtin functions tests. assert(to_string(42) == '42')