Exemple #1
0
def chain_comp(self, tree: TypeTree):
    symbol_to_data = {
        "<=": "less_equals",
        ">=": "greater_equals",
        "<": "less",
        ">": "greater",
    }

    # Separate expressions and comparison operators.
    expressions = tree.children[::2]
    comparisons = tree.children[1::2]

    # Generate comparison trees.
    comp_trees = [
        TypeTree(symbol_to_data[symbol], [a, b], tree.meta)
        for symbol, a, b in zip(comparisons, expressions[:-1], expressions[1:])
    ]

    # Build up nested tree.
    prev_tree = comp_trees[0]
    for comp_tree in comp_trees[1:]:
        prev_tree = TypeTree("logic_and", [prev_tree, comp_tree], tree.meta)

    # Override this node with last.
    tree.data = prev_tree.data
    tree.children = prev_tree.children

    self.visit(tree)
Exemple #2
0
    def __init__(self,
                 tree: TypeTree,
                 scope: Callable,
                 args=None,
                 stack_trace: Optional[List[TypeTree]] = None):
        self.scope = scope
        self.local_scope = dict()
        self.used = set()
        self.stack_trace: List[
            TypeTree] = [] if stack_trace is None else stack_trace

        if args is not None:
            assign(self, self.local_scope, args[0], args[1])

        if tree.data != "block":
            tree.children = [TypeTree(tree.data, tree.children, tree.meta)]
            tree.data = "block"

        tree.children[-1] = TypeTree("return_n", [tree.children[-1]],
                                     tree.meta)

        def ret(value_type):
            if tree.return_type is None:
                tree.return_type = value_type
            self.assert_(tree.return_type == value_type,
                         "block has different return types", tree)

        self.ret = ret

        self.visit_children(tree)  # sets tree.return_type
Exemple #3
0
def math_assign(self, tree: TypeTree):
    symbol = tree.children[0]
    expression = tree.children[1]

    # Make the current node an assign.
    operation = tree.data.replace("_assign", "")
    tree.data = "assign"

    # Make a child node with the math operation.
    tree.children[1] = TypeTree(operation, [symbol, expression], tree.meta)

    return self.visit(tree)
Exemple #4
0
    def string(self, tree: TypeTree):
        tree.data = "array"
        # Evaluate string using Python
        try:
            text = eval(tree.children[0])
        except SyntaxError as err:
            raise VolpeError(err.msg, tree, self.stack_trace)
        self.assert_(is_ascii(text), "strings can only have ascii characters",
                     tree)

        tree.children = []
        for eval_character in text:
            tree.children.append(
                TypeTree("character",
                         [Token("CHARACTER", "'" + eval_character + "'")],
                         tree.meta))
        self.visit_children(tree)
        return VolpeArray(char, len(tree.children))
Exemple #5
0
def parse_trees(file_path: str, imports: Dict):
    if file_path in imports:
        return

    with open(file_path) as vlp_file:
        try:
            tree = imports[file_path] = volpe_parser.parse(vlp_file.read())
        except UnexpectedEOF:
            raise VolpeError(
                "unexpected end of input (did you return from main?)")
        except UnexpectedCharacters as err:
            # Return cursor to start of file.
            vlp_file.seek(0)
            line = vlp_file.readlines()[err.line - 1]
            symbol = line[err.column - 1]
            # Print the line.
            error_message = f"unexpected symbol '{symbol}'"
            error_message += f"\n{err.line}| {line}"
            # Add the cursor.
            padding = " " * (len(str(err.line)) + err.column)
            error_message += f"\n{padding} ^"
            raise VolpeError(error_message)

    for subtree in imports[file_path].iter_subtrees():
        subtree.meta.file_path = file_path

        if subtree.data == "import_":
            directory = path.dirname(file_path)
            import_path = path.join(
                directory, *[child.value
                             for child in subtree.children]) + ".vlp"
            parse_trees(import_path, imports)

            obj_tree = TypeTree("object", [], subtree.meta)
            subtree.data = "func_call"
            subtree.children = [
                TypeTree("func", [obj_tree, imports[import_path]],
                         subtree.meta), obj_tree
            ]

    return tree
