Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added len() function #147

Merged
merged 15 commits into from
May 28, 2024
21 changes: 21 additions & 0 deletions core/builtin_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")))
Expand Down Expand Up @@ -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"))
Expand Down
25 changes: 20 additions & 5 deletions core/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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:
Expand All @@ -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):
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions stdlib/array.rn
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}

Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/len.rn
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions tests/len.rn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"code": 0, "stdout": "10\n4\n3\n2\n1\n0\nTypeError: Object of type \"Number\" has no len()\n", "stderr": ""}
1 change: 1 addition & 0 deletions tests/modules2.rn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"code": 0, "stdout": "A\nr\nr\na\ny\n", "stderr": ""}
Loading