-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast_rpy.py
132 lines (104 loc) · 2.91 KB
/
ast_rpy.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
INTEND_TYPE = ' '
INTEND_COUNT = 4
class Element:
name = None
value = None
type = None
child = None
arg0 = None
arg1 = None
indent = 0
class Str(Element):
def __init__(self, value):
self.value = value if value is not None else ''
def __str__(self):
return raw_str(self.value)
class Text(Element):
def __init__(self, text, character=None):
self.value = text
self.arg0 = character
class Statement(Element):
def __init__(self, units, value=None):
self.name = [units] if isinstance(units, str) else units
self.value = value
class Assign(Element):
def __init__(self, name, type_, child):
self.name = name
self.type = type_
self.child = [child] if isinstance(child, Element) else child
class Block(Element):
def __init__(self, type_, name, child, indent=0):
self.type = type_
self.name = name
self.child = child
self.intend = indent
class Func(Element):
def __init__(self, name, child):
self.name = name
self.child = [child] if isinstance(child, Element) else child
def raw_str(string):
return f"'{string}'"
def idt(level):
"""
Spawn indent
:param level:
:return:
"""
if level is None:
return ''
return INTEND_TYPE * INTEND_COUNT * level
def stmt(*e):
return ' '.join([str(x) for x in e if x is not None])
def ast2rpy(ast_map, end='\n'):
"""
Normal AST parser
:param end:
:param ast_map:
:return:
"""
if type(ast_map) == Block:
return block2rpy(ast_map)
else:
return '\n'.join(_ast2rpy(x) for x in ast_map) + end
def block2rpy(block):
"""
Block parser
:param block:
:return:
"""
rpy_script = ''
rpy_script += f'{idt(block.indent)}{block.type} {block.name}:\n'
if block.child is not None:
for x in block.child:
x.indent += 1
rpy_script += ast2rpy(block.child, end='')
return rpy_script
def _ast2rpy(ast_map: list):
"""
AST parser for non newline elements
:param ast_map:
:return:
"""
if isinstance(ast_map, Element):
ast_map = [ast_map]
elif ast_map is None:
return ''
elif type(ast_map) == str:
return raw_str(ast_map)
rpy_script = ''
for e in ast_map:
tp = type(e)
if tp == Str:
rpy_script += Str.value
elif tp == Statement:
rpy_script += stmt(f"{idt(e.indent)}{' '.join(e.name)}", e.value)
elif tp == Func:
rpy_script += f"{idt(e.indent)}{e.name}({_ast2rpy(e.child)})"
elif tp == Assign:
rpy_script += f"{idt(e.indent)}{e.type} {e.name} = {_ast2rpy(e.child)}"
elif tp == Block:
if e.child:
rpy_script += block2rpy(e)
elif tp == Text:
rpy_script += idt(e.indent) + stmt(e.arg0, raw_str(e.value))
return rpy_script