Exemple #6
0
def volpe_llvm(tree: TypeTree,
               verbose=False,
               more_verbose=False,
               console=False):
    if more_verbose:
        print(tree.pretty())

    arg_scope = {}

    def scope(name, local_tree: TypeTree):
        if name in arg_scope:
            return arg_scope[name]
        raise VolpeError(f"variable `{name}` not found", local_tree)

    AnnotateScope(tree, scope)

    if verbose:
        print(tree.pretty())

    module = ir.Module("program")
    module.func_count = itertools.count()

    run_func = ir.Function(
        module,
        ir.FunctionType(unknown, [unwrap(tree.return_type).as_pointer()]),
        "run")
    with build_func(run_func) as (b, args):
        arg_scope = {}

        def scope(name):
            return arg_scope[name]

        def ret(value):
            b.store(value, args[0], 8)
            b.ret_void()

        LLVMScope(b, tree, scope, ret, None)

    return str(module)
Exemple #7
0
def assign(self, scope: dict, tree: TypeTree, value):
    if tree.data == "object":
        self.assert_(isinstance(value, VolpeObject),
                     "can only destructure object", tree)
        self.assert_(
            len(tree.children) == len(value.type_dict),
            "only full deconstruction is allowed", tree)
        used = set()
        for i, child in enumerate(tree.children):
            key, attribute = get_obj_key_value(child, i)
            self.assert_(key in value.type_dict,
                         f"object doesn't have attribute {key}", child)
            self.assert_(key not in used, f"{key} has already been used",
                         child)
            used.add(key)
            assign(self, scope, attribute, value.type_dict[key])

    elif tree.data == "attribute":
        self.assert_(
            self.visit(tree) == value, "wrong type in attribute assignment",
            tree)

    elif tree.data == "array":
        self.assert_(isinstance(value, VolpeArray),
                     "can only destructure array", tree)
        self.assert_(value.count == len(tree.children),
                     "array has wrong length", tree)
        for child in tree.children:
            assign(self, scope, child, value.element)

    elif tree.data == "array_index":
        self.assert_(
            self.visit(tree) == value, "wrong type in array assignment", tree)

    else:
        self.assert_(tree.data == "symbol", f"cannot assign to {tree.data}",
                     tree)
        scope[tree.children[0].value] = value

    tree.return_type = value
Exemple #8
0
 def escaped_character(tree: TypeTree):
     # let Python parse the escaped character (guaranteed ascii by lark)
     evaluated = eval(f"{tree.children[0]}")
     return tree.return_type(ord(evaluated))
Exemple #9
0
 def character(tree: TypeTree):
     return tree.return_type(ord(tree.children[0].value[1]))
Exemple #10
0
 def integer(tree: TypeTree):
     return tree.return_type(int(tree.children[0].value))
Exemple #11
0
 def func(self, tree: TypeTree):
     tree.children = [TypeTree("inst", tree.children, tree.meta)]
     tree.instances = dict()
     return VolpeClosure(tree=tree, scope=self.get_scope())
Exemple #12
0
 def visit(self, tree: TypeTree):
     tree.return_type = getattr(self, tree.data)(tree)
     if tree.return_type is None:
         tree.return_type = int1
     return tree.return_type
Exemple #13
0
 def if_then(self, tree: TypeTree):
     tree.data = "implication"
     tree.children[1] = TypeTree("return_n", [tree.children[1]], tree.meta)
     return self.visit(tree)
Exemple #14
0
 def constant_array_like(self, tree: TypeTree):
     tree.data = "constant_array"
     element_type, parent_array = self.visit_children(tree)
     self.assert_(isinstance(parent_array, VolpeArray),
                  "can only get size of arrays", tree)
     return VolpeArray(element_type, parent_array.count)