diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index baf8eab..2fda55c 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -98,6 +98,26 @@ def execute_print(self, exec_ctx: Context) -> RTResult[Value]: def execute_print_ret(self, exec_ctx: Context) -> RTResult[Value]: return RTResult[Value]().success(String(str(exec_ctx.symbol_table.get("value")))) + @args(["value"]) + def execute_len(self, exec_ctx: Context) -> RTResult[Value]: + val = exec_ctx.symbol_table.get("value") + try: + if val is not None and val.__class__ is not Value: + if hasattr(val, "__len__"): + ret = int(val.__len__()) + elif hasattr(val, "__exec_len__"): + ret = int(val.__exec_len__()) + else: + raise TypeError() + return RTResult[Value]().success(Number(ret)) + raise TypeError() + except TypeError: + return RTResult[Value]().failure( + Error( + self.pos_start, self.pos_end, "TypeError", f'Object of type "{val.__class__.__name__}" has no len()' + ) + ) + @args(["value"]) def execute_input(self, exec_ctx: Context) -> RTResult[Value]: text = input(str(exec_ctx.symbol_table.get("value"))) @@ -552,6 +572,7 @@ def create_global_symbol_table() -> SymbolTable: ret.set("cls", BuiltInFunction("clear")) ret.set("require", BuiltInFunction("require")) ret.set("exit", BuiltInFunction("exit")) + ret.set("len", BuiltInFunction("len")) # Datatype validator methods ret.set("is_num", BuiltInFunction("is_num")) ret.set("is_int", BuiltInFunction("is_int")) diff --git a/core/datatypes.py b/core/datatypes.py index 96b056e..6b4abcc 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -134,6 +134,9 @@ def __init__(self, generator: Generator[RTResult[Value], None, None]) -> None: super().__init__() self.it = generator + def __len__(self) -> int: + return len(list(self.it)) + def iter(self) -> Iterator: return self @@ -334,6 +337,9 @@ def copy(self) -> Boolean: def is_true(self) -> bool: return self.value + def __len__(self) -> int: + return 1 if self.value else 0 + def __str__(self) -> str: return "true" if self.value else "false" @@ -625,7 +631,7 @@ def set_index(self, index: Value, value: Value) -> ResultTuple: return self, None def contains(self, value: Value) -> ResultTuple: - ret = Boolean.false() + ret: Boolean = Boolean.false() for val in self.elements: cmp, err = val.get_comparison_eq(value) if err is not None: @@ -640,21 +646,21 @@ def is_true(self) -> bool: return len(self.elements) > 0 def copy(self) -> Array: - copy = Array(self.elements) + copy: Array = Array(self.elements) copy.set_pos(self.pos_start, self.pos_end) copy.set_context(self.context) return copy - def __str__(self): + def __str__(self) -> str: return self.__repr__() - def __repr__(self): + def __repr__(self) -> str: return f'[{", ".join(repr(x) for x in self.elements)}]' def __iter__(self): return iter(self.elements) - def __getitem__(self, index): + def __getitem__(self, index) -> Value: return self.elements[index] def __len__(self): @@ -755,6 +761,9 @@ def get_comparison_ne(self, other: Value) -> ResultTuple: return Boolean.false(), None + def __len__(self) -> int: + return len(self.values) + def copy(self) -> HashMap: copy = HashMap(self.values) copy.set_pos(self.pos_start, self.pos_end) @@ -1099,6 +1108,12 @@ class Instance(BaseInstance): def __init__(self, parent_class: Class) -> None: super().__init__(parent_class, None) + def __exec_len__(self): + try: + return self.operator("__len__")[0].value + except AttributeError: + return Null.null() + def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: method = method.copy() if method.symbol_table is None: diff --git a/stdlib/array.rn b/stdlib/array.rn index 6d7cc89..f032382 100644 --- a/stdlib/array.rn +++ b/stdlib/array.rn @@ -6,7 +6,7 @@ class Array { fun map(func) { new_elements = [] - for i = 0 to this.len() { + for i = 0 to this.__len__() { arr_append(new_elements, func(arr_get(this.list, i))) } @@ -22,7 +22,7 @@ class Array { return (this.list)[start:end] } - fun len() -> arr_len(this.list) + fun __len__() -> arr_len(this.list) fun is_empty() -> this.list == [] fun to_string() -> str(this.list) fun is_array() -> true diff --git a/tests/len.rn b/tests/len.rn new file mode 100644 index 0000000..248b488 --- /dev/null +++ b/tests/len.rn @@ -0,0 +1,21 @@ +class Test +{ + fun __constructor__(){}; + fun __len__() + { + return 10 + } +} + +print(len(Test())) # 10 +print(len("test")) # 4 +print(len([1,2,3])) # 3 +print(len({"some": 123, "this": "ok"})) +print(len(true)) +print(len(false)) + +try { + print(len(234)) +} catch as err { + print(err) # TypeError +} \ No newline at end of file diff --git a/tests/len.rn.json b/tests/len.rn.json new file mode 100644 index 0000000..aaf8684 --- /dev/null +++ b/tests/len.rn.json @@ -0,0 +1 @@ +{"code": 0, "stdout": "10\n4\n3\n2\n1\n0\nTypeError: Object of type \"Number\" has no len()\n", "stderr": ""} \ No newline at end of file