This repository has been archived by the owner on Apr 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mlang.py
118 lines (88 loc) · 3.12 KB
/
mlang.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
import click
from tabulate import tabulate
from compiler.utils import CompilerError
def _echo_error(err):
click.echo(click.style(str(err), fg='red'), err=True)
@click.group()
def cli():
pass
@cli.command('scanner', short_help='Display table of tokens')
@click.argument('file', type=click.File('r'))
def scanner(file):
""" Displays result of processing given fine by scanner in form of table of tokens """
from compiler.scanner import MScanner
# tokenize
try:
tokens = MScanner().tokenize(file.read())
except CompilerError as err:
return _echo_error(err)
# display table
click.echo(tabulate(
[(t.lineno, t.columnno, t.type, t.value) for t in tokens],
headers=("row", "col", "type", "value"),
tablefmt="fancy_grid"
))
@cli.command('parser', short_help='Run parser on given file')
@click.argument('file', type=click.File('r'))
def parser(file):
""" Runs parser on given file and displays potential error """
from compiler.parser import MParser
from compiler.scanner import MLexer
# parses file
try:
MParser().parse(file.read(), lexer=MLexer())
except CompilerError as err:
return _echo_error(err)
@cli.command('ast', short_help='Display AST tree')
@click.argument('file', type=click.File('r'))
def ast(file):
""" Displays AST tree that represents parser file """
from compiler.parser import MParser
from compiler.scanner import MLexer
from compiler.printer import ASTPrinter
# parse file
try:
root = MParser().parse(file.read(), lexer=MLexer(), tracking=True)
except CompilerError as err:
return _echo_error(err)
# print tree
click.echo(ASTPrinter().generate(root))
@cli.command('types', short_help='Performs type check')
@click.argument('file', type=click.File('r'))
def types(file):
""" Performs type check and displays possible errors """
from compiler.types import TypeChecker
from compiler.parser import MParser
from compiler.scanner import MLexer
# parse file
try:
root = MParser().parse(file.read(), lexer=MLexer(), tracking=True)
except CompilerError as err:
return _echo_error(err)
# check types and collect errors
checker = TypeChecker(collect_errors=True)
checker.check(root)
# print errors
for err in checker.errors:
_echo_error(err)
@cli.command('execute', short_help='Executes program')
@click.argument('file', type=click.File('r'))
def execute(file):
""" Performs parsing, scanning, type check and execution """
from compiler.parser import MParser
from compiler.scanner import MLexer
from compiler.types import TypeChecker
from compiler.interpreter import Interpreter
try:
# parse file
root = MParser().parse(file.read(), lexer=MLexer(), tracking=True)
# check types
TypeChecker().check(root)
# execute
result = Interpreter().execute_with_return(root)
except CompilerError as err:
return _echo_error(err)
if result is not None:
click.echo(f"Execution returned: {result}")
if __name__ == '__main__':
cli()