def preprocess_var_decls(tree): """Eliminate global variable declarations of the form S = Set() M = Map() and return a list of pairs of variables names and type names (i.e., 'Set' or 'Map'). """ assert isinstance(tree, P.Module) pat = P.Assign([P.Name(P.PatVar('_VAR'), P.Wildcard())], P.Call(P.Name(P.PatVar('_KIND'), P.Load()), [], [], None, None)) decls = OrderedSet() body = [] changed = False for stmt in tree.body: match = P.match(pat, stmt) if match is not None: var, kind = match['_VAR'], match['_KIND'] if kind not in ['Set', 'Map']: raise L.ProgramError( 'Unknown declaration initializer {}'.format(kind)) decls.add((var, kind)) changed = True else: body.append(stmt) if changed: tree = tree._replace(body=body) return tree, list(decls)
def visit_Import(self, node): pat = P.Import([P.alias("incoq.runtime", P.PatVar("_ALIAS"))]) match = P.match(pat, node) if match is None: return node # Remove the import. Record the alias to remove its uses. if match["_ALIAS"] is not None: qual = P.Name(match["_ALIAS"], P.Load()) self.quals.add(qual) return []
def visit_Compare(self, node): node = self.generic_visit(node) # Translate multiple comparisons into conjunctions of # each individual comparison. assert len(node.ops) == len(node.comparators) > 0 if len(node.ops) > 1: conds = [] values = [node.left] + list(node.comparators) for i in range(len(values) - 1): conds.append( P.Compare(values[i], [node.ops[i]], [values[i + 1]])) node = P.BoolOp(P.And(), conds) return node
def handle_fs_SYMCONFIG(self, _func, symbol: P.Str, **kargs): name = symbol.s d = {} for k, v in kargs.items(): d[k] = P.literal_eval(v) self.info.symconfig_info.append((name, d)) return ()
def preprocess_var_decls(tree): """Eliminate global variable declarations of the form S = Set() M = Map() and return a list of pairs of variables names and type names (i.e., 'Set' or 'Map'). """ assert isinstance(tree, P.Module) pat = P.Assign( [P.Name(P.PatVar("_VAR"), P.Wildcard())], P.Call(P.Name(P.PatVar("_KIND"), P.Load()), [], [], None, None) ) decls = OrderedSet() body = [] changed = False for stmt in tree.body: match = P.match(pat, stmt) if match is not None: var, kind = match["_VAR"], match["_KIND"] if kind not in ["Set", "Map"]: raise L.ProgramError("Unknown declaration initializer {}".format(kind)) decls.add((var, kind)) changed = True else: body.append(stmt) if changed: tree = tree._replace(body=body) return tree, list(decls)
def visit_Expr(self, node): match = P.match(self.pat, node) if match is not None: query = P.Parser.pe(node.value.args[0].s) call = node.value._replace(args=[query]) node = node._replace(value=call) return node
def visit_Assign(self, node): node = self.generic_visit(node) # Translate multiple assignments as a single statement # (e.g. "a = b = c") into sequential single assignments. if len(node.targets) > 1: stmts = [] values = list(node.targets) + [node.value] for lhs, rhs in reversed(list(pairs(values))): rhs_load = P.ContextSetter.run(rhs, P.Load) stmts.append(P.Assign([lhs], rhs_load)) node = stmts return node
def visit_Import(self, node): pat = P.Import([P.alias('incoq.runtime', P.PatVar('_ALIAS'))]) match = P.match(pat, node) if match is None: return node # Remove the import. Record the alias to remove its uses. if match['_ALIAS'] is not None: qual = P.Name(match['_ALIAS'], P.Load()) self.quals.add(qual) return []
def postprocess_var_decls(tree, decls): """Prepend global variable declarations to the program. Each given declaration is a triple of a variable name, type name (e.g., 'Set' or 'Map'), and a declaration comment string. """ assert isinstance(tree, P.Module) header = () for var_name, type_name, comment in decls: header += P.Parser.pc(''' COMMENT(_S) _VAR = _TYPE() ''', subst={ '_S': P.Str(comment), '_VAR': var_name, '_TYPE': type_name }) tree = tree._replace(body=header + tree.body) return tree
def visit_Attribute(self, node): # Note: As written, this will remove all aliases, not just the # prefix alias. That is, if A is an alias for the runtime in # quals, this will rewrite A.A...A.foo as foo. This shouldn't # be a problem because we shouldn't see aliases chained in this # manner. node = self.generic_visit(node) # Check prefix against each alias and the fully qualified path. # If none match, no change. for qual in self.quals: pat = P.Attribute(qual, P.PatVar("_ATTR"), P.Load()) match = P.match(pat, node) if match is not None: break else: return node return P.Name(match["_ATTR"], P.Load())
class QueryDirectiveRewriter(P.NodeTransformer): """Take QUERY(<source>, **<kargs>) directives and replace the first argument with the corresponding parsed Python AST. """ # We'll use NodeTransformer rather than MacroProcessor because # MacroProcessor makes it hard to reconstruct the node. pat = P.Expr( P.Call(P.Name('QUERY', P.Load()), [P.Str(P.PatVar('_source'))], P.PatVar('_keywords'), None, None)) def visit_Expr(self, node): match = P.match(self.pat, node) if match is not None: query = P.Parser.pe(node.value.args[0].s) call = node.value._replace(args=[query]) node = node._replace(value=call) return node
def visit_Attribute(self, node): # Note: As written, this will remove all aliases, not just the # prefix alias. That is, if A is an alias for the runtime in # quals, this will rewrite A.A...A.foo as foo. This shouldn't # be a problem because we shouldn't see aliases chained in this # manner. node = self.generic_visit(node) # Check prefix against each alias and the fully qualified path. # If none match, no change. for qual in self.quals: pat = P.Attribute(qual, P.PatVar('_ATTR'), P.Load()) match = P.match(pat, node) if match is not None: break else: return node return P.Name(match['_ATTR'], P.Load())
def suite_helper(self, node): node = self.generic_visit(node) if len(node.body) == 0: node = node._replace(body=[P.Pass()]) return node
def handle_fs_QUERY(self, _func, query, **kargs): d = {} for k, v in kargs.items(): d[k] = P.literal_eval(v) self.info.query_info.append((query, d)) return ()
def handle_fs_CONFIG(self, _func, **kargs): d = {} for k, v in kargs.items(): d[k] = P.literal_eval(v) self.info.config_info.append(d) return ()
def postprocess_header(tree, header): """Add comment lines for each string in header.""" header = tuple( P.Parser.ps('COMMENT(_S)', subst={'_S': P.Str(line)}) for line in header) return tree._replace(body=header + tree.body)