Skip to content

Commit

Permalink
Merge pull request #147 from Vardan2009/len-function
Browse files Browse the repository at this point in the history
Added `len()` function support.
  • Loading branch information
Almas-Ali authored May 28, 2024
2 parents f9e6bd8 + cb0e6f3 commit d313573
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 7 deletions.
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": ""}

0 comments on commit d313573

Please sign in to comment.