-
Notifications
You must be signed in to change notification settings - Fork 0
/
pcb_operator_convert.py
111 lines (87 loc) · 4.61 KB
/
pcb_operator_convert.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
import asp.codegen.ast_tools as ast_tools
import asp.codegen.cpp_ast as cpp_ast
# this should get pulled into Asp
class CppAttribute(cpp_ast.Generable):
def __init__(self, value, attr):
self._fields = ["value", "attr"]
self.value = value
self.attr = attr
def generate(self, with_semicolon=False):
yield "%s.%s" % (self.value, self.attr)
class CppClass(cpp_ast.Generable):
def __init__(self, classname, body, parentclass=None):
self.fields = ["classname", "parentclass"]
self.classname = classname
self.parentclass = parentclass
self.body = body
def generate(self, with_semicolon=True):
decl = "class %s " % self.classname
if self.parentclass:
decl += ": public %s" % self.parentclass
yield decl + "{\n"
# everything is public, for now
yield "public:\n"
for line in self.body.generate():
yield line
yield "};\n"
class PcbOperatorConvert(ast_tools.NodeTransformer):
"""
This class is used to convert from a semantic model (expressed in terms of nodes in pcb_operator_sm)
to a C++ AST that can then be further transformed or directly generated.
"""
def convert(self, sm):
"""
Entry point. Call this on the semantic model. Returns the C++ AST.
"""
return self.visit(sm)
def visit_UnaryPredicate(self, node):
#FIXME: this should actually have const in the signature for the input, but doesn't look like CodePy
# supports this properly
#
# the proper signature should be bool foo (const T& x) const
return cpp_ast.FunctionBody(cpp_ast.FunctionDeclaration(cpp_ast.Value("bool", "myfunc"),
[cpp_ast.Reference(cpp_ast.Value("const double", self.visit(node.input)))]),
cpp_ast.Block(contents=[self.visit(node.body)]))
def visit_BinaryPredicate(self, node):
#FIXME: same problem as UnaryPredicate
return CppClass("MyBinaryPredicate",
cpp_ast.FunctionBody(cpp_ast.Template("class T", cpp_ast.FunctionDeclaration(cpp_ast.Value("bool", "call"),
[cpp_ast.Reference(cpp_ast.Value("T", self.visit(x))) for x in node.inputs])),
cpp_ast.Block(contents=[self.visit(node.body)])),
"BinaryPredicateObj")
def visit_UnaryFunction(self, node):
# FIXME: have to worry about type specialization on return & passed-in types
return CppClass("MyUnaryFunction",
cpp_ast.FunctionBody(cpp_ast.Template("class T", cpp_ast.FunctionDeclaration(cpp_ast.Value("T", "call"),
[cpp_ast.Reference(cpp_ast.Value("T", self.visit(node.input)))])),
cpp_ast.Block(contents=[self.visit(node.body)])),
"UnaryFunctionObj")
def visit_BoolReturn(self, node):
return cpp_ast.ReturnStatement(self.visit(node.value))
def visit_FunctionReturn(self, node):
#FIXME: is this correct?
return cpp_ast.ReturnStatement(cpp_ast.TypeCast(cpp_ast.Value("T", ""), cpp_ast.Line("*(new "+str(self.visit(node.ret_type))+")")))
def visit_BoolConstant(self, node):
if node.value:
return "true"
else:
return "false"
def visit_Constant(self, node):
if isinstance(node.value, int):
return cpp_ast.CNumber(node.value)
else:
return cpp_ast.CName(node.value)
def visit_IfExp(self, node):
return cpp_ast.IfConv(self.visit(node.test), self.visit(node.body), else_=self.visit(node.orelse))
def visit_Compare(self, node):
import ast
comparator_map = {ast.Eq:"==", ast.NotEq:"!=", ast.Lt:"<", ast.LtE:"<=", ast.Gt:">", ast.GtE:">="}
return cpp_ast.Compare(self.visit(node.left), comparator_map[node.op.__class__], self.visit(node.right))
def visit_BinaryOp(self, node):
import ast
binop_map = {ast.Add:"+", ast.Sub:"-"}
return cpp_ast.BinOp(self.visit(node.left), binop_map[node.op.__class__], self.visit(node.right))
def visit_Attribute(self, node):
return CppAttribute(self.visit(node.value), self.visit(node.attr))
def visit_Identifier(self, node):
return cpp_ast.CName(node.name)