From 4b45d440ea472177072b9e0a5bf4f6bb56483095 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 20:32:18 +0400 Subject: [PATCH 01/14] Added `help()` shell function `help()` displays help info for each data type --- core/datatypes.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++ radon.py | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/core/datatypes.py b/core/datatypes.py index b323990..71b7e7e 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -110,6 +110,12 @@ def copy(self: Self) -> Self: def is_true(self) -> bool: return False + + # Help text for help() in radon + def __help_repr__(self) -> str: + return """ +This data type help is not implemented yet +""" def illegal_operation(self, *others: Value) -> RTError: if len(others) == 0: @@ -149,6 +155,13 @@ def __next__(self) -> RTResult[Value]: def __str__(self) -> str: return "" + def __help_repr__(self) -> str: + return """ +Iterator + +An Iterator is an object that enables traversal over a collection, one element at a time. +""" + def __repr__(self) -> str: return str(self) @@ -279,6 +292,22 @@ def is_true(self) -> bool: def __str__(self) -> str: return str(self.value) + + def __help_repr__(self) -> str: + return """ +Number + +A Number represents a numeric value. It can be an integer, float, or other numeric type. + +Operations: + +, -, *, / -> Basic arithmetic operations. + //, % -> Integer division and modulus. + ^ -> Exponentiation. + math.factorial() -> Gets the factorial of a number (standard math library) + str() -> Converts the number to its string representation. + +Example: 25 +""" def __repr__(self) -> str: return str(self.value) @@ -345,6 +374,19 @@ def __str__(self) -> str: def __repr__(self) -> str: return "true" if self.value else "false" + + def __help_repr__(self) -> str: + return """ +Boolean + +A Boolean represents a truth value: True or False. + +Operations: + and, or, not -> Logical operations. + ==, != -> Equality and inequality checks. + +Example: true +""" @classmethod def true(cls) -> Boolean: @@ -480,6 +522,22 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'"{self.value}"' + + def __help_repr__(self) -> str: + return """ +String + +A String is a sequence of characters. + +Methods: + len(str) -> Returns the length of the string. + +String standard library methods: + find(str) -> Find a character in a string and return its index (-1 if not found) + to_int() -> Magic method to convert string to int if possible + +Example: "Hello World!" +""" def __iter__(self) -> PyIterator[str]: return iter(self.value) @@ -656,6 +714,29 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'[{", ".join(repr(x) for x in self.elements)}]' + + def __help_repr__(self) -> str: + return """ +Array + +An Array is an ordered collection of elements. + +Methods: + len(arr) -> Returns the number of elements in the array. + +Array standard library methods: + map(func) -> Map an array with a function + append(item) -> Append an element from the right + pop(index) -> Removes and returns the last element of the array. + extend(arr) -> Extend by another array + find(element) -> Get the index of an element in the array (-1 if not found) + + is_empty() -> Returns boolean indicating if the array is empty or not + to_string() -> Convert to string + is_array() -> returns true + +Example: [1,2,3,true,"Hello World!"] +""" def __iter__(self): return iter(self.elements) @@ -772,6 +853,15 @@ def copy(self) -> HashMap: def __str__(self) -> str: return self.__repr__() + + def __help_repr__(self) -> str: + return """ +HashMap + +A HashMap is a collection of key-value pairs. + +Example: {"key":"value"} +""" def __repr__(self) -> str: __val = ", ".join([f"{repr(k)}: {repr(v)}" for k, v in self.values.items()]) diff --git a/radon.py b/radon.py index 379dd5d..964686c 100755 --- a/radon.py +++ b/radon.py @@ -29,7 +29,7 @@ def start_text() -> None: f"\033[1;34mRadon {base_core.__version__} on {platform.machine()} {platform.system()} ({sys.platform})\033[0m" ) print(f"\033[1;33mDocumentation:\033[0m {documentation_link}") - print("\033[1;32mType \033[1;31mlicense()\033[1;32m for more info\033[0m") + print("\033[1;32mType \033[1;31mhelp(obj), license(), credits()\033[1;32m for more info\033[0m") print("\033[1;32mType \033[1;31mexit()\033[1;32m to quit the shell.\033[0m") From 43f627994c4ad9264738edde9c1fb201719459b4 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 20:36:43 +0400 Subject: [PATCH 02/14] Update builtin_funcs.py --- core/builtin_funcs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index 2fda55c..ac82eb7 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -122,6 +122,14 @@ def execute_len(self, exec_ctx: Context) -> RTResult[Value]: def execute_input(self, exec_ctx: Context) -> RTResult[Value]: text = input(str(exec_ctx.symbol_table.get("value"))) return RTResult[Value]().success(String(text)) + + @args(["obj"]) + def execute_help(self, exec_ctx: Context) -> RTResult[Value]: + obj = exec_ctx.symbol_table.get("obj") + if obj is None: + return RTResult[Value]().failure(Error(self.pos_start, self.pos_end, "TypeError", 'Argument is null')) + print(obj.__help_repr__()) + return RTResult[Value]().success(obj) @args([]) def execute_input_int(self, exec_ctx: Context) -> RTResult[Value]: @@ -608,6 +616,7 @@ def create_global_symbol_table() -> SymbolTable: # Shell functions ret.set("license", BuiltInFunction("license")) ret.set("credits", BuiltInFunction("credits")) + ret.set("help", BuiltInFunction("help")) # Built-in classes ret.set("File", bic.BuiltInClass("File", bic.FileObject)) ret.set("String", bic.BuiltInClass("String", bic.StringObject)) From a9e1a32dd98f3d2ca757f6ae8383637d6b63731b Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 20:37:02 +0400 Subject: [PATCH 03/14] fix: ruff formatting --- core/builtin_funcs.py | 4 ++-- core/datatypes.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index ac82eb7..ac7acf7 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -122,12 +122,12 @@ def execute_len(self, exec_ctx: Context) -> RTResult[Value]: def execute_input(self, exec_ctx: Context) -> RTResult[Value]: text = input(str(exec_ctx.symbol_table.get("value"))) return RTResult[Value]().success(String(text)) - + @args(["obj"]) def execute_help(self, exec_ctx: Context) -> RTResult[Value]: obj = exec_ctx.symbol_table.get("obj") if obj is None: - return RTResult[Value]().failure(Error(self.pos_start, self.pos_end, "TypeError", 'Argument is null')) + return RTResult[Value]().failure(Error(self.pos_start, self.pos_end, "TypeError", "Argument is null")) print(obj.__help_repr__()) return RTResult[Value]().success(obj) diff --git a/core/datatypes.py b/core/datatypes.py index 71b7e7e..097dbfe 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -110,7 +110,7 @@ def copy(self: Self) -> Self: def is_true(self) -> bool: return False - + # Help text for help() in radon def __help_repr__(self) -> str: return """ @@ -292,7 +292,7 @@ def is_true(self) -> bool: def __str__(self) -> str: return str(self.value) - + def __help_repr__(self) -> str: return """ Number @@ -374,7 +374,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return "true" if self.value else "false" - + def __help_repr__(self) -> str: return """ Boolean @@ -522,7 +522,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'"{self.value}"' - + def __help_repr__(self) -> str: return """ String @@ -714,7 +714,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'[{", ".join(repr(x) for x in self.elements)}]' - + def __help_repr__(self) -> str: return """ Array @@ -853,7 +853,7 @@ def copy(self) -> HashMap: def __str__(self) -> str: return self.__repr__() - + def __help_repr__(self) -> str: return """ HashMap From 21022c23acebe96f69519d9ff19348cd8754bc97 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 21:18:05 +0400 Subject: [PATCH 04/14] Added support for user-defined objects --- core/datatypes.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/datatypes.py b/core/datatypes.py index 097dbfe..f07f170 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1230,6 +1230,11 @@ def operator(self, operator: str, *args: Value) -> ResultTuple: def __repr__(self) -> str: # TODO: make this overloadable as well return f"" + + def __help_repr__(self) -> str: + try: + return self.operator("__help_repr__")[0].value + except AttributeError: return f"No custom help for class `{self.parent_class.name}`" class BaseClass(Value, ABC): From 1c3231dc99c37f222dfe58ea3916d06d0c53d848 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 21:18:38 +0400 Subject: [PATCH 05/14] fix: ruff formatting --- core/datatypes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index f07f170..7b69253 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1230,11 +1230,12 @@ def operator(self, operator: str, *args: Value) -> ResultTuple: def __repr__(self) -> str: # TODO: make this overloadable as well return f"" - + def __help_repr__(self) -> str: try: return self.operator("__help_repr__")[0].value - except AttributeError: return f"No custom help for class `{self.parent_class.name}`" + except AttributeError: + return f"No custom help for class `{self.parent_class.name}`" class BaseClass(Value, ABC): From 0f142dddccf5936da3bd3014f96f991c6554e126 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 21:30:44 +0400 Subject: [PATCH 06/14] fix: __help_repr__ function --- core/datatypes.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 7b69253..1ce637b 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1204,6 +1204,10 @@ def __exec_len__(self): except AttributeError: return Null.null() + def __help_repr__(self) -> str: + result = str(self.operator("__help_repr__")[0]) + return result + def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: method = method.copy() if method.symbol_table is None: @@ -1231,12 +1235,6 @@ def __repr__(self) -> str: # TODO: make this overloadable as well return f"" - def __help_repr__(self) -> str: - try: - return self.operator("__help_repr__")[0].value - except AttributeError: - return f"No custom help for class `{self.parent_class.name}`" - class BaseClass(Value, ABC): name: str From ad6b3c23fd5dde1e96c34a9ffb79715ae0d5d864 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 22:35:21 +0400 Subject: [PATCH 07/14] Added dynamic help for custom functions --- core/datatypes.py | 32 ++++++++++++++++++++++++++++++-- core/interpreter.py | 5 ++++- core/nodes.py | 3 +++ core/parser.py | 10 +++++++++- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 1ce637b..9384c81 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1037,6 +1037,8 @@ def copy(self) -> PyAPI: class BaseFunction(Value): name: str symbol_table: Optional[SymbolTable] + desc: str + arg_names: list[str] def __init__(self, name: Optional[str], symbol_table: Optional[SymbolTable]) -> None: super().__init__() @@ -1111,6 +1113,7 @@ def check_and_populate_args(self, arg_names, args, kwargs, defaults, exec_ctx): class BaseInstance(Value, ABC): + methods: list[BaseFunction] = [] parent_class: BaseClass symbol_table: SymbolTable @@ -1205,7 +1208,13 @@ def __exec_len__(self): return Null.null() def __help_repr__(self) -> str: - result = str(self.operator("__help_repr__")[0]) + result: str = f"Help on object {self.parent_class.name}:\n\nclass {self.parent_class.name}\n" + for k in self.symbol_table.symbols: + f = self.symbol_table.symbols[k] + if isinstance(f, BaseFunction): + result += f"| fun {k}({','.join([f.__repr__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + elif isinstance(f, Value) and k != "this": + result += f"| {k} = {f!r}\n" return result def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: @@ -1213,6 +1222,7 @@ def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: if method.symbol_table is None: method.symbol_table = SymbolTable() method.symbol_table.set("this", self) + self.methods.append(method) return RTResult[BaseFunction]().success(method) def operator(self, operator: str, *args: Value) -> ResultTuple: @@ -1288,6 +1298,16 @@ def get(self, name: str) -> Optional[Value]: return None return method + def __help_repr__(self) -> str: + result: str = f"Help on object {self.name}:\n\nclass {self.name}\n" + for k in self.symbol_table.symbols: + f = self.symbol_table.symbols[k] + if isinstance(f, BaseFunction): + result += f"| fun {k}({','.join([f.__repr__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + elif isinstance(f, Value) and k != "this": + result += f"| {k} = {f!r}\n" + return result + def create(self, args: list[Value]) -> RTResult[BaseInstance]: res = RTResult[BaseInstance]() @@ -1342,12 +1362,14 @@ def __init__( arg_names: list[str], defaults: list[Optional[Value]], should_auto_return: bool, + desc: str, ) -> None: super().__init__(name, symbol_table) self.body_node = body_node self.arg_names = arg_names self.defaults = defaults self.should_auto_return = should_auto_return + self.desc = desc def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value]: from core.interpreter import Interpreter # Lazy import @@ -1374,7 +1396,13 @@ def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value def copy(self) -> Function: copy = Function( - self.name, self.symbol_table, self.body_node, self.arg_names, self.defaults, self.should_auto_return + self.name, + self.symbol_table, + self.body_node, + self.arg_names, + self.defaults, + self.should_auto_return, + self.desc, ) copy.set_context(self.context) copy.set_pos(self.pos_start, self.pos_end) diff --git a/core/interpreter.py b/core/interpreter.py index 12f5339..48e4b84 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -469,6 +469,7 @@ def visit_FuncDefNode(self, node: FuncDefNode, context: Context) -> RTResult[Val res = RTResult[Value]() func_name = node.var_name_tok.value if node.var_name_tok else None + func_desc = node.desc assert func_name is None or isinstance(func_name, str) body_node = node.body_node arg_names = [str(arg_name.value) for arg_name in node.arg_name_toks] @@ -483,7 +484,9 @@ def visit_FuncDefNode(self, node: FuncDefNode, context: Context) -> RTResult[Val defaults.append(default_value) func_value = ( - Function(func_name, context.symbol_table, body_node, arg_names, defaults, node.should_auto_return) + Function( + func_name, context.symbol_table, body_node, arg_names, defaults, node.should_auto_return, func_desc + ) .set_context(context) .set_pos(node.pos_start, node.pos_end) ) diff --git a/core/nodes.py b/core/nodes.py index 9d5af21..eae9d8b 100755 --- a/core/nodes.py +++ b/core/nodes.py @@ -236,6 +236,7 @@ class FuncDefNode: body_node: Node should_auto_return: bool static: bool + desc: str pos_start: Position pos_end: Position @@ -248,6 +249,7 @@ def __init__( body_node: Node, should_auto_return: bool, static: bool = False, + desc: str = "", ) -> None: self.var_name_tok = var_name_tok self.arg_name_toks = arg_name_toks @@ -255,6 +257,7 @@ def __init__( self.body_node = body_node self.should_auto_return = should_auto_return self.static = static + self.desc = desc if self.var_name_tok: self.pos_start = self.var_name_tok.pos_start diff --git a/core/parser.py b/core/parser.py index a9b5b69..4978774 100755 --- a/core/parser.py +++ b/core/parser.py @@ -1309,6 +1309,14 @@ def func_def(self) -> ParseResult[Node]: ) self.advance(res) + self.skip_newlines() + + desc: str = "[No Description]" + + if self.current_tok.type == TT_STRING: + # Set description + desc = str(self.current_tok.value) + self.advance(res) body = res.register(self.statements()) if res.error: @@ -1320,7 +1328,7 @@ def func_def(self) -> ParseResult[Node]: self.advance(res) - return res.success(FuncDefNode(var_name_tok, arg_name_toks, defaults, body, False, static=static)) + return res.success(FuncDefNode(var_name_tok, arg_name_toks, defaults, body, False, static=static, desc=desc)) def switch_statement(self) -> ParseResult[Node]: res = ParseResult[Node]() From 27bd5767f3f1460b8fb82a49bb8cce6243bb92cd Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 22:36:27 +0400 Subject: [PATCH 08/14] Removed unnecessary property `methods` --- core/datatypes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 9384c81..649bb23 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1113,7 +1113,6 @@ def check_and_populate_args(self, arg_names, args, kwargs, defaults, exec_ctx): class BaseInstance(Value, ABC): - methods: list[BaseFunction] = [] parent_class: BaseClass symbol_table: SymbolTable @@ -1222,7 +1221,6 @@ def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: if method.symbol_table is None: method.symbol_table = SymbolTable() method.symbol_table.set("this", self) - self.methods.append(method) return RTResult[BaseFunction]().success(method) def operator(self, operator: str, *args: Value) -> ResultTuple: From 74edcfd66dc1c62c39483eee5863d8f45e580eda Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 22:51:37 +0400 Subject: [PATCH 09/14] Added help for standalone functions + tests --- core/datatypes.py | 7 +++++-- tests/help.rn | 33 +++++++++++++++++++++++++++++++++ tests/help.rn.json | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/help.rn create mode 100644 tests/help.rn.json diff --git a/core/datatypes.py b/core/datatypes.py index 649bb23..b3b3ab2 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1211,7 +1211,7 @@ def __help_repr__(self) -> str: for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, BaseFunction): - result += f"| fun {k}({','.join([f.__repr__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + result += f"| fun {k}({','.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1301,7 +1301,7 @@ def __help_repr__(self) -> str: for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, BaseFunction): - result += f"| fun {k}({','.join([f.__repr__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + result += f"| fun {k}({','.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1352,6 +1352,9 @@ class Function(BaseFunction): defaults: list[Optional[Value]] should_auto_return: bool + def __help_repr__(self) -> str: + return f"Help on function {self.name}\n| fun {self.name}({','.join(self.arg_names)})\n|\t{self.desc}\n" + def __init__( self, name: Optional[str], diff --git a/tests/help.rn b/tests/help.rn new file mode 100644 index 0000000..708a895 --- /dev/null +++ b/tests/help.rn @@ -0,0 +1,33 @@ +class Test +{ + property1 = "Hello, World!" + + fun __constructor__() + { + + } + + fun func1(arg1,arg2) + { + "Description for func1" + } + + fun func2(arg1) + { + "Description for func2" + } + + fun no_description() { + return null + } +} + +fun standalone(arg1,arg2) +{ + "This is a standalone function" +} + +help("Hello") +help(Test) +help(Test()) +help(standalone) \ No newline at end of file diff --git a/tests/help.rn.json b/tests/help.rn.json new file mode 100644 index 0000000..b99b04d --- /dev/null +++ b/tests/help.rn.json @@ -0,0 +1 @@ +{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1,arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1,arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on function standalone\n| fun standalone(arg1,arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file From 1b44ccfa9d66b2de85799c0487084051b1a26185 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 23:01:04 +0400 Subject: [PATCH 10/14] Added no description text for arrow functions --- core/parser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/parser.py b/core/parser.py index 4978774..69810f7 100755 --- a/core/parser.py +++ b/core/parser.py @@ -1300,7 +1300,9 @@ def func_def(self) -> ParseResult[Node]: return res assert body is not None - return res.success(FuncDefNode(var_name_tok, arg_name_toks, defaults, body, True, static=static)) + return res.success( + FuncDefNode(var_name_tok, arg_name_toks, defaults, body, True, static=static, desc="[No Description]") + ) self.skip_newlines() if self.current_tok.type != TT_LBRACE: @@ -1312,7 +1314,6 @@ def func_def(self) -> ParseResult[Node]: self.skip_newlines() desc: str = "[No Description]" - if self.current_tok.type == TT_STRING: # Set description desc = str(self.current_tok.value) From 02b403565dba5e79811bb7b4bb5917a8987ce3d3 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 23:12:38 +0400 Subject: [PATCH 11/14] Added help support for args with default values --- core/datatypes.py | 12 +++++++++--- tests/help.rn.json | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index b3b3ab2..aa833ae 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1211,7 +1211,7 @@ def __help_repr__(self) -> str: for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, BaseFunction): - result += f"| fun {k}({','.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + result += f"| fun {k}({', '.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1301,7 +1301,7 @@ def __help_repr__(self) -> str: for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, BaseFunction): - result += f"| fun {k}({','.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + result += f"| fun {k}({', '.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1353,7 +1353,13 @@ class Function(BaseFunction): should_auto_return: bool def __help_repr__(self) -> str: - return f"Help on function {self.name}\n| fun {self.name}({','.join(self.arg_names)})\n|\t{self.desc}\n" + arg_strs: list[str] = [] + for i in range(len(self.arg_names)): + if self.defaults[i] is not None: + arg_strs.append(f"{self.arg_names[i]} = {self.defaults[i]}") + else: + arg_strs.append(self.arg_names[i]) + return f"Help on function {self.name}\n| fun {self.name}({', '.join(arg_strs)})\n|\t{self.desc}\n" def __init__( self, diff --git a/tests/help.rn.json b/tests/help.rn.json index b99b04d..2510ad6 100644 --- a/tests/help.rn.json +++ b/tests/help.rn.json @@ -1 +1 @@ -{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1,arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1,arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on function standalone\n| fun standalone(arg1,arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file +{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1, arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1, arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on function standalone\n| fun standalone(arg1, arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file From 1c912dc9ba748c8c025dd26e1925737cdac20be8 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 23:33:48 +0400 Subject: [PATCH 12/14] One general function for printing function help + help returns null --- core/builtin_funcs.py | 2 +- core/datatypes.py | 15 +++++++++------ tests/help.rn.json | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index ac7acf7..2215014 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -129,7 +129,7 @@ def execute_help(self, exec_ctx: Context) -> RTResult[Value]: if obj is None: return RTResult[Value]().failure(Error(self.pos_start, self.pos_end, "TypeError", "Argument is null")) print(obj.__help_repr__()) - return RTResult[Value]().success(obj) + return RTResult[Value]().success(Null.null()) @args([]) def execute_input_int(self, exec_ctx: Context) -> RTResult[Value]: diff --git a/core/datatypes.py b/core/datatypes.py index aa833ae..2184bb8 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1210,8 +1210,8 @@ def __help_repr__(self) -> str: result: str = f"Help on object {self.parent_class.name}:\n\nclass {self.parent_class.name}\n" for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] - if isinstance(f, BaseFunction): - result += f"| fun {k}({', '.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + if isinstance(f, Function): + result += f.__help_repr_method__() elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1300,8 +1300,8 @@ def __help_repr__(self) -> str: result: str = f"Help on object {self.name}:\n\nclass {self.name}\n" for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] - if isinstance(f, BaseFunction): - result += f"| fun {k}({', '.join([a.__str__() for a in f.arg_names])})\n|\t {f.desc}\n|\n" + if isinstance(f, Function): + result += f.__help_repr_method__() elif isinstance(f, Value) and k != "this": result += f"| {k} = {f!r}\n" return result @@ -1353,13 +1353,16 @@ class Function(BaseFunction): should_auto_return: bool def __help_repr__(self) -> str: + return f"Help on function {self.name}\n{self.__help_repr_method__()}" + + def __help_repr_method__(self) -> str: arg_strs: list[str] = [] for i in range(len(self.arg_names)): if self.defaults[i] is not None: - arg_strs.append(f"{self.arg_names[i]} = {self.defaults[i]}") + arg_strs.append(f"{self.arg_names[i]} = {self.defaults[i].__repr__()}") else: arg_strs.append(self.arg_names[i]) - return f"Help on function {self.name}\n| fun {self.name}({', '.join(arg_strs)})\n|\t{self.desc}\n" + return f"| fun {self.name}({', '.join(arg_strs)})\n|\t{self.desc}\n" def __init__( self, diff --git a/tests/help.rn.json b/tests/help.rn.json index 2510ad6..2887d3a 100644 --- a/tests/help.rn.json +++ b/tests/help.rn.json @@ -1 +1 @@ -{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1, arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t [No Description]\n|\n| fun func1(arg1, arg2)\n|\t Description for func1\n|\n| fun func2(arg1)\n|\t Description for func2\n|\n| fun no_description()\n|\t [No Description]\n|\n\nHelp on function standalone\n| fun standalone(arg1, arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file +{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t[No Description]\n| fun func1(arg1, arg2)\n|\tDescription for func1\n| fun func2(arg1)\n|\tDescription for func2\n| fun no_description()\n|\t[No Description]\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t[No Description]\n| fun func1(arg1, arg2)\n|\tDescription for func1\n| fun func2(arg1)\n|\tDescription for func2\n| fun no_description()\n|\t[No Description]\n\nHelp on function standalone\n| fun standalone(arg1, arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file From 0a66b5d53e0765b33a2a18d33249e090e38474d6 Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 23:57:41 +0400 Subject: [PATCH 13/14] changed spacing --- core/datatypes.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 2184bb8..0a45925 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1207,13 +1207,13 @@ def __exec_len__(self): return Null.null() def __help_repr__(self) -> str: - result: str = f"Help on object {self.parent_class.name}:\n\nclass {self.parent_class.name}\n" + result: str = f"Help on object {self.parent_class.name}:\n\nclass {self.parent_class.name}\n|\n" for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, Function): result += f.__help_repr_method__() elif isinstance(f, Value) and k != "this": - result += f"| {k} = {f!r}\n" + result += f"| {k} = {f!r}\n|\n" return result def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]: @@ -1297,13 +1297,13 @@ def get(self, name: str) -> Optional[Value]: return method def __help_repr__(self) -> str: - result: str = f"Help on object {self.name}:\n\nclass {self.name}\n" + result: str = f"Help on object {self.name}:\n\nclass {self.name}\n|\n" for k in self.symbol_table.symbols: f = self.symbol_table.symbols[k] if isinstance(f, Function): result += f.__help_repr_method__() elif isinstance(f, Value) and k != "this": - result += f"| {k} = {f!r}\n" + result += f"| {k} = {f!r}\n|\n" return result def create(self, args: list[Value]) -> RTResult[BaseInstance]: @@ -1353,7 +1353,7 @@ class Function(BaseFunction): should_auto_return: bool def __help_repr__(self) -> str: - return f"Help on function {self.name}\n{self.__help_repr_method__()}" + return f"Help on function {self.name}:\n\n{self.__help_repr_method__()}" def __help_repr_method__(self) -> str: arg_strs: list[str] = [] @@ -1362,7 +1362,7 @@ def __help_repr_method__(self) -> str: arg_strs.append(f"{self.arg_names[i]} = {self.defaults[i].__repr__()}") else: arg_strs.append(self.arg_names[i]) - return f"| fun {self.name}({', '.join(arg_strs)})\n|\t{self.desc}\n" + return f"| fun {self.name}({', '.join(arg_strs)})\n|\t{self.desc}\n|\n" def __init__( self, From 9ad2f736b0e19d61a71d4d60f734e8d7bb9cf94e Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan Date: Wed, 29 May 2024 23:59:06 +0400 Subject: [PATCH 14/14] updated tests to match new output --- tests/help.rn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/help.rn.json b/tests/help.rn.json index 2887d3a..8f37aa4 100644 --- a/tests/help.rn.json +++ b/tests/help.rn.json @@ -1 +1 @@ -{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t[No Description]\n| fun func1(arg1, arg2)\n|\tDescription for func1\n| fun func2(arg1)\n|\tDescription for func2\n| fun no_description()\n|\t[No Description]\n\nHelp on object Test:\n\nclass Test\n| property1 = \"Hello, World!\"\n| fun __constructor__()\n|\t[No Description]\n| fun func1(arg1, arg2)\n|\tDescription for func1\n| fun func2(arg1)\n|\tDescription for func2\n| fun no_description()\n|\t[No Description]\n\nHelp on function standalone\n| fun standalone(arg1, arg2)\n|\tThis is a standalone function\n\n", "stderr": ""} \ No newline at end of file +{"code": 0, "stdout": "\nString\n\nA String is a sequence of characters.\n\nMethods:\n len(str) -> Returns the length of the string.\n\nString standard library methods:\n find(str) -> Find a character in a string and return its index (-1 if not found)\n to_int() -> Magic method to convert string to int if possible\n\nExample: \"Hello World!\"\n\nHelp on object Test:\n\nclass Test\n|\n| property1 = \"Hello, World!\"\n|\n| fun __constructor__()\n|\t[No Description]\n|\n| fun func1(arg1, arg2)\n|\tDescription for func1\n|\n| fun func2(arg1)\n|\tDescription for func2\n|\n| fun no_description()\n|\t[No Description]\n|\n\nHelp on object Test:\n\nclass Test\n|\n| property1 = \"Hello, World!\"\n|\n| fun __constructor__()\n|\t[No Description]\n|\n| fun func1(arg1, arg2)\n|\tDescription for func1\n|\n| fun func2(arg1)\n|\tDescription for func2\n|\n| fun no_description()\n|\t[No Description]\n|\n\nHelp on function standalone:\n\n| fun standalone(arg1, arg2)\n|\tThis is a standalone function\n|\n\n", "stderr": ""} \ No newline at end of file