some refactoring, mostly working

This commit is contained in:
hneemann 2021-01-05 22:57:50 +01:00
parent da350b285a
commit 00d8a2f845
15 changed files with 125 additions and 71 deletions

View File

@ -150,7 +150,7 @@ public class SubstituteLibrary implements LibraryInterface {
c.getAttributes().set(Keys.IS_GENERIC, false);
generify(attr, c);
return ElementLibrary.createCustomDescription(new File(filename), c).isSubstitutedBuiltIn();
return ElementLibrary.createCustomDescription(new File(filename), c, library).isSubstitutedBuiltIn();
}
private void generify(ElementAttributes attr, Circuit circuit) throws IOException {

View File

@ -19,6 +19,7 @@ import java.util.Map;
public class ElementAttributes implements HGSMap {
private HashMap<String, Object> attributes;
private transient ArrayList<AttributeListener> listeners;
private transient HashMap<String, Object> cache;
/**
* Creates a new instance
@ -293,4 +294,16 @@ public class ElementAttributes implements HGSMap {
} else
return get(k);
}
public void putToCache(String key, Object value) {
if (cache == null)
cache = new HashMap<>();
cache.put(key, value);
}
public Object getFromCache(String key) {
if (cache == null)
return null;
return cache.get(key);
}
}

View File

@ -253,13 +253,6 @@ public class ElementTypeDescription {
return inputPins.get(i);
}
/**
* @return true if this is a custom component
*/
public boolean isCustom() {
return false;
}
/**
* @return the class loader, the component is loaded from. Maybe null.
*/

View File

@ -39,7 +39,6 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
// shapes are recreated if attributes are changed, therefore a factory is necessary and not only a simple shape!
private transient ShapeFactory shapeFactory;
private transient Transform transform;
private transient Context genericArgs;
// these fields are stored to disk
private String elementName;
@ -461,22 +460,6 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
return interactor != null;
}
/**
* Sets the generic arguments for this element
*
* @param genericArgs the arguments
*/
public void setGenericArgs(Context genericArgs) {
this.genericArgs = genericArgs;
}
/**
* @return the generic arguments for this element
*/
public Context getGenericArgs() {
return genericArgs;
}
/**
* Sets the name of this element
*

View File

@ -39,14 +39,13 @@ public class CustomElement implements Element {
* @param depth recursion depth, used to detect a circuit which contains itself
* @param errorVisualElement visual element used for error indicating
* @param containingVisualElement the containing visual element
* @param library the library to use
* @return the {@link ModelCreator}
* @throws PinException PinException
* @throws NodeException NodeException
* @throws ElementNotFoundException ElementNotFoundException
*/
public ModelCreator getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement, LibraryInterface library) throws PinException, NodeException, ElementNotFoundException {
return descriptionCustom.getModelCreator(subName, depth, errorVisualElement, containingVisualElement, library);
public ModelCreator getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement) throws PinException, NodeException, ElementNotFoundException {
return descriptionCustom.getModelCreator(subName, depth, errorVisualElement, containingVisualElement);
}
@Override

View File

@ -587,7 +587,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file));
}
ElementTypeDescriptionCustom description = createCustomDescription(file, circuit);
ElementTypeDescriptionCustom description = createCustomDescription(file, circuit, this);
description.setShortName(createShortName(file.getName(), circuit.getAttributes().getLabel()));
String descriptionText = Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION));
@ -622,8 +622,8 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
* @return the type description
* @throws PinException PinException
*/
public static ElementTypeDescriptionCustom createCustomDescription(File file, Circuit circuit) throws PinException {
ElementTypeDescriptionCustom d = new ElementTypeDescriptionCustom(file, circuit);
public static ElementTypeDescriptionCustom createCustomDescription(File file, Circuit circuit, ElementLibrary library) throws PinException {
ElementTypeDescriptionCustom d = new ElementTypeDescriptionCustom(file, circuit, library);
d.setElementFactory(attributes -> new CustomElement(d));
return d;
}

View File

@ -32,6 +32,7 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
private final File file;
private final Circuit circuit;
private final ResolveGenerics resolveGenerics;
private final LibraryInterface library;
private String description;
private NetList netList;
private boolean isCustom = true;
@ -44,11 +45,12 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
* @param circuit the circuit
* @throws PinException PinException
*/
ElementTypeDescriptionCustom(File file, Circuit circuit) throws PinException {
ElementTypeDescriptionCustom(File file, Circuit circuit, ElementLibrary library) throws PinException {
super(file.getName(), (ElementFactory) null, circuit.getInputNames());
this.file = file;
this.circuit = circuit;
resolveGenerics = new ResolveGenerics();
this.library = library;
resolveGenerics = new ResolveGenerics(circuit, library);
setShortName(file.getName());
addAttribute(Keys.ROTATE);
addAttribute(Keys.LABEL);
@ -105,13 +107,12 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
* @param subName name of the circuit, used to name unique elements
* @param depth recursion depth, used to detect a circuit which contains itself
* @param containingVisualElement the containing visual element
* @param library the library used
* @return the {@link ModelCreator}
* @throws PinException PinException
* @throws NodeException NodeException
* @throws ElementNotFoundException ElementNotFoundException
*/
ModelCreator getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement, LibraryInterface library) throws PinException, NodeException, ElementNotFoundException {
ModelCreator getModelCreator(String subName, int depth, VisualElement errorVisualElement, VisualElement containingVisualElement) throws PinException, NodeException, ElementNotFoundException {
if (netList == null)
netList = new NetList(circuit);
@ -119,14 +120,13 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
throw new NodeException(Lang.get("err_recursiveNestingAt_N0", circuit.getOrigin()));
if (isGeneric()) {
Circuit c = resolveGenerics.resolveCircuit(containingVisualElement, circuit, library).getCircuit();
Circuit c = resolveGenerics.resolveCircuit(containingVisualElement.getElementAttributes()).getCircuit();
return new ModelCreator(c, library, true, new NetList(new NetList(c), errorVisualElement), subName, depth, errorVisualElement);
} else
return new ModelCreator(circuit, library, true, new NetList(netList, errorVisualElement), subName, depth, errorVisualElement);
}
@Override
public boolean isCustom() {
return isCustom;
}
@ -198,4 +198,30 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
public boolean isGeneric() {
return circuit.getAttributes().get(Keys.IS_GENERIC);
}
@Override
public PinDescriptions getInputDescription(ElementAttributes elementAttributes) throws NodeException {
if (isGeneric()) {
try {
Circuit c = resolveGenerics.resolveCircuit(elementAttributes).getCircuit();
return new PinDescriptions(c.getInputNames());
} catch (ElementNotFoundException | PinException e) {
return super.getInputDescription(elementAttributes);
}
} else
return super.getInputDescription(elementAttributes);
}
@Override
public PinDescriptions getOutputDescriptions(ElementAttributes elementAttributes) throws PinException {
if (isGeneric()) {
try {
Circuit c = resolveGenerics.resolveCircuit(elementAttributes).getCircuit();
return new PinDescriptions(c.getOutputNames());
} catch (ElementNotFoundException | PinException | NodeException e) {
return super.getOutputDescriptions(elementAttributes);
}
} else
return super.getOutputDescriptions(elementAttributes);
}
}

View File

@ -7,6 +7,8 @@ package de.neemann.digital.draw.library;
import de.neemann.digital.analyse.SubstituteLibrary;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.draw.elements.Circuit;
import de.neemann.digital.draw.elements.VisualElement;
@ -16,6 +18,8 @@ import de.neemann.digital.hdl.hgs.*;
import de.neemann.digital.hdl.hgs.function.Function;
import de.neemann.digital.hdl.hgs.function.InnerFunction;
import de.neemann.digital.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.*;
@ -26,39 +30,63 @@ import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
* Resolves a generic circuit and makes it non generic
*/
public class ResolveGenerics {
private static final Logger LOGGER = LoggerFactory.getLogger(ResolveGenerics.class);
private static final Context EMPTY_CONTEXT = new Context();
public static final String GEN_ARGS_KEY = "genArgs";
private final HashMap<String, Statement> map;
private LibraryInterface library;
private final HashMap<Context, CircuitHolder> circuitMap;
private final Circuit circuit;
private final LibraryInterface library;
/**
* Creates a new instance
*
* @param circuit the circuit to resolve
* @param library the library to ude
*/
public ResolveGenerics() {
public ResolveGenerics(Circuit circuit, LibraryInterface library) {
this.circuit = circuit;
this.library = library;
map = new HashMap<>();
circuitMap = new HashMap<>();
}
/**
* Resolves the generics
*
* @param visualElement the visual element
* @param circuit the circuit to resolve
* @param library the library to ude
* @param attributes the visual elements attributes
* @return the resolved circuit
* @throws NodeException NodeException
* @throws ElementNotFoundException ElementNotFoundException
*/
public CircuitHolder resolveCircuit(VisualElement visualElement, Circuit circuit, LibraryInterface library) throws NodeException, ElementNotFoundException {
this.library = library;
public CircuitHolder resolveCircuit(ElementAttributes attributes) throws NodeException, ElementNotFoundException {
Context context = EMPTY_CONTEXT;
if (attributes != null)
context = (Context) attributes.getFromCache(GEN_ARGS_KEY);
CircuitHolder ch = circuitMap.get(context);
if (ch == null) {
ch = innerResolveCircuit(attributes);
circuitMap.put(context, ch);
}
return ch;
}
public CircuitHolder innerResolveCircuit(ElementAttributes parentAttributes) throws NodeException, ElementNotFoundException {
LOGGER.info("create concrete circuit based on " + circuit.getOrigin());
final Circuit c = circuit.createDeepCopy();
ArrayList<VisualElement> newComponents = new ArrayList<>();
final Args args = createArgs(visualElement, c, newComponents);
final Args args = createArgs(parentAttributes, c, newComponents);
for (VisualElement ve : c.getElements()) {
String gen = ve.getElementAttributes().get(Keys.GENERIC).trim();
ElementAttributes elementAttributes = ve.getElementAttributes();
String gen = elementAttributes.get(Keys.GENERIC).trim();
try {
if (!gen.isEmpty()) {
boolean isCustom = library.getElementType(ve.getElementName(), ve.getElementAttributes()).isCustom();
ElementTypeDescription elementTypeDescription = library.getElementType(ve.getElementName(), elementAttributes);
boolean isCustom = elementTypeDescription instanceof ElementTypeDescriptionCustom;
Statement genS = getStatement(gen);
Context mod = createContext(c, newComponents);
if (isCustom) {
@ -67,10 +95,10 @@ public class ResolveGenerics {
genS.execute(mod);
} else {
mod.declareVar("args", args)
.declareVar("this", new SubstituteLibrary.AllowSetAttributes(ve.getElementAttributes()));
.declareVar("this", new SubstituteLibrary.AllowSetAttributes(elementAttributes));
genS.execute(mod);
}
ve.setGenericArgs(mod);
elementAttributes.putToCache(GEN_ARGS_KEY, mod);
}
} catch (HGSEvalException | ParserException | IOException e) {
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", ve, gen), e);
@ -97,18 +125,18 @@ public class ResolveGenerics {
}
}
private Args createArgs(VisualElement visualElement, Circuit circuit, ArrayList<VisualElement> newComponents) throws NodeException {
private Args createArgs(ElementAttributes attributes, Circuit circuit, ArrayList<VisualElement> newComponents) throws NodeException {
Context context;
if (visualElement != null) {
context = visualElement.getGenericArgs();
if (attributes != null) {
context = (Context) attributes.getFromCache(GEN_ARGS_KEY);
if (context == null) {
String argsCode = visualElement.getElementAttributes().get(Keys.GENERIC);
String argsCode = attributes.get(Keys.GENERIC);
try {
Statement s = getStatement(argsCode);
context = createContext(circuit, newComponents);
s.execute(context);
} catch (HGSEvalException | ParserException | IOException e) {
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", visualElement, argsCode), e);
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", null, argsCode), e);
ex.setOrigin(circuit.getOrigin());
throw ex;
}
@ -214,16 +242,16 @@ public class ResolveGenerics {
circuit.delete(gic);
for (VisualElement v : circuit.getElements()) {
try {
boolean isCustom = library.getElementType(v.getElementName(), v.getElementAttributes()).isCustom();
boolean isCustom = library.getElementType(v.getElementName(), v.getElementAttributes()) instanceof ElementTypeDescriptionCustom;
if (isCustom)
v.getElementAttributes().set(Keys.GENERIC, createGenericCode(v.getGenericArgs()));
v.getElementAttributes().set(Keys.GENERIC, createGenericCode((Context) v.getElementAttributes().getFromCache(GEN_ARGS_KEY)));
else
v.getElementAttributes().set(Keys.GENERIC, "");
} catch (ElementNotFoundException e) {
// can not happen
e.printStackTrace();
}
v.setGenericArgs(null);
v.getElementAttributes().putToCache(GEN_ARGS_KEY, null);
}
circuit.getAttributes().set(Keys.IS_GENERIC, false);

View File

@ -65,7 +65,7 @@ public class ModelCreator implements Iterable<ModelEntry> {
*/
public static Circuit fixGenerics(Circuit circuit, LibraryInterface library) throws NodeException, ElementNotFoundException {
if (circuit.getAttributes().get(Keys.IS_GENERIC))
return new ResolveGenerics().resolveCircuit(null, circuit, library).getCircuit();
return new ResolveGenerics(circuit, library).resolveCircuit(null).getCircuit();
else
return circuit;
}
@ -170,7 +170,7 @@ public class ModelCreator implements Iterable<ModelEntry> {
combineNames(subName, me.getVisualElement().getElementAttributes().getLabel()),
depth + 1,
containingVisualElement != null ? containingVisualElement : me.getVisualElement(),
me.getVisualElement(), library);
me.getVisualElement());
modelCreators.add(child);
HashMap<Net, Net> netMatch = new HashMap<>();

View File

@ -33,8 +33,13 @@ public class TextShape implements Shape {
*/
public TextShape(ElementAttributes attr, PinDescriptions inputs, PinDescriptions outputs) {
String text = attr.get(Keys.DESCRIPTION);
if (text.length() == 0)
text = Lang.get("elem_Text");
if (text.length() == 0) {
String gen = attr.get(Keys.GENERIC);
if (gen.isEmpty())
text = Lang.get("elem_Text");
else
text = gen.replace(" ", "\u00A0");
}
this.text = Lang.evalMultilingualContent(text);
fontSize = attr.get(Keys.FONT_SIZE);

View File

@ -375,7 +375,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
file = new File(name);
try {
ElementTypeDescriptionCustom description =
ElementLibrary.createCustomDescription(file, circuit);
ElementLibrary.createCustomDescription(file, circuit, library);
description.setShortName(name);
description.setDescription(Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION)));
new ElementHelpDialog(Main.this, description, circuit.getAttributes()).setVisible(true);

View File

@ -1176,8 +1176,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
modify(checkNetRename(element, modified, mod));
}
Circuit concreteCircuit = new ResolveGenerics()
.resolveCircuit(element, getCircuit(), library)
Circuit concreteCircuit = new ResolveGenerics(getCircuit(), library)
.resolveCircuit(element.getElementAttributes())
.cleanupConcreteCircuit()
.getCircuit();

View File

@ -36,7 +36,6 @@ import static de.neemann.digital.draw.model.ModelCreator.fixGenerics;
public class HDLModel implements Iterable<HDLCircuit> {
private final ElementLibrary elementLibrary;
private final HashMap<Circuit, HDLCircuit> circuitMap;
private final ResolveGenerics resolveGenerics = new ResolveGenerics();
private final HashMap<String, GenericsCache> genericInstanceNumbers;
private HDLCircuit main;
private Renaming renaming;
@ -68,7 +67,7 @@ public class HDLModel implements Iterable<HDLCircuit> {
final Circuit circuit = tdc.getCircuit();
if (circuit.getAttributes().get(Keys.IS_GENERIC)) {
ResolveGenerics.CircuitHolder holder = resolveGenerics.resolveCircuit(v, circuit, elementLibrary);
ResolveGenerics.CircuitHolder holder = new ResolveGenerics(circuit, elementLibrary).resolveCircuit(v.getElementAttributes());
GenericsCache cache = genericInstanceNumbers.computeIfAbsent(v.getElementName(), t -> new GenericsCache());

View File

@ -53,7 +53,7 @@ public class TestExecutor {
static private Model createModel(Circuit.TestCase testCase, Circuit circuit, ElementLibrary library) throws NodeException, ElementNotFoundException, PinException {
final Model model;
if (circuit != null && circuit.getAttributes().get(Keys.IS_GENERIC) && testCase.hasGenericCode()) {
Circuit c = new ResolveGenerics().resolveCircuit(testCase.getVisualElement(), circuit, library).getCircuit();
Circuit c = new ResolveGenerics(circuit, library).resolveCircuit(testCase.getVisualElement().getElementAttributes()).getCircuit();
model = new ModelCreator(c, library, false).createModel(false);
} else
model = new ModelCreator(circuit, library).createModel(false);

View File

@ -23,6 +23,8 @@ import junit.framework.TestCase;
import java.io.File;
import java.util.List;
import static de.neemann.digital.draw.library.ResolveGenerics.GEN_ARGS_KEY;
/**
* Reads all examples and tries to create the model.
* Makes sure that all examples are creatable (one can build the model)
@ -32,6 +34,12 @@ public class TestExamples extends TestCase {
private int testCasesInFiles;
public void testDebug() throws Exception {
File f = new File("/home/hneemann/Dokumente/Java/digital/src/main/dig/generic/barrelShifter/TestBarrelShifter.dig");
check(f);
}
/**
* Tests the examples which are distributed
*
@ -123,13 +131,13 @@ public class TestExamples extends TestCase {
VisualElement element = initCodeList.get(0);
Circuit concreteCircuit = new ResolveGenerics()
.resolveCircuit(element, circuit, library)
Circuit concreteCircuit = new ResolveGenerics(circuit, library)
.resolveCircuit(element.getElementAttributes())
.cleanupConcreteCircuit()
.getCircuit();
for (VisualElement ve : concreteCircuit.getElements()) {
assertNull(ve.getGenericArgs());
assertNull(ve.getElementAttributes().getFromCache(GEN_ARGS_KEY));
assertFalse(ve.equalsDescription(GenericInitCode.DESCRIPTION));
}