diff --git a/examples/calculator.noug b/examples/calculator.noug index de7e0dc..9d17920 100644 --- a/examples/calculator.noug +++ b/examples/calculator.noug @@ -145,7 +145,7 @@ while:main_loop True then print_in_red(error_msg) continue end - + # tokenize var tokens = [] var floating_point = 0 @@ -280,7 +280,7 @@ while:main_loop True then if debug.is_debug_enabled then \ print(tokens) - + # parse var i = -1 var last_token = "" @@ -415,7 +415,7 @@ while:main_loop True then end var last_token = token end - + if len(stack) >= 1 then if verbose then print(stack(-1)) var answer = stack(-1) diff --git a/lib_/_conffiles_.py b/lib_/_conffiles_.py index 7f1796b..c298df2 100644 --- a/lib_/_conffiles_.py +++ b/lib_/_conffiles_.py @@ -40,10 +40,10 @@ def copy(self): """Return a copy of self""" copy = Conffiles(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, Conffiles) and self.name == other.name - + # functions def execute__conffiles_access_data(self, context: Context): """Returns the asked data. RTFileNotFoundError if file not found, or None if not_found_ok=True""" @@ -56,7 +56,7 @@ def execute__conffiles_access_data(self, context: Context): file_name.pos_start, file_name.pos_end, "first", "_conffiles.access_data", "str", file_name, context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_access_data" )) - + if file_name.value == "please give me a syntax warning": eval("1 is 1") # easter egg lol @@ -67,7 +67,7 @@ def execute__conffiles_access_data(self, context: Context): not_found_ok.pos_start, not_found_ok.pos_end, "second", "_conffiles.access_data", "int", not_found_ok, context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_access_data" )) - + data = src.conffiles.access_data(file_name.value) if data is None: if not_found_ok.is_true(): @@ -76,7 +76,7 @@ def execute__conffiles_access_data(self, context: Context): file_name.pos_start, file_name.pos_end, f"config file not found: {file_name}.", context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_access_data", custom=True )) - + return RTResult().success(String(data, self.pos_start, self.pos_end).set_context(context)) functions["access_data"] = { @@ -101,7 +101,7 @@ def execute__conffiles_write_data(self, context: Context): file_name.pos_start, file_name.pos_end, "first", "_conffiles.write_data", "str", file_name, context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_write_data" )) - + data_to_write = nice_str_from_idk(data).value if name_reserved_ok is None: @@ -113,7 +113,7 @@ def execute__conffiles_write_data(self, context: Context): name_reserved_ok.pos_start, name_reserved_ok.pos_end, "second", "_conffiles.write_data", "int", name_reserved_ok, context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_write_data" )) - + errmsg = src.conffiles.write_data(file_name.value, data_to_write, silent=True, return_error_messages=True) if errmsg is not None: @@ -132,7 +132,7 @@ def execute__conffiles_write_data(self, context: Context): errmsg, context, origin_file="lib_._conffiles_.Conffiles.execute__conffiles_write_data" )) - + return RTResult().success(NoneValue(self.pos_start, self.pos_end, False).set_context(context)) functions["write_data"] = { diff --git a/lib_/lorem.noug b/lib_/lorem.noug index 1804417..c684530 100644 --- a/lib_/lorem.noug +++ b/lib_/lorem.noug @@ -26,11 +26,11 @@ def ipsum(paragraphs) var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " var last_paragraph_first_sentence = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." var last_sentence = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." - + for i = 0 to paragraphs then var paragraph = "" var sentence = "" - + var sentences = random.randint(5, 10) for j = 0 to sentences then if j == 0 and i != 0 then @@ -40,17 +40,17 @@ def ipsum(paragraphs) do var sentence = random.choice(lorem_sentences)\ then loop while sentence == last_sentence end - + var last_sentence = sentence if i != 0 and j == 0 then var last_paragraph_first_sentence = sentence - + var paragraph += sentence + if j != sentences-1 then ' ' else '' end - + var text += paragraph if i != paragraphs-1 then var text += "\n\n" end - + return text end diff --git a/lib_/math_.py b/lib_/math_.py index 0f33987..89f2f66 100644 --- a/lib_/math_.py +++ b/lib_/math_.py @@ -536,7 +536,7 @@ def execute_math_factorial(self, exec_context: Context): value.pos_start, value.pos_end, "first", "math.factorial", "non-negative integer (int)", value, exec_context, "lib_.math_.Math.execute_math_factorial" )) - + if value.value < 0: return RTResult().failure(RunTimeError( value.pos_start, value.pos_end, diff --git a/lib_/random_.py b/lib_/random_.py index b8f54f6..6066422 100644 --- a/lib_/random_.py +++ b/lib_/random_.py @@ -33,7 +33,7 @@ def copy(self): """Return a copy of self""" copy = Random(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, Random) and self.name == other.name @@ -138,13 +138,13 @@ def execute_random_shuffle(self, exec_ctx: Context): list_.pos_start, list_.pos_end, "first", "random.shuffle", "list", list_, exec_ctx, "lib_.random_.Random.execute_random_shuffle" )) - + py_list = list_.elements.copy() random.shuffle(py_list) list_.elements = py_list return RTResult().success(list_) - + functions["shuffle"] = { "function": execute_random_shuffle, "param_names": ["list_"], @@ -153,7 +153,7 @@ def execute_random_shuffle(self, exec_ctx: Context): "run_noug_dir": False, "noug_dir": False } - + def execute_random_seed(self, exec_ctx: Context): """Set the seed to generate pseudo-random numbers.""" # Params: @@ -168,7 +168,7 @@ def execute_random_seed(self, exec_ctx: Context): )) random.seed(seed.value) return RTResult().success(NoneValue(self.pos_start, self.pos_end, False)) - + functions["seed"] = { "function": execute_random_seed, "param_names": ["seed"], diff --git a/lib_/statistics_.py b/lib_/statistics_.py index 729a04a..b145abd 100644 --- a/lib_/statistics_.py +++ b/lib_/statistics_.py @@ -41,7 +41,7 @@ def copy(self): """Return a copy of self""" copy = Statistics(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, Statistics) and self.name == other.name @@ -460,7 +460,7 @@ def execute_statistics_quantiles(self, exec_ctx: Context): "run_noug_dir": False, "noug_dir": False } - + def execute_statistics_scope(self, exec_ctx: Context): """Returns the scope of a list, i.e. the difference between the max and the min value.""" # Params: diff --git a/lib_/time_.py b/lib_/time_.py index 66679f5..1a73b9c 100644 --- a/lib_/time_.py +++ b/lib_/time_.py @@ -36,7 +36,7 @@ def copy(self): """Return a copy of self""" copy = Time(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, Time) and self.name == other.name diff --git a/lib_/unicodedata_.py b/lib_/unicodedata_.py index 7258408..6e27e7c 100644 --- a/lib_/unicodedata_.py +++ b/lib_/unicodedata_.py @@ -34,7 +34,7 @@ def copy(self): """Return a copy of self""" copy = UnicodeData(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, UnicodeData) and self.name == other.name @@ -311,7 +311,7 @@ def execute_unicodedata_normalize(self, exec_ctx: Context): form.value, uni_str.value # type: ignore ), self.pos_start, self.pos_end ) - ) + ) functions["normalize"] = { "function": execute_unicodedata_normalize, diff --git a/lib_/webbrowser_.py b/lib_/webbrowser_.py index 0e645c5..e1b63d6 100644 --- a/lib_/webbrowser_.py +++ b/lib_/webbrowser_.py @@ -45,10 +45,10 @@ def copy(self): """Return a copy of self""" copy = WebBrowser(self.name) return self.set_context_and_pos_to_a_copy(copy) - + def is_eq(self, other: Value): return isinstance(other, WebBrowser) and self.name == other.name - + # functions def open(self, context: Context): """ @@ -70,7 +70,7 @@ def open(self, context: Context): url.pos_start, url.pos_end, "first", "webbrowser.open", "str", url, context, "lib_.webbrowser_.WebBrowser.open" )) - + if new is None: new = Number(0, url.pos_end, self.pos_end).set_context(context) if not (isinstance(new, Number) and isinstance(new.value, int)): @@ -83,10 +83,10 @@ def open(self, context: Context): new.pos_start, new.pos_end, "the 'new' argument should either be 0 (same window), 1 (new window), or 2 (new tab)", context, origin_file="lib_.webbrowser_.WebBrowser.open" )) - + if autoraise is None: autoraise = Number(True, self.pos_start, self.pos_end).set_context(context) - + try: webbrowser.open(url.value, new.value, autoraise.is_true()) except webbrowser.Error as e: diff --git a/src/conffiles.py b/src/conffiles.py index 4f069be..21b467a 100644 --- a/src/conffiles.py +++ b/src/conffiles.py @@ -51,14 +51,14 @@ def _write_readme(readme_file: str, version_guide_file: str, version: str, versi with open(readme_file, "w+", encoding="UTF-8") as readme: if readme.readlines() != README_TEXT: readme.writelines(README_TEXT) - - + + if os.path.isfile(version_guide_file): with open(version_guide_file, "r+", encoding="UTF-8") as versions_f: versions = versions_f.readlines() else: versions = [] - + if f"Version {version} has an id of {version_id}.\n" not in versions: with open(version_guide_file, "a+", encoding="UTF-8") as versions_f_ap: versions_f_ap.write(f"Version {version} has an id of {version_id}.\n") @@ -89,7 +89,7 @@ def _determine_config_directory(): version, version_id = src.noug_version.VERSION, src.noug_version.VERSION_ID _write_readme(root_config_directory + "/" + "README.md", root_config_directory + "/" + "version_guide.txt", version, str(version_id)) - + version_directory = os.path.abspath(root_config_directory + "/" + str(version_id) + "/") if not os.path.isdir(version_directory): os.mkdir(version_directory) @@ -150,7 +150,7 @@ def _find_files_in_legacy_directories(): print_context = print_context_f.read() else: print_context = "0" - + if debug.endswith("\n"): debug = debug[:-1] if print_context.endswith("\n"): @@ -185,7 +185,7 @@ def create_config_files(): # checks if the config path is empty (create or copy config files) if len(os.listdir(CONFIG_DIRECTORY)) == 0: _create_or_copy_files() - + define_expected_type("debug", "int") define_expected_type("print_context", "int") define_expected_type("print_time", "int") diff --git a/src/errors/errors.py b/src/errors/errors.py index cb36c83..f7bca1e 100644 --- a/src/errors/errors.py +++ b/src/errors/errors.py @@ -80,7 +80,7 @@ def as_string(self): result += '\t' + line + '\n ' result += f'{self.error_name}: {self.details}' if self.details != '' else f'{self.error_name}' return result - + def set_pos(self, pos_start: Position, pos_end: Position): self.pos_start = pos_start self.pos_end = pos_end @@ -168,7 +168,7 @@ def generate_traceback(self): lines_to_append.append((line_to_append, 1)) pos = ctx.entry_pos ctx = ctx.parent - + for line, count in lines_to_append: if count <= 5: for _ in range(count): @@ -180,7 +180,7 @@ def generate_traceback(self): return f"(from {self.origin_file})\nTraceback (most recent call last):\n" + result else: return "Traceback (most recent call last):\n" + result - + class RTIndexError(RunTimeError): """Index error (like '[1, 2](2)')""" diff --git a/src/lexer/lexer.py b/src/lexer/lexer.py index e99fd5a..e72fb6a 100644 --- a/src/lexer/lexer.py +++ b/src/lexer/lexer.py @@ -64,7 +64,7 @@ def next_char(self, n_next_chars: int = 1): chars_to_return = next_char else: chars_to_return = "" - + for _ in range(n_next_chars-1): new_pos.advance(self.get_char(new_pos)) next_char = self.get_char(new_pos) @@ -75,7 +75,7 @@ def next_char(self, n_next_chars: int = 1): # get the next char in the code (or None if this is EOF (end of file)) next_char = self.get_char(new_pos) return next_char - + def is_empty_file(self, tokens: list[Token]): """Returns if the given list of tokens corresponds to an empty file or not.""" if len(tokens) == 0: @@ -337,7 +337,7 @@ def make_meta(self, is_empty_file: bool, dont_panic_on_errors: bool = False) -> "src.lexer.lexer.Lexer.make_tokens" ) current_char = self.advance() - + meta_name = "" while current_char is not None and current_char in LETTERS: meta_name += current_char @@ -349,7 +349,7 @@ def make_meta(self, is_empty_file: bool, dont_panic_on_errors: bool = False) -> while current_char is not None and current_char in LETTERS: meta_argument += current_char current_char = self.advance() - + if current_char is not None and current_char in " \N{NBSP}\N{NNBSP}\t": current_char = self.advance() diff --git a/src/lexer/position.py b/src/lexer/position.py index ad08bb3..27fe1d5 100644 --- a/src/lexer/position.py +++ b/src/lexer/position.py @@ -37,7 +37,7 @@ def advance(self, current_char: str | None = None): self.colon = 0 return self - + def set_file_name(self, new_file_name: str): self.file_name = new_file_name return self diff --git a/src/lexer/token.py b/src/lexer/token.py index 01c1117..4b58947 100644 --- a/src/lexer/token.py +++ b/src/lexer/token.py @@ -42,7 +42,7 @@ def __repr__(self) -> str: def __str__(self): return repr(self) - + def __eq__(self, other: object): if not isinstance(other, Token): return False diff --git a/src/lexer/token_types.py b/src/lexer/token_types.py index 89b812f..e6ee6bd 100644 --- a/src/lexer/token_types.py +++ b/src/lexer/token_types.py @@ -14,7 +14,7 @@ # dict of all the token types TT = { "NEWLINE": 'new line', # new line - + "INT": 'int', # integer, corresponds to python int "FLOAT": 'float', # float number, corresponds to python float "STRING": 'str', # string type, corresponds to python str @@ -32,10 +32,10 @@ "POW": '^', # ^ "PERC": '%', # % "FLOORDIV": '//', # // - + "TO": '>>', # >> "TO_AND_OVERWRITE": '!>>', # !>> - + "EQ": '=', # = "PLUSEQ": '+=', # += "INCREMENT": '++', # ++ @@ -57,32 +57,32 @@ "GTEEQ": ">==", # >== "LTEQ": "<<=", # <<= "GTEQ": ">>=", # >>= - + "BITWISEOR": '|', # | "LEGACYABS": 'legacy absolute value', # | (legacy absolute value) "BITWISEAND": '&', # & "BITWISEXOR": '^^', # ^^ "BITWISENOT": '~', # ~ - + "EE": '==', # == "NE": '!=', # != "LT": '<', # < "GT": '>', # > "LTE": '<=', # <= "GTE": '>=', # >= - + "RPAREN": ')', # ) "LPAREN": '(', # ( "RSQUARE": ']', # ] "LSQUARE": '[', # [ - + "COMMA": ',', # , "COLON": ':', # : "ARROW": '->', # -> "INTERROGATIVE_PNT": '?', # ? "DOLLAR": "$", # $ - + "EOF": 'end of file', # end of file } diff --git a/src/nougaro.py b/src/nougaro.py index f9ec69a..7d3fbc4 100644 --- a/src/nougaro.py +++ b/src/nougaro.py @@ -102,7 +102,7 @@ def run( # we make tokens with the Lexer if text is None: return NoneValue(DEFAULT_POSITION.copy(), DEFAULT_POSITION.copy(), False), None, lexer_metas - + # Skip the NOUGAROIGNORE comments ############### lines = text.split("\n") new_lines: list[str] = [] diff --git a/src/parser/nodes.py b/src/parser/nodes.py index 10779ad..6518c54 100644 --- a/src/parser/nodes.py +++ b/src/parser/nodes.py @@ -26,7 +26,7 @@ class Node: def __eq__(self, other: object) -> bool: return False - + def __ne__(self, other: object) -> bool: return not self == other @@ -41,7 +41,7 @@ def __init__(self, token: _Token): def __repr__(self): return f'num:{self.token}' - + def __eq__(self, other: object): if not isinstance(other, NumberNode): return False @@ -79,7 +79,7 @@ def __init__(self, token: _Token): def __repr__(self): return f'string_node:{self.token}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, StringNode): return False @@ -97,7 +97,7 @@ def __init__(self, element_nodes: list[tuple[Node, bool]], pos_start: _Position, def __repr__(self): return f'list:{str(self.element_nodes)}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, ListNode): return False @@ -153,7 +153,7 @@ def __init__(self, var_name_tokens_list: list[_Token | Node], attr: bool = False def __repr__(self): return f'var_access:{self.var_name_tokens_list}' + ('(is attr in var assign)' if self.attr else '') - + def __eq__(self, other: object) -> bool: if not isinstance(other, VarAccessNode): return False @@ -171,7 +171,7 @@ def __init__(self, var_name_token: _Token): def __repr__(self): return f'var_delete:{self.var_name_token}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, VarDeleteNode): return False @@ -234,7 +234,7 @@ def __init__(self, nodes_and_tokens_list: list[Node | _Token | list[Node]]): def __repr__(self): return f'bin_op_comp:({", ".join([str(x) for x in self.nodes_and_tokens_list])})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, BinOpCompNode): return False @@ -262,14 +262,14 @@ def __init__(self, op_token: _Token, node: Node | list[Node]): def __repr__(self): return f'unary_op:({self.op_token}, {self.node})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, UnaryOpNode): return False if self.attr != other.attr: return False return self.op_token == other.op_token and self.node == other.node - + class AbsNode(Node): """Node for the legacy absolute value syntax (|-12|)""" @@ -348,7 +348,7 @@ def __init__(self, assertion: Node, pos_start: _Position, pos_end: _Position, er def __repr__(self): return f'assert:({self.assertion}, {self.errmsg})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, AssertNode): return False @@ -391,7 +391,7 @@ def __repr__(self): label = f":{self.label}" if self.label is not None else "" return f"for{label} {self.var_name_token} = {self.start_value_node} to {self.end_value_node} step " \ f"{self.step_value_node} then {self.body_node}" - + def __eq__(self, other: object) -> bool: if not isinstance(other, ForNode): return False @@ -431,7 +431,7 @@ def __init__(self, var_name_token: _Token, body_node: Node, list_node: Node | Li def __repr__(self): label = f":{self.label}" if self.label is not None else "" return f"for{label} {self.var_name_token} in {self.list_node} then {self.body_node}" - + def __eq__(self, other: object) -> bool: if not isinstance(other, ForNodeList): return False @@ -462,7 +462,7 @@ def __init__(self, condition_node: Node, body_node: Node, label: str | None = No def __repr__(self): label = f":{self.label}" if self.label is not None else "" return f'while{label} {self.condition_node} then {self.body_node}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, WhileNode): return False @@ -492,7 +492,7 @@ def __init__(self, body_node: Node, condition_node: Node, label: str | None = No def __repr__(self): label = f":{self.label}" if self.label is not None else "" return f"do{label} {self.body_node} then loop while {self.condition_node}" - + def __eq__(self, other: object) -> bool: if not isinstance(other, DoWhileNode): return False @@ -550,7 +550,7 @@ def __repr__(self): if self.node_to_return is not None: return f"{repr_} and return {self.node_to_return}" return repr_ - + def __eq__(self, other: object) -> bool: if not isinstance(other, BreakNode): return False @@ -611,7 +611,7 @@ def __init__(self, var_name_token: _Token | None, param_names_tokens: list[_Toke def __repr__(self): return f'def:{self.var_name_token}({self.param_names_tokens}, {self.optional_params})->{self.body_node}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, FuncDefNode): return False @@ -650,7 +650,7 @@ def __repr__(self): return f'class:{self.var_name_token}({self.parent_var_name_token})->{self.body_node}' else: return f'class:{self.var_name_token}->{self.body_node}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, ClassNode): return False @@ -681,10 +681,10 @@ def __init__( self.pos_start = self.node_to_call.pos_start self.pos_end = pos_end - + def __repr__(self): return f'call:{self.node_to_call}({self.arg_nodes})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, CallNode): return False @@ -735,7 +735,7 @@ def __repr__(self): if self.as_identifier is None: return f"import:{'.'.join(names)}" return f'import:{".".join(names)}:as:{self.as_identifier}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, ImportNode): return False @@ -761,7 +761,7 @@ def __repr__(self): return f"export:{self.expr_or_identifier}" else: return f"export:{self.expr_or_identifier}:as:{self.as_identifier}" - + def __eq__(self, other: object) -> bool: if not isinstance(other, ExportNode): return False @@ -806,7 +806,7 @@ def __init__( def __repr__(self): return f'write:({self.expr_to_write}{self.to_token.type}{self.file_name_expr} at line {self.line_number})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, WriteNode): return False @@ -851,7 +851,7 @@ def __init__(self, file_name_expr: Node, identifier: _Token | None, line_number: def __repr__(self): return f'read:({self.file_name_expr}>>{self.identifier} at line {self.line_number})' - + def __eq__(self, other: object) -> bool: if not isinstance(other, ReadNode): return False @@ -874,14 +874,14 @@ def __init__(self, identifier: _Token, pos_start: _Position, pos_end: _Position) def __repr__(self): return f'${self.identifier}' - + def __eq__(self, other: object) -> bool: if not isinstance(other, DollarPrintNode): return False if self.attr != other.attr: return False return self.identifier == other.identifier - + class DefaultNode(Node): """ node""" @@ -891,7 +891,7 @@ def __init__(self, pos_start: _Position, pos_end: _Position): def __repr__(self): return "" - + def __eq__(self, other: object) -> bool: if not isinstance(other, DefaultNode): return False @@ -905,6 +905,6 @@ class NoNode(Node): """If the file to execute is empty or filled by back lines, this node is the only node of the node list.""" def __repr__(self): return "NoNode" - + def __eq__(self, other: object) -> bool: return isinstance(other, NoNode) and self.attr == other.attr diff --git a/src/parser/parser.py b/src/parser/parser.py index 0b96fb5..2b5dd2a 100644 --- a/src/parser/parser.py +++ b/src/parser/parser.py @@ -217,7 +217,7 @@ def statements(self, stop: list[tuple[Any, str] | str] | None = None) -> ParseRe return result assert statement is not None assert not isinstance(statement, list) - + statements.append((statement, False)) # we append the statement to our list of there is no error # (NEWLINE+ statement)* @@ -286,7 +286,7 @@ def statements(self, stop: list[tuple[Any, str] | str] | None = None) -> ParseRe return result assert statement is not None assert not isinstance(statement, list) - + statements.append((statement, False)) return result.success(ListNode( # we put all the nodes parsed here into a ListNode @@ -323,7 +323,7 @@ def statement(self) -> ParseResult: # only one statement self.reverse(result.to_reverse_count) # assert expr is not None assert not isinstance(expr, list) - + return result.success(ReturnNode(expr, pos_start, self.current_token.pos_start.copy())) # KEYWORD:IMPORT IDENTIFIER @@ -456,7 +456,7 @@ def statement(self) -> ParseResult: # only one statement return result expr_to_return = result.register(self.expr()) if result.error is not None: - return result + return result return result.success( BreakNode(pos_start, self.current_token.pos_start.copy(), expr_to_return, label) @@ -518,7 +518,7 @@ def expr(self) -> ParseResult: )) # comp_expr ((KEYWORD:AND|KEYWORD:OR|KEYWORD:XOR|BITWISEAND|BITWISEOR|BITWISEXOR) comp_expr)* - node = result.register(self.bin_op(self.comp_expr, + node = result.register(self.bin_op(self.comp_expr, ( (TT["KEYWORD"], "and"), (TT["KEYWORD"], "or"), @@ -634,7 +634,7 @@ def read_expr(self, pos_start: Position) -> ParseResult: ) if result.error is not None: return result - + identifier = self.current_token result.register_advancement() self.advance() @@ -678,7 +678,7 @@ def assert_expr(self, pos_start: Position) -> ParseResult: errmsg = result.register(self.expr()) if result.error is not None: return result - + assert not isinstance(assertion, list) assert not isinstance(errmsg, list) @@ -702,7 +702,7 @@ def var_assign(self) -> ParseResult: result = self.check_for_and_advance( result, "expected 'var' keyboard.", "KEYWORD", "var", "var_assign" ) - + if result.error is not None: return result all_names_list: list[list[Node | Token]] = [] @@ -850,7 +850,7 @@ def assign_identifier(self) -> tuple[list[Node | Token], None] | tuple[None, Err return None, result.error # type: ignore assert expr_node is not None assert not isinstance(expr_node, list) - + arg_nodes.append((expr_node, mul)) cur_tok = self.current_token @@ -1002,7 +1002,7 @@ def power(self) -> ParseResult: return result assert value is not None assert not isinstance(value, list) - + values_list: list[Node] = [value] assert self.current_token is not None @@ -1014,7 +1014,7 @@ def power(self) -> ParseResult: return result assert value is not None assert not isinstance(value, list) - + values_list.append(value) return self.bin_op(values_list, (TT["POW"],), self.factor) # do not remove the comma after 'TT["POW"]' !! @@ -1068,7 +1068,7 @@ def call(self) -> ParseResult: # we advance result.register_advancement() self.advance() - + # expr expr_ = result.register(self.expr()) if result.error is not None: @@ -1102,7 +1102,7 @@ def call(self) -> ParseResult: assert expr_ is not None assert not isinstance(expr_, list) expr_and_mul = (expr_, mul) - + arg_nodes.append(expr_and_mul) cur_tok = self.current_token @@ -1118,7 +1118,7 @@ def call(self) -> ParseResult: if result.error is not None: return result assert not isinstance(call_node, list) - + call_node = CallNode(call_node, arg_nodes, pos_end) return result.success(call_node) @@ -1257,7 +1257,7 @@ def string_expr(self, token: Token) -> ParseResult: to_return_tok.value = to_return_str return result.success(StringNode(to_return_tok)) - + def identifier_and_interrogative_point(self, token: Token) -> ParseResult: result = ParseResult() # the identifier is in the token in 'token' @@ -1285,7 +1285,7 @@ def identifier_and_interrogative_point(self, token: Token) -> ParseResult: assert value is not None # append the token to our list assert not isinstance(value, list) - + choices.append(value) break # the expr is the final value we want to parse # E.g.: `identifier ? identifier ? expr ? whatever` : we don't want the `? whatever` @@ -1325,7 +1325,7 @@ def paren_expr(self) -> ParseResult: return result return result.success(expr) - + def dollar_print_expr(self, token: Token) -> ParseResult: result = ParseResult() result = self.advance_and_check_for(result, "expected identifier or nothing after '$'", @@ -1358,7 +1358,7 @@ def list_expr(self) -> ParseResult: result = self.check_for_and_advance(result, "expected '['.", "LSQUARE", None, "list_expr") if result.error is not None: return result - + cur_tok = self.current_token while cur_tok is not None and self.current_token.type == TT["NEWLINE"]: result.register_advancement() @@ -1371,7 +1371,7 @@ def list_expr(self) -> ParseResult: return result.success(ListNode( element_nodes, pos_start, pos_end )) - + # there are elements # MUL? expr (COMMA NEWLINE?* MUL? expr)?* if self.current_token.type == TT["MUL"]: # MUL? @@ -1387,7 +1387,7 @@ def list_expr(self) -> ParseResult: assert expr_ is not None assert not isinstance(expr_, list) expr_and_mul = (expr_, mul) - + element_nodes.append(expr_and_mul) while self.current_token.type == TT["COMMA"]: # (COMMA NEWLINE?* MUL? expr)?* @@ -1414,7 +1414,7 @@ def list_expr(self) -> ParseResult: assert expr_ is not None assert not isinstance(expr_, list) expr_and_mul = (expr_, mul) - + element_nodes.append(expr_and_mul) cur_tok = self.current_token @@ -1430,7 +1430,7 @@ def list_expr(self) -> ParseResult: return result return result.success(ListNode( element_nodes, pos_start, pos_end - )) + )) def if_expr(self) -> ParseResult: """ @@ -1561,7 +1561,7 @@ def if_expr_cases( assert statements is not None assert not isinstance(condition, list) assert not isinstance(statements, list) - + cases.append((condition, statements)) if self.current_token.matches(TT["KEYWORD"], 'end'): @@ -1752,7 +1752,7 @@ def for_expr(self) -> ParseResult: else: # statement body = result.register(self.statement()) - + if result.error is not None: return result assert body is not None @@ -1760,7 +1760,7 @@ def for_expr(self) -> ParseResult: assert not isinstance(end_value, list) assert not isinstance(step_value, list) assert not isinstance(body, list) - + return result.success(ForNode(var_name, start_value, end_value, step_value, body, label)) def while_expr(self) -> ParseResult: @@ -1823,7 +1823,7 @@ def while_expr(self) -> ParseResult: else: # statement body = result.register(self.statement()) - + if result.error is not None: return result assert body is not None @@ -1843,7 +1843,7 @@ def do_expr(self) -> ParseResult: result = self.check_for_and_advance(result, "expected 'do'.", "KEYWORD", "do", "do_expr") if result.error is not None: return result - + label = None if self.current_token.type == TT["COLON"]: result = self.advance_and_check_for( @@ -1961,7 +1961,7 @@ def func_def(self) -> ParseResult: else: var_name_token = None errmsg = "expeted identifier or '('." - + # LPAREN result = self.check_for_and_advance(result, errmsg, "LPAREN", None, "func_def") @@ -2006,7 +2006,7 @@ def func_def(self) -> ParseResult: param_names_tokens.append(self.current_token) result.register_advancement() self.advance() - + cur_tok = self.current_token while cur_tok is not None and cur_tok.type == TT["NEWLINE"]: result.register_advancement() @@ -2031,7 +2031,7 @@ def func_def(self) -> ParseResult: result = self.check_for( result, "expected identifier after '('", "IDENTIFIER", origin_file="func_def" ) - + identifier = self.current_token result = self.advance_check_for_and_advance( result, "expected '=' after identifier", "EQ", origin_file="func_def" @@ -2067,7 +2067,7 @@ def func_def(self) -> ParseResult: self.current_token.pos_start, self.current_token.pos_end, error_msg, "src.parser.parser.Parser.func_def" )) - + identifier = self.current_token result = self.advance_check_for_and_advance( result, "expected '=' after identifier", "EQ", origin_file="func_def" @@ -2255,7 +2255,7 @@ def bin_op( else: left = func_a # func_a is a list: this is the left operand assert func_b is not None - + assert self.current_token is not None if left_has_priority: diff --git a/src/runtime/context.py b/src/runtime/context.py index 4e9ddd7..5280746 100644 --- a/src/runtime/context.py +++ b/src/runtime/context.py @@ -24,7 +24,7 @@ class Context: def __init__(self, display_name: str | None, entry_pos: Position, parent: Self | None = None, value_im_attribute_of: str | None = None): """Note on value_im_attribute_of: - + In commit a17aa2bc was introduced a bug where `(1).b` returned: > `AttributeError: attribute of 1 has no attribute 'b'.` diff --git a/src/runtime/interpreter.py b/src/runtime/interpreter.py index 68512b6..663817a 100644 --- a/src/runtime/interpreter.py +++ b/src/runtime/interpreter.py @@ -55,7 +55,7 @@ def __init__(self, run: RunFunction, noug_dir_: str, args: list[String], work_di self._methods = None self.init_methods() assert self._methods is not None - + def init_methods(self): self._methods = { "AbsNode": self.visit_AbsNode, @@ -427,7 +427,7 @@ def visit_BinOpNode(self, node: BinOpNode, ctx: Context, methods_instead_of_func if error is not None: # there is an error return res.failure(error) - + assert result is not None return res.success(result.set_pos(node.pos_start, node.pos_end)) @@ -542,7 +542,7 @@ def visit_UnaryOpNode(self, node: UnaryOpNode, ctx: Context, methods_instead_of_ if error is not None: # there is an error return result.failure(error) - + assert value is not None return result.success(value.set_pos(node.pos_start, node.pos_end)) @@ -638,7 +638,7 @@ def visit_VarAssignNode(self, node: VarAssignNode, ctx: Context, methods_instead "excepted identifier.", ctx, origin_file=f"{_ORIGIN_FILE}.visit_VarAssignNode" )) - + assert isinstance(var_name[0], Token) assert isinstance(var_name[0].value, str) final_var_name: str = var_name[0].value @@ -671,7 +671,7 @@ def visit_VarAssignNode(self, node: VarAssignNode, ctx: Context, methods_instead value = result.register(self.visit(var_name[0], ctx, methods_instead_of_funcs)) if result.should_return(): return result - + assert isinstance(value, Value) for node_or_tok in var_name[1:-1]: @@ -866,7 +866,7 @@ def visit_AssertNode(self, node: AssertNode, ctx: Context, methods_instead_of_fu if result.should_return(): # check for errors return result assert assertion is not None - + errmsg = result.register(self.visit(node.errmsg, ctx, methods_instead_of_funcs)) # we get the error message if result.should_return(): # check for errors return result @@ -1054,7 +1054,7 @@ def visit_ForNodeList(self, node: ForNodeList, ctx: Context, methods_instead_of_ value = NoneValue(node.body_node.pos_start, node.body_node.pos_end, False) elements.append(value) - + if outer_loop_should_continue: assert result.break_or_continue_pos is not None pos_start, pos_end = result.break_or_continue_pos @@ -1103,7 +1103,7 @@ def visit_WhileNode(self, node: WhileNode, ctx: Context, methods_instead_of_func if result.should_return(True): # error or 'return' statement return result - + if value is None: value = NoneValue(node.body_node.pos_start, node.body_node.pos_end, False) @@ -1157,7 +1157,7 @@ def visit_DoWhileNode(self, node: DoWhileNode, ctx: Context, methods_instead_of_ if result.should_return(True): # error or 'return' statement return result - + if value is None: value = NoneValue(node.body_node.pos_start, node.body_node.pos_end, False) @@ -1571,7 +1571,7 @@ def _init_constructor(self, constructor: Constructor, outer_context: Context, re obj_attrs[key] = value.copy() object_ = Object(obj_attrs, constructor, constructor.pos_start, constructor.pos_end) object_.type_ = constructor.name - + if call_with_module_context: assert constructor.module_context is not None inner_ctx = Context(constructor.name, constructor.pos_start, constructor.module_context) diff --git a/src/runtime/symbol_table.py b/src/runtime/symbol_table.py index 558e8f7..69210db 100644 --- a/src/runtime/symbol_table.py +++ b/src/runtime/symbol_table.py @@ -65,12 +65,12 @@ def exists(self, name: str, look_in_parent: bool = False) -> bool: def set_parent(self, parent: Self): self.parent = parent return self - + def __eq__(self, other: object): if not isinstance(other, SymbolTable): return False return self.symbols == other.symbols - + def __ne__(self, other: object): return not self == other diff --git a/src/runtime/values/basevalues/basevalues.py b/src/runtime/values/basevalues/basevalues.py index b293743..6e2c701 100644 --- a/src/runtime/values/basevalues/basevalues.py +++ b/src/runtime/values/basevalues/basevalues.py @@ -204,7 +204,7 @@ def __repr__(self): return str(self.value) except ValueError: return "(this number can not be displayed)" - + def to_python_str(self) -> str: """Returns self.value, as a python str""" return self.__repr__() @@ -481,7 +481,7 @@ def __init__(self, elements: list[Value], pos_start: _Position, pos_end: _Positi def __repr__(self): return f'[{", ".join([x.__str__() for x in self.elements])}]' - + def to_python_str(self) -> str: return self.__repr__() @@ -624,7 +624,7 @@ def is_in(self, other: Value): ).set_context(self.context), None else: return None, self.can_not_be_in(other) - + def is_true(self): return bool(len(self.elements)) @@ -657,7 +657,7 @@ def __init__(self, name: str, functions_and_constants: dict[str, Value], pos_sta def __repr__(self): return f"" - + def to_python_str(self) -> str: return self.__repr__() @@ -721,13 +721,13 @@ def __init__(self, name: str | None, symbol_table: SymbolTable, attributes: dict def __repr__(self): return f"" - + def to_python_str(self) -> str: return self.__repr__() def is_true(self): return False - + def is_eq(self, other: Value): if not isinstance(other, Constructor): return False @@ -798,10 +798,10 @@ def __init__(self, attributes: dict[str, Value], constructor: Constructor, def __repr__(self): return f"<{self.type_} object>" - + def to_python_str(self) -> str: return self.__repr__() - + def is_eq(self, other: Value): if not isinstance(other, Object): return False @@ -869,7 +869,7 @@ def __repr__(self): def __str__(self): return 'None' - + def to_python_str(self) -> str: return self.__repr__() @@ -954,7 +954,7 @@ def __repr__(self): def __str__(self): return '' - + def to_python_str(self) -> str: return self.__repr__() diff --git a/src/runtime/values/basevalues/value.py b/src/runtime/values/basevalues/value.py index a861b69..b4db5a8 100644 --- a/src/runtime/values/basevalues/value.py +++ b/src/runtime/values/basevalues/value.py @@ -40,7 +40,7 @@ def __init__(self, pos_start: Position, pos_end: Position): def __repr__(self) -> str: return "BaseValue" - + def to_python_str(self) -> str: return "BaseValue" diff --git a/src/runtime/values/functions/base_builtin_func.py b/src/runtime/values/functions/base_builtin_func.py index 7c74b3e..aebea6d 100644 --- a/src/runtime/values/functions/base_builtin_func.py +++ b/src/runtime/values/functions/base_builtin_func.py @@ -31,10 +31,10 @@ def __repr__(self): def is_eq(self, other: Value): return isinstance(other, BaseBuiltInFunction) and self.name == other.name - + def get_comparison_eq(self, other: Value): return Number(self.is_eq(other), self.pos_start, other.pos_end).set_context(self.context), None - + def get_comparison_ne(self, other: Value): return Number(not self.is_eq(other), self.pos_start, other.pos_end).set_context(self.context), None diff --git a/src/runtime/values/functions/base_function.py b/src/runtime/values/functions/base_function.py index 07d8ca8..0942f7a 100644 --- a/src/runtime/values/functions/base_function.py +++ b/src/runtime/values/functions/base_function.py @@ -30,13 +30,13 @@ def __init__( # (if 'name' is None, we have something like `def()->foo`) self.type_ = 'func' self.call_with_module_context: bool = call_with_module_context - + def __repr__(self) -> str: return "BaseFunction" def to_python_str(self) -> str: return repr(self) - + def to_str(self): return String(repr(self), self.pos_start, self.pos_end).set_context(self.context), None @@ -95,7 +95,7 @@ def populate_args(param_names: list[str], args: list[Value], should_respect_args_number: bool = True): # this function is not overwritten """Make the args match to the param names in the symbol table. - + Any in the args must be replaced with a DefaultValue. """ # We need the context for the symbol table :) diff --git a/src/runtime/values/functions/builtin_function.py b/src/runtime/values/functions/builtin_function.py index dea982e..01dee1a 100644 --- a/src/runtime/values/functions/builtin_function.py +++ b/src/runtime/values/functions/builtin_function.py @@ -163,7 +163,7 @@ def execute_void(self): "run_noug_dir": False, "noug_dir": False } - + def execute_print(self, exec_ctx: Context): """Print 'value'""" # Optional params: @@ -443,7 +443,7 @@ def execute_input_num(self, exec_ctx: Context): )) else: text = input() - + try: number = int(text) break @@ -454,7 +454,7 @@ def execute_input_num(self, exec_ctx: Context): except ValueError: print(f"'{text}' must be a number. Try again: ") return RTResult().success(Number(number, self.pos_start, self.pos_end)) - + builtin_functions["input_num"] = { "function": execute_input_num, "param_names": [], @@ -880,7 +880,7 @@ def execute_get(self, exec_ctx: Context): f'list index {index_.value} out of range.', exec_ctx, "src.runtime.values.functions.builtin_function.BuiltInFunction.execute_get" )) - + builtin_functions["get"] = { "function": execute_get, "param_names": ["list", "index"], @@ -986,7 +986,7 @@ def execute_max(self, exec_ctx: Context): max_ = max(list_) return RTResult().success(Number(max_, self.pos_start, self.pos_end)) - + builtin_functions["max"] = { "function": execute_max, "param_names": ["list"], @@ -1086,7 +1086,7 @@ def execute_split(self, exec_ctx: Context): final_list = List(new_list, self.pos_start, self.pos_end) return RTResult().success(final_list) - + builtin_functions["split"] = { "function": execute_split, "param_names": ["str"], @@ -1399,7 +1399,7 @@ def execute_example(self, exec_ctx: Context, run: RunFunction, noug_dir: str): return_example_value = exec_ctx.symbol_table.getf("return_example_value") if return_example_value is None: return_example_value = Number(False, self.pos_start, self.pos_end) - + if not isinstance(return_example_value, Number): return RTResult().failure(RTTypeErrorF( return_example_value.pos_start, return_example_value.pos_end, @@ -1408,7 +1408,7 @@ def execute_example(self, exec_ctx: Context, run: RunFunction, noug_dir: str): )) file_name = os.path.abspath(noug_dir + "/examples/" + example_name.value + ".noug") - + exec_ctx.symbol_table.set( "file_name", String(file_name, self.pos_start, self.pos_end) ) @@ -1699,7 +1699,7 @@ def execute___test__(self, exec_ctx: Context, run: RunFunction, noug_dir: str): if should_i_return.is_true(): return self.execute_run(exec_ctx, run, noug_dir) - + result = self.execute_run(exec_ctx, run, noug_dir) if result.error is not None: return result @@ -1876,7 +1876,7 @@ def execute_round(self, exec_ctx: Context): result = int(round(number_, n_digits.value)) else: result = round(number_, n_digits.value) - + return RTResult().success(Number(result, self.pos_start, self.pos_end)) builtin_functions["round"] = { @@ -1887,14 +1887,14 @@ def execute_round(self, exec_ctx: Context): "run_noug_dir": False, "noug_dir": False } - + def execute_sort(self, exec_ctx: Context): """Like python’s sort()""" assert exec_ctx.symbol_table is not None result = RTResult() list_ = exec_ctx.symbol_table.getf("list_") mode = exec_ctx.symbol_table.getf("mode") - + if not isinstance(list_, List): assert list_ is not None return result.failure(RTTypeErrorF( @@ -2067,7 +2067,7 @@ def execute_path_exists(self, exec_ctx: Context) -> RTResult: exec_ctx, origin_file="src.runtime.values.functions.builtin_function.BuiltInFunction.execute_path_exists" )) - + path_exists = os.path.exists(path.value) return RTResult().success(Number(path_exists, self.pos_start, self.pos_end)) diff --git a/src/runtime/values/functions/function.py b/src/runtime/values/functions/function.py index 5702d9e..4637893 100644 --- a/src/runtime/values/functions/function.py +++ b/src/runtime/values/functions/function.py @@ -47,13 +47,13 @@ def is_eq(self, other: Value): self.optional_params == other.optional_params are_nodes_eq = self.body_node == other.body_node return is_eq and are_nodes_eq - + def get_comparison_eq(self, other: Value): return Number(self.is_eq(other), self.pos_start, other.pos_end), None - + def get_comparison_ne(self, other: Value): return Number(not self.is_eq(other), self.pos_start, other.pos_end), None - + def to_python_str(self): return self.__repr__() @@ -104,7 +104,7 @@ def execute(self, args: list[Value], interpreter_: type[Interpreter], run: RunFu return_value = result.function_return_value else: return_value = NoneValue(self.pos_start, self.pos_end, False) - + if return_value is None: return_value = NoneValue(self.pos_start, self.pos_end, False) return result.success(return_value) @@ -153,7 +153,7 @@ def copy(self): copy.set_context(self.context) copy.attributes = self.attributes.copy() return copy - + def is_eq(self, other: Value): if not isinstance(other, Method): return False diff --git a/src/runtime/values/functions/sort_builtin_function.py b/src/runtime/values/functions/sort_builtin_function.py index baf0a77..1a4d341 100644 --- a/src/runtime/values/functions/sort_builtin_function.py +++ b/src/runtime/values/functions/sort_builtin_function.py @@ -69,7 +69,7 @@ def sort( comparison, error = _get_comparison_gt(list_to_sort, i) if error is not None: return result.failure(error) - + assert comparison is not None while i + 1 < len(list_to_sort) and comparison.is_true(): @@ -79,7 +79,7 @@ def sort( return result.failure(error) assert comparison is not None - sorted_ = list_to_sort + sorted_ = list_to_sort elif mode == "sleep" or mode == "sleep-verbose": # sleep sort # sleep sort was implemented by Mistera. Please refer to him if you have any questions about it, as I # completely don’t have any ideas on how tf asyncio works @@ -90,7 +90,7 @@ def sort( for i in list_to_sort: if not isinstance(i, Number) or not isinstance(i.value, int): return result.failure(RTTypeError( - i.pos_start, i.pos_end, + i.pos_start, i.pos_end, f"sleep mode: expected list of int, but found {i.type_} inside the list.", exec_ctx, origin_file="src.runtime.values.functions.builtin_function.BuiltInFunction.execute_sort"