Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add dedicated null datatype #128

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/builtin_classes/file_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def close(ctx):
res = RTResult()
self = ctx.symbol_table.get("this")
self.file.close()
return res.success(Number.null())
return res.success(Null.null())

@args([])
@method
Expand Down
28 changes: 19 additions & 9 deletions core/builtin_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def execute_print(self, exec_ctx):
value = exec_ctx.symbol_table.get("value")

print(value)
return RTResult().success(Number.null())
return RTResult().success(Null.null())

@args(["value"])
def execute_print_ret(self, exec_ctx):
Expand All @@ -95,7 +95,7 @@ def execute_input_int(self, exec_ctx):
@args([])
def execute_clear(self, exec_ctx):
os.system("cls" if os.name == "nt" else "clear")
return RTResult().success(Number.null())
return RTResult().success(Null.null())

@args(["value"])
def execute_is_number(self, exec_ctx):
Expand Down Expand Up @@ -143,7 +143,7 @@ def execute_arr_append(self, exec_ctx):
return RTResult().failure(RTError(self.pos_start, self.pos_end, "First argument must be array", exec_ctx))

array_.elements.append(value)
return RTResult().success(Number.null())
return RTResult().success(Null.null())

@args(["array", "index"], [None, Number(-1)])
def execute_arr_pop(self, exec_ctx):
Expand Down Expand Up @@ -181,7 +181,7 @@ def execute_arr_extend(self, exec_ctx):
return RTResult().failure(RTError(self.pos_start, self.pos_end, "Second argument must be array", exec_ctx))

arrayA.elements.extend(arrayB.elements)
return RTResult().success(Number.null())
return RTResult().success(Null.null())

@args(["array", "index"])
def execute_arr_find(self, exec_ctx):
Expand Down Expand Up @@ -350,7 +350,7 @@ def execute_pyapi(self, exec_ctx):
res.register(PyAPI(code.value).set_pos(self.pos_start, self.pos_end).set_context(self.context).pyapi(ns))
if res.should_return():
return res
return res.success(Number.null())
return res.success(Null.null())

@args([])
def execute_sys_args(self, exec_ctx):
Expand Down Expand Up @@ -416,12 +416,21 @@ def execute_require(self, exec_ctx):
)

if should_exit:
return RTResult().success_exit(Number.null())
return RTResult().success(Number.null())
return RTResult().success_exit(Null.null())
return RTResult().success(Null.null())

@args([])
def execute_exit(self, exec_ctx):
return RTResult().success_exit(Number.null())
return RTResult().success_exit(Null.null())

@args(["value"])
def execute_is_null(self, ctx):
value = ctx.symbol_table.get("value")

if isinstance(value, Null):
return RTResult().success(Boolean(True))
else:
return RTResult().success(Boolean(False))


def run(
Expand Down Expand Up @@ -470,7 +479,7 @@ def create_global_symbol_table() -> SymbolTable:
import core.builtin_classes as bic

ret = SymbolTable()
ret.set("null", Number.null())
ret.set("null", Null.null())
ret.set("false", Boolean.false())
ret.set("true", Boolean.true())
ret.set("print", BuiltInFunction("print"))
Expand All @@ -489,6 +498,7 @@ def create_global_symbol_table() -> SymbolTable:
ret.set("is_bool", BuiltInFunction("is_bool"))
ret.set("is_array", BuiltInFunction("is_array"))
ret.set("is_fun", BuiltInFunction("is_fun"))
ret.set("is_null", BuiltInFunction("is_null"))
# Internal array methods
ret.set("arr_append", BuiltInFunction("arr_append"))
ret.set("arr_pop", BuiltInFunction("arr_pop"))
Expand Down
37 changes: 30 additions & 7 deletions core/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,6 @@ def __str__(self) -> str:
def __repr__(self) -> str:
return str(self.value)

@classmethod
def null(cls) -> Number:
return cls(0)

@classmethod
def one(cls) -> Number:
return cls(1)
Expand Down Expand Up @@ -820,7 +816,7 @@ def _radonify(value: object) -> Value:
case False:
return Boolean.false()
case None:
return Number.null()
return Null.null()
case _ if inspect.isfunction(value):
from core.builtin_funcs import BuiltInFunction, args # Lazy import

Expand Down Expand Up @@ -924,7 +920,7 @@ def pyapi(self, ns: HashMap) -> RTResult[Value]:
self.context,
)
)
return RTResult[Value]().success(Number.null())
return RTResult[Value]().success(Null.null())

def copy(self) -> PyAPI:
copy = PyAPI(self.code)
Expand Down Expand Up @@ -1243,7 +1239,7 @@ def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value
if res.should_return() and res.func_return_value is None:
return res

ret_value = (value if self.should_auto_return else None) or res.func_return_value or Number.null()
ret_value = (value if self.should_auto_return else None) or res.func_return_value or Null.null()
return res.success(ret_value)

def copy(self) -> Function:
Expand Down Expand Up @@ -1274,3 +1270,30 @@ def copy(self) -> Module:

def __repr__(self) -> str:
return f"<module {self.name} @ {self.file_path!r}>"


class Null(Value):
def __repr__(self) -> str:
return "null"

def copy(self) -> Null:
return self

def is_true(self) -> bool:
return False

def get_comparison_eq(self, other: Value) -> ResultTuple:
if isinstance(other, Null):
return Boolean.true(), None
else:
return Boolean.false(), None

def get_comparison_ne(self, other: Value) -> ResultTuple:
if isinstance(other, Null):
return Boolean.false(), None
else:
return Boolean.true(), None

@classmethod
def null(cls) -> Null:
return cls()
26 changes: 13 additions & 13 deletions core/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def visit_IncludeNode(self, node: IncludeNode, context: Context) -> RTResult[Val
)

if should_exit:
return RTResult[Value]().success_exit(Number.null())
return RTResult[Value]().success_exit(Null.null())
assert isinstance(node.module.value, str), "this could be a bug in the parser"
module = Module(node.module.value, module_name, symbol_table)
res = RTResult[Value]()
Expand Down Expand Up @@ -277,17 +277,17 @@ def visit_IfNode(self, node: IfNode, context: Context) -> RTResult[Value]:
if res.should_return():
return res
assert expr_value is not None
return res.success(Number.null() if should_return_null else expr_value)
return res.success(Null.null() if should_return_null else expr_value)

if node.else_case is not None:
expr, should_return_null = node.else_case
expr_value = res.register(self.visit_block(expr, context))
if res.should_return():
return res
assert expr_value is not None
return res.success(Number.null() if should_return_null else expr_value)
return res.success(Null.null() if should_return_null else expr_value)

return res.success(Number.null())
return res.success(Null.null())

def visit_ForNode(self, node: ForNode, context: Context) -> RTResult[Value]:
res = RTResult[Value]()
Expand Down Expand Up @@ -363,7 +363,7 @@ def condition():
elements.append(value)

return res.success(
Number.null()
Null.null()
if node.should_return_null
else Array(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)
Expand Down Expand Up @@ -395,7 +395,7 @@ def visit_WhileNode(self, node: WhileNode, context: Context) -> RTResult[Value]:
elements.append(value)

return res.success(
Number.null()
Null.null()
if node.should_return_null
else Array(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)
Expand Down Expand Up @@ -473,7 +473,7 @@ def visit_ReturnNode(self, node: ReturnNode, context: Context) -> RTResult[Value
if res.should_return():
return res
else:
value = Number.null()
value = Null.null()
assert value is not None

return res.success_return(value)
Expand Down Expand Up @@ -502,9 +502,9 @@ def visit_TryNode(self, node: TryNode, context):
res.error.pos_start, res.error.pos_end, res.error.details, res.error.context, handled_error
)
)
return res.success(Number.null())
return res.success(Null.null())
else:
return res.success(Number.null())
return res.success(Null.null())

def visit_ForInNode(self, node: ForInNode, context: Context) -> RTResult[Value]:
res = RTResult[Value]()
Expand Down Expand Up @@ -536,7 +536,7 @@ def visit_ForInNode(self, node: ForInNode, context: Context) -> RTResult[Value]:
elements.append(element)

if should_return_null:
return res.success(Number.null())
return res.success(Null.null())
return res.success(Array(elements).set_context(context).set_pos(node.pos_start, node.pos_end))

def visit_SliceGetNode(self, node: SliceGetNode, context: Context) -> RTResult[Value]:
Expand Down Expand Up @@ -766,18 +766,18 @@ def visit_SwitchNode(self, node: SwitchNode, context: Context) -> RTResult[Value
if res.should_fallthrough:
should_continue = True
continue
return res.success(Number.null())
return res.success(Null.null())
should_continue = False

if node.default is not None:
res.register(self.visit(node.default, context))
if res.should_return():
return res
return res.success(Number.null())
return res.success(Null.null())
return res.failure(RTError(node.pos_start, node.subject_node.pos_end, "No cases matched", context))

def visit_FallthroughNode(self, node: FallthroughNode, context: Context) -> RTResult[Value]:
return RTResult[Value]().success(Number.null()).fallthrough()
return RTResult[Value]().success(Null.null()).fallthrough()

def visit_AttrAccessNode(self, node: AttrAccessNode, context: Context) -> RTResult[Value]:
res = RTResult[Value]()
Expand Down
2 changes: 1 addition & 1 deletion core/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1528,7 +1528,7 @@ def success_exit(self, exit_value: T) -> RTResult[T]:

def fallthrough(self) -> RTResult[T]:
# No `self.reset()` because this is meant to be used in conjunction with other methods
# e.g. `res.success(Number.null()).fallthrough()`
# e.g. `res.success(Null.null()).fallthrough()`
self.should_fallthrough = True
return self

Expand Down
2 changes: 1 addition & 1 deletion examples/operator_overloading.rn
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class WrongOp {
}

fun dump(name = null) {
if name == null {
if is_null(name) {
print("WrongOp("+this.x+")")
} else {
print(name+" = WrongOp("+this.x+")")
Expand Down
2 changes: 1 addition & 1 deletion tests/closures.rn
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
fun make_var() {
val = null
return fun(new_val=null) {
if new_val == null {
if is_null(new_val) {
return val
} else {
nonlocal val = new_val
Expand Down
2 changes: 1 addition & 1 deletion tests/closures.rn.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"code": 0, "stdout": "0\n0\n69\n0\n69\n420\n", "stderr": ""}
{"code": 0, "stdout": "null\nnull\n69\nnull\n69\n420\n", "stderr": ""}