-
Notifications
You must be signed in to change notification settings - Fork 1
/
parser.py
98 lines (74 loc) · 2.76 KB
/
parser.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
import re
from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
import parsimonious.exceptions
from datatypes import (
Number,
String,
Queue,
Boolean,
Block,
)
from identifier import Identifier
IncompleteParseError = parsimonious.exceptions.IncompleteParseError
VisitationError = parsimonious.exceptions.VisitationError
with open("grammar.peg") as f:
grammar = Grammar(f.read())
class Visitor(NodeVisitor):
def visit_program(self, node, visited_children):
return self._flatten(visited_children)
def visit_statements(self, node, visited_children):
return self._flatten(visited_children)
def visit_statement(self, node, visited_children):
assert len(visited_children) == 1
return visited_children[0]
def visit_command(self, node, visited_children):
assert len(visited_children) == 1
return Queue(visited_children)
def visit_string(self, node, visited_children):
# Drop the wrapping quotes
contents = node.text[1:-1]
# Unescape escaped quotes
literal = String(re.sub(r'\\["bfnrtv\\]', self._unescape_string, contents))
return Queue([literal])
def _unescape_string(self, match):
escape = match.group(0)
return {
r'\"': '"',
r'\b': "\b",
r'\f': "\f",
r'\n': "\n",
r'\r': "\r",
r'\t': "\t",
r'\v': "\v",
r'\\': "\\",
}.get(escape, escape)
def visit_number(self, node, visited_children):
literal = Number(int(node.text))
return Queue([literal])
def visit_boolean(self, node, visited_children):
literal = Boolean(node.text == "true")
return Queue([literal])
def visit_identifier(self, node, visited_children):
literal = Identifier(node.text)
return Queue([literal])
def visit_whitespace(self, node, visited_children):
return Queue([])
def visit_comment(self, node, visited_children):
return Queue([])
def visit_lbracket(self, node, visited_children):
return Queue([])
def visit_rbracket(self, node, visited_children):
return Queue([])
def visit_block(self, node, visited_children):
_lbr, *queues, _rbr = visited_children
return Queue([Block(self._flatten(queues).statements)])
def generic_visit(self, node, visited_children):
if node.expr_name == "":
return self._flatten(visited_children)
assert False, f"Missing visitor for node type: {node.expr_name}"
def _flatten(self, visited_children):
return Queue([stmt for queue in visited_children for stmt in queue.statements])
def parse(text):
tree = grammar.parse(text)
return Visitor().visit(tree)