From 224ec0bc9841a342c9f7aa5a295acf9e0bf5ebf6 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Wed, 8 Mar 2023 11:50:03 -0500 Subject: [PATCH] Add a repl --- genir.py | 5 ++--- ir.py | 10 ++++++---- main.py | 12 ++++++++++-- silly_thing.py | 28 +++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/genir.py b/genir.py index d0891d1..1698029 100644 --- a/genir.py +++ b/genir.py @@ -1,9 +1,8 @@ from emis_funky_funktions import * from typing import * -from silly_thing import * from pattern import lex_and_parse_pattern -from ir import Function, Application, Int, Variable, LetBinding, Unit +from ir import Expression, Function, Application, Int, Variable, LetBinding, ReplHole import json @@ -23,7 +22,7 @@ def json_to_ir(j: JsonType) -> Expression: case [first, *rest]: return Application(json_to_ir(first), [json_to_ir(a) for a in rest]) case []: - return Unit() + return ReplHole() raise Exception('Unreachable') else: return Int(j) \ No newline at end of file diff --git a/ir.py b/ir.py index b2ed306..086c43d 100644 --- a/ir.py +++ b/ir.py @@ -3,7 +3,7 @@ from emis_funky_funktions import * from typing import Mapping, Sequence, Tuple, TypeAlias -Expression: TypeAlias = 'Function | Application | Int | Variable | Builtin | LetBinding | Unit' +Expression: TypeAlias = 'Function | Application | Int | Variable | Builtin | LetBinding | ReplHole' Pattern: TypeAlias = 'NamePattern | IntPattern | SPattern | IgnorePattern' @dataclass(frozen=True) @@ -119,9 +119,11 @@ class SPattern: return 'S ' + repr(self.pred) @dataclass(frozen=True) -class Unit: +class ReplHole: + bindings: Sequence[Tuple[str, Expression]] = tuple() + def subst(self, expression: Expression, variable: str) -> Expression: - return self + return ReplHole((*self.bindings, (variable, expression))) def is_value(self) -> bool: return True @@ -280,7 +282,7 @@ class Application: body = rest match body: case []: - return Some(Unit()) + return Some(ReplHole()) case [body_first, *body_rest]: return Some(LetBinding(lhs, rhs, Application(body_first, body_rest))) else: diff --git a/main.py b/main.py index 29c011f..c8e555e 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,16 @@ from emis_funky_funktions import * from genir import json_to_ir -from silly_thing import evaluate +from silly_thing import repl, repl_expr import json, sys -print(evaluate(json_to_ir(json.loads(open(sys.argv[1]).read())))) \ No newline at end of file +def main(): + match sys.argv: + case [_, file]: + repl_expr(json_to_ir(json.loads(open(sys.argv[1]).read()))) + case _: + repl() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/silly_thing.py b/silly_thing.py index fa104aa..84c533b 100644 --- a/silly_thing.py +++ b/silly_thing.py @@ -1,8 +1,10 @@ from emis_funky_funktions import * from typing import Collection, Sequence, TypeAlias -from ir import Expression +from ir import Expression, ReplHole, subst_all +from genir import json_to_ir +import json from dataclasses import dataclass from operator import add @@ -35,6 +37,30 @@ def evaluate(expr: Expression) -> Expression: raise AssertionError('Evaluate called on a value which cannot step:', expr) raise Exception('Unreachable') +def repl_expr(expr: Expression, bindings: Sequence[Tuple[str, Expression]] = tuple()): + expr_subst = subst_all(bindings, expr) + result = evaluate(expr_subst) + if isinstance(result, ReplHole): + print('Environment updated\n') + repl(result.bindings) + else: + print(result, end='\n\n') + repl(bindings) + +def repl(bindings: Sequence[Tuple[str, Expression]] = tuple()): + print('Enter a JSON expression:') + try: + expr = input('-> ') + except EOFError: + print('') + return + try: + ast = json.loads(expr) + except json.decoder.JSONDecodeError as e: + print(f'Bad json: ', e.args[0], end='\n\n') + return repl(bindings) + repl_expr(json_to_ir(ast), bindings) + if __name__ == '__main__': import doctest doctest.testmod() \ No newline at end of file