def check_assocs(self, n, inters, assocs): if assocs == thin.Null_Iir: # Also cover the case of no interfaces return inter = inters for assoc in thinutils.chain_iter(assocs): if iirs.Get_Kind(assoc) \ == iirs.Iir_Kind.Association_Element_By_Individual: continue formal = iirs.Get_Formal(assoc) if formal == thin.Null_Iir: self.error( Location.from_node(assoc), "association by position for {}".format( nodeutils.get_identifier_str(inter))) # Should the tool report all errors ? return assoc_inter = thin.Iirs_Utils.Get_Interface_Of_Formal(formal) while assoc_inter != inter: if inter == thin.Null_Iir: self.error( Location.from_node(assoc), "incorrect association order for {}".format( nodeutils.get_identifier_str(assoc_inter))) return inter = iirs.Get_Chain(inter) if iirs.Get_Whole_Association_Flag(assoc): inter = iirs.Get_Chain(inter)
def nodes_iter(n): """Iterate of all nodes of n, including n. Nodes are returned only once.""" if n == Null_Iir: return # print 'nodes_iter for {0}'.format(n) yield n for f in fields_iter(n): typ = nodes_meta.get_field_type(f) # print ' {0}: field {1} (type: {2})'.format( # n, fields_image(f), types_image(typ)) if typ == nodes_meta.types.Iir: attr = nodes_meta.get_field_attribute(f) if attr == Attr.ANone: for n1 in nodes_iter(nodes_meta.Get_Iir(n, f)): yield n1 elif attr == Attr.Chain: n2 = nodes_meta.Get_Iir(n, f) while n2 != Null_Iir: for n1 in nodes_iter(n2): yield n1 n2 = iirs.Get_Chain(n2) elif attr == Attr.Maybe_Ref: if not iirs.Get_Is_Ref(n, f): for n1 in nodes_iter(nodes_meta.Get_Iir(n, f)): yield n1 elif typ == types.Iir_List: attr = nodes_meta.get_field_attribute(f) if attr == Attr.ANone: for n1 in list_iter(nodes_meta.Get_Iir_List(n, f)): for n2 in nodes_iter(n1): yield n2
def sequential_iter(n): """Iterator on sequential statements. The first node must be either a process or a subprogram body.""" if n == thin.Null_Iir: return k = iirs.Get_Kind(n) if k in [ iirs.Iir_Kind.Process_Statement, iirs.Iir_Kind.Sensitized_Process_Statement, iirs.Iir_Kind.Function_Body, iirs.Iir_Kind.Procedure_Body ]: for n1 in chain_iter(iirs.Get_Sequential_Statement_Chain(n)): yield n1 for n2 in sequential_iter(n1): yield n2 elif k == iirs.Iir_Kind.If_Statement: while True: n = iirs.Get_Chain(n) if n == thin.Null_Iir: break yield n for n1 in sequential_iter(n): yield n1 elif k == iirs.Iir_Kind.Case_Statement: for ch in chain_iter(iirs.Get_Case_Statement_Alternative_Chain(n)): stmt = iirs.Get_Associated_Chain(ch) if stmt != thin.Null_Iir: for n1 in chain_iter(stmt): yield n1 for n2 in sequential_iter(n1): yield n2 elif k in [ iirs.Iir_Kind.For_Loop_Statement, iirs.Iir_Kind.While_Loop_Statement ]: for n1 in chain_iter(iirs.Get_Sequential_Statement_Chain(n)): yield n1 for n2 in sequential_iter(n1): yield n2 elif k in [ iirs.Iir_Kind.Assertion_Statement, iirs.Iir_Kind.Wait_Statement, iirs.Iir_Kind.Null_Statement, iirs.Iir_Kind.Exit_Statement, iirs.Iir_Kind.Next_Statement, iirs.Iir_Kind.Return_Statement, iirs.Iir_Kind.Variable_Assignment_Statement, iirs.Iir_Kind.Simple_Signal_Assignment_Statement, iirs.Iir_Kind.Procedure_Call_Statement ]: return else: assert False, "unknown node of kind {}".format(kind_image(k))
def check_declarations(self, decl): decl_col = -1 colon_col = -1 subtype_col = -1 assign_col = -1 line = -1 while decl != thin.Null_Iir: loc = elocations.Get_Start_Location(decl) fe, ln, co = utils.Location_To_File_Line_Col(loc) if ln <= line: self.error(Location.from_node(decl), "one generic/port per line") else: if co != decl_col and decl_col >= 0: self.error(Location.from_node(decl), "name is not aligned with previous one") # Check alignment of ':' colon_loc = elocations.Get_Colon_Location(decl) _, ln1, colon_co = utils.Location_To_File_Line_Col(colon_loc) if colon_co != colon_col and colon_col >= 0: self.error(Location.from_node(decl), "':' is not aligned with previous one") colon_col = colon_co # Check alignment of subtype. st = iirs.Get_Subtype_Indication(decl) if st != thin.Null_Iir: st_loc = thinutils.leftest_location(st) _, ln1, st_co = utils.Location_To_File_Line_Col(st_loc) if st_co != subtype_col and subtype_col >= 0: self.error(Location.from_node(decl), "subtype is not aligned with previous one") subtype_col = st_co # Check alignment of ':=' assign_loc = elocations.Get_Assign_Location(decl) if assign_loc != thin.No_Location: _, ln1, assign_co = \ utils.Location_To_File_Line_Col(assign_loc) if assign_co != assign_col and assign_col >= 0: self.error(Location.from_node(decl), "':=' is not aligned with previous one") assign_col = assign_co decl_col = co line = ln decl = iirs.Get_Chain(decl)
def check(self, input, ast): for du in thinutils.chain_iter(iirs.Get_First_Design_Unit(ast)): ent = iirs.Get_Library_Unit(du) if iirs.Get_Kind(ent) != iirs.Iir_Kind.Entity_Declaration: continue gen = iirs.Get_Generic_Chain(ent) if gen != thin.Null_Iir: self.check_declarations(gen) ports = iirs.Get_Port_Chain(ent) if ports != thin.Null_Iir: self.check_declarations(ports) port = ports while port != thin.Null_Iir: if not iirs.Get_Has_Mode(port): self.error(Location.from_node(port), "in/out/inout required for port") port = iirs.Get_Chain(port)
def chk_case_alternatives(self, alt, level): when_loc = None while alt != thin.Null_Iir: alt_loc = iirs.Get_Location(alt) if not iirs.Get_Same_Alternative_Flag(alt): # Indentation of 'when' when_loc = alt_loc self.chk_level(alt, alt_loc, level) stmts = iirs.Get_Associated_Chain(alt) if nodeutils.is_one_stmt(stmts) \ and nodeutils.is_same_line(iirs.Get_Location(stmts), alt_loc): # This is ok (providing this is a simple statement...) # TODO pass else: self.chk_sequential(stmts, level + self._l) elif not nodeutils.is_same_line(alt_loc, when_loc): self.chk_level(alt, alt_loc, level + 3) alt = iirs.Get_Chain(alt)
def chain_iter(n): """Iterate of a chain headed by node n""" while n != Null_Iir: yield n n = iirs.Get_Chain(n)
def execute(self, files): inputs = [] props = ['synth'] # First file for filename in files: if filename.startswith('--'): # Handle properties if filename == '--import': props = ['import'] elif filename == '--synth': props = ['synth'] elif filename == '--top': props = ['synth', 'top'] elif filename == '--tb': props = ['tb'] else: fatal("unknown property '{0}'".format(filename)) continue # Read the file fid = thin.Get_Identifier(filename.encode('utf-8')) fe = thin.Read_Source_File(0, fid) if fe == thin.No_Source_File_Entry: fatal('cannot open {0}'.format(filename)) fbuf = thin.Get_File_Buffer(fe) flen = thin.Get_File_Length(fe) # Not very efficient (it copies the string), but let's use it # for now. filebuf = ctypes.string_at(fbuf, flen) input = RuleInput(filename, fe) input.filebuf = filebuf input.props = props inputs.append(input) if 'import' not in input.props: self._nbr_files += 1 # Again, not very efficient (creates the substrings). flines = filebuf.splitlines(True) loc = Location(filename) for r in self._file_rules: r.check(loc, flines) # Then tokens thin.Scanner.Flag_Comment.value = True for input in inputs: if 'import' not in input.props: thin.Scanner.Set_File(input.fe) filebuf = input.filebuf while True: thin.Scanner.Scan() tok = thin.Scanner.Current_Token.value loc = TokLocation(input.filename, thin.Scanner.Get_Current_Line(), thin.Scanner.Get_Token_Column(), thin.Scanner.Get_Token_Position(), thin.Scanner.Get_Position()) if tok == tokens.Tok.Comment: input.comments[loc.line] = (loc.start, loc.end) for r in self._lex_rules: r.check(loc, filebuf, tok) if tok == tokens.Tok.Eof: break thin.Scanner.Close_File() if not (self._syntax_rules or self._syntax_node_rules or self._sem_rules or self._sem_node_rules or self._synth_rules): return # Then syntax # The parser doesn't handle comments thin.Scanner.Flag_Comment.value = False # Keep extra locations thin.Flags.Flag_Elocations.value = True # Keep all parenthesis thin.Parse.Flag_Parse_Parenthesis.value = True # Be sure to initialize std and work (and only once). # Humm, not very elegant. if thin.Get_Libraries_Chain() == thin.Null_Iir: thin.analyze_init() for input in inputs: thin.Scanner.Set_File(input.fe) loc = Location(input.filename) input.ast = thin.Parse.Parse_Design_File() if 'import' not in input.props: for r in self._syntax_rules: r.check(input, input.ast) if self._syntax_node_rules: for n in thinutils.nodes_iter(input.ast): for r in self._syntax_node_rules: r.check(loc, n) thin.Scanner.Close_File() # Then semantic if self._sem_rules or self._sem_node_rules or self._synth_rules: # Reduce Canon thin.Canon.Flag_Concurrent_Stmts.value = False thin.Canon.Flag_Configurations.value = False thin.Canon.Flag_Associations.value = False # First add all units in the work library, so that they they are # known by the analyzer. for input in inputs: unit_ast = iirs.Get_First_Design_Unit(input.ast) while unit_ast != thin.Null_Iir: # Detach the unit from its design file next_unit_ast = iirs.Get_Chain(unit_ast) iirs.Set_Chain(unit_ast, thin.Null_Iir) # Add thin.Add_Design_Unit_Into_Library(unit_ast, False) input.units_ast.append(unit_ast) unit_ast = next_unit_ast # Handle all unit for input in inputs: if 'import' not in input.props: for unit in input.units_ast: if iirs.Get_Library_Unit(unit) == thin.Null_Iir: # Over-written. # FIXME: remove from the list ? continue # Be sure the unit was analyzed. It could have been # already analyzed if referenced. And a unit cannot be # analyzed twice. if iirs.Get_Date_State(unit) == iirs.Date_State.Parse: thin.Finish_Compilation(unit, False) iirs.Set_Date_State(unit, iirs.Date_State.Analyze) for r in self._sem_rules: r.check(input, unit) for n in thinutils.nodes_iter(unit): for r in self._sem_node_rules: r.check(input, n) for input in inputs: if 'synth' in input.props: for unit in input.units_ast: if iirs.Get_Library_Unit(unit) == thin.Null_Iir: # Over-written. continue for r in self._synth_rules: r.check(input, unit)
def is_one_alt(alts): assert not iirs.Get_Same_Alternative_Flag(alts) next_alt = iirs.Get_Chain(alts) return next_alt == thin.Null_Iir \ or not iirs.Get_Same_Alternative_Flag(next_alt)
def is_one_stmt(chain): return chain != thin.Null_Iir \ and iirs.Get_Chain(chain) == thin.Null_Iir