Ejemplo n.º 1
0
    def visitMath(self, ctx: BSParser.MathContext):
        deff = self.visitVariableDefinition(ctx.variableDefinition())
        symbol = Symbol(deff['name'], self.scope_stack[-1],
                        ChemTypeResolver.numbers())

        for use in ctx.primary():
            var = self.visitPrimary(use)

            # This places any constants into the global symbol table.
            # By doing this, it makes it significantly easier to handle
            # arithmetic later in the compilation process.
            if 'value' in var.keys() and not self.symbol_table.get_global(
                    var['name']):
                globalz = Symbol(var['name'], 'global',
                                 ChemTypeResolver.numbers())
                globalz.value = Number(var['name'], 1, var['value'])
                self.symbol_table.add_global(globalz)

            if not ChemTypeResolver.is_number_in_set(var['types']):
                local = self.symbol_table.get_local(var['name'])
                if not local:
                    raise UndefinedVariable("{} is not defined.".format(
                        var['name']))
                local.types.update(ChemTypeResolver.numbers())
                if ChemTypes.UNKNOWN in local.types:
                    local.types.remove(ChemTypes.UNKNOWN)
                self.symbol_table.update_symbol(local)

        self.symbol_table.add_local(symbol)

        return None
Ejemplo n.º 2
0
 def visitNumberAssignment(self, ctx: BSParser.NumberAssignmentContext):
     deff = self.visitVariableDefinition(ctx.variableDefinition())
     symbol = Symbol(deff['name'], self.scope_stack[-1],
                     ChemTypeResolver.numbers())
     self.symbol_table.add_local(symbol)
     # Yes, this is assigning value to something,
     # But this is a constant.  So we know all
     # of the values up front.  This also makes
     # the IRVisitor easier to work with.
     value = self.visitLiteral(ctx.literal())
     const = Symbol('CONST_{}'.format(value), 'global',
                    ChemTypeResolver.numbers())
     const.value = Number('CONST_{}'.format(value), 1, value)
     self.symbol_table.add_global(const)
Ejemplo n.º 3
0
    def visitRepeat(self, ctx: BSParser.RepeatContext):
        # 'repeat value times' is translated in the IR as while (value > 0), with a decrement
        #   appended to the end of the expression block; hence,
        #    to ease translation later, we add a global for const(0) and const(1)
        if not self.symbol_table.get_global('CONST_0'):
            globalz = Symbol('CONST_0', 'global', ChemTypeResolver.numbers())
            globalz.value = Number('CONST_0', 1, 0)
            self.symbol_table.add_global(globalz)

        if not self.symbol_table.get_global('CONST_1'):
            globalz = Symbol('CONST_1', 'global', ChemTypeResolver.numbers())
            globalz.value = Number('CONST_1', 1, 1)
            self.symbol_table.add_global(globalz)

        self.visitChildren(ctx)
Ejemplo n.º 4
0
    def visitBinops(self, ctx: BSParser.BinopsContext):
        op1 = self.visitPrimary(ctx.primary(0))
        op2 = self.visitPrimary(ctx.primary(1))

        # This places any constants into the global symbol table.
        # By doing this, it makes it significantly easier to handle
        # arithmetic later in the compilation process.
        if 'value' in op1.keys() and not self.symbol_table.get_global(
                op1['name']):
            globalz = Symbol(op1['name'], 'global', ChemTypeResolver.numbers())
            globalz.value = Number(op1['name'], 1, op1['value'])
            self.symbol_table.add_global(globalz)
        if 'value' in op2.keys() and not self.symbol_table.get_global(
                op2['name']):
            globalz = Symbol(op2['name'], 'global', ChemTypeResolver.numbers())
            globalz.value = Number(op2['name'], 1, op2['value'])
            self.symbol_table.add_global(globalz)
Ejemplo n.º 5
0
 def visitPrimary(self, ctx: BSParser.PrimaryContext):
     if ctx.variable():
         primary = self.visitVariable(ctx.variable())
     else:
         value = self.visitLiteral(ctx.literal())
         # It's a constant, thus, the size must be 1 and index 0.
         primary = {
             'name': "{}{}".format(self.const, value),
             "index": 0,
             'value': value,
             'types': ChemTypeResolver.numbers()
         }
     return primary
Ejemplo n.º 6
0
    def visitReturnStatement(self, ctx: BSParser.ReturnStatementContext):
        # It's either a primary or a method call
        types = set()
        if ctx.primary():
            var = self.visitPrimary(ctx.primary())
            local = self.symbol_table.get_local(var['name'],
                                                self.scope_stack[-1])
            # If we don't have a local, this is a constant.
            if local:
                types = self.symbol_table.get_local(var['name']).types
            else:
                types = ChemTypeResolver.numbers()
        elif ctx.methodCall():
            method_name, args = self.visitMethodCall(ctx.methodCall())
            types = self.symbol_table.functions[method_name].types
        else:
            raise UnsupportedOperation(
                "Only method calls or values are returnable.")

        return types
