Beispiel #1
0
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
Beispiel #2
0
    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')
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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')