-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathatomese_yacc.py
162 lines (135 loc) · 5.15 KB
/
atomese_yacc.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"""
START -> LIST_OF_TOP_LEVEL_ATOMS
LIST_OF_TOP_LEVEL_ATOMS -> TOP_LEVEL_ATOM
| LIST_OF_TOP_LEVEL_ATOMS TOP_LEVEL_ATOM
TOP_LEVEL_ATOM -> ATOM
ATOM -> NODE
| LINK
NODE -> ATOM_OPENNING ATOM_TYPE NODE_NAME ATOM_CLOSING
LINK -> ATOM_OPENNING ATOM_TYPE ATOM_LIST ATOM_CLOSING
| ATOM_OPENNING ATOM_TYPE STV_DEFINITION ATOM_LIST ATOM_CLOSING
STV_DEFINITION -> ATOM_OPENNING STV FLOAT FLOAT ATOM_CLOSING
ATOM_LIST -> ATOM
| ATOM_LIST ATOM
"""
from typing import List, Any, Optional
import ply.yacc as yacc
from das.atomese_lex import AtomeseLex
from das.metta_lex import BASIC_TYPE
from das.exceptions import AtomeseSyntaxError, UndefinedSymbolError
from das.expression_hasher import ExpressionHasher
from das.expression import Expression
from das.base_yacc import BaseYacc
class AtomeseYacc(BaseYacc):
### Parser rules ###
def p_START(self, p):
"""START : LIST_OF_TOP_LEVEL_ATOMS EOF
| EOF
|"""
p[0] = 'SUCCESS'
def p_LIST_OF_TOP_LEVEL_ATOMS_base(self, p):
"""LIST_OF_TOP_LEVEL_ATOMS : TOP_LEVEL_ATOM"""
p[0] = [p[1]]
if self.check_mode or not self.action_broker:
return
def p_LIST_OF_TOP_LEVEL_ATOMS_recursion(self, p):
"""LIST_OF_TOP_LEVEL_ATOMS : LIST_OF_TOP_LEVEL_ATOMS TOP_LEVEL_ATOM"""
p[0] = [*p[1], p[2]]
def p_TOP_LEVEL_ATOM(self, p):
"""TOP_LEVEL_ATOM : ATOM"""
atom = p[1]
p[0] = p[1]
if self.check_mode or not self.action_broker:
return
if atom.elements is not None:
atom.toplevel = True
self.action_broker.new_top_level_expression(atom)
def p_ATOM_node(self, p):
"""ATOM : NODE"""
p[0] = p[1]
def p_ATOM_link(self, p):
"""ATOM : LINK"""
p[0] = p[1]
def p_NODE(self, p):
"""NODE : ATOM_OPENNING ATOM_TYPE NODE_NAME ATOM_CLOSING"""
if self.check_mode or not self.action_broker:
p[0] = f"<{p[2]}: {p[3]}>"
return
node_type = p[2]
node_name = p[3]
if node_type not in self.types:
self.types.add(node_type)
expression = self._typedef(node_type, BASIC_TYPE)
expression.toplevel = True
self.action_broker.new_top_level_typedef_expression(expression)
terminal_name = f"{node_type}:{node_name}"
if terminal_name not in self.nodes:
self.nodes.add(terminal_name)
expression = self._typedef(terminal_name, node_type)
expression.toplevel = True
self.action_broker.new_top_level_typedef_expression(expression)
expression = self._new_terminal(terminal_name)
self.action_broker.new_terminal(expression)
else:
expression = self._new_terminal(terminal_name)
p[0] = expression
def p_STV_DEFINITION(self, p):
"""STV_DEFINITION : ATOM_OPENNING STV FLOAT FLOAT ATOM_CLOSING"""
pass
def p_LINK_no_stv(self, p):
"""LINK : ATOM_OPENNING ATOM_TYPE ATOM_LIST ATOM_CLOSING"""
if self.check_mode or not self.action_broker:
p[0] = f"<{p[2]}: {p[3]}>"
return
link_type = p[2]
targets = p[3]
expression = self._new_link(link_type, targets)
p[0] = expression
def p_LINK_stv(self, p):
"""LINK : ATOM_OPENNING ATOM_TYPE STV_DEFINITION ATOM_LIST ATOM_CLOSING"""
if self.check_mode or not self.action_broker:
p[0] = f"<{p[2]}: {p[4]}>"
return
link_type = p[2]
targets = p[4]
expression = self._new_link(link_type, targets)
p[0] = expression
def p_ATOM_LIST_base(self, p):
"""ATOM_LIST : ATOM"""
atom = p[1]
p[0] = [atom]
if self.check_mode or not self.action_broker:
return
if atom.elements is not None:
self.action_broker.new_expression(atom)
def p_ATOM_LIST_recursion(self, p):
"""ATOM_LIST : ATOM_LIST ATOM"""
atom = p[2]
p[0] = [*p[1], atom]
if self.check_mode or not self.action_broker:
return
if atom.elements is not None:
self.action_broker.new_expression(atom)
def p_error(self, p):
error = f"Syntax error in line {self.lexer.lineno} " + \
f"Current token: {p}"
raise AtomeseSyntaxError(error)
### End of parser rules ###
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.lex_wrap = AtomeseLex()
super().setup()
self.parser = yacc.yacc(module=self)
self.types = set()
self.nodes = set()
named_type_hash = self._get_named_type_hash(BASIC_TYPE)
self.parent_type[named_type_hash] = named_type_hash
def _new_link(self, link_type, targets):
if link_type not in self.types:
self.types.add(link_type)
expression = self._typedef(link_type, BASIC_TYPE)
expression.toplevel = True
self.action_broker.new_top_level_typedef_expression(expression)
head_expression = self._new_symbol(link_type)
expression = self._nested_expression([head_expression, *targets])
return expression