Ejemplo n.º 7
0
 def visitDetect(self, ctx: BSParser.DetectContext):
     deff = self.visitVariableDefinition(ctx.variableDefinition())
     self.symbol_table.add_local(
         Symbol(deff['name'], self.scope_stack[-1],
                ChemTypeResolver.numbers()))
     use = self.visitVariable(ctx.variable())
     var = self.symbol_table.get_local(use['name'])
     if not var:
         raise UndefinedVariable("{} is not defined.".format(use['name']))
     module = self.symbol_table.get_global(ctx.IDENTIFIER().__str__())
     if not module:
         raise UndefinedVariable(
             "{} isn't declared in the manifest.".format(
                 ctx.IDENTIFIER().__str__()))
     if ChemTypes.MODULE not in module.types:
         raise UndefinedVariable(
             "There is no module named {} declared in the manifest.".format(
                 module.name))
     if not ChemTypeResolver.is_mat_in_set(var.types):
         var.types.add(ChemTypes.MAT)
         self.symbol_table.update_symbol(var)
     return None
Ejemplo n.º 8
0
    def visitRepeat(self, ctx: BSParser.RepeatContext):
        # get the (statically defined!) repeat value and add to local symbol table
        value = self.visitLiteral(ctx)
        val = {
            'name': "REPEAT_{}".format(value),
            "index": 0,
            'value': value,
            'types': ChemTypeResolver.numbers()
        }

        if 'value' in val.keys() and not self.symbol_table.get_local(
                val['name']):
            localz = Symbol(val['name'], 'global', ChemTypeResolver.numbers())
            localz.value = Number(val['name'], 1, val['value'])
            self.symbol_table.add_local(localz)

        # finished with this block
        self.functions[self.scope_stack[-1]]['blocks'][
            self.current_block.nid] = self.current_block

        # insert header block for the conditional
        header_block = BasicBlock()
        header_label = Label("bsbbr_{}_h".format(header_block.nid))
        self.labels[header_label.name] = header_block.nid
        header_block.add(header_label)
        self.graph.add_node(header_block.nid,
                            function=self.scope_stack[-1],
                            label=header_label.label)
        self.functions[self.scope_stack[-1]]['blocks'][
            header_block.nid] = header_block
        self.graph.add_edge(self.current_block.nid, header_block.nid)

        zero = self.symbol_table.get_global('CONST_0')
        op = BinaryOp(left={
            'name': val['name'],
            'offset': 0,
            'size': 1,
            'var': self.symbol_table.get_local(val['name'])
        },
                      right={
                          'name': zero.name,
                          'offset': 0,
                          'size': 1,
                          'var': zero
                      },
                      op=RelationalOps.GT)
        condition = Conditional(
            RelationalOps.GT, op.left,
            op.right)  # Number('Constant_{}'.format(0), 1, 0))
        header_block.add(condition)

        self.control_stack.append(header_block)

        # set up the true block
        true_block = BasicBlock()
        true_label = Label("bsbbr_{}_t".format(true_block.nid))
        self.labels[true_label.name] = true_block.nid
        true_block.add(true_label)
        self.graph.add_node(true_block.nid, function=self.scope_stack[-1])
        self.functions[self.scope_stack[-1]]['blocks'][
            true_block.nid] = true_block
        condition.true_branch = true_label
        self.graph.add_edge(header_block.nid, true_block.nid)

        self.current_block = true_block
        self.visitBlockStatement(ctx.blockStatement())

        # repeat is translated to a while loop as: while (exp > 0);
        # hence, we update exp by decrementing.
        one = self.symbol_table.get_global('CONST_1')

        ir = Math(
            {
                'name': val['name'],
                'offset': 0,
                'size': 1,
                'var': self.symbol_table.get_local(val['name'])
            }, {
                'name': val['name'],
                'offset': 0,
                'size': 1,
                'var': self.symbol_table.get_local(val['name'])
            }, {
                'name': one.name,
                'offset': 0,
                'size': 1,
                'var': one
            }, BinaryOps.SUBTRACT)

        self.current_block.add(ir)

        # the block statement may contain nested loops
        # If so, the current block is the last false block created for the inner-most loop
        #    otherwise, the current block is the true_block created above
        # Either way, we can pop the control stack to find where to place the back edge
        #   and immediately make the back edge (from 'current block' to the parent
        parent_block = self.control_stack.pop()
        self.graph.add_edge(self.current_block.nid, parent_block.nid)

        # we now deal with the false branch
        false_block = BasicBlock()

        false_label = Label("bsbbr_{}_f".format(false_block.nid))
        self.labels[false_label.name] = false_block.nid
        false_block.add(false_label)
        condition.false_branch = false_label
        self.graph.add_edge(header_block.nid, false_block.nid)
        # We are done, so we need to handle the book keeping for
        # next basic block generation.
        self.graph.add_node(false_block.nid, function=self.scope_stack[-1])
        self.functions[self.scope_stack[-1]]['blocks'][
            false_block.nid] = false_block

        self.current_block = false_block

        return NOP()
Ejemplo n.º 9
0
    def build_declares(self):
        if self.types_used == TypesUsed.COMPLEX:
            types = ChemTypeResolver._available_types
        else:
            types = ChemTypeResolver._naive_types
            types.add(ChemTypes.UNKNOWN)

        declares = ""
        defines = ""
        asserts = ""

        for name, var in self.symbol_table.globals.items():
            """
            Declare the constants for all global variables.
            """
            if ChemTypes.UNKNOWN in var.types:
                var.types.remove(ChemTypes.UNKNOWN)
            if ChemTypes.INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION in var.types:
                var.types.remove(
                    ChemTypes.INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION)

            declares += f"; Declaring constants for: {self.get_smt_name(var).upper()}{self.nl}"
            for enum in types:
                declares += f"(declare-const {self.get_smt_name(var, ChemTypes(enum))} Bool){self.nl}"
            declares += self.nl
            defines += f"; Defining the assignment of: {self.get_smt_name(var).upper()}{self.nl}"
            for t in var.types:
                """
                Now we actually state the typing assignment of each variable.
                """
                defines += "(assert (= {} true)){}".format(
                    self.get_smt_name(var, t), self.nl)

            if self.types_used == TypesUsed.SIMPLE:
                """
                If it's naive, then make sure that unknown is false.
                In other words, we must have a nat/real/mat type.
                """
                defines += "; Ensure that {} is a not unknown type{}".format(
                    self.get_smt_name(var).upper(), self.nl)
                defines += "(assert (= {} false)){}".format(
                    self.get_smt_name(var, ChemTypes.UNKNOWN), self.nl)
        for name, scope in self.symbol_table.scope_map.items():
            """
            Declare the constants for all local variables.
            """
            for symbol in scope.locals:
                var = scope.locals[symbol]
                if ChemTypes.UNKNOWN in var.types and ChemTypes.INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION in var.types:
                    if len(var.types) > 2:
                        var.types.remove(
                            ChemTypes.
                            INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION)
                        var.types.remove(ChemTypes.UNKNOWN)
                else:
                    if ChemTypes.UNKNOWN in var.types and len(var.types) > 1:
                        var.types.remove(ChemTypes.UNKNOWN)
                    elif ChemTypes.INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION in var.types and len(
                            var.types) > 1:
                        var.types.remove(
                            ChemTypes.
                            INSUFFICIENT_INFORMATION_FOR_CLASSIFICATION)
                declares += "; Declaring constants for: {}{}".format(
                    self.get_smt_name(var).upper(), self.nl)
                for enum in types:
                    """
                    Declare the constants for all scoped variables.
                    """
                    declares += "(declare-const {} Bool){}".format(
                        self.get_smt_name(var, ChemTypes(enum)), self.nl)

                declares += self.nl
                defines += "; Defining the assignment of: {}{}".format(
                    self.get_smt_name(var).upper(), self.nl)
                for t in var.types:
                    defines += "(assert (= {} true)){}".format(
                        self.get_smt_name(var, t), self.nl)

                if self.types_used == TypesUsed.SIMPLE:
                    """
                    If it's naive, then make sure that unknown is false.
                    In other words, we must have a nat/real/mat type.
                    """
                    defines += "; Ensure that {} is not unknown type{}".format(
                        self.get_smt_name(var).upper(), self.nl)
                    defines += "(assert (= {} false)){}".format(
                        self.get_smt_name(var, ChemTypes.UNKNOWN), self.nl)
                if var.types & ChemTypeResolver.numbers():
                    """
                    Build the asserts for things that are numbers.
                    We will only check naively: in that if we intersect,
                    And we have something, then we know it's a number.
                    """
                    asserts += self.assert_material(var, False)
                if var.types & ChemTypeResolver.materials():
                    """
                    Build the asserts for things that are numbers.
                    We will only check naively: in that if we intersect,
                    And we have something, then we know it's a mat.
                    """
                    asserts += self.assert_material(var)
        self.add_smt(
            "; ==============={}; Declaring Constants{}; ==============={}".
            format(self.nl, self.nl, self.nl))
        self.add_smt(declares)
        # self.add_smt("; ==============={}; Declaring typing{}; ==============={}".format(self.nl, self.nl, self.nl))
        # self.add_smt(defines)
        self.add_smt(
            "; ==============={}; Declaring Asserts{}; ==============={}".
            format(self.nl, self.nl, self.nl))
        self.add_smt(asserts)