Skip to content

Commit

Permalink
refactor interpreter according to the new parser
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulMarisOUMary committed Mar 11, 2024
1 parent e19d391 commit 8ee7a93
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 45 deletions.
54 changes: 23 additions & 31 deletions moon/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
TOutputCallback = Callable[[object], None]
TInputCallback = Callable[[object], str]

class BreakType:
class StopType:
pass

class ContinueType: # ? Should be renamed to Skip
class SkipType:
pass

class ReturnType:
class ResultType:
def __init__(self, value) -> None:
self.value = value

Expand Down Expand Up @@ -102,53 +102,53 @@ def execute(
return eval(f"{repr(leftvalue)} {operator} {repr(rightvalue)}")

# Control Structures
case "if_statement":
case "ifelse_statements":
# CONTAINS BLOCK
condition, if_expressions, else_expressions = next
executed_condition = execute(condition)
if executed_condition:
for expression in if_expressions: # type: ignore
result = execute(expression)
if isinstance(result, (BreakType, ContinueType, ReturnType)):
if isinstance(result, (StopType, SkipType, ResultType)):
return result
elif else_expressions:
for expression in else_expressions: # type: ignore
result = execute(expression)
if isinstance(result, (BreakType, ContinueType)):
if isinstance(result, (StopType, SkipType)):
return result

# Loop structure
case "while_statement":
case "while_statements":
# CONTAINS BLOCK
condition, block_expressions = next
while execute(condition):
result = None
for expression in block_expressions: # type: ignore
result = execute(expression)
if isinstance(result, (BreakType, ContinueType, ReturnType)):
if isinstance(result, (StopType, SkipType, ResultType)):
break
if isinstance(result, BreakType):
if isinstance(result, StopType):
break
elif isinstance(result, ReturnType):
elif isinstance(result, ResultType):
return result
elif isinstance(result, ContinueType):
elif isinstance(result, SkipType):
continue

case "break_statement":
return BreakType()
case "stop_statement":
return StopType()

case "continue_statement":
return ContinueType()
case "skip_statement":
return SkipType()

# Try-Catch and raise

# Functions
case "action_statement":
case "action_statements":
# CONTAINS BLOCK
funcname, params, block_expressions = next
environment[funcname] = (params, block_expressions)

case "call_statement":
case "call":
funcname, params = next
param_values = [execute(p) for p in params] # type: ignore

Expand All @@ -159,34 +159,26 @@ def execute(
result = None
for expression in block_expressions:
result = execute(expression, sub_environment)
if isinstance(result, ReturnType):
if isinstance(result, ResultType):
result = result.value
break
environment.update({k: v for k, v in sub_environment.items() if k in environment and v != environment.get(k)})
return result

case "return_statement":
case "result_statement":
expressions = next[0]
result = execute(expressions[0])
return ReturnType(result)
return ResultType(result)

# Classes

# Modules

# Built-in
case "print_statement":
if len(next) > 1:
raise ValueError("print")
output_callback(
*[
custom_repr(
execute(expression)
)
for expression in next[0] # type: ignore
]
)
case "ask_statement":
output_callback(*[custom_repr(execute(expression)) for expression in next[0]]) # type: ignore

case "ask":
prompt = execute(next[0])
return autocast(
input_callback(
Expand Down
10 changes: 6 additions & 4 deletions moon/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from .lexer import tokens, LexTokenT

# REMINDER: (value) in Python is not a tuple; (value,) is a tuple

tokens = tokens

precedence = (
Expand Down Expand Up @@ -65,7 +67,7 @@ def p_optional_inline_params(p: TYP):

def p_action_statements(p: TYP):
"""action_statements : ACTION IDENTIFIER optional_inline_params suite"""
p[0] = ("action_statement", p[2], p[3], p[4])
p[0] = ("action_statements", p[2], p[3], p[4])

## Composite

Expand Down Expand Up @@ -105,11 +107,11 @@ def p_variable_declaration_statement(p: TYP):

def p_stop_statement(p: TYP):
"""stop_statement : STOP"""
p[0] = ("stop_statement")
p[0] = ("stop_statement", )

def p_skip_statement(p: TYP):
"""skip_statement : SKIP"""
p[0] = ("skip_statement")
p[0] = ("skip_statement", )

def p_result_statement(p: TYP):
"""result_statement : RESULT optional_inline_args"""
Expand Down Expand Up @@ -204,7 +206,7 @@ def p_integer_boolean(p: TYP):

def p_integer_null(p: TYP):
"""null_literal : NULL"""
p[0] = ("null_literal")
p[0] = ("null_literal",)

# Empty

Expand Down
2 changes: 1 addition & 1 deletion tests/test_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def test_while_statements(input_code, expected_output, capsys):
("x is 0\nwhile true\n\tprint x\n\tx is x + 1\n\tif x > 5\n\t\tif x is 10\n\t\t\tstop", "0\n1\n2\n3\n4\n5\n6\n7\n8\n9"),
("x is 0\nwhile true\n\tx is x + 1\n\tif x is 3\n\t\tskip\n\tprint x\n\n\tif x is 10\n\t\tstop", "1\n2\n4\n5\n6\n7\n8\n9\n10"),
])
def test_break_statements(input_code, expected_output, capsys):
def test_stop_statements(input_code, expected_output, capsys):
code_to_output(input_code)

captured = capsys.readouterr()
Expand Down
18 changes: 9 additions & 9 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_boolean_literal(input_code, expected_output):
assert parse_code(input_code) == expected_output
## Null
@pytest.mark.parametrize("input_code, expected_output", [
("null", [("null_literal")]),
("null", [("null_literal",)]),
])
def test_null_literal(input_code, expected_output):
assert parse_code(input_code) == expected_output
Expand Down Expand Up @@ -136,7 +136,7 @@ def test_ask(input_code, expected_output):
## Variable Assignment
@pytest.mark.parametrize("input_code, expected_output", [
# Literals assignment
("var is null", [("variable_declaration_statement", "var", ("null_literal"))]),
("var is null", [("variable_declaration_statement", "var", ("null_literal",))]),
("var is false", [("variable_declaration_statement", "var", ("boolean_literal", False))]),
("var is true", [("variable_declaration_statement", "var", ("boolean_literal", True))]),
("var is 1", [("variable_declaration_statement", "var", ("integer_literal", 1))]),
Expand Down Expand Up @@ -173,14 +173,14 @@ def test_variable_declaration_statement(input_code, expected_output):

## Stop
@pytest.mark.parametrize("input_code, expected_output", [
("stop", [("stop_statement")]),
("stop", [("stop_statement",)]),
])
def test_stop_statement(input_code, expected_output):
assert parse_code(input_code) == expected_output

## Skip
@pytest.mark.parametrize("input_code, expected_output", [
("skip", [("skip_statement")]),
("skip", [("skip_statement",)]),
])
def test_skip_statement(input_code, expected_output):
assert parse_code(input_code) == expected_output
Expand Down Expand Up @@ -230,11 +230,11 @@ def test_while_statements(input_code, expected_output):

## Action
@pytest.mark.parametrize("input_code, expected_output", [
("action func_name\n\tprint 1", [("action_statement", "func_name", [], [("print_statement", [("integer_literal", 1)])])]),
("action func_name\n\tprint 1\n\tprint 2", [("action_statement", "func_name", [], [("print_statement", [("integer_literal", 1)]), ("print_statement", [("integer_literal", 2)])])]),
("action func_name a\n\tprint 1", [("action_statement", "func_name", ['a'], [("print_statement", [("integer_literal", 1)])])]),
("action func_name a b\n\tprint 1", [("action_statement", "func_name", ['a', 'b'], [("print_statement", [("integer_literal", 1)])])]),
("action func_name a b\n\tprint 1\n\tprint 2", [("action_statement", "func_name", ['a', 'b'], [("print_statement", [("integer_literal", 1)]), ("print_statement", [("integer_literal", 2)])])]),
("action func_name\n\tprint 1", [("action_statements", "func_name", [], [("print_statement", [("integer_literal", 1)])])]),
("action func_name\n\tprint 1\n\tprint 2", [("action_statements", "func_name", [], [("print_statement", [("integer_literal", 1)]), ("print_statement", [("integer_literal", 2)])])]),
("action func_name a\n\tprint 1", [("action_statements", "func_name", ['a'], [("print_statement", [("integer_literal", 1)])])]),
("action func_name a b\n\tprint 1", [("action_statements", "func_name", ['a', 'b'], [("print_statement", [("integer_literal", 1)])])]),
("action func_name a b\n\tprint 1\n\tprint 2", [("action_statements", "func_name", ['a', 'b'], [("print_statement", [("integer_literal", 1)]), ("print_statement", [("integer_literal", 2)])])]),
])
def test_action_statements(input_code, expected_output):
assert parse_code(input_code) == expected_output

0 comments on commit 8ee7a93

Please sign in to comment.