-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
128 lines (114 loc) · 4.37 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from dataclasses import dataclass
from io import TextIOWrapper
from pathlib import Path
from pprint import pprint
from smol.checker.checker import Checker, CheckerContext
from smol.interpreter.interpreter import Interpreter, InterpreterContext
from smol.lexer.lexer import Lexer
from smol.parser.parser import Parser
from smol.utils import StageContext
@dataclass(frozen=True)
class SmolContext:
file: TextIOWrapper | None
path: Path | None
debug: bool = False
no_checker: bool = False
def compile_file(ctx: SmolContext):
raise NotImplementedError("Compiling files is not implemented yet")
def check_file(ctx: SmolContext):
assert ctx.file is not None, "File is not specified"
assert ctx.path is not None, "Path is not specified"
kw_context = {
"current_directory": ctx.path.parent,
"current_file": ctx.path.name,
}
context = StageContext(**kw_context)
lexer = Lexer.from_file(ctx.file, context)
parser = Parser.from_lexer(lexer)
parsed = parser.parse()
context = CheckerContext(**kw_context)
checker = Checker(parsed, context)
for error in checker.check():
print(error)
if not checker.has_errors:
print("No errors found")
def interpret_file(ctx: SmolContext):
assert ctx.file is not None, "File is not specified"
assert ctx.path is not None, "Path is not specified"
kw_context = {
"current_directory": ctx.path.parent,
"current_file": ctx.path.name,
}
context = StageContext(**kw_context)
lexer = Lexer.from_file(ctx.file, context)
parser = Parser.from_lexer(lexer)
program = parser.parse()
icontext = InterpreterContext(**kw_context)
ccontext = CheckerContext(**kw_context)
if ctx.no_checker:
interpreter = Interpreter(program, icontext)
pprint(interpreter.run())
return
checker = Checker(program, ccontext)
for error in checker.check():
print(error)
if not checker.has_errors:
interpreter = Interpreter(program, icontext)
pprint(interpreter.run())
def repl(ctx: SmolContext):
content: list[str] = []
while True:
line = input("> " if len(content) == 0 else ". ")
# if two last lines are empty and user presses enter, we execute the program
if line != "" or not (len(content) > 0 and content[-1] == ""):
content.append(line)
continue
joined = "\n".join(content)
context = StageContext(current_directory=Path.cwd())
lexer = Lexer(joined, context)
parser = Parser.from_lexer(lexer)
parsed = parser.parse()
icontext = InterpreterContext(current_directory=Path.cwd())
ccontext = CheckerContext(current_directory=Path.cwd())
checker = Checker(parsed, ccontext)
for error in checker.check():
print(error)
if not checker.has_errors:
print("No errors found during typecheking")
interpreter = Interpreter(parsed, icontext)
pprint(interpreter.run())
content = []
if __name__ == "__main__":
# If none arguments are passed then invoke repl()
# Otherwise based on the argument passed start interpreting or compilation of passed file
import argparse
parser = argparse.ArgumentParser(description="Interpreter for the smol language")
parser.add_argument(
"run_type",
nargs="?",
choices=["repl", "r", "interpret", "i", "compile", "c", "check"],
help="Run type",
)
parser.add_argument("file", nargs="?", help="File to interpret", type=open)
parser.add_argument("--debug", "-d", action="store_true")
parser.add_argument("--no-checker", action="store_true")
parsed_args = parser.parse_args()
file_path: Path | None = (
Path(parsed_args.file.name).resolve() if parsed_args.file else None
)
smol_context = SmolContext(
parsed_args.file, file_path, parsed_args.debug, parsed_args.no_checker
)
match (parsed_args.file, parsed_args.run_type):
case (None, "repl" | "r" | None):
repl(smol_context)
case (None, _):
print("No file specified")
case (_, "interpret" | "i"):
interpret_file(smol_context)
case (_, "compile" | "c"):
compile_file(smol_context)
case (_, "check"):
check_file(smol_context)
case (_, _):
raise Exception("Invalid run_type")