refactor specfiles/scripts
[libfirm] / scripts / spec_util.py
1 import sys
2 import imp
3
4 abstracts = set()
5 def abstract(cls):
6         abstracts.add(cls)
7         return cls
8 def isAbstract(nodetype):
9         return nodetype in abstracts
10
11 def op(cls):
12         cls.__is_firm_op = True
13         return cls
14 def isOp(nodetype):
15         return hasattr(nodetype, "__is_firm_op")
16
17 def is_dynamic_pinned(node):
18         return node.pinned in ["memory", "exception"]
19
20 def is_fragile(node):
21         return hasattr(node, "flags") and "fragile" in node.flags
22
23 def inout_contains(l, name):
24         for entry in l:
25                 if entry[0] == name:
26                         return True
27         return False
28
29 def verify_node(node):
30         if not hasattr(node, "pinned"):
31                 print "%s: NO PINNED SET" % node.name
32         elif node.pinned not in ["yes", "no", "memory", "exception"]:
33                 print "%s: UNKNOWN PINNED MODE: %s" % (node.name, node.pinned)
34
35         if not hasattr(node, "flags"):
36                 if not isAbstract(node):
37                         print "WARNING: no flags specified for %s\n" % node.name
38         elif type(node.flags) != list:
39                 print "ERROR: flags of %s not a list" % node.name
40
41         if hasattr(node, "pinned_init") and not is_dynamic_pinned(node):
42                 print "ERROR: node %s has pinned_init attribute but is not marked as dynamically pinned" % node.name
43         if hasattr(node, "flags") and "uses_memory" in node.flags:
44                 if not inout_contains(node.ins, "mem"):
45                         print "ERROR: memory op %s needs an input named 'mem'" % node.name
46         if is_fragile(node):
47                 if not is_dynamic_pinned(node):
48                         print "ERROR: fragile node %s must be dynamically pinned" % node.name
49                 if not hasattr(node, "throws_init"):
50                         print "ERROR: fragile node %s needs a throws_init attribute" % node.name
51                 if not inout_contains(node.outs, "X_regular"):
52                         print "ERROR: fragile node %s needs an output named 'X_regular'" % node.name
53                 if not inout_contains(node.outs, "X_except"):
54                         print "ERROR: fragile node %s needs an output named 'X_except'" % node.name
55         else:
56                 if hasattr(node, "throws_init"):
57                         print "ERROR: throws_init only makes sense for fragile nodes"
58
59
60 def setldefault(node, attr, val):
61         # Don't use hasattr, as these things should not be inherited
62         if attr not in node.__dict__:
63                 setattr(node, attr, val)
64
65 def setdefault(node, attr, val):
66         # Don't use hasattr, as these things should not be inherited
67         if not hasattr(node, attr):
68                 setattr(node, attr, val)
69
70 def setnodedefaults(node):
71         setldefault(node, "name", node.__name__)
72         if isAbstract(node):
73                 return
74
75         setdefault(node, "ins", [])
76         setdefault(node, "arity", len(node.ins))
77         setdefault(node, "attrs", [])
78         setdefault(node, "constructor_args", [])
79         setdefault(node, "customSerializer", False)
80         if hasattr(node, "__doc__"):
81                 node.doc = trim_docstring(node.__doc__)
82         else:
83                 node.doc = ""
84         if hasattr(node, "outs"):
85                 node.mode = "mode_T"
86
87 def load_spec(filename):
88         module = imp.load_source('spec', filename)
89         nodes = []
90         for x in module.__dict__.values():
91                 if not isOp(x):
92                         continue
93                 setnodedefaults(x)
94                 verify_node(x)
95                 nodes.append(x)
96         nodes.sort(key=lambda x: x.name)
97         module.nodes = nodes
98         if len(nodes) == 0:
99                 print "Warning: No nodes found in spec file '%s'" % filename
100         if not hasattr(module, "name"):
101                 print "Warning: No name specified in file '%s'" % filename
102         return module
103
104 def trim_docstring(docstring):
105     if not docstring:
106         return ''
107     # Convert tabs to spaces (following the normal Python rules)
108     # and split into a list of lines:
109     lines = docstring.expandtabs().splitlines()
110     # Determine minimum indentation (first line doesn't count):
111     indent = sys.maxint
112     for line in lines[1:]:
113         stripped = line.lstrip()
114         if stripped:
115             indent = min(indent, len(line) - len(stripped))
116     # Remove indentation (first line is special):
117     trimmed = [lines[0].strip()]
118     if indent < sys.maxint:
119         for line in lines[1:]:
120             trimmed.append(line[indent:].rstrip())
121     # Strip off trailing and leading blank lines:
122     while trimmed and not trimmed[-1]:
123         trimmed.pop()
124     while trimmed and not trimmed[0]:
125         trimmed.pop(0)
126     # Return a single string:
127     return '\n'.join(trimmed)