These are my notes and insights while extending the VisB Java code for new features (optional, ignore, repeat, for attributes, inclusion, and better error reporting) and then rewriting the core of VisB in Prolog
Note: still under construction !
This is very convenient. With a simple declaration I can now store VisB items as Prolog facts:
:- dynamic visb_svg_file/3,visb_item/4, visb_event/4.
Adding a fact is simply calling assert(visb_item(ID,Attr,TypedExpr,Desc) and looking up facts using arbitrary patterns is just calling visb_item(SvgID,SvgAttribute,Formula,_Desc). This call can serve as an enumerator/iterator over all VisB items (if all variables unbound), or to look up items for particular SVG Ids or particular attributes.
In Java, a VisB item is declared in this class (VisBItem.java), with setters and getters (which I feel are complete overkill here). Items are stored in a list
List<VisBItem> visBItems = new ArrayList<>();
where we add using
visBItems.add(new VisBItem(id, attribute, value, optional))
Note: we have no convenient way to look up arbitrary patterns. Here are the contents of VisBItem.java, which also includes one parsing method:
package de.prob2.ui.visb.visbobjects; import de.prob.animator.domainobjects.IEvalElement; import de.prob2.ui.visb.VisBParser; import de.prob2.ui.visb.exceptions.VisBNestedException; import de.prob.model.classicalb.ClassicalBModel; import de.prob.exception.ProBError; import de.prob.statespace.Trace; import de.prob.animator.domainobjects.EvaluationException; import de.prob.animator.domainobjects.ClassicalB; import de.prob2.ui.prob2fx.CurrentTrace; import de.prob.animator.domainobjects.FormulaExpand; import java.util.Objects; /** * The VisBItem is designed for the JSON / VisB file */ public class VisBItem { private String id; private String attribute; private String value; // B Formula to compute value of attribute for SVG object id private Boolean optional; // if true then we ignore identifier not found errors and simply disable this item private IEvalElement parsedFormula; // if different from null the formula has already been parsed /** * * @param id this has to be the id used in the svg file to correspond with that svg element * @param attribute this has to be an actual svg attribute, that can be handled via {@link VisBParser} * @param value this formula has to provide a valid value usable with the given attribute * @param optional true if this item is optional, i.e., will be ignored if the value formula contains unknown ids */ public VisBItem(String id, String attribute, String value, Boolean optional) { this.id = id; this.attribute = attribute.toLowerCase(); this.value = value; this.optional = optional; } public String getId() { return id; } public String getAttribute() { return attribute; } public String getValue() { return value; } public Boolean itemIsOptional() { return optional; } public IEvalElement getParsedFormula() { // getter which does not require CurrentTrace; but cannot parse on demand return parsedFormula; } /** * parse the formula of VisBItem and store parsed formula in parsedFormula attribute */ public IEvalElement getParsedValueFormula(CurrentTrace currentTrace) throws VisBNestedException, ProBError { String formulaToEval = this.getValue(); try { if (this.parsedFormula != null) { return this.parsedFormula; // is already parsed } else if(currentTrace.getModel() instanceof ClassicalBModel) { this.parsedFormula = currentTrace.getModel().parseFormula(formulaToEval, FormulaExpand.EXPAND); // use parser associated with the current model, DEFINITIONS are accessible } else { this.parsedFormula = new ClassicalB(formulaToEval, FormulaExpand.EXPAND); // use classicalB parser // Note: Rodin parser does not have IF-THEN-ELSE nor STRING manipulation, cumbersome for VisB } } catch (EvaluationException e){ System.out.println("\nException for "+ this.getId() + "."+ this.getAttribute() + " : " + e); throw(new VisBNestedException("Exception parsing B formula for VisB item "+ this.getId() + "."+ this.getAttribute() + " : ",e)); } return this.parsedFormula; } @Override public String toString(){ return "{ID: " + this.id +", ATTRIBUTE: "+this.attribute+", VALUE: "+this.value+"} "; } @Override public boolean equals(Object obj) { if(!(obj instanceof VisBItem)) { return false; } VisBItem other = (VisBItem) obj; return this.id.equals(other.id) && this.attribute.equals(other.attribute) && this.value.equals(other.value); } @Override public int hashCode() { return Objects.hash(id, attribute, value); } }
The existing Java code held the above VisB items in a list: List<VisBItem>. Let us examine a few Prolog queries, to show the versatility and conciseness:
visb_item(train1,visibility,_,_)
visb_item(train,visibility,Formula,_)
visb_item(ID,Attr,Formula,Desc), DoSomething, fail
findall(conflict(ID,Attr), (visb_item(ID,Attr,F1,_),visb_item(ID,Attr,F2,_), F1 @< F2), Cs)
To implement the latter in Java you need to: