예제 #1
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Constant(self, node: ast.Constant) -> None:
        try:
            f = FUNCTIONS[node.prop]
        except KeyError:
            raise CCLSymbolError(node, f'Property {node.prop} is not known.')

        if len(f.type.args) != 1 or f.type.args[0] != ObjectType.ATOM:
            raise CCLTypeError(node,
                               f'Function {node.prop} is not a property.')

        if node.element not in ELEMENT_NAMES:
            raise CCLSymbolError(node, f'Element {node.element} not known.')

        self.global_table.define(
            ConstantSymbol(node.name, node, f, node.element))
예제 #2
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_EE(self, node: ast.EE) -> None:
        s1 = self.current_table.resolve(node.idx_row)
        s2 = self.current_table.resolve(node.idx_col)
        if s1 is not None or s2 is not None:
            raise CCLSymbolError(
                node, 'Index/indices for EE expression already defined.')

        table = SymbolTable(self.current_table)
        table.define(ObjectSymbol(node.idx_row, node, ObjectType.ATOM, None))
        table.define(ObjectSymbol(node.idx_col, node, ObjectType.ATOM, None))
        node.symbol_table = table

        self._iterating_over |= {node.idx_row, node.idx_col}
        self.current_table = table
        self.visit(node.diag)
        self.visit(node.off)
        self.visit(node.rhs)

        if {node.diag.result_type, node.off.result_type, node.rhs.result_type
            } != {NumericType.FLOAT}:
            raise CCLTypeError(
                node, f'EE expression has to have all parts with Float type.')

        self._iterating_over -= {node.idx_row, node.idx_col}

        assert self.current_table.parent is not None
        self.current_table = self.current_table.parent

        node.result_type = ArrayType(ObjectType.ATOM)
예제 #3
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Function(self, node: ast.Function) -> None:
        # Functions have only one numerical argument
        def check_args(
                expected: Union[ObjectType, NumericType, ArrayType],
                given: Union[ObjectType, NumericType, ArrayType]) -> bool:
            if expected == given:
                return True
            if given == NumericType.INT and expected == NumericType.FLOAT:
                return True

            return False

        self.visit(node.arg)

        try:
            f = FUNCTIONS[node.name]
        except KeyError:
            raise CCLSymbolError(node, f'Function {node.name} is not known.')

        assert isinstance(node.arg.result_type,
                          (ObjectType, NumericType, ArrayType))
        assert isinstance(f.type.args[0], (ObjectType, NumericType, ArrayType))

        if not check_args(f.type.args[0], node.arg.result_type):
            raise CCLTypeError(
                node.arg, f'Incompatible argument type for function {f.name}. '
                f'Got {node.arg.result_type}, expected {f.type.args[0]}.')

        assert isinstance(f.type.return_type, (NumericType, ArrayType))
        node.result_type = f.type.return_type
예제 #4
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Property(self, node: ast.Property) -> None:
        try:
            f = FUNCTIONS[node.prop]
        except KeyError:
            raise CCLSymbolError(node, f'Function {node.prop} is not known.')

        self.global_table.define(FunctionSymbol(node.name, node, f))
예제 #5
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Substitution(self, node: ast.Substitution) -> None:
        if isinstance(node.lhs, ast.Name):
            name = node.lhs.val
            indices: Tuple[ast.Name, ...] = tuple()
            if node.constraints is not None:
                raise CCLSymbolError(
                    node,
                    f'Substitution symbol {name} cannot have a constraint.')
        else:  # ast.Subscript
            name = node.lhs.name.val
            indices = node.lhs.indices

        s = self.current_table.resolve(name)
        if s is None:
            ns = SubstitutionSymbol(name, node, indices)
            self.global_table.define(ns)
            ns.rules[node.constraints] = node.rhs
        else:
            if not isinstance(s, SubstitutionSymbol):
                raise CCLSymbolError(
                    node,
                    f'Symbol {s.name} already defined as something else.')
            if indices != s.indices:
                raise CCLSymbolError(
                    node,
                    f'Substitution symbol {s.name} has different indices defined.'
                )
            if node.constraints in s.rules:
                raise CCLTypeError(
                    node,
                    f'Same constraint already defined for symbol {s.name}.')
            s.rules[node.constraints] = node.rhs

        used_names: Set[str] = set()
        if node.constraints is not None:
            used_names |= NameGetter().visit(node.constraints,
                                             self.global_table)
        used_names |= NameGetter().visit(node.rhs, self.global_table)

        for used_name in used_names:
            symbol = self.global_table.resolve(used_name)
            if isinstance(symbol, SubstitutionSymbol):
                raise CCLSymbolError(
                    node,
                    f'Cannot nest substitution {used_name} in another substitution {name}.'
                )
예제 #6
0
파일: symboltable.py 프로젝트: krab1k/CCL
 def check_substitutions_default(self) -> None:
     for symbol in self.global_table.symbols.values():
         if isinstance(symbol, SubstitutionSymbol):
             if None not in symbol.rules:
                 raise CCLSymbolError(
                     symbol.def_node,
                     f'No default option specified for Substitution symbol {symbol.name}.'
                 )
예제 #7
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Predicate(self, node: ast.Predicate) -> None:
        try:
            f = PREDICATES[node.name]
        except KeyError:
            raise CCLSymbolError(node, f'Predicate {node.name} not defined.')

        if len(f.type.args) != len(node.args):
            raise CCLSymbolError(
                node,
                f'Predicate {f.name} should have {len(f.type.args)} arguments '
                f'but got {len(node.args)} instead.')

        for arg_type, arg in zip(f.type.args, node.args):
            if isinstance(arg_type, ObjectType):
                self.visit(arg)
                assert isinstance(arg, ast.Name)
                name = self._indices_mapping.get(arg.val, arg.val)
                if name not in self.iterating_over:
                    raise CCLSymbolError(
                        arg, f'Object {arg.val} not bound to ForEach or Sum.')
                if arg.result_type != arg_type:
                    raise CCLTypeError(
                        arg,
                        f'Predicate\'s {node.name} argument is not {arg_type}.'
                    )
            elif arg_type == StringType:
                # Note that name would not have result_type set as it's really a String
                if not isinstance(arg, ast.Name):
                    raise CCLTypeError(
                        arg,
                        f'Predicate {node.name} expected string argument.')
            elif isinstance(arg_type, NumericType):
                if not isinstance(arg.result_type, NumericType):
                    raise CCLTypeError(
                        arg,
                        f'Predicate {node.name} expected numeric argument.')
            else:
                raise Exception('We should not get here!')

        if f.name == 'element' and str(
                node.args[1].val).lower() not in ELEMENT_NAMES:
            raise CCLTypeError(node.args[1],
                               f'Unknown element {node.args[1].val}.')
예제 #8
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_ForEach(self, node: ast.ForEach) -> None:
        s = self.current_table.resolve(node.name.val)
        if s is not None:
            raise CCLSymbolError(
                node.name, f'Loop variable {node.name.val} already defined.')

        table = SymbolTable(self.current_table)

        atom_indices: Set[str] = set()
        if node.atom_indices is not None:
            i1, i2 = node.atom_indices
            s1 = self.current_table.resolve(i1)
            s2 = self.current_table.resolve(i2)
            if s1 is not None or s2 is not None:
                raise CCLSymbolError(
                    node,
                    f'Decomposition of bond symbol {node.name.val} used already defined names.'
                )

            bonded_constraint = ast.Predicate(
                (node.line, node.column), 'bonded', (
                    ast.Name((node.line, node.column), i1),
                    ast.Name((node.line, node.column), i2),
                ))
            table.define(
                ObjectSymbol(i1, node, ObjectType.ATOM, bonded_constraint))
            table.define(
                ObjectSymbol(i2, node, ObjectType.ATOM, bonded_constraint))
            atom_indices = {i1, i2}

        self._iterating_over |= atom_indices | {node.name.val}

        node.symbol_table = table
        table.define(
            ObjectSymbol(node.name.val, node, node.type, node.constraints))
        self.current_table = table
        for statement in node.body:
            self.visit(statement)

        self._iterating_over -= atom_indices | {node.name.val}

        assert self.current_table.parent is not None
        self.current_table = self.current_table.parent
예제 #9
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Sum(self, node: ast.Sum) -> None:
        s = self.current_table.resolve(node.name.val)
        if s is None:
            raise CCLSymbolError(node.name,
                                 f'Symbol {node.name.val} not defined.')

        node.name.result_type = s.symbol_type

        if not isinstance(s, ObjectSymbol):
            raise CCLSymbolError(
                node.name,
                f'Sum has to iterate over Atom or Bond not {s.symbol_type}.')

        self._iterating_over.add(node.name.val)
        if s.constraints is not None:
            self.visit(s.constraints)

        self.visit(node.expr)
        self._iterating_over.remove(node.name.val)
        node.result_type = node.expr.result_type
예제 #10
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Name(self, node: ast.Name) -> None:
        name = self._indices_mapping.get(node.val, node.val)
        s = self.current_table.resolve(name)
        if s is not None:
            if isinstance(s, SubstitutionSymbol):
                self.visit(s.rules[None])
            if s.symbol_type == ParameterType.COMMON:
                node.result_type = NumericType.FLOAT
            else:
                node.result_type = s.symbol_type

        else:
            raise CCLSymbolError(node, f'Symbol {name} not defined.')
예제 #11
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Object(self, node: ast.Object) -> None:
        if node.atom_indices is not None:
            i1, i2 = node.atom_indices
            s1 = self.current_table.resolve(i1)
            s2 = self.current_table.resolve(i2)
            if s1 is not None or s2 is not None:
                raise CCLSymbolError(
                    node,
                    f'Decomposition of bond symbol {node.name} used already defined names.'
                )

            self.global_table.define(
                ObjectSymbol(i1, node, ObjectType.ATOM, None))
            self.global_table.define(
                ObjectSymbol(i2, node, ObjectType.ATOM, None))
        self.global_table.define(
            ObjectSymbol(node.name, node, node.type, node.constraints))
예제 #12
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_For(self, node: ast.For) -> None:
        s = self.current_table.resolve(node.name.val)
        if s is not None:
            raise CCLSymbolError(
                node.name, f'Loop variable {node.name.val} already defined.')

        self._iterating_over.add(node.name.val)
        table = SymbolTable(self.current_table)
        node.symbol_table = table
        table.define(VariableSymbol(node.name.val, node, NumericType.INT))
        self.current_table = table
        for statement in node.body:
            self.visit(statement)

        self._iterating_over.remove(node.name.val)

        assert self.current_table.parent is not None
        self.current_table = self.current_table.parent
예제 #13
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Assign(self, node: ast.Assign) -> None:
        def check_types(lhs: CCLType, rhs: CCLType) -> bool:
            if isinstance(lhs, ArrayType) and isinstance(rhs, ArrayType):
                return lhs == rhs
            # Can assign number to all elements of the vector/matrix
            if isinstance(lhs, ArrayType) and isinstance(rhs, NumericType):
                return True
            if isinstance(lhs, NumericType) and isinstance(rhs, NumericType):
                # Cannot assign Float to Int, OK otherwise
                if lhs == NumericType.INT and rhs == NumericType.FLOAT:
                    return False
                return True

            return False

        self.visit(node.rhs)
        rtype = node.rhs.result_type
        if not isinstance(rtype, (NumericType, ArrayType)):
            raise CCLTypeError(
                node.rhs,
                f'Only Numbers and Arrays can be assigned not {rtype}.')
        if isinstance(node.lhs, ast.Name):
            s = self.current_table.resolve(node.lhs.val)
            if s is not None:
                if s.name in self._iterating_over:
                    raise CCLTypeError(
                        node, f'Cannot assign to loop variable {s.name}.')
                if isinstance(s, SubstitutionSymbol):
                    raise CCLSymbolError(
                        node.lhs,
                        f'Cannot assign to a substitution symbol {s.name}.')
                if isinstance(s, ParameterSymbol):
                    raise CCLSymbolError(
                        node.lhs,
                        f'Cannot assign to a parameter symbol {s.name}.')
                symbol_type = s.symbol_type
                if check_types(symbol_type, rtype):
                    node.lhs.result_type = symbol_type
                else:
                    raise CCLTypeError(
                        node,
                        f'Cannot assign {rtype} to the variable {s.name} of type {symbol_type}.'
                    )
            else:
                # New symbols are defined at method scope
                self.symbol_table.define(
                    VariableSymbol(node.lhs.val, node, rtype))
                node.lhs.result_type = rtype
        elif isinstance(node.lhs, ast.Subscript):  # ast.Subscript
            s = self.current_table.resolve(node.lhs.name.val)
            index_types = []
            for idx in node.lhs.indices:
                self.visit(idx)
                index_types.append(idx.result_type)
                if idx.val not in self._iterating_over:
                    raise CCLSymbolError(
                        idx,
                        f'Object {idx.val} not bound to any For/ForEach/Sum.')
            if s is not None:
                symbol_type = s.symbol_type
                # Check whether indices are correct
                if isinstance(s, SubstitutionSymbol):
                    raise CCLSymbolError(
                        node.lhs,
                        f'Cannot assign to a substitution symbol {s.name}.')
                if not isinstance(symbol_type, ArrayType):
                    raise CCLTypeError(
                        node.lhs,
                        f'Cannot assign to non-Array type {symbol_type}.')
                index_types = []
                for idx in node.lhs.indices:
                    self.visit(idx)
                    index_types.append(idx.result_type)
                if symbol_type.indices != tuple(index_types):
                    indices_str = ', '.join(str(i) for i in index_types)
                    raise CCLTypeError(
                        node.lhs, f'Cannot index Array of type {symbol_type} '
                        f'using index/indices of type(s) {indices_str}.')

                node.lhs.name.result_type = s.symbol_type
            else:
                if not all(isinstance(i, ObjectType) for i in index_types):
                    raise CCLTypeError(
                        node.lhs,
                        f'Cannot index with something different than Atom or Bond.'
                    )

                # Hack for Mypy as it does not recognize the previous check
                it = cast(Sequence[ObjectType], index_types)
                self.symbol_table.define(
                    VariableSymbol(node.lhs.name.val, node, ArrayType(*it)))
                node.lhs.name.result_type = ArrayType(*it)
            node.lhs.result_type = rtype
        else:
            raise Exception('Should not get here!')
