1 /* 2 * Copyright (c) 2019 Helmut Neemann. 3 * Use of this source code is governed by the GPL v3 license 4 * that can be found in the LICENSE file. 5 */ 6 package de.neemann.digital.draw.library; 7 8 import de.neemann.digital.core.NodeException; 9 import de.neemann.digital.core.element.*; 10 import de.neemann.digital.draw.elements.Circuit; 11 import de.neemann.digital.draw.elements.PinException; 12 import de.neemann.digital.draw.elements.VisualElement; 13 import de.neemann.digital.draw.model.ModelCreator; 14 import de.neemann.digital.draw.model.NetList; 15 import de.neemann.digital.hdl.hgs.Parser; 16 import de.neemann.digital.hdl.hgs.ParserException; 17 import de.neemann.digital.hdl.hgs.refs.Reference; 18 import de.neemann.digital.hdl.hgs.refs.ReferenceToStruct; 19 import de.neemann.digital.hdl.hgs.refs.ReferenceToVar; 20 import de.neemann.digital.lang.Lang; 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.util.TreeSet; 25 26 /** 27 * The description of a nested element. 28 * This is a complete circuit which is used as a element. 29 */ 30 public final class ElementTypeDescriptionCustom extends ElementTypeDescription { 31 private static final int MAX_DEPTH = 30; 32 private final File file; 33 private final Circuit circuit; 34 private final ResolveGenerics resolveGenerics; 35 private final LibraryInterface library; 36 private String description; 37 private NetList netList; 38 private String declarationDefault; 39 40 /** 41 * Creates a new element 42 * 43 * @param file the file which is loaded 44 * @param circuit the circuit 45 * @throws PinException PinException 46 */ ElementTypeDescriptionCustom(File file, Circuit circuit, ElementLibrary library)47 ElementTypeDescriptionCustom(File file, Circuit circuit, ElementLibrary library) throws PinException { 48 super(file.getName(), (ElementFactory) null, circuit.getInputNames()); 49 this.file = file; 50 this.circuit = circuit; 51 this.library = library; 52 resolveGenerics = new ResolveGenerics(circuit, library); 53 setShortName(file.getName()); 54 addAttribute(Keys.ROTATE); 55 addAttribute(Keys.LABEL); 56 addAttribute(Keys.SHAPE_TYPE); 57 if (isGeneric()) 58 addAttribute(Keys.GENERIC); 59 } 60 61 /** 62 * Returns the filename 63 * The returned file is opened if the user wants to modify the element 64 * 65 * @return the filename 66 */ getFile()67 public File getFile() { 68 return file; 69 } 70 71 /** 72 * @return the elements attributes 73 */ getAttributes()74 public ElementAttributes getAttributes() { 75 return circuit.getAttributes(); 76 } 77 78 /** 79 * @return the circuit 80 */ getCircuit()81 public Circuit getCircuit() { 82 return circuit; 83 } 84 85 /** 86 * Returns the resolved circuit if it is a generic circuit 87 * 88 * @param attributes the defining attributes 89 * @return the resolved circuit 90 * @throws NodeException NodeException 91 * @throws ElementNotFoundException ElementNotFoundException 92 */ getResolvedCircuit(ElementAttributes attributes)93 public Circuit getResolvedCircuit(ElementAttributes attributes) throws NodeException, ElementNotFoundException { 94 if (isGeneric()) 95 return resolveGenerics.resolveCircuit(attributes).getCircuit(); 96 else 97 return circuit; 98 } 99 100 /** 101 * Sets a custom description for this field 102 * 103 * @param description the description 104 */ setDescription(String description)105 public void setDescription(String description) { 106 this.description = description; 107 } 108 109 @Override getDescription(ElementAttributes elementAttributes)110 public String getDescription(ElementAttributes elementAttributes) { 111 if (description != null) 112 return description; 113 else 114 return super.getDescription(elementAttributes); 115 } 116 117 /** 118 * Gets a {@link ModelCreator} of this circuit. 119 * Every time this method is called a new {@link ModelCreator} is created. 120 * 121 * @param subName name of the circuit, used to name unique elements 122 * @param depth recursion depth, used to detect a circuit which contains itself 123 * @param containingVisualElement the containing visual element 124 * @return the {@link ModelCreator} 125 * @throws PinException PinException 126 * @throws NodeException NodeException 127 * @throws ElementNotFoundException ElementNotFoundException 128 */ getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement)129 ModelCreator getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement) throws PinException, NodeException, ElementNotFoundException { 130 if (netList == null) 131 netList = new NetList(circuit); 132 133 if (depth > MAX_DEPTH) 134 throw new NodeException(Lang.get("err_recursiveNestingAt_N0", circuit.getOrigin())); 135 136 if (isGeneric()) { 137 Circuit c = resolveGenerics.resolveCircuit(containingVisualElement.getElementAttributes()).getCircuit(); 138 139 return new ModelCreator(c, library, true, new NetList(new NetList(c), errorVisualElement), subName, depth, errorVisualElement); 140 } else 141 return new ModelCreator(circuit, library, true, new NetList(netList, errorVisualElement), subName, depth, errorVisualElement); 142 } 143 144 /** 145 * @return the generics field default value 146 * @throws NodeException NodeException 147 */ getDeclarationDefault()148 public String getDeclarationDefault() throws NodeException { 149 if (declarationDefault == null) 150 declarationDefault = createDeclarationDefault(circuit); 151 return declarationDefault; 152 } 153 154 /** 155 * Creates the default for custom element declarations 156 * 157 * @param circuit the circuit 158 * @return the default code template 159 * @throws NodeException NodeException 160 */ createDeclarationDefault(Circuit circuit)161 public static String createDeclarationDefault(Circuit circuit) throws NodeException { 162 TreeSet<String> nameSet = new TreeSet<>(); 163 for (VisualElement ve : circuit.getElements()) { 164 String gen = ve.getElementAttributes().get(Keys.GENERIC).trim(); 165 if (!gen.isEmpty()) { 166 try { 167 Parser p = new Parser(gen); 168 p.enableRefReadCollection(); 169 p.parse(false); 170 for (Reference r : p.getRefsRead()) { 171 if (r instanceof ReferenceToStruct) { 172 ReferenceToStruct st = (ReferenceToStruct) r; 173 if (st.getParent() instanceof ReferenceToVar) { 174 ReferenceToVar var = (ReferenceToVar) st.getParent(); 175 if (var.getName().equals("args")) { 176 nameSet.add(st.getName()); 177 } 178 } 179 } 180 } 181 } catch (ParserException | IOException e) { 182 final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", ve, gen), e); 183 ex.setOrigin(circuit.getOrigin()); 184 throw ex; 185 } 186 } 187 } 188 StringBuilder sb = new StringBuilder(); 189 for (String name : nameSet) 190 sb.append(name).append(" := ;\n"); 191 return sb.toString(); 192 } 193 194 /** 195 * @return true if the circuit is generic 196 */ isGeneric()197 public boolean isGeneric() { 198 return circuit.getAttributes().get(Keys.IS_GENERIC); 199 } 200 201 @Override getInputDescription(ElementAttributes elementAttributes)202 public PinDescriptions getInputDescription(ElementAttributes elementAttributes) throws NodeException { 203 if (isGeneric()) { 204 try { 205 Circuit c = resolveGenerics.resolveCircuit(elementAttributes).getCircuit(); 206 return new PinDescriptions(c.getInputNames()); 207 } catch (Exception e) { 208 return super.getInputDescription(elementAttributes); 209 } 210 } else 211 return super.getInputDescription(elementAttributes); 212 } 213 214 @Override getOutputDescriptions(ElementAttributes elementAttributes)215 public PinDescriptions getOutputDescriptions(ElementAttributes elementAttributes) throws PinException { 216 if (isGeneric()) { 217 try { 218 Circuit c = resolveGenerics.resolveCircuit(elementAttributes).getCircuit(); 219 return new PinDescriptions(c.getOutputNames()); 220 } catch (Exception e) { 221 return super.getOutputDescriptions(elementAttributes); 222 } 223 } else 224 return super.getOutputDescriptions(elementAttributes); 225 } 226 } 227