From 6140fa4f8e04052ec235de41584c15a0cd35ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Mosser?= Date: Tue, 6 Aug 2024 17:22:23 -0400 Subject: [PATCH 1/2] fixed missing JAR in published extension --- langium/CHANGELOG.md | 2 +- langium/package-lock.json | 4 ++-- langium/package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/langium/CHANGELOG.md b/langium/CHANGELOG.md index f5331df..a6deef7 100644 --- a/langium/CHANGELOG.md +++ b/langium/CHANGELOG.md @@ -2,7 +2,7 @@ ### Unreleased -### v0.2.1 (2024-08-06) +### v0.2.2 (2024-08-06) - Leader: Cass Braun - Features: - Added patterns and compositions to grammar with basic language support diff --git a/langium/package-lock.json b/langium/package-lock.json index 0f4891d..813c693 100644 --- a/langium/package-lock.json +++ b/langium/package-lock.json @@ -1,12 +1,12 @@ { "name": "jpipe-extension", - "version": "0.2.0", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jpipe-extension", - "version": "0.2.0", + "version": "0.2.2", "license": "MIT", "dependencies": { "langium": "~3.0.0", diff --git a/langium/package.json b/langium/package.json index aa0f709..f5eb3b9 100644 --- a/langium/package.json +++ b/langium/package.json @@ -4,7 +4,7 @@ "description": "Language Support for the jPipe language", "author": "McMaster Centre for Software Certification (McSCert)", "publisher": "mcscert", - "version": "0.2.1", + "version": "0.2.2", "license": "MIT", "icon": "images/logo.png", "repository": { From 8539682b35bbfdc3c8283fa03771f2acfcd5d7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Mosser?= Date: Sat, 14 Sep 2024 17:31:07 -0400 Subject: [PATCH 2/2] Support for load statement --- .../antlr4/ca/mcscert/jpipe/syntax/JPipe.g4 | 19 +++++-- .../jpipe/actions/ExecutionEngine.java | 16 +++++- .../ca/mcscert/jpipe/actions/LoadFile.java | 54 +++++++++++++++++++ .../jpipe/compiler/CompilerFactory.java | 22 ++++++++ .../jpipe/compiler/model/ChainBuilder.java | 5 ++ .../compiler/steps/ActionListProvider.java | 17 ++++++ .../java/ca/mcscert/jpipe/model/Unit.java | 33 +++++++++++- compiler/src/main/puml/model.puml | 18 ++++--- compiler/src/test/resources/load.jd | 23 ++++++++ 9 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 compiler/src/main/java/ca/mcscert/jpipe/actions/LoadFile.java create mode 100644 compiler/src/test/resources/load.jd diff --git a/compiler/src/main/antlr4/ca/mcscert/jpipe/syntax/JPipe.g4 b/compiler/src/main/antlr4/ca/mcscert/jpipe/syntax/JPipe.g4 index 83e7876..f7ce4f5 100644 --- a/compiler/src/main/antlr4/ca/mcscert/jpipe/syntax/JPipe.g4 +++ b/compiler/src/main/antlr4/ca/mcscert/jpipe/syntax/JPipe.g4 @@ -5,19 +5,25 @@ grammar JPipe; ******************/ // Root rule for parsing (called by the compilationChain) -unit : (justification)+ EOF; +unit : (justification | pattern | load)+ EOF; // Declare a justification -justification : JUSTIFICATION id=ID OPEN justif_body CLOSE; +justification : JUSTIFICATION id=ID (IMPLEMENTS parent=ID)? OPEN justif_body CLOSE; justif_body : (evidence | sub_conclusion | strategy | relation | conclusion)+; +pattern : PATTERN id=ID (IMPLEMENTS parent=ID)? OPEN pattern_body CLOSE; +pattern_body : (evidence | sub_conclusion | strategy | relation | conclusion | abstract)+; + +load : LOAD path=STRING; + // Body of a justification/pattern content +element : id=ID IS name=STRING; -element: id=ID IS name=STRING; evidence : EVIDENCE element; strategy : STRATEGY element; sub_conclusion : SUBCONCLUSION element; conclusion : CONCLUSION element; +abstract : ABSTRACT_SUP element; relation : from=ID SUPPORT_LNK to=ID; @@ -28,13 +34,20 @@ relation : from=ID SUPPORT_LNK to=ID; // Keywords JUSTIFICATION : 'justification'; +IMPLEMENTS : 'implements'; IS : 'is'; + EVIDENCE : 'evidence'; STRATEGY : 'strategy'; SUBCONCLUSION : 'sub-conclusion'; CONCLUSION : 'conclusion'; +PATTERN : 'pattern'; +ABSTRACT_SUP : '@support'; + SUPPORT_LNK : 'supports'; +LOAD : 'load'; + // Making whitespaces and newlines irrelevant to the syntax WHITESPACE : [ \t]+ -> channel(HIDDEN); NEWLINE : ('\r'? '\n' | '\r')+ -> channel(HIDDEN); diff --git a/compiler/src/main/java/ca/mcscert/jpipe/actions/ExecutionEngine.java b/compiler/src/main/java/ca/mcscert/jpipe/actions/ExecutionEngine.java index 0da531c..3717c35 100644 --- a/compiler/src/main/java/ca/mcscert/jpipe/actions/ExecutionEngine.java +++ b/compiler/src/main/java/ca/mcscert/jpipe/actions/ExecutionEngine.java @@ -3,6 +3,8 @@ import ca.mcscert.jpipe.error.ErrorManager; import ca.mcscert.jpipe.error.FatalException; import ca.mcscert.jpipe.model.Unit; +import java.io.File; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; @@ -41,11 +43,23 @@ public ExecutionEngine(boolean failOnError) { * @return the Unit after all the actions have been applied. */ public Unit spawn(String fileName, List actions) { - Unit unit = new Unit(fileName); + Unit unit = new Unit(fileName, Paths.get(fileName)); this.update(unit, actions); return unit; } + /** + * Enrich an existing compilation unit with actions (coming from a load for example). + * + * @param context the unit to enrich. + * @param actions the actions to execute. + * @return the enriched unit. + */ + public Unit enrich(Unit context, List actions) { + this.update(context, actions); + return context; + } + private void update(Unit u, List actions) { List errors = new ArrayList<>(); this.execute(actions, u, errors); diff --git a/compiler/src/main/java/ca/mcscert/jpipe/actions/LoadFile.java b/compiler/src/main/java/ca/mcscert/jpipe/actions/LoadFile.java new file mode 100644 index 0000000..9f3d053 --- /dev/null +++ b/compiler/src/main/java/ca/mcscert/jpipe/actions/LoadFile.java @@ -0,0 +1,54 @@ +package ca.mcscert.jpipe.actions; + +import ca.mcscert.jpipe.compiler.CompilerFactory; +import ca.mcscert.jpipe.compiler.model.Source; +import ca.mcscert.jpipe.compiler.model.Transformation; +import ca.mcscert.jpipe.compiler.steps.io.FileReader; +import ca.mcscert.jpipe.error.SemanticError; +import ca.mcscert.jpipe.model.Unit; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Load a file referenced in another file. + */ +public class LoadFile implements Action { + + private static final Logger logger = LogManager.getLogger(); + + private final String fileName; + + public LoadFile(String fileName) { + this.fileName = fileName; + } + + @Override + public void execute(Unit context) throws Exception { + Path p = new File(fileName).toPath().normalize(); + canLoad(p, context); + context.addLoadedFile(p); + Transformation> partial = CompilerFactory.actionProvider(); + Source reader = new FileReader(); + try (InputStream in = reader.provideFrom(p.toString())) { + List actions = partial.fire(in, p.toString()); + ExecutionEngine engine = new ExecutionEngine(); + engine.enrich(context, actions); + } + } + + + private void canLoad(Path p, Unit context) { + + if (context.isInScope(p)) { + throw new SemanticError("Cannot load file " + p + " as it is already loaded"); + } + if (!p.toFile().exists()) { + throw new SemanticError("Cannot load file " + p + " (file not found or not readable)"); + } + } + +} diff --git a/compiler/src/main/java/ca/mcscert/jpipe/compiler/CompilerFactory.java b/compiler/src/main/java/ca/mcscert/jpipe/compiler/CompilerFactory.java index ee06dfa..7c4f25c 100644 --- a/compiler/src/main/java/ca/mcscert/jpipe/compiler/CompilerFactory.java +++ b/compiler/src/main/java/ca/mcscert/jpipe/compiler/CompilerFactory.java @@ -1,6 +1,10 @@ package ca.mcscert.jpipe.compiler; +import ca.mcscert.jpipe.actions.Action; import ca.mcscert.jpipe.cli.Configuration; +import ca.mcscert.jpipe.compiler.model.ChainBuilder; +import ca.mcscert.jpipe.compiler.model.ChainCompiler; +import ca.mcscert.jpipe.compiler.model.Transformation; import ca.mcscert.jpipe.compiler.steps.ActionListInterpretation; import ca.mcscert.jpipe.compiler.steps.ActionListProvider; import ca.mcscert.jpipe.compiler.steps.Apply; @@ -14,6 +18,7 @@ import ca.mcscert.jpipe.compiler.steps.io.FileReader; import ca.mcscert.jpipe.compiler.steps.io.GraphVizRenderer; import ca.mcscert.jpipe.visitors.exporters.GraphVizExporter; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -56,4 +61,21 @@ private static Compiler defaultCompiler(Configuration config) { .andThen(new GraphVizRenderer(config.getFormat())); } + + /** + * Provide a partial compilation chain to get actions out of a given filename. + * + * @return a default instance of Compiler. + */ + public static Transformation> actionProvider() { + List errors = new ArrayList<>(); + return new FileReader() + .andThen(new CharStreamProvider()) + .andThen(new Lexer(errors)) + .andThen(new Parser(errors)) + .andThen(new LazyHaltAndCatchFire<>(errors)) + .andThen(new ActionListProvider()) + .asTransformation(); + } + } diff --git a/compiler/src/main/java/ca/mcscert/jpipe/compiler/model/ChainBuilder.java b/compiler/src/main/java/ca/mcscert/jpipe/compiler/model/ChainBuilder.java index d624e5f..45a661d 100644 --- a/compiler/src/main/java/ca/mcscert/jpipe/compiler/model/ChainBuilder.java +++ b/compiler/src/main/java/ca/mcscert/jpipe/compiler/model/ChainBuilder.java @@ -43,4 +43,9 @@ public ChainCompiler andThen(Sink sink) { return new ChainCompiler<>(this.source, this.chain, sink); } + + public Transformation asTransformation() { + return this.chain; + } + } diff --git a/compiler/src/main/java/ca/mcscert/jpipe/compiler/steps/ActionListProvider.java b/compiler/src/main/java/ca/mcscert/jpipe/compiler/steps/ActionListProvider.java index b834e49..367e5b4 100644 --- a/compiler/src/main/java/ca/mcscert/jpipe/compiler/steps/ActionListProvider.java +++ b/compiler/src/main/java/ca/mcscert/jpipe/compiler/steps/ActionListProvider.java @@ -7,9 +7,12 @@ import ca.mcscert.jpipe.actions.CreateRelation; import ca.mcscert.jpipe.actions.CreateStrategy; import ca.mcscert.jpipe.actions.CreateSubConclusion; +import ca.mcscert.jpipe.actions.LoadFile; import ca.mcscert.jpipe.compiler.model.Transformation; import ca.mcscert.jpipe.syntax.JPipeBaseListener; import ca.mcscert.jpipe.syntax.JPipeParser; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import org.antlr.v4.runtime.tree.ParseTree; @@ -58,6 +61,13 @@ public List collect() { return result; } + @Override + public void enterLoad(JPipeParser.LoadContext ctx) { + String relativePath = linearize(this.buildContext.unitFileName, + strip(ctx.path.getText())); + result.add(new LoadFile(relativePath)); + } + @Override public void enterJustification(JPipeParser.JustificationContext ctx) { this.buildContext = buildContext.updateCurrentJustification(ctx.id.getText()); @@ -101,6 +111,13 @@ public void enterRelation(JPipeParser.RelationContext ctx) { private String strip(String s) { return s.substring(1, s.length() - 1); } + + private String linearize(String rootFile, String fileName) { + Path root = Paths.get(rootFile).getParent(); + Path target = Paths.get(fileName); + return root.resolve(target).toString(); + } + } } diff --git a/compiler/src/main/java/ca/mcscert/jpipe/model/Unit.java b/compiler/src/main/java/ca/mcscert/jpipe/model/Unit.java index e7e11c4..132be9a 100644 --- a/compiler/src/main/java/ca/mcscert/jpipe/model/Unit.java +++ b/compiler/src/main/java/ca/mcscert/jpipe/model/Unit.java @@ -2,7 +2,11 @@ import ca.mcscert.jpipe.model.elements.JustificationElement; import ca.mcscert.jpipe.visitors.ModelVisitor; +import java.io.File; +import java.nio.file.Path; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; /** * Define what a compilation Unit is in JPipe. @@ -11,21 +15,39 @@ public final class Unit implements Visitable { private final String name; private final SymbolTable contents; + private final Set loaded; /** * Instantiates a compilation unit, using its name (source file). * * @param name the source file used to run the compiler. + * @param filePath path of the original file; */ - public Unit(String name) { + public Unit(String name, Path filePath) { this.name = name; this.contents = new SymbolTable<>(); + this.loaded = new HashSet<>(); + loaded.add(filePath.normalize().toString()); } public String getName() { return name; } + + public boolean isInScope(Path p) { + return this.loaded.contains(p.normalize().toString()); + } + + /** + * Add a path as part of the files loaded to contribute to this unit. + * + * @param p the path to add + */ + public void addLoadedFile(Path p) { + this.loaded.add(p.normalize().toString()); + } + /** * Record a new justification inside the unit symbol table. * @@ -60,4 +82,13 @@ public void accept(ModelVisitor visitor) { visitor.visit(this); } + + @Override + public String toString() { + return "Unit{" + + "name='" + name + '\'' + + ", contents=" + contents + + ", loaded=" + loaded + + '}'; + } } diff --git a/compiler/src/main/puml/model.puml b/compiler/src/main/puml/model.puml index 4bcc352..8339a84 100644 --- a/compiler/src/main/puml/model.puml +++ b/compiler/src/main/puml/model.puml @@ -9,24 +9,25 @@ class Unit { Unit *--> "1..*" Justification -class Justification { +class Justification implements Visitable { + name: String } -Justification *--> "1" Conclusion +Justification --> "1\nconclusion" Conclusion +Justification *-> "symbols\n*" JustificationElement -abstract class JustificationElement { +abstract class JustificationElement implements Visitable { + id: Symbol + label: String } class Conclusion extends JustificationElement -Conclusion -> "1" Strategy +Conclusion -> "1\nstrategy" Strategy class Strategy extends JustificationElement -Strategy -> "1..*" Support +Strategy -> "1..*\nsupports" Support abstract class Support extends JustificationElement @@ -34,6 +35,11 @@ class Evidence extends Support class SubConclusion extends Support -Strategy "1" <-- SubConclusion +Strategy "1\nstrategy" <-- SubConclusion + +interface Visitable { + + accept(v: ModelVisitor) + +} @enduml \ No newline at end of file diff --git a/compiler/src/test/resources/load.jd b/compiler/src/test/resources/load.jd new file mode 100644 index 0000000..4e34580 --- /dev/null +++ b/compiler/src/test/resources/load.jd @@ -0,0 +1,23 @@ +load "simple.jd" + +justification prove_models2 { + + evidence Su1 is "Atomic Petri Nets are available" + strategy St1 is "Merge atomic models" + Su1 supports St1 + + sub-conclusion SC1 is "Complete model is merged" + St1 supports SC1 + + evidence Su2 is "Prover is available" + evidence Su3 is "Scenario are available as TINA artefacts" + strategy St2 is "Prove model" + Su2 supports St2 + Su3 supports St2 + SC1 supports St2 + + conclusion C is "Model is correct" + St2 supports C + +} +