예제 #14
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def visit_Subscript(self, node: ast.Subscript) -> None:
        s = self.current_table.resolve(node.name.val)
        if not isinstance(s, SubstitutionSymbol):
            self.visit(node.name)

        symbol_type = node.name.result_type

        index_types_list = []
        for idx in node.indices:
            self.visit(idx)
            index_types_list.append(idx.result_type)
            mapped_val = self._indices_mapping.get(idx.val, idx.val)
            if isinstance(idx.result_type, ObjectType) and \
                    mapped_val not in self.iterating_over:
                raise CCLSymbolError(
                    idx,
                    f'Object {mapped_val} not bound to any For/ForEach/Sum.')
        index_types = tuple(index_types_list)
        index_types_str = ', '.join(str(i) for i in index_types)

        if isinstance(s, ParameterSymbol):
            if symbol_type == ParameterType.ATOM and index_types != (
                    ObjectType.ATOM, ):
                raise CCLTypeError(
                    node,
                    f'Cannot index atom parameter with {index_types_str}.')
            if symbol_type == ParameterType.BOND:
                if index_types not in ((ObjectType.BOND, ), (ObjectType.ATOM,
                                                             ObjectType.ATOM)):
                    raise CCLTypeError(
                        node,
                        f'Cannot index bond parameter with {index_types_str}.')

                # Check whether two atoms are actually bonded, i.e., 'bonded' predicate exists
                if index_types == (ObjectType.ATOM, ObjectType.ATOM):
                    s1 = self.current_table.resolve(node.indices[0].val)
                    s2 = self.current_table.resolve(node.indices[1].val)
                    assert s1 is not None and isinstance(s1, ObjectSymbol)
                    assert s2 is not None and isinstance(s2, ObjectSymbol)

                    idx1 = node.indices[0].val
                    idx2 = node.indices[1].val
                    results: Set[Optional[ast.ASTNode]] = {None}
                    for c in (c for c in (s1.constraints, s2.constraints)
                              if c is not None):
                        # Search for either bonded(i, j) or bonded(j, i)
                        results.add(
                            ast.search_ast_element(
                                c,
                                ast.Predicate((-1, -1), 'bonded', (ast.Name(
                                    (-1, -1), idx1), ast.Name(
                                        (-1, -1), idx2)))))
                        results.add(
                            ast.search_ast_element(
                                c,
                                ast.Predicate((-1, -1), 'bonded', (ast.Name(
                                    (-1, -1), idx2), ast.Name(
                                        (-1, -1), idx1)))))

                    if results == {None}:
                        raise CCLSymbolError(
                            node,
                            f'Cannot index bond parameter by two non-bonded atoms.'
                        )

            if symbol_type == NumericType.FLOAT:
                raise CCLTypeError(node, f'Cannot index common parameter.')
        elif isinstance(s, VariableSymbol) and isinstance(
                symbol_type, ArrayType):
            if symbol_type.indices != index_types:
                raise CCLTypeError(
                    node, f'Cannot index Array of type {symbol_type} '
                    f'using index/indices of type(s) {index_types_str}.')
        elif isinstance(s, FunctionSymbol):
            assert isinstance(symbol_type, FunctionType)
            if symbol_type.args != index_types:
                raise CCLTypeError(
                    node,
                    f'Cannot use function {s.function.name}: {s.function.type} '
                    f'with arguments of type(s) {index_types_str}')

            assert isinstance(s.function.type.return_type,
                              (NumericType, ArrayType))
            node.result_type = s.function.type.return_type
            return
        elif isinstance(s, SubstitutionSymbol):
            if len(s.indices) != len(index_types):
                raise CCLTypeError(
                    node,
                    f'Bad number of indices for {s.name}, got {len(index_types)}, '
                    f'expected {len(s.indices)}.')
            if not all(isinstance(t, ObjectType) for t in index_types):
                raise CCLTypeError(
                    node,
                    f'Substitution indices for symbol {s.name} must have type Atom or Bond.'
                )

            self._indices_mapping.update(
                {si.val: ni.val
                 for si, ni in zip(s.indices, node.indices)})
            types = set()
            for constraint, expr in s.rules.items():
                if constraint is not None:
                    self.visit(constraint)
                self.visit(expr)
                types.add(expr.result_type)

            if len(types) > 1:
                raise CCLTypeError(
                    node,
                    f'All expressions within a substitution symbol {s.name} must have same type.'
                )

            for si in s.indices:
                self._indices_mapping.pop(si.val)
        else:
            raise CCLTypeError(
                node,
                f'Cannot index type {symbol_type} with indices of type(s) {index_types_str}'
            )

        # Return Float if not assigned already
        node.result_type = NumericType.FLOAT
예제 #15
0
파일: symboltable.py 프로젝트: krab1k/CCL
    def define(self, symbol: Symbol) -> None:
        if self.resolve(symbol.name):
            raise CCLSymbolError(symbol.def_node,
                                 f'Symbol {symbol.name} already defined.')

        self.symbols[symbol.name] = symbol