def _fold_constants(program: Node) -> bool: """Fold constants in a program. Returns True if constants were folded. """ assert program.kind == 'program' assignments = program.find(lambda node: node.kind == 'assignment') for asn in assignments: if _fold_assignment(asn): return True return False
def __init__(self, ident: str, params: Sequence[Node], return_type: str, body: Node): self.arity = len(params) self.param_types = [p.children[0].value for p in params] self.param_idents = [p.children[1].value for p in params] self.return_type = return_type self.body = body if len(set(self.param_idents)) < len(self.param_idents): raise YovecError('duplicate parameters') variables = body.find(lambda node: node.kind == 'variable') for var in variables: if var.value not in self.param_idents: raise YovecError('undefined variable: {}'.format(var.value)) calls = body.find(lambda node: node.kind == 'call') for call in calls: if call.children[0].value == ident: raise YovecError('recursion is not allowed')
def _propagate_constants(program: Node) -> bool: """Propagate constants in a program. Returns True if a constant was propagated. """ assert program.kind == 'program' variables = program.find(lambda node: node.kind == 'variable') for var in variables: replacement, delta = _propagate_var(program, var) if delta: var.parent.replace_child(var, replacement) # type: ignore return True return False
def _fold_assignment(assignment: Node) -> bool: """Fold constants in an assignment. Returns True if constants were folded.""" assert assignment.kind == 'assignment' numbers = assignment.find(lambda node: node.kind == 'number') for num in numbers: expr = num.parent for transform in Transform().functions: replacement, delta = transform(expr) if delta: expr.parent.replace_child(expr, replacement) # type: ignore return True return False
def _graph_deps(program: Node) -> Dict[str, Set[str]]: """Graph variable dependencies.""" assert program.kind == 'program' logger.debug('graphing variable dependencies') graph = {} assignments = program.find(lambda node: node.kind == 'assignment') for asn in assignments: variable = asn.children[0] expr = asn.children[1] unique = { v.value for v in expr.find(lambda node: node.kind == 'variable') } graph[variable.value] = unique return graph
def _propagate_var(program: Node, var: Node) -> Tuple[Node, bool]: """Propagate constants in a variable. Returns True if a constant was propagated. """ if var.parent.kind == 'assignment' and var.parent.children.index(var) == 0: #$ type: ignore # Found "A" in "let A = expr" return var, False assignments = program.find(lambda node: node.kind == 'assignment' and node.children[0].value == var.value) if len(assignments) == 0: # Found external variable; cannot propagate return var, False expr = assignments[0].children[1].clone() if expr.kind == 'variable': # Found assignment of single variable return expr, True elif len(expr.find(lambda node: node.kind == 'variable')) == 0: # Found assignment of constant expression return expr, True else: return var, False
def yolol_to_text(program: Node) -> str: """Format a YOLOL program as text.""" assert program.kind == 'program' assignments = program.find(lambda node: node.kind == 'assignment') formatted = [_format_assignment(a) for a in assignments] text = '' curr = [] for f in formatted: line = ' '.join(curr) if len(f) > 70: stderr.write('Warning: line exceeds 70 characters\n') text += '{}\n{}\n'.format(line, f) curr = [] elif len(line) + len(' ') + len(f) > 70: text += '{}\n'.format(line) curr = [f] else: curr.append(f) if len(curr) > 0: text += '{}\n'.format(' '.join(curr)) return text.strip('\n')