From b1e58093e6e8d1f336ec860827da6f49ada98cc1 Mon Sep 17 00:00:00 2001 From: angelcaru Date: Fri, 31 May 2024 23:57:40 +0200 Subject: [PATCH 1/3] Explicit variable declaration Closes #154 --- core/errors.py | 5 +++- core/interpreter.py | 27 ++++++++++++++++----- core/parser.py | 40 +++++++++++++++++-------------- core/tokens.py | 3 +-- stdlib/argparser.rn | 48 +++++++++++++++++++------------------- stdlib/array.rn | 11 ++++----- stdlib/math.rn | 39 ++++++++++++++++--------------- stdlib/radiation.rn | 2 +- stdlib/string.rn | 8 +++---- stdlib/system.rn | 2 +- stdlib/universe.rn | 10 ++++---- tests/classes.rn | 11 +++++---- tests/closures.rn | 8 +++---- tests/empty-blocks.rn | 2 +- tests/files.rn | 2 +- tests/functions.rn | 2 +- tests/hashmap.rn | 8 +++---- tests/help.rn | 4 ++-- tests/in-op.rn | 10 ++++---- tests/incdec.rn | 6 ++--- tests/incdec.rn.json | 2 +- tests/json_class.rn | 8 +++---- tests/loops.rn | 6 ++--- tests/modules2.rn | 2 +- tests/pyapi_advanced.rn | 6 ++--- tests/radiation-modules.rn | 4 ++-- tests/requests-tests.rn | 16 ++++++------- tests/scope-bug.rn | 8 +++---- tests/slice-bruteforce.rn | 2 +- tests/slicings.rn | 10 ++++---- tests/string_class.rn | 18 +++++++------- tests/switch-case.rn | 4 ++-- tests/thicc-hm.rn | 2 +- 33 files changed, 178 insertions(+), 158 deletions(-) diff --git a/core/errors.py b/core/errors.py index c6798d9..423e134 100755 --- a/core/errors.py +++ b/core/errors.py @@ -129,8 +129,11 @@ def generate_radiation(self) -> str: ctx = self.context while ctx: + fn = pos.fn if pos is not None else None + ln = pos.ln + 1 if pos is not None else None + name = ctx.display_name if ctx is not None else None result = ( - f" File {Log.light_info(pos.fn)}, line {Log.light_info(str(pos.ln + 1))}, in {Log.light_info(ctx.display_name)}\n" + f" File {Log.light_info(fn)}, line {Log.light_info(str(ln))}, in {Log.light_info(name)}\n" + result ) pos = ctx.parent_entry_pos # type: ignore diff --git a/core/interpreter.py b/core/interpreter.py index 50c79f4..9db727b 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -11,19 +11,30 @@ class Interpreter: - def assign(self, *, var_name, value, context, extra_names=[], qualifier=None, pos_start, pos_end): - res = RTResult() + def assign( + self, + *, + var_name: str, + value: Value, + context: Context, + extra_names: list[Token] = [], + qualifier: Optional[Token] = None, + pos_start: Position, + pos_end: Position, + ) -> RTResult[Value]: + res = RTResult[Value]() if extra_names != []: assert qualifier is None nd = context.symbol_table.get(var_name) prev = None - if not nd: + if nd is None: return res.failure(RTError(pos_start, pos_end, f"'{var_name}' not defined", context)) for index, name_tok in enumerate(extra_names): name = name_tok.value + assert isinstance(name, str) if not isinstance(nd, Class) and not isinstance(nd, Instance): return res.failure(RTError(pos_start, pos_end, "Value must be instance of class or class", context)) @@ -31,15 +42,17 @@ def assign(self, *, var_name, value, context, extra_names=[], qualifier=None, po prev = nd nd = nd.symbol_table.symbols[name] if name in nd.symbol_table.symbols else None - if not nd and index != len(extra_names) - 1: + if nd is None and index != len(extra_names) - 1: return res.failure(RTError(pos_start, pos_end, f"'{name}' not defined", context)) + assert prev is not None + assert isinstance(name, str) res.register(prev.symbol_table.set(name, value)) if res.should_return(): return res return res.success(value) - res.register(context.symbol_table.set(var_name, value, qualifier)) + res.register(context.symbol_table.set_var(var_name, value, qualifier)) if res.should_return(): return res return res.success(value) @@ -132,9 +145,11 @@ def visit_VarAccessNode(self, node: VarAccessNode, context: Context) -> RTResult def visit_VarAssignNode(self, node: VarAssignNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() var_name = node.var_name_tok.value + assert isinstance(var_name, str) value = res.register(self.visit(node.value_node, context)) if res.should_return(): return res + assert value is not None return self.assign( var_name=var_name, @@ -247,7 +262,7 @@ def visit_ImportNode(self, node: ImportNode, context: Context) -> RTResult[Value res = RTResult[Value]() res.register( - self.assign(var_name=name, value=module, context=context, pos_start=node.pos_start, pos_end=node.pos_end) + self.assign(var_name=name, value=module, context=context, pos_start=node.pos_start, pos_end=node.pos_end, qualifier=Token(TT_KEYWORD, "const", pos_start=node.pos_start)) ) if res.should_return(): return res diff --git a/core/parser.py b/core/parser.py index 8599ace..4014ea6 100755 --- a/core/parser.py +++ b/core/parser.py @@ -292,7 +292,7 @@ def expr(self) -> ParseResult[Node]: var_assign_node = res.try_register(self.assign_expr()) if var_assign_node is not None: return res.success(var_assign_node) - elif res.error: + elif res.error is not None: return res else: self.reverse(res.to_reverse_count) @@ -316,7 +316,7 @@ def assign_expr(self) -> ParseResult[Node]: self.advance(res) qualifier = None - if self.current_tok.type == TT_KEYWORD and self.current_tok.value in ("global", "nonlocal", "const"): + if self.current_tok.type == TT_KEYWORD and self.current_tok.value in ("var", "const"): qualifier = self.current_tok self.advance(res) @@ -1682,22 +1682,27 @@ def get(self, name: str) -> Optional[Value]: return self.parent.get(name) return value - def set(self, name: str, value: Value, qualifier: Optional[Token] = None) -> RTResult[None]: - class dummy: - TT_KW = TT_KEYWORD + def set(self, name: str, value: Value) -> RTResult[None]: + if name in self.consts: + return RTResult[None]().failure( + RTError(value.pos_start, value.pos_end, f"Cannot reassign to constant {name}", value.context) + ) + self.symbols[name] = value + return RTResult[None]().success(None) + def set_var(self, name: str, value: Value, qualifier_tok: Optional[Token] = None) -> RTResult[None]: if name in self.consts: return RTResult[None]().failure( RTError(value.pos_start, value.pos_end, f"Cannot reassign to constant {name}", value.context) ) + qualifier = None if qualifier_tok is None else qualifier_tok.value + assert qualifier is None or isinstance(qualifier, str) match qualifier: case None: - self.symbols[name] = value - case Token(dummy.TT_KW, "nonlocal"): if name in self.symbols: self.symbols[name] = value - elif self.parent: - self.parent.set(name, value, qualifier) + elif self.parent is not None: + self.parent.set_var(name, value, qualifier) else: return RTResult[None]().failure( RTError( @@ -1707,21 +1712,20 @@ class dummy: value.context, ) ) - case Token(dummy.TT_KW, "global"): - if self.parent is None: - self.symbols[name] = value - else: - self.parent.set(name, value, qualifier) - case Token(dummy.TT_KW, "const"): + case "var": + if name in self.symbols: + return RTResult[None]().failure( + RTError(value.pos_start, value.pos_end, f"Cannot re-declare variable {name}", value.context) + ) + self.symbols[name] = value + case "const": self.symbols[name] = value self.consts.add(name) - case _: - assert False, "invalid qualifier" return RTResult[None]().success(None) def set_static(self, name: str, value: Value, qualifier: Optional[Token] = None) -> RTResult[None]: res = RTResult[None]() - res.register(self.set(name, value, qualifier)) + res.register(self.set_var(name, value, qualifier)) if res.should_return(): return res self.statics.add(name) diff --git a/core/tokens.py b/core/tokens.py index 2208a2e..5d89863 100755 --- a/core/tokens.py +++ b/core/tokens.py @@ -124,8 +124,6 @@ def copy(self) -> Position: "catch", "as", "in", - "nonlocal", - "global", "const", "static", "assert", @@ -135,6 +133,7 @@ def copy(self) -> Position: "fallthrough", "raise", "fallout", + "var", ] TokenValue: TypeAlias = Optional[str | int | float] diff --git a/stdlib/argparser.rn b/stdlib/argparser.rn index dabb66b..d9394d2 100644 --- a/stdlib/argparser.rn +++ b/stdlib/argparser.rn @@ -1,8 +1,8 @@ -_i = 0 -FULLNAME_INVALID = _i++ -FULLNAME_FLAG = _i++ -FULLNAME_NAMED = _i++ +var _i = 0 +const FULLNAME_INVALID = _i++ +const FULLNAME_FLAG = _i++ +const FULLNAME_NAMED = _i++ _i = 0 fun str_starts_with(s, prefix) { @@ -30,7 +30,7 @@ class Argparser { assert is_null(default_), "Required positional arguments cannot have a default value" } if is_null(conversor) { - nonlocal conversor = fun(x) -> x + conversor = fun(x) -> x } arr_append(this.pos_opts, {"name": name, "desc": desc, "default": default_, "required": required, "conversor": conversor}) return this @@ -47,7 +47,7 @@ class Argparser { fun add_named(name, desc, default_=null, conversor=null) { assert str_starts_with(name, "--"), "Named arguments must start with '--'" if is_null(conversor) { - nonlocal conversor = fun(x) -> x + conversor = fun(x) -> x } arr_append(this.named, {"name": name, "desc": desc, "default": default_, "conversor": conversor}) return this @@ -63,17 +63,17 @@ class Argparser { } fun usage(program_name) { - ret = "Usage: "+program_name+" \n" + var ret = "Usage: "+program_name+" \n" ret += "OPTIONS:\n" for opt in this.pos_opts { - nonlocal ret += " " + opt["name"] + ": " + opt["desc"] + "\n" + ret += " " + opt["name"] + ": " + opt["desc"] + "\n" } ret += "FLAGS:\n" for flag in this.flags { - nonlocal ret += " " + flag["fullname"] + ", " + flag["shortname"] + ": " + flag["desc"] + "\n" + ret += " " + flag["fullname"] + ", " + flag["shortname"] + ": " + flag["desc"] + "\n" } for named in this.named { - nonlocal ret += " " + named["name"] + " : " + named["desc"] + "\n" + ret += " " + named["name"] + " : " + named["desc"] + "\n" } return ret } @@ -109,14 +109,14 @@ class Argparser { fun parse(args=null) { if is_null(args) { - nonlocal args = argv[:] + args = argv[:] } - pos_opts = this.pos_opts - flags = this.flags + var pos_opts = this.pos_opts + var flags = this.flags - program_name = arr_pop(args, 0) - parsed = {} - required_opts = {} + var program_name = arr_pop(args, 0) + var parsed = {} + var required_opts = {} for pos_opt in pos_opts { parsed[pos_opt["name"]] = pos_opt["default"] if pos_opt["required"] { @@ -129,9 +129,9 @@ class Argparser { for named in this.named { parsed[named["name"]] = named["default"] } - pos_opts_idx = 0 + var pos_opts_idx = 0 while arr_len(args) > 0 { - arg = arr_pop(args, 0) + var arg = arr_pop(args, 0) if str_starts_with(arg, "-") { if str_starts_with(arg, "--") { switch this.fullname_type(arg) { @@ -141,8 +141,8 @@ class Argparser { if arr_len(args) == 0 { this.report_error(program_name, "missing value for flag: '"+arg+"'") } - value = arr_pop(args, 0) - conversor = this.get_named_conversor(arg) + const value = arr_pop(args, 0) + const conversor = this.get_named_conversor(arg) try { parsed[arg] = conversor(value) } catch as e { @@ -152,7 +152,7 @@ class Argparser { } } else { for letter in arg[1:] { - flag = this.flag_by_shortname(letter) + const flag = this.flag_by_shortname(letter) if is_null(flag) { this.report_error(program_name, "unknown flag: '-"+letter+"'") } else { @@ -164,15 +164,15 @@ class Argparser { if pos_opts_idx >= arr_len(pos_opts) { this.report_error(program_name, "unexpected positional argument: '" + arg + "'") } - arg_name = pos_opts[pos_opts_idx]["name"] - conversor = pos_opts[pos_opts_idx]["conversor"] + const arg_name = pos_opts[pos_opts_idx]["name"] + const conversor = pos_opts[pos_opts_idx]["conversor"] try { parsed[arg_name] = conversor(arg) } catch as e { this.report_error(program_name, "invalid value for argument: '" + arg_name + "': " + str(e)) } required_opts[arg_name] = false - nonlocal pos_opts_idx++ + pos_opts_idx++ } } for required in required_opts { diff --git a/stdlib/array.rn b/stdlib/array.rn index f032382..9719190 100644 --- a/stdlib/array.rn +++ b/stdlib/array.rn @@ -4,10 +4,10 @@ class Array { } fun map(func) { - new_elements = [] + const new_elements = [] - for i = 0 to this.__len__() { - arr_append(new_elements, func(arr_get(this.list, i))) + for elt in this.list { + arr_append(new_elements, func(elt)) } return new_elements @@ -17,10 +17,7 @@ class Array { fun pop(index) -> arr_pop(this.list, index) fun extend(list) -> arr_extend(this.list, list) fun find(index) -> arr_find(this.list, index) - fun slice(start, end) { - # These parentheses are dumb. We need to find another way. - return (this.list)[start:end] - } + fun slice(start, end) -> ((this.list)[start:end]) fun __len__() -> arr_len(this.list) fun is_empty() -> this.list == [] diff --git a/stdlib/math.rn b/stdlib/math.rn index 1cf983b..493ce31 100644 --- a/stdlib/math.rn +++ b/stdlib/math.rn @@ -1,12 +1,12 @@ # The Math class provides all types of math functionalites for radon language. -static const PI = 3.14159265358979323846 +const PI = 3.14159265358979323846 -static fun sqrt(number) -> number ^ 0.5 -static fun pow(base, power) -> base ^ power -static fun mod(a, b) -> a % b +fun sqrt(number) -> number ^ 0.5 +fun pow(base, power) -> base ^ power +fun mod(a, b) -> a % b -static fun factorial(number) { +fun factorial(number) { if number == 0 { return 1 } @@ -14,8 +14,9 @@ static fun factorial(number) { } # Same as mod, but implemented in pure radon. -static fun modulas(a, b) { - frac = a / b +fun modulas(a, b) { + const frac = a / b + var floor = 0 if frac > 0 { floor = int(frac) } else { @@ -24,46 +25,46 @@ static fun modulas(a, b) { return a - b * floor } # Same as modulas, but actually spelled correctly -modulus = modulas +const modulus = modulas # Same as pow, but implemented in pure radon. -static fun power(n, p) { - result = n +fun power(n, p) { + var result = n for i=1 to p { - result = result * n + result *= n } return result } # Sine implementation in radon. -static fun sin(n) { - n = n % (2 * this.PI) +fun sin(n) { + var n = n % (2 * this.PI) if n < 0 { n = 2 * this.PI - n } - sign = 1 + var sign = 1 if n > this.PI { n = n - this.PI sign = -1 } - result = n - coefficient = 3 + var result = n + var coefficient = 3 for i=0 to 10 { pow_val = n ^ coefficient frac = factorial(coefficient) if i % 2 == 0{ - result = result - (pow_val / frac) + result -= pow_val / frac } else { - result = result + (pow_val / frac) + result += pow_val / frac } - coefficient = coefficient + 2 + coefficient += 2 } return sign * result } diff --git a/stdlib/radiation.rn b/stdlib/radiation.rn index 53d0b08..c9dc581 100644 --- a/stdlib/radiation.rn +++ b/stdlib/radiation.rn @@ -19,7 +19,7 @@ fun LogicalError(message = null) -> message fun RuntimeError(message = null) -> message # List of all errors -errors = [ +const errors = [ ValueError, TypeError, IOError, diff --git a/stdlib/string.rn b/stdlib/string.rn index a15460a..0a6fa34 100644 --- a/stdlib/string.rn +++ b/stdlib/string.rn @@ -17,12 +17,12 @@ class String { # TODO: Need to fix fun join(separator = " ") { - result = "" + var result = "" for i = 0 to str_len(this.value) { - result = result + str_get(this.value) + result += str_get(this.value) if i < str_len(this.value) - 1 { - result = result + separator + result += separator } } return result @@ -30,7 +30,7 @@ class String { # Find a character in a string and return its index fun find(data) { - result = 0 + var result = 0 for i = 0 to str_len(this.value) { if this.value == data { diff --git a/stdlib/system.rn b/stdlib/system.rn index 2a1b918..7266024 100644 --- a/stdlib/system.rn +++ b/stdlib/system.rn @@ -1,6 +1,6 @@ class System { fun __constructor__() { - ns = {} + const ns = {} pyapi("import platform; import sys; os_name = platform.system(); platform = sys.platform", ns) this.name = ns["os_name"] this.platform = ns["platform"] diff --git a/stdlib/universe.rn b/stdlib/universe.rn index 8c37257..6b91844 100644 --- a/stdlib/universe.rn +++ b/stdlib/universe.rn @@ -1,13 +1,13 @@ -words = [[84, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101, 32, 119, 97, 115, 32, 99, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 116, 104, 101, 32, 66, 105, 103, 32, 66, 97, 110, 103], [84, 104, 101, 32, 82, 97, 100, 111, 110, 32, 80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 76, 97, 110, 103, 117, 97, 103, 101, 32, 119, 97, 115, 32, 99, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 77, 100, 46, 32, 65, 108, 109, 97, 115, 32, 65, 108, 105], [70, 97, 115, 116, 32, 100, 111, 101, 115, 110, 39, 116, 32, 109, 101, 97, 110, 32, 101, 102, 102, 105, 99, 105, 101, 110, 116], [84, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101, 32, 105, 115, 32, 97, 32, 118, 97, 115, 116, 32, 112, 108, 97, 99, 101], [82, 97, 100, 111, 110, 32, 108, 105, 107, 101, 32, 116, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101]] +const words = [[84, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101, 32, 119, 97, 115, 32, 99, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 116, 104, 101, 32, 66, 105, 103, 32, 66, 97, 110, 103], [84, 104, 101, 32, 82, 97, 100, 111, 110, 32, 80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 76, 97, 110, 103, 117, 97, 103, 101, 32, 119, 97, 115, 32, 99, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 77, 100, 46, 32, 65, 108, 109, 97, 115, 32, 65, 108, 105], [70, 97, 115, 116, 32, 100, 111, 101, 115, 110, 39, 116, 32, 109, 101, 97, 110, 32, 101, 102, 102, 105, 99, 105, 101, 110, 116], [84, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101, 32, 105, 115, 32, 97, 32, 118, 97, 115, 116, 32, 112, 108, 97, 99, 101], [82, 97, 100, 111, 110, 32, 108, 105, 107, 101, 32, 116, 104, 101, 32, 85, 110, 105, 118, 101, 114, 115, 101]] -ns = {} +const ns = {} pyapi("def chr_func(c: int) -> str: return chr(c)", ns) -chr = ns["chr_func"] +const chr = ns["chr_func"] for i=0 to arr_len(words) { - temp_str = "" + var temp_str = "" for j=0 to arr_len(arr_get(words, i)) { - nonlocal temp_str += chr(arr_get(arr_get(words, i), j)) + temp_str += chr(arr_get(arr_get(words, i), j)) } print(temp_str) } diff --git a/tests/classes.rn b/tests/classes.rn index 2183639..2cb5b3a 100755 --- a/tests/classes.rn +++ b/tests/classes.rn @@ -20,18 +20,18 @@ class Foo { return Foo(this.x + other.x) } - static fun i_am_static() { + fun i_am_static() { print("i am static") } - static const c = "i am static const" + const c = "i am static const" } -a = Foo(34) -b = Foo(35) +var a = Foo(34) +var b = Foo(35) a.dump() b.dump() -c = a + b +var c = a + b c.dump() print(c.get_x()) @@ -43,3 +43,4 @@ Foo.i_am_static() print(Foo.c) print("END") + diff --git a/tests/closures.rn b/tests/closures.rn index 57a6ec2..da3d13b 100644 --- a/tests/closures.rn +++ b/tests/closures.rn @@ -1,17 +1,17 @@ fun make_var() { - val = null + var val = null return fun(new_val=null) { if is_null(new_val) { return val } else { - nonlocal val = new_val + val = new_val } } } -v1 = make_var() -v2 = make_var() +const v1 = make_var() +const v2 = make_var() print(v1()) print(v2()) diff --git a/tests/empty-blocks.rn b/tests/empty-blocks.rn index fe0bc63..a95ef5e 100644 --- a/tests/empty-blocks.rn +++ b/tests/empty-blocks.rn @@ -20,5 +20,5 @@ while false {} for _ = 0 to 10 {} for _ in [] {} -hm = {} +const hm = {} diff --git a/tests/files.rn b/tests/files.rn index e7dac47..d482173 100644 --- a/tests/files.rn +++ b/tests/files.rn @@ -1,5 +1,5 @@ -f = File("hello.txt", "w") +var f = File("hello.txt", "w") f.write("Lorem ipsum dolor sit amet, consectetur adipiscing elit.") f.close() diff --git a/tests/functions.rn b/tests/functions.rn index f6d16b9..df1f763 100755 --- a/tests/functions.rn +++ b/tests/functions.rn @@ -19,7 +19,7 @@ fun higher_order(f, l) { return nested } -g = higher_order(f, [4, 7, 2, 4, 3]) +const g = higher_order(f, [4, 7, 2, 4, 3]) print(g(50)) print("END") diff --git a/tests/hashmap.rn b/tests/hashmap.rn index d207971..2b9393d 100644 --- a/tests/hashmap.rn +++ b/tests/hashmap.rn @@ -1,20 +1,20 @@ # HashMap data type in Radon -hashmap = { +const hashmap = { "name": "John", "age": 23, "address": "123 Main St" } print(hashmap) -value = hashmap["name"] +const value = hashmap["name"] print(value) hashmap["bcd"] = 234 hashmap["abc"] = 456 print(hashmap) -adrs = "address" +const adrs = "address" print(hashmap[adrs]) for key in hashmap { @@ -23,7 +23,7 @@ for key in hashmap { print(hashmap[key]) } -keys = ["name", "age", "address", "noexist"] +const keys = ["name", "age", "address", "noexist"] try { for key in keys { diff --git a/tests/help.rn b/tests/help.rn index 708a895..02c5cb6 100644 --- a/tests/help.rn +++ b/tests/help.rn @@ -1,6 +1,6 @@ class Test { - property1 = "Hello, World!" + const property1 = "Hello, World!" fun __constructor__() { @@ -30,4 +30,4 @@ fun standalone(arg1,arg2) help("Hello") help(Test) help(Test()) -help(standalone) \ No newline at end of file +help(standalone) diff --git a/tests/in-op.rn b/tests/in-op.rn index be70904..9fbe8db 100644 --- a/tests/in-op.rn +++ b/tests/in-op.rn @@ -1,5 +1,5 @@ # with Array -arr = [1,2,3,4,5] +var arr = [1,2,3,4,5] # with if-else if 1 in arr { @@ -20,7 +20,7 @@ while 3 in arr { arr = [1,2,3,4,5] assert 4 in arr -hm = { +const hm = { "key1": "value1", "key2": "value2" } @@ -51,9 +51,9 @@ class Person { } } -john = Person("John") -bob = Person("Bob") -alice = Person("Alice") +const john = Person("John") +const bob = Person("Bob") +const alice = Person("Alice") john.befriend(bob) assert "Bob" in john diff --git a/tests/incdec.rn b/tests/incdec.rn index bc0c6c2..44d9b08 100644 --- a/tests/incdec.rn +++ b/tests/incdec.rn @@ -1,5 +1,5 @@ -x = 69 +var x = 69 print(x) x++ print(x) @@ -13,11 +13,11 @@ print(x--) print(x--) print("----------------") -y = 69 +var y = 69 print(x + " " + y) if true { x++ - nonlocal y++ + y++ } print(x + " " + y) diff --git a/tests/incdec.rn.json b/tests/incdec.rn.json index eaa8b91..eb013e9 100644 --- a/tests/incdec.rn.json +++ b/tests/incdec.rn.json @@ -1 +1 @@ -{"code": 0, "stdout": "69\n70\n69\n69\n70\n71\n72\n71\n70\n----------------\n69 69\n69 70\n----------------\n69\n74\n69\n345\n69.0\n1564031349.0\n312806269\n4\n", "stderr": ""} \ No newline at end of file +{"code": 0, "stdout": "69\n70\n69\n69\n70\n71\n72\n71\n70\n----------------\n69 69\n70 70\n----------------\n70\n75\n70\n350\n70.0\n1680700000.0\n336140000\n0\n", "stderr": ""} \ No newline at end of file diff --git a/tests/json_class.rn b/tests/json_class.rn index f005c68..82330b0 100644 --- a/tests/json_class.rn +++ b/tests/json_class.rn @@ -1,5 +1,5 @@ # Fake json data from https://jsonplaceholder.typicode.com/users -radon_object = [ +const radon_object = [ { "id": 1, "name": "Leanne Graham", @@ -232,12 +232,12 @@ radon_object = [ } ] -json = Json() +const json = Json() -json_string = json.dumps(radon_object) +const json_string = json.dumps(radon_object) assert type(json_string) == type("example string") # Need to fix empty string type -radon_object_loaded = json.loads(json_string) +const radon_object_loaded = json.loads(json_string) assert type(radon_object_loaded) == type([1]) # Need to fix empty array type # assert radon_object == radon_object_loaded diff --git a/tests/loops.rn b/tests/loops.rn index 94276c1..9357f0d 100755 --- a/tests/loops.rn +++ b/tests/loops.rn @@ -1,8 +1,8 @@ -i = 0 +var i = 0 while i < 10 { print(i) - nonlocal i = i + 1 + i++ } print("----------------------") @@ -13,7 +13,7 @@ for i = 0 to 10 { print("----------------------") -l = [4, 7, 2, 4, 3] +const l = [4, 7, 2, 4, 3] for x in l { print(x) diff --git a/tests/modules2.rn b/tests/modules2.rn index 678b899..e3c3040 100644 --- a/tests/modules2.rn +++ b/tests/modules2.rn @@ -1,5 +1,5 @@ import array as a -arr = a.Array(["A", "r", "r", "a", "y"]) +const arr = a.Array(["A", "r", "r", "a", "y"]) arr.map(print) diff --git a/tests/pyapi_advanced.rn b/tests/pyapi_advanced.rn index bca9f53..7cabe80 100644 --- a/tests/pyapi_advanced.rn +++ b/tests/pyapi_advanced.rn @@ -1,5 +1,5 @@ -ns = {} +const ns = {} ns["cb"] = fun(x, y) -> (x + y) * 101 @@ -12,10 +12,10 @@ def my_func(x, y): print(f'Return value (from Radon function in Python): {cb(34, 35)}') ", ns) -func = ns["my_func"] +const func = ns["my_func"] print("func is: " + print_ret(func)) -ret = func("hello", "world") +const ret = func("hello", "world") print("Return value (from Python function in Radon): " + str(ret)) diff --git a/tests/radiation-modules.rn b/tests/radiation-modules.rn index e895a8e..091f603 100644 --- a/tests/radiation-modules.rn +++ b/tests/radiation-modules.rn @@ -1,6 +1,6 @@ import radiation -errors = radiation.errors +const errors = radiation.errors # print(radiation.errors[0]) @@ -13,4 +13,4 @@ try { } catch as err { print(err) -} \ No newline at end of file +} diff --git a/tests/requests-tests.rn b/tests/requests-tests.rn index 42e6e7d..e2505af 100644 --- a/tests/requests-tests.rn +++ b/tests/requests-tests.rn @@ -1,29 +1,29 @@ # API testing -requests = Requests() -json = Json() +const requests = Requests() +const json = Json() # get request testing -response_get = requests.get("https://jsonplaceholder.typicode.com/posts") +const response_get = requests.get("https://jsonplaceholder.typicode.com/posts") assert arr_len(json.loads(response_get)) == 100 # post request testing -response_post = requests.post("https://jsonplaceholder.typicode.com/posts", {"title": "foo", "body": "bar", "userId": 1}) -value = json.loads(response_post) +const response_post = requests.post("https://jsonplaceholder.typicode.com/posts", {"title": "foo", "body": "bar", "userId": 1}) +var value = json.loads(response_post) assert value["id"] == 101 # put request testing -response_put = requests.put("https://jsonplaceholder.typicode.com/posts/1", {"title": "foo", "body": "bar", "userId": 1}) +const response_put = requests.put("https://jsonplaceholder.typicode.com/posts/1", {"title": "foo", "body": "bar", "userId": 1}) value = json.loads(response_put) assert value["id"] == 1 # patch request testing -response_patch = requests.patch("https://jsonplaceholder.typicode.com/posts/52", {"title": "foo"}) +const response_patch = requests.patch("https://jsonplaceholder.typicode.com/posts/52", {"title": "foo"}) value = json.loads(response_patch) assert value["id"] == 52 # delete request testing -response_delete = requests.delete("https://jsonplaceholder.typicode.com/posts/1") +const response_delete = requests.delete("https://jsonplaceholder.typicode.com/posts/1") assert json.loads(response_delete) == {} print("API testing passed!") diff --git a/tests/scope-bug.rn b/tests/scope-bug.rn index a5bf43e..59372fb 100644 --- a/tests/scope-bug.rn +++ b/tests/scope-bug.rn @@ -1,9 +1,9 @@ -string1 = "this is my string." -string_obj = String(string1) +const string1 = "this is my string." +const string_obj = String(string1) -v = "i" -count = string_obj.count(v) +const v = "i" +const count = string_obj.count(v) print(count) diff --git a/tests/slice-bruteforce.rn b/tests/slice-bruteforce.rn index 5b0e8e3..ff8353a 100644 --- a/tests/slice-bruteforce.rn +++ b/tests/slice-bruteforce.rn @@ -55,7 +55,7 @@ fun test(l) { print(l[::]) } -l = [0] +const l = [0] for i = 0 to 100 { arr_append(l, i) diff --git a/tests/slicings.rn b/tests/slicings.rn index f29bef4..3b09982 100644 --- a/tests/slicings.rn +++ b/tests/slicings.rn @@ -1,7 +1,7 @@ # Slicing # Array of Numbers slicing -my_arr = [1,2,3,4,5,6,7,8,9,0] +var my_arr = [1,2,3,4,5,6,7,8,9,0] assert my_arr[0] == 1 assert my_arr[0:5] == [1,2,3,4,5] assert my_arr[0:9:2] == [1,3,5,7,9] @@ -9,14 +9,14 @@ assert my_arr[::-1] == [0,9,8,7,6,5,4,3,2,1] # assert my_arr[0:9:-1] == [] # Invalid Syntax: Expected EOF # Array of Strings slicing -my_str_arr = ["This", "is", "an", "example", "string"] +const my_str_arr = ["This", "is", "an", "example", "string"] assert my_str_arr[0] == "This" assert my_str_arr[0:3] == ["This", "is", "an"] assert my_str_arr[0:5:2] == ["This", "an", "string"] assert my_str_arr[::-1] == ["string", "example", "an", "is", "This"] # Complex Array slicing -my_complex_arr = [1, "This", 2, "is", 3, "an", 4, "example", 5, "string", 4.64, 2.4556, 324.2345] +const my_complex_arr = [1, "This", 2, "is", 3, "an", 4, "example", 5, "string", 4.64, 2.4556, 324.2345] assert my_complex_arr[0] == 1 assert my_complex_arr[11] == 2.4556 assert my_complex_arr[-2] == 2.4556 @@ -25,7 +25,7 @@ assert my_complex_arr[0:10:2] == [1, 2, 3, 4, 5] assert my_complex_arr[::-1] == [324.2345, 2.4556, 4.64, "string", 5, "example", 4, "an", 3, "is", 2, "This", 1] # String slicing -my_str = "This is an example string" +var my_str = "This is an example string" assert my_str[0:4:1] == "This" assert my_str[5:7] == "is" @@ -45,5 +45,5 @@ assert my_arr[0] == 10 # updating values in string my_str = "This is an example string" -new_str = my_str[19] = "S" +const new_str = my_str[19] = "S" assert new_str == "This is an example String" diff --git a/tests/string_class.rn b/tests/string_class.rn index 3484383..95cd768 100644 --- a/tests/string_class.rn +++ b/tests/string_class.rn @@ -1,28 +1,28 @@ -s = String("This is a string") +const s = String("This is a string") -s_upper = s.upper() +const s_upper = s.upper() assert s_upper == "THIS IS A STRING" -s_lower = s.lower() +const s_lower = s.lower() assert s_lower == "this is a string" -s_capitalize = s.capitalize() +const s_capitalize = s.capitalize() assert s_capitalize == "This is a string" -s_title = s.title() +const s_title = s.title() assert s_title == "This Is A String" -s_swapcase = s.swapcase() +const s_swapcase = s.swapcase() assert s_swapcase == "tHIS IS A STRING" -s_len = s.length() +const s_len = s.length() assert s_len == 16 -s_count = s.count("i") +const s_count = s.count("i") assert s_count == 3 try { s.count() # is throwing Python exception !! } catch as err { print(err) -} \ No newline at end of file +} diff --git a/tests/switch-case.rn b/tests/switch-case.rn index 7281478..d05823c 100644 --- a/tests/switch-case.rn +++ b/tests/switch-case.rn @@ -35,7 +35,7 @@ for x in [1, 2, 3, 4] { } print("---------------") -i = 0 +var i = 0 for x in [1, 2, 3, 2, 5] { print(str(i) + " " + str(x)) switch x { @@ -50,6 +50,6 @@ for x in [1, 2, 3, 2, 5] { case 3 { print("three or second two") } default { print("default") } } - nonlocal i++ + i++ } diff --git a/tests/thicc-hm.rn b/tests/thicc-hm.rn index 49aac9c..bccced4 100644 --- a/tests/thicc-hm.rn +++ b/tests/thicc-hm.rn @@ -1,4 +1,4 @@ -radon_object = [ +const radon_object = [ { "id": 1, "name": "Leanne Graham", From 9ccc0363d119ee8d02106fd9fe7c0cd2cc5d966c Mon Sep 17 00:00:00 2001 From: angelcaru Date: Sat, 1 Jun 2024 09:42:05 +0200 Subject: [PATCH 2/3] Fix ruff formatting --- core/errors.py | 3 +-- core/interpreter.py | 9 ++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/errors.py b/core/errors.py index 423e134..8ccf4f9 100755 --- a/core/errors.py +++ b/core/errors.py @@ -133,8 +133,7 @@ def generate_radiation(self) -> str: ln = pos.ln + 1 if pos is not None else None name = ctx.display_name if ctx is not None else None result = ( - f" File {Log.light_info(fn)}, line {Log.light_info(str(ln))}, in {Log.light_info(name)}\n" - + result + f" File {Log.light_info(fn)}, line {Log.light_info(str(ln))}, in {Log.light_info(name)}\n" + result ) pos = ctx.parent_entry_pos # type: ignore ctx = ctx.parent # type: ignore diff --git a/core/interpreter.py b/core/interpreter.py index 9db727b..a69e698 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -262,7 +262,14 @@ def visit_ImportNode(self, node: ImportNode, context: Context) -> RTResult[Value res = RTResult[Value]() res.register( - self.assign(var_name=name, value=module, context=context, pos_start=node.pos_start, pos_end=node.pos_end, qualifier=Token(TT_KEYWORD, "const", pos_start=node.pos_start)) + self.assign( + var_name=name, + value=module, + context=context, + pos_start=node.pos_start, + pos_end=node.pos_end, + qualifier=Token(TT_KEYWORD, "const", pos_start=node.pos_start), + ) ) if res.should_return(): return res From ceab54ad86b9d94bff736591c49d86fdf7b058ae Mon Sep 17 00:00:00 2001 From: angelcaru Date: Sat, 1 Jun 2024 11:35:43 +0200 Subject: [PATCH 3/3] Fix statics --- core/interpreter.py | 6 ++++-- core/parser.py | 6 ++---- tests/classes.rn | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/interpreter.py b/core/interpreter.py index a69e698..f09f157 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -52,7 +52,9 @@ def assign( return res return res.success(value) - res.register(context.symbol_table.set_var(var_name, value, qualifier)) + qualifier_str = None if qualifier is None else qualifier.value + assert qualifier_str is None or isinstance(qualifier_str, str) + res.register(context.symbol_table.set_var(var_name, value, qualifier_str)) if res.should_return(): return res return res.success(value) @@ -524,7 +526,7 @@ def visit_FuncDefNode(self, node: FuncDefNode, context: Context) -> RTResult[Val assert context.symbol_table is not None assert isinstance(func_name, str), "this could be a bug in the parser" if node.static: - context.symbol_table.set_static(func_name, func_value) + context.symbol_table.set_static(func_name, func_value, "var") else: context.symbol_table.set(func_name, func_value) diff --git a/core/parser.py b/core/parser.py index 4014ea6..e41b290 100755 --- a/core/parser.py +++ b/core/parser.py @@ -1690,13 +1690,11 @@ def set(self, name: str, value: Value) -> RTResult[None]: self.symbols[name] = value return RTResult[None]().success(None) - def set_var(self, name: str, value: Value, qualifier_tok: Optional[Token] = None) -> RTResult[None]: + def set_var(self, name: str, value: Value, qualifier: Optional[str] = None) -> RTResult[None]: if name in self.consts: return RTResult[None]().failure( RTError(value.pos_start, value.pos_end, f"Cannot reassign to constant {name}", value.context) ) - qualifier = None if qualifier_tok is None else qualifier_tok.value - assert qualifier is None or isinstance(qualifier, str) match qualifier: case None: if name in self.symbols: @@ -1723,7 +1721,7 @@ def set_var(self, name: str, value: Value, qualifier_tok: Optional[Token] = None self.consts.add(name) return RTResult[None]().success(None) - def set_static(self, name: str, value: Value, qualifier: Optional[Token] = None) -> RTResult[None]: + def set_static(self, name: str, value: Value, qualifier: Optional[str] = None) -> RTResult[None]: res = RTResult[None]() res.register(self.set_var(name, value, qualifier)) if res.should_return(): diff --git a/tests/classes.rn b/tests/classes.rn index 2cb5b3a..97bf664 100755 --- a/tests/classes.rn +++ b/tests/classes.rn @@ -20,10 +20,10 @@ class Foo { return Foo(this.x + other.x) } - fun i_am_static() { + static fun i_am_static() { print("i am static") } - const c = "i am static const" + static const c = "i am static const" } var a = Foo(34)