diff --git a/.gitignore b/.gitignore index 49bb2c2b2..15da593af 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ enroute.zip .idea *.iml +languageServers-log/AlloyLanguageServer.log diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..7b016a89f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/README.md b/README.md index 4eaf33cef..db8fc6338 100644 --- a/README.md +++ b/README.md @@ -78,12 +78,12 @@ Bndtools will continuously create the final executable. The projects are setup t Ensure you have the [Osmorc] plugin is enabled, as this plugin is needed for Bndtools support. It should be enabled by default. -1. Choose "Import Project" -2. Select the `org.alloytools.alloy` directory. +1. Choose `Import project from existing Sources` by using `Ctrl + Shift + a`. +2. Select the root folder (default folder name is `org.alloytools.alloy`). 3. Choose "Import project from external model: Bnd/Bndtools" and click "Next" -4. For "Select Bnd/Bndtools project to import", all projects should be checked - by default, click "Next" +4. For "Select Bnd/Bndtools project to import", all projects should be checked by default, click "Next" 5. For project SDK, Choose "1.8", Click Finish +6. Select folder `org/alloytools/kodkod/nativesat/jni` as `Resource Folder` by selecting module `org.alloytools.kodkod.nativesat`, selecting folder `jni` -> `right click` -> `Mark Directory As` -> `Resource Root`. Note: do *not* link the Gradle project, as this will prevent you from running Alloy within IDEA. diff --git a/cnf/.project b/cnf/.project index 0b7164229..b0d9ea35d 100644 --- a/cnf/.project +++ b/cnf/.project @@ -5,6 +5,11 @@ + + org.eclipse.buildship.core.gradleprojectbuilder + + + org.eclipse.jdt.core.javabuilder @@ -13,5 +18,17 @@ org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + 1687449709131 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/cnf/.settings/org.eclipse.buildship.core.prefs b/cnf/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/cnf/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/cnf/build.bnd b/cnf/build.bnd index 21510a285..4ca8bea32 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -12,6 +12,7 @@ javac.source: 1.8 javac.target: 1.8 javac.compliance: 1.8 javac.debug: on +-sources false Git-Descriptor: ${system-allow-fail;git describe --dirty --always} Git-SHA: ${system-allow-fail;git rev-list -1 HEAD} @@ -27,6 +28,7 @@ Bundle-Version: ${base.version}.${tstamp} # Remove -SNAPSHOT for release version -pom: version=${base.version}-SNAPSHOT -groupid: org.alloytools +-includepackage *;from:=classes # @@ -61,8 +63,4 @@ usr = ${env;REPOSITORY_USERNAME;} -connection-settings: ${if;${pwd};server;-dummy};id=https://oss.sonatype.org;username=${usr};password=${pwd}, -bnd -# -# Install a copy in the local Maven repository (~/.m2/repository) -# - - +-includepackage *;from:=classes diff --git a/cnf/central.mvn b/cnf/central.mvn index 37dea4666..f3fa8700b 100644 --- a/cnf/central.mvn +++ b/cnf/central.mvn @@ -1,12 +1,30 @@ +biz.aQute.bnd:aQute.libg:6.0.0 +biz.aQute:biz.aQute.wrapper.hamcrest:1.3 +biz.aQute:biz.aQute.wrapper.junit:4.13.1 +com.google.code.gson:gson:2.8.9 +com.google.code.gson:gson:2.8.9 +commons-io:commons-io:jar:2.6 +commons-io:commons-io:jar:2.6 +de.jflex:jflex:1.6.1 +org.alloytools:pardinus.core:1.3.0 +org.alloytools:pardinus.nativesat:1.3.0 +org.eclipse.equinox:org.eclipse.equinox.common:jar:3.6.0 +org.eclipse.equinox:org.eclipse.equinox.common:jar:3.6.0 org.eclipse.jdt:org.eclipse.jdt.annotation:2.1.100 +org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.4.1 +org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.4.1 +org.eclipse.lsp4j:org.eclipse.lsp4j:0.4.1 +org.eclipse.lsp4j:org.eclipse.lsp4j:0.4.1 org.sat4j:org.sat4j.core:2.3.1 org.sat4j:org.sat4j.maxsat:2.3.1 org.sat4j:org.sat4j.pb:2.3.1 -de.jflex:jflex:1.6.1 org.slf4j:slf4j-api:1.7.28 org.slf4j:slf4j-simple:1.7.5 org.alloytools:pardinus.core:1.3.0 org.alloytools:pardinus.nativesat:1.3.0 biz.aQute:biz.aQute.wrapper.hamcrest:1.3 biz.aQute:biz.aQute.wrapper.junit:4.13.1 -biz.aQute.bnd:aQute.libg:6.0.0 \ No newline at end of file +biz.aQute.bnd:aQute.libg:6.1.0 +org.osgi:org.osgi.annotation.bundle:1.1.1 +org.osgi:osgi.annotation:8.0.1 +com.io7m.jpplib:io7m-jpplib-core:0.7.4 diff --git a/org.alloytools.alloy.application/.classpath b/org.alloytools.alloy.application/.classpath index bcafe71e5..ae30f860a 100644 --- a/org.alloytools.alloy.application/.classpath +++ b/org.alloytools.alloy.application/.classpath @@ -1,12 +1,19 @@ - - - - + + + + + + + + + - + + + diff --git a/org.alloytools.alloy.application/.project b/org.alloytools.alloy.application/.project index 2f98f1715..1d348fb1e 100644 --- a/org.alloytools.alloy.application/.project +++ b/org.alloytools.alloy.application/.project @@ -10,6 +10,11 @@ + + org.eclipse.buildship.core.gradleprojectbuilder + + + bndtools.core.bndbuilder @@ -19,5 +24,17 @@ org.eclipse.jdt.core.javanature bndtools.core.bndnature + org.eclipse.buildship.core.gradleprojectnature + + + 1687449709165 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/org.alloytools.alloy.application/.settings/org.eclipse.buildship.core.prefs b/org.alloytools.alloy.application/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/org.alloytools.alloy.application/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/org.alloytools.alloy.application/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.application/.settings/org.eclipse.jdt.core.prefs index 2f809de6d..978ab1820 100644 --- a/org.alloytools.alloy.application/.settings/org.eclipse.jdt.core.prefs +++ b/org.alloytools.alloy.application/.settings/org.eclipse.jdt.core.prefs @@ -26,9 +26,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=17 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -91,7 +91,7 @@ org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning -org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning @@ -134,7 +134,7 @@ org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.processAnnotations=disabled org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME @@ -143,6 +143,7 @@ org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 org.eclipse.jdt.core.formatter.align_type_members_on_columns=true org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 @@ -150,21 +151,24 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_c org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_assignment=2 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=2 org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=2 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=2 org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=2 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 @@ -256,11 +260,12 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -291,6 +296,8 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -315,13 +322,17 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -369,6 +380,8 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do no org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -405,9 +418,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -446,10 +462,14 @@ org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=true org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/org.alloytools.alloy.application/bnd.bnd b/org.alloytools.alloy.application/bnd.bnd index ff7ee2679..d22a42e87 100644 --- a/org.alloytools.alloy.application/bnd.bnd +++ b/org.alloytools.alloy.application/bnd.bnd @@ -5,7 +5,9 @@ lib/apple-osx-ui.jar;version=file,\ org.alloytools:pardinus.core;version='1.3.0',\ org.alloytools.alloy.core;version=latest,\ - aQute.libg + org.alloytools.alloy.dash;version=latest,\ + aQute.libg,\ + org.alloytools.api -testpath: \ biz.aQute.wrapper.junit, \ biz.aQute.wrapper.hamcrest, \ @@ -15,3 +17,4 @@ Private-Package: \ edu.mit.csail.sdg.alloy4graph,\ edu.mit.csail.sdg.alloy4viz,\ edu.mit.csail.sdg.alloy4whole,\ + ca.uwaterloo.watform.dash4whole,\ \ No newline at end of file diff --git a/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/Dash.java b/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/Dash.java new file mode 100644 index 000000000..19edc69b9 --- /dev/null +++ b/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/Dash.java @@ -0,0 +1,271 @@ +package ca.uwaterloo.watform.dash4whole; + +import java.util.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.Files; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +import edu.mit.csail.sdg.alloy4.Version; + +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.alloy4viz.VizGUI; +import edu.mit.csail.sdg.ast.Command; +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.translator.A4Options; +import edu.mit.csail.sdg.translator.A4Solution; +import edu.mit.csail.sdg.translator.TranslateAlloyToKodkod; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.mainfunctions.MainFunctions; + + + + +public class Dash { + + @SuppressWarnings("resource" ) + + public static void executeCommands(CompModule c, Integer commandNumber, A4Reporter rep) { + // Choose some default options for how you want to execute the commands + A4Options options = new A4Options(); + + List commands = c.getAllCommands(); + // this is an annoying way to convert a list to an array + Integer i = 1; + for (Command cmd : commands) { + if (i == commandNumber | commandNumber == 0) { + System.out.println("Executing command: " + cmd); + A4Solution ans = null; + try { + ans = MainFunctions.executeCommand(cmd,c,rep, options); + } catch (Exception e) { + DashUtilFcns.handleException(e); + } + if (ans.satisfiable()) { + if (cmd.expects == 1) + System.out.println("Result: SAT (CORRECT)"); + else if (cmd.expects == 0) + System.out.println("Result: SAT (INCORRECT)"); + else + System.out.println("Result: SAT (nothing expected)"); + } else { + if (cmd.expects == 0) + System.out.println("Result: UNSAT (CORRECT)"); + else if (cmd.expects == 1) + System.out.println("Result: UNSAT (INCORRECT)"); + else + System.out.println("Result: UNSAT (nothing expected)"); + } + + } + i++; + } + if (commandNumber >= i) { + System.err.println("Command number: " + commandNumber + " does not exist in file"); + } + } + + public static void main(String args[]) throws Exception { + + if(args.length == 0) { + System.out.println("Arguments: (-m traces|tcmc|electrum) (-single) (-reach) (-c #) (-p) (-t) (-tla) (-r) filename(s)"); + System.out.println("-m traces|tcmc|electrum is verification method"); + System.out.println("-single includes single event input fact"); + System.out.println("-reach includes reachability fact (for tcmc only)"); + System.out.println("-enough includes enoughOperations pred"); + System.out.println("-c # is commandNumber to execute"); + System.out.println("-t is translateOnly"); + System.out.println("-r is resolveOnly"); + System.out.println("-e is echo file from internal parsed data"); + System.out.println("-tla translates the file to TLA+, translated file has the same path and name unless otherwise specified"); + System.out.println("expects .dsh or .als file"); + System.out.println("if given a .als files, it ignores other options and runs all its commands"); + System.exit(0); + } + + // simple roll-our-own argument parser + // to avoid having to import an external package + + List filelist = new ArrayList<>(); + + // default values + String method = "traces"; + int commandNumber = 0; + boolean translateOnly = false; + boolean printOnly = false; + boolean resolveOnly = false; + boolean translateTLA = false; + + for (int i=0; i 0) // if the file has a dot and no "dsh" after it, it is assumed to be a different type of file + { + System.err.println("Expected a Dash file with 'dsh' or 'als' extension: "+filename); + break; + } + else filename = filename + ".dsh"; // if there is no dot, it is assumed that the user forgot to add .dsh + } + + Path f = Paths.get(filename); + + if (Files.notExists(f)) { + System.err.println(filename + " : does not exist"); + return; + } + + Path directory = f.toAbsolutePath().getParent(); + if (directory.toString() != null) + DashOptions.dashModelLocation = directory.toString(); + + + System.out.println("Reading: " + filename ); + + A4Reporter rep = new A4Reporter(); + + if (filename.endsWith(".als")) { + try { + CompModule c = MainFunctions.parseAlloyFileAndResolveAll(filename, rep); + System.out.println("Parsed Alloy file"); + // will raise an exception if problems + System.out.println("Resolved Alloy file"); + executeCommands(c,commandNumber,rep); + } catch (Exception e) { + DashUtilFcns.handleException(e); + } + } else { + try { + DashModule d = MainFunctions.parseDashFile(filename, rep); + System.out.println("Parsed Dash file"); + if (d == null) DashErrors.emptyFile(filename); + + if (printOnly) { + System.out.println(d.toStringAlloy()); + } else if(translateTLA) + { + d = MainFunctions.resolveDash(d, rep); + String moduleWithExtension = f.getFileName().toString(); + String moduleName = moduleWithExtension.substring(0, moduleWithExtension.length()-4); + String contents = MainFunctions.translateTLA(d,moduleName); + + // by default, the target is a file in the same folder as the source + String TLAfilename = filename.substring(0,filename.length()-4)+".tla"; + + // allow user to specify the target right next to the source if they want + try + { + String target = filelist.get(i+1); + if(target.endsWith(".tla")) + { + i++; // if an explicit target is mentioned, it is skipped over in the next iteration + TLAfilename = target; + } + } + catch(ArrayIndexOutOfBoundsException e){} + + System.out.println("Translating "+filename+" to TLA+ and writing to "+TLAfilename); + + File out = new File(TLAfilename); + if (!out.exists()) out.createNewFile(); + System.out.println("Creating: " + TLAfilename); + FileWriter fw = new FileWriter(out.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fw); + bw.write(contents); + bw.close(); + } + else { + d = MainFunctions.resolveDash(d, rep); + System.out.println("Resolved Dash"); + CompModule c = MainFunctions.translate(d, rep); + System.out.println("Translated Dash to Alloy"); + // if problem exception would be raised + if (translateOnly) { + String outfilename = filename.substring(0,filename.length()-4) + "-" + method + ".als"; + File out = new File(outfilename); + if (!out.exists()) out.createNewFile(); + System.out.println("Creating: " + outfilename); + FileWriter fw = new FileWriter(out.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fw); + bw.write(d.toStringAlloy()); + bw.close(); + } else { + c = MainFunctions.resolveAlloy(c,rep); + System.out.println("Resolved Alloy"); + if (!resolveOnly) { + executeCommands(c,commandNumber,rep); + } + } + } + } catch (Exception e) { + DashUtilFcns.handleException(e); + } + } + } + } +} + diff --git a/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/DashMainTest.java b/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/DashMainTest.java new file mode 100644 index 000000000..57d235bf4 --- /dev/null +++ b/org.alloytools.alloy.application/src/main/java/ca/uwaterloo/watform/dash4whole/DashMainTest.java @@ -0,0 +1,66 @@ +/* + The purpose of this code is to help + with debugging +*/ + +package ca.uwaterloo.watform.dash4whole; + +import java.util.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.Files; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.alloy4viz.VizGUI; +import edu.mit.csail.sdg.ast.Command; +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.translator.A4Options; +import edu.mit.csail.sdg.translator.A4Solution; +import edu.mit.csail.sdg.translator.TranslateAlloyToKodkod; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashFQN; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.mainfunctions.MainFunctions; + + + + +public class DashMainTest { + + + + + public static void main(String args[]) { + + System.out.println("Starting DashMainTest"); + A4Reporter rep = new A4Reporter(); + if(args.length != 0) { + // first arg is filename + String fname = args[0]; + DashModule d = + MainFunctions.parseAndResolveDashFile(fname,rep); + if (args.length == 2) { + // transition name + d.debug(args[1]); + } else d.debug(); + } + /* + DashModule d = + MainFunctions.parseAndResolveDashFile( + "/Users/nday/UW/github/org.alloytools.alloy/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans1.dsh",rep); + */ + //List p = DashFQN.allPrefixes("A/B/C"); + //List k = (new String[]{"A", "A/B", "A/B/C"} ; + //System.out.println("all prefixes: " + p); + //assert(p.equals()); + System.out.println("Finish DashMainTest"); + } +} + diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4graph/GraphViewer.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4graph/GraphViewer.java index e6ef4cdf6..a074b07f3 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4graph/GraphViewer.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4graph/GraphViewer.java @@ -615,7 +615,7 @@ public void actionPerformed(ActionEvent e) { } Util.setCurrentDirectory(filename.getParentFile()); } catch (Throwable ex) { - OurDialog.alert(parent, "An error has occured in writing the output file:\n" + ex); + OurDialog.alert(parent, "An error has occurred in writing the output file:\n" + ex); } } diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/AlloyModel.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/AlloyModel.java index 4b696e846..8294b0fbc 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/AlloyModel.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/AlloyModel.java @@ -58,8 +58,8 @@ public final class AlloyModel { * If A extends B, then "(A,B)" will be in this map. *

* AlloyModel's constructor ensures the following:
- * (1) hierachy.keySet() is always a subset of this.types
- * (2) hierachy.valueSet() is always a subset of this.types
+ * (1) hierarchy.keySet() is always a subset of this.types
+ * (2) hierarchy.valueSet() is always a subset of this.types
* (3) "univ" is never in the keySet
* (4) null is never in the keySet nor valueSet
* (5) there is no cycle in this relation diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/MagicLayout.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/MagicLayout.java index 3e1fdbbd7..48d9fa42a 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/MagicLayout.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/MagicLayout.java @@ -191,7 +191,7 @@ private final boolean hasLikelyProjectionTypeName(final String n) { *

    *
  • interesting example: 2d game grid *
  • ex: toplogical sort -- layout tree and list, not cnxn between them - *
  • look for homogenius binary relation (a -> a) + *
  • look for homogeneous binary relation (a -> a) *
  • may be several relations defining the spine *
*/ @@ -210,7 +210,7 @@ private void spine() { if (!enumerationTypes.contains(targetType)) { spines.add(r); } - // however, binary relations named parent should be layed + // however, binary relations named parent should be laid // out backwards if (r.getName().equals("parent")) { vizState.layoutBack.put(r, true); diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/StaticInstanceReader.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/StaticInstanceReader.java index 713516543..19ad35595 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/StaticInstanceReader.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4viz/StaticInstanceReader.java @@ -66,7 +66,7 @@ public final class StaticInstanceReader { private final LinkedHashMap sig2type = new LinkedHashMap(); /** - * This maps each Sig ot its corresponding unique VIsualizer AlloyAtom (if + * This maps each Sig to its corresponding unique VIsualizer AlloyAtom (if * isMeta is true). */ private final LinkedHashMap sig2atom = new LinkedHashMap(); diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/CLIFacade.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/CLIFacade.java new file mode 100644 index 000000000..f344f5586 --- /dev/null +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/CLIFacade.java @@ -0,0 +1,30 @@ +package edu.mit.csail.sdg.alloy4whole; + +import javax.swing.SwingUtilities; + +import org.alloytools.alloy.infrastructure.api.AlloyMain; + +import aQute.lib.getopt.Options; + + +@AlloyMain( + name = "gui", + isDefault = true ) +public class CLIFacade { + + interface GuiOptions extends Options { + + } + + public void _gui(GuiOptions options) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + new SimpleGUI(options._arguments().toArray(new String[0])); + } + }); + + } +} + diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/DemoFileSystem.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/DemoFileSystem.java index 9d9b598e3..3e5dd6d27 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/DemoFileSystem.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/DemoFileSystem.java @@ -21,6 +21,7 @@ import java.util.Set; import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.ast.Attr; import edu.mit.csail.sdg.ast.Command; import edu.mit.csail.sdg.ast.Decl; @@ -54,14 +55,14 @@ PrimSig makeSig(String name, boolean isAbstract, boolean isOne) throws Err { } PrimSig makeSig(PrimSig parent, String name, boolean isAbstract, boolean isOne) throws Err { - PrimSig ans = new PrimSig(name, parent, (isAbstract ? Attr.ABSTRACT : null), (isOne ? Attr.ONE : null)); + PrimSig ans = new PrimSig(null, name, Pos.UNKNOWN, parent, (isAbstract ? Attr.ABSTRACT : null), (isOne ? Attr.ONE : null)); sigs.add(ans); return ans; } void runFor3(Expr expr) throws Err { A4Options opt = new A4Options(); - Command cmd = new Command(false, 3, 3, 3, expr.and(fact)); + Command cmd = new Command(false, 3, 3, 3, null, expr.and(fact)); A4Solution sol = TranslateAlloyToKodkod.execute_command(NOP, sigs, cmd, opt); System.out.println(sol.toString().trim()); if (sol.satisfiable()) { diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/ExampleUsingTheAPI.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/ExampleUsingTheAPI.java index 29cbf8276..1a1930629 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/ExampleUsingTheAPI.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/ExampleUsingTheAPI.java @@ -22,6 +22,7 @@ import java.util.List; import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4.Util; import edu.mit.csail.sdg.ast.Attr; import edu.mit.csail.sdg.ast.Command; @@ -54,10 +55,10 @@ public static void main(String[] args) throws Err { PrimSig B = new PrimSig("B"); // one sig A1 extends A {} - PrimSig A1 = new PrimSig("A1", A, Attr.ONE); + PrimSig A1 = new PrimSig(null, "A1", Pos.UNKNOWN, A, Attr.ONE); // one sig A2 extends A {} - PrimSig A2 = new PrimSig("A2", A, Attr.ONE); + PrimSig A2 = new PrimSig(null, "A2", Pos.UNKNOWN, A, Attr.ONE); // A { f: B lone->lone B } Expr f = A.addField("f", B.lone_arrow_lone(B)); @@ -71,13 +72,13 @@ public static void main(String[] args) throws Err { // If you want "setOf", you need: A.addField(null, "g", B.setOf()) // pred someG { some g } - Func someG = new Func(null, "SomeG", null, null, g.some()); + Func someG = new Func(null, Pos.UNKNOWN, "SomeG", null, null, g.some()); // pred atMostThree[x:univ, y:univ] { #(x+y) >= 3 } Decl x = UNIV.oneOf("x"); Decl y = UNIV.oneOf("y"); Expr body = x.get().plus(y.get()).cardinality().lte(ExprConstant.makeNUMBER(3)); - Func atMost3 = new Func(null, "atMost3", Util.asList(x, y), null, body); + Func atMost3 = new Func(null, Pos.UNKNOWN, "atMost3", Util.asList(x, y), null, body); List sigs = Arrays.asList(new Sig[] { A, B, A1, A2 @@ -85,14 +86,14 @@ public static void main(String[] args) throws Err { // run { some A && atMostThree[B,B] } for 3 but 3 int, 3 seq Expr expr1 = A.some().and(atMost3.call(B, B)); - Command cmd1 = new Command(false, 3, 3, 3, expr1); + Command cmd1 = new Command(false, 3, 3, 3, null, expr1); A4Solution sol1 = TranslateAlloyToKodkod.execute_command(NOP, sigs, cmd1, opt); System.out.println("[Solution1]:"); System.out.println(sol1.toString()); // run { some f && SomeG[] } for 3 but 2 int, 1 seq, 5 A, exactly 6 B Expr expr2 = f.some().and(someG.call()); - Command cmd2 = new Command(false, 3, 2, 1, expr2); + Command cmd2 = new Command(false, 3, 2, 1, null, expr2); cmd2 = cmd2.change(A, false, 1); cmd2 = cmd2.change(B, true, 1); A4Solution sol2 = TranslateAlloyToKodkod.execute_command(NOP, sigs, cmd2, opt); diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/PreferencesDialog.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/PreferencesDialog.java index 499f47bb0..04c3af904 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/PreferencesDialog.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/PreferencesDialog.java @@ -10,6 +10,7 @@ import static edu.mit.csail.sdg.alloy4.A4Preferences.ImplicitThis; import static edu.mit.csail.sdg.alloy4.A4Preferences.InferPartialInstance; import static edu.mit.csail.sdg.alloy4.A4Preferences.LAF; +import static edu.mit.csail.sdg.alloy4.A4Preferences.LineNumbers; import static edu.mit.csail.sdg.alloy4.A4Preferences.NoOverflow; import static edu.mit.csail.sdg.alloy4.A4Preferences.RecordKodkod; import static edu.mit.csail.sdg.alloy4.A4Preferences.SkolemDepth; @@ -345,13 +346,17 @@ private static boolean staticLibrary(String name) { } } // check if in system path - for (String str : (System.getenv("PATH")).split(Pattern.quote(File.pathSeparator))) { + for (String str : (System.getenv("PATH")).split(Pattern.quote(File.pathSeparator))) + try { Path pth = Paths.get(str); if (Files.exists(pth.resolve(name))) { if (isDebug) System.out.println("Loaded: " + name + " at " + pth); return true; } + } catch (java.nio.file.InvalidPathException e) { + if (isDebug) + System.out.println("Invalid file path on PATH: " + str + ", ignoring"); } if (isDebug) @@ -420,6 +425,7 @@ protected Component initEditorPane() { JPanel p = OurUtil.makeGrid(2, gbc().make(), mkCombo(FontName), mkCombo(FontSize), mkCombo(TabSize)); addToGrid(p, mkCheckBox(SyntaxDisabled), gbc().pos(0, 3).gridwidth(2)); addToGrid(p, mkCheckBox(AntiAlias), gbc().pos(0, 4).gridwidth(2)); + addToGrid(p, mkCheckBox(LineNumbers), gbc().pos(0, 5).gridwidth(2)); // JPanel p = new JPanel(new GridBagLayout()); // addToGrid(p, mkCheckBox(SyntaxDisabled), gbc().pos(0, diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleCLI.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleCLI.java index 5de8c4ebd..0871426b1 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleCLI.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleCLI.java @@ -235,9 +235,9 @@ public static void main(String[] args) throws Exception { x.b.toString(sb, 4); rep.flush(); } - for (Pair x : m.getAllAssertions()) { - sb.append("\nAssertion ").append(x.a).append("\n"); - x.b.toString(sb, 4); + for (edu.mit.csail.sdg.ast.Assert x : m.getAllAssertions()) { + sb.append("\nAssertion ").append(x.label).append("\n"); + x.expr.toString(sb, 4); rep.flush(); } if (m == world) diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleGUI.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleGUI.java index 2fc53db2c..29dc8a8cf 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleGUI.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleGUI.java @@ -29,6 +29,7 @@ import static edu.mit.csail.sdg.alloy4.A4Preferences.ImplicitThis; import static edu.mit.csail.sdg.alloy4.A4Preferences.InferPartialInstance; import static edu.mit.csail.sdg.alloy4.A4Preferences.LAF; +import static edu.mit.csail.sdg.alloy4.A4Preferences.LineNumbers; import static edu.mit.csail.sdg.alloy4.A4Preferences.Model0; import static edu.mit.csail.sdg.alloy4.A4Preferences.Model1; import static edu.mit.csail.sdg.alloy4.A4Preferences.Model2; @@ -123,6 +124,8 @@ import org.alloytools.alloy.core.AlloyCore; +import aQute.lib.io.IO; + //import com.apple.eawt.Application; //import com.apple.eawt.ApplicationAdapter; //import com.apple.eawt.ApplicationEvent; @@ -597,7 +600,7 @@ public void run() { * Find a temporary directory to store Alloy files; it's guaranteed to be a * canonical absolute path. */ - private static synchronized String alloyHome(JFrame parent) { + public static synchronized String alloyHome(JFrame parent) { if (alloyHome != null) return alloyHome; String temp = System.getProperty("java.io.tmpdir"); @@ -626,7 +629,7 @@ private static synchronized String alloyHome(JFrame parent) { * Create an empty temporary directory for use, designate it "deleteOnExit", * then return it. It is guaranteed to be a canonical absolute path. */ - private static String maketemp(JFrame parent) { + public static String maketemp(JFrame parent) { Random r = new Random(new Date().getTime()); while (true) { int i = r.nextInt(1000000); @@ -1440,6 +1443,7 @@ private Runner doRefreshOption() { else addToMenu(optmenu, AntiAlias); addToMenu(optmenu, A4Preferences.LAF); + addToMenu(optmenu, LineNumbers); optmenu.addSeparator(); @@ -1493,6 +1497,14 @@ private Runner doOptRefreshFont() { return null; } + private Runner doOptRefreshLineNumbers() { + if ( wrap ) { + return wrapMe(); + } + text.enableLineNumbers(LineNumbers.get()); + return null; + } + /** This method toggles the "antialias" checkbox. */ private Runner doOptAntiAlias() { if (!wrap) { @@ -1841,7 +1853,7 @@ private static SimTupleset convert(Object object) throws Err { } /** Converts an A4Solution into a SimInstance object. */ - private static SimInstance convert(Module root, A4Solution ans) throws Err { + public static SimInstance convert(Module root, A4Solution ans) throws Err { SimInstance ct = new SimInstance(root, ans.getBitwidth(), ans.getMaxSeq()); for (Sig s : ans.getAllReachableSigs()) { if (!s.builtin) @@ -2003,7 +2015,7 @@ public void run() { * The constructor; this method will be called by the AWT event thread, using * the "invokeLater" method. */ - private SimpleGUI(final String[] args) { + SimpleGUI(final String[] args) { UIManager.put("ToolTip.font", new FontUIResource("Courier New", Font.PLAIN, 14)); @@ -2220,7 +2232,7 @@ private void finishInit(String[] args, int width) { PreferencesDialog.logOnChange(log, A4Preferences.allUserPrefs().toArray(new Pref< ? >[0])); // Create the text area - text = new OurTabbedSyntaxWidget(fontName, fontSize, TabSize.get(), frame); + text = new OurTabbedSyntaxWidget(fontName, fontSize, TabSize.get(), LineNumbers.get(), frame); text.listeners.add(this); text.enableSyntax(!SyntaxDisabled.get()); @@ -2282,6 +2294,7 @@ private void finishInit(String[] args, int width) { prefDialog.addChangeListener(wrapToChangeListener(doOptAntiAlias()), AntiAlias); prefDialog.addChangeListener(wrapToChangeListener(doOptSyntaxHighlighting()), SyntaxDisabled); prefDialog.addChangeListener(wrapToChangeListener(doLookAndFeel()), LAF); + prefDialog.addChangeListener(wrapToChangeListener(doOptRefreshLineNumbers()), LineNumbers); } finally { wrap = false; } @@ -2312,12 +2325,11 @@ private void finishInit(String[] args, int width) { frame.setJMenuBar(bar); // Open the given file, if a filename is given in the command line - for (String f : args) - if (f.toLowerCase(Locale.US).endsWith(".als")) { - File file = new File(f); - if (file.exists() && file.isFile()) - doOpenFile(file.getPath()); - } + for (String f : args) { + File file = IO.getFile(f); + if (file.isFile()) + doOpenFile(file.getPath()); + } // Update the title and status bar notifyChange(); diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleReporter.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleReporter.java index 113692e8d..9c19e83e2 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleReporter.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SimpleReporter.java @@ -78,7 +78,7 @@ * parallel problem) */ -final class SimpleReporter extends A4Reporter { +public final class SimpleReporter extends A4Reporter { public static final class SimpleCallback1 implements WorkerCallback { @@ -601,7 +601,7 @@ private static void writeXML(A4Reporter rep, Module mod, String filename, A4Solu private int warn = 0; /** Task that performs solution enumeration. */ - static final class SimpleTask2 implements WorkerTask { + public static final class SimpleTask2 implements WorkerTask { private static final long serialVersionUID = 0; public int index = -1; // [electrum] registers which iteration operation to perform @@ -683,7 +683,7 @@ private static void validate(String filename) throws Exception { } /** Task that perform one command. */ - static final class SimpleTask1 implements WorkerTask { + public static final class SimpleTask1 implements WorkerTask { private static final long serialVersionUID = 0; public A4Options options; @@ -762,38 +762,40 @@ else if (ai.highLevelCore().a.size() > 0) rep.cb("", " #" + (i + 1) + ": Unknown.\n"); continue; } + StringBuilder sb = new StringBuilder(); if (result.get(i).endsWith(".xml")) { rep.cb("", " #" + (i + 1) + ": "); rep.cb("link", r.check ? "Counterexample found. " : "Instance found. ", "XML: " + result.get(i)); - rep.cb("", r.label + (r.check ? " is invalid" : " is consistent")); + sb.append(r.label + (r.check ? " is invalid" : " is consistent")); if (r.expects == 0) - rep.cb("", ", contrary to expectation"); + sb.append(", contrary to expectation"); else if (r.expects == 1) - rep.cb("", ", as expected"); + sb.append(", as expected"); } else if (result.get(i).endsWith(".core")) { rep.cb("", " #" + (i + 1) + ": "); rep.cb("link", r.check ? "No counterexample found. " : "No instance found. ", "CORE: " + result.get(i)); - rep.cb("", r.label + (r.check ? " may be valid" : " may be inconsistent")); + sb.append(r.label + (r.check ? " may be valid" : " may be inconsistent")); if (r.expects == 1) - rep.cb("", ", contrary to expectation"); + sb.append(", contrary to expectation"); else if (r.expects == 0) - rep.cb("", ", as expected"); + sb.append(", as expected"); } else { if (r.check) - rep.cb("", " #" + (i + 1) + ": No counterexample found. " + r.label + " may be valid"); + sb.append(" #" + (i + 1) + ": No counterexample found. " + r.label + " may be valid"); else - rep.cb("", " #" + (i + 1) + ": No instance found. " + r.label + " may be inconsistent"); + sb.append(" #" + (i + 1) + ": No instance found. " + r.label + " may be inconsistent"); if (r.expects == 1) - rep.cb("", ", contrary to expectation"); + sb.append(", contrary to expectation"); else if (r.expects == 0) - rep.cb("", ", as expected"); + sb.append(", as expected"); } - rep.cb("", ".\n"); + sb.append(".\n"); + rep.cb("", sb.toString()); } rep.cb("", "\n"); } if (rep.warn > 1) - rep.cb("bold", "Note: There were " + rep.warn + " compilation warnings. Please scroll up to see them.\n"); + rep.cb("bold", "Note: There were " + rep.warn + " compilation warnings.\n"); if (rep.warn == 1) rep.cb("bold", "Note: There was 1 compilation warning. Please scroll up to see it.\n"); diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SwingLogPanel.java b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SwingLogPanel.java index ae0a6a30d..3f9c1c149 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SwingLogPanel.java +++ b/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/SwingLogPanel.java @@ -453,7 +453,7 @@ public void copy() { log.copy(); } - /** Removes any messages writtin in "red" style. */ + /** Removes any messages written in "red" style. */ public void clearError() { if (log == null) return; diff --git a/org.alloytools.alloy.core/.classpath b/org.alloytools.alloy.core/.classpath index 133ceaf5e..7854e99ab 100644 --- a/org.alloytools.alloy.core/.classpath +++ b/org.alloytools.alloy.core/.classpath @@ -1,17 +1,25 @@ - - - - + + + + + + + + + - + - + + - + + + diff --git a/org.alloytools.alloy.core/.project b/org.alloytools.alloy.core/.project index 36737ffb6..fc4184230 100644 --- a/org.alloytools.alloy.core/.project +++ b/org.alloytools.alloy.core/.project @@ -10,6 +10,11 @@
+ + org.eclipse.buildship.core.gradleprojectbuilder + + + bndtools.core.bndbuilder @@ -19,5 +24,17 @@ org.eclipse.jdt.core.javanature bndtools.core.bndnature + org.eclipse.buildship.core.gradleprojectnature + + + 1687449709176 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/org.alloytools.alloy.core/.settings/org.eclipse.buildship.core.prefs b/org.alloytools.alloy.core/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/org.alloytools.alloy.core/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/org.alloytools.alloy.core/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.core/.settings/org.eclipse.jdt.core.prefs index 2f809de6d..fee4ef9bf 100644 --- a/org.alloytools.alloy.core/.settings/org.eclipse.jdt.core.prefs +++ b/org.alloytools.alloy.core/.settings/org.eclipse.jdt.core.prefs @@ -23,12 +23,12 @@ org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignor org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable -org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=17 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -84,9 +84,9 @@ org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning -org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=warning org.eclipse.jdt.core.compiler.problem.nullReference=warning -org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=warning org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore @@ -134,7 +134,7 @@ org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.processAnnotations=disabled org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME @@ -143,6 +143,7 @@ org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 org.eclipse.jdt.core.formatter.align_type_members_on_columns=true org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 @@ -150,21 +151,24 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_c org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_assignment=2 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=2 org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=2 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=2 org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=2 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 @@ -256,11 +260,12 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -291,6 +296,8 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -315,13 +322,17 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -369,6 +380,8 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do no org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -405,9 +418,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -446,10 +462,14 @@ org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=true org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/org.alloytools.alloy.core/bnd.bnd b/org.alloytools.alloy.core/bnd.bnd index 00b1a105b..164412e55 100644 --- a/org.alloytools.alloy.core/bnd.bnd +++ b/org.alloytools.alloy.core/bnd.bnd @@ -3,11 +3,14 @@ -includeresource: \ src/main/resources, \ @${repo;slf4j.api}, \ - + -buildpath: \ - org.alloytools:pardinus.core;version=1.3.0,\ - org.alloytools:pardinus.nativesat;version=1.3.0,\ - org.eclipse.jdt.annotation + org.alloytools:pardinus.core;version='1.3.0',\ + org.alloytools:pardinus.nativesat;version='1.3.0',\ + org.eclipse.jdt.annotation,\ + aQute.libg,\ + org.alloytools.api,\ + slf4j.api -testpath: \ biz.aQute.wrapper.junit, \ @@ -24,7 +27,9 @@ Export-Package: \ edu.mit.csail.sdg.sim,\ edu.mit.csail.sdg.translator,\ org.alloytools.util.table,\ - org.alloytools.alloy.core + org.alloytools.alloy.core, \ + org.alloytools.alloy.core.util, \ + com.io7m.jpplib.core, \ Private-Package: \ java_cup.runtime diff --git a/org.alloytools.alloy.core/parser/Alloy.cup b/org.alloytools.alloy.core/parser/Alloy.cup index 7d4f26005..12e02e32b 100644 --- a/org.alloytools.alloy.core/parser/Alloy.cup +++ b/org.alloytools.alloy.core/parser/Alloy.cup @@ -26,6 +26,7 @@ package edu.mit.csail.sdg.parser; import java.util.Stack; import java.util.List; import java.util.ArrayList; +import java.util.Locale; import java.util.TreeSet; import java.util.Map; import java.util.LinkedHashMap; @@ -164,7 +165,6 @@ parser code {: ch.put(CompSym.ENUM, "enum"); ch.put(CompSym.EQUALS, "="); ch.put(CompSym.EXACTLY, "exactly"); - ch.put(CompSym.EXH, "exh"); ch.put(CompSym.EXPECT, "expect"); ch.put(CompSym.EXTENDS, "extends"); ch.put(CompSym.FACT, "fact"); @@ -202,7 +202,6 @@ parser code {: ch.put(CompSym.ONE, "one"); ch.put(CompSym.OPEN, "open"); ch.put(CompSym.OR, "||"); - ch.put(CompSym.PART, "part"); ch.put(CompSym.PLUS, "+"); ch.put(CompSym.PLUSPLUS, "++"); ch.put(CompSym.PRED, "pred"); @@ -298,7 +297,7 @@ parser code {: if (content==null && loaded!=null) content = loaded.get(filename); if (content==null) content = Util.readAll(filename); if (loaded!=null) loaded.put(filename,content); - content = MarkdownHandler.strip(content); + if (content.startsWith("---") || filename.toLowerCase(Locale.ROOT).endsWith(".md")) content = MarkdownHandler.strip(content); content = Util.convertLineBreak(content); isr = new StringReader(content); CompFilter s = new CompFilter(u, seenDollar, filename, lineOffset, new BufferedReader(isr)); @@ -378,9 +377,9 @@ action code {: } } if (n!=null) - parser.alloymodule.addCommand(follow, p, n, o.label.equals("c"), overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); + parser.alloymodule.addCommand(follow, p, n, o, overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); else - parser.alloymodule.addCommand(follow, p, e, o.label.equals("c"), overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); + parser.alloymodule.addCommand(follow, p, e, o, overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); } private Expr t(Pos pos, Pos oldClosing, Expr left, Expr right, Pos close) throws Err { if (right instanceof ExprVar) { @@ -446,7 +445,6 @@ terminal Pos ELSE; // else terminal Pos ENUM; // enum terminal Pos EQUALS; // = == terminal Pos EXACTLY; // exactly -terminal Pos EXH; // exh exhaustive terminal Pos EXPECT; // expect terminal Pos EXTENDS; // extends terminal Pos FACT; // fact @@ -484,7 +482,6 @@ terminal Pos ONE2; // one // The filter enables us to di terminal Pos ONE; // one // The filter enables us to disambiguate terminal Pos OPEN; // open terminal Pos OR; // || or -terminal Pos PART; // part partition terminal Pos PLUS; // + terminal Pos PLUSPLUS; // ++ terminal Pos PRED; // pred @@ -648,9 +645,9 @@ Spec ::= Spec Vis:p ENUM:o Name:a LBRACE RBRACE:c { Spec ::= Spec FACT:o Super:e {: parser.alloymodule.addFact (o , "" , e); :}; Spec ::= Spec FACT:o Name:n Super:e {: nod(n); parser.alloymodule.addFact (o , n.label , e); :}; Spec ::= Spec FACT:o STR:n Super:e {: parser.alloymodule.addFact (o , n.string , e); :}; -Spec ::= Spec ASSERT:o Super:e {: parser.alloymodule.addAssertion (o , "" , e); :}; -Spec ::= Spec ASSERT:o Name:n Super:e {: nod(n); parser.alloymodule.addAssertion (o , n.label , e); :}; -Spec ::= Spec ASSERT:o STR:n Super:e {: parser.alloymodule.addAssertion (o , n.string , e); :}; +Spec ::= Spec ASSERT:o Super:e {: parser.alloymodule.addAssertion (o , null , "" , e); :}; +Spec ::= Spec ASSERT:o Name:n Super:e {: nod(n); parser.alloymodule.addAssertion (o , n.pos, n.label , e); :}; +Spec ::= Spec ASSERT:o STR:n Super:e {: parser.alloymodule.addAssertion (o , null, n.string , e); :}; Spec ::= Spec Sig ; Spec ::= Spec Function ; Spec ::= Spec Predicate ; @@ -673,8 +670,8 @@ Command ::= Command IMPLIES CommandPrefix:o Name:n Scope:s Expects:c { Expects ::= {: RESULT=null; :}; Expects ::= EXPECT NUMBER:a {: RESULT=a; :}; -Scope ::= FOR NUMBER:a {: RESULT=new ArrayList(); RESULT.add(new CommandScope(a.pos, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; -Scope ::= FOR NUMBER:a BUT Typescopes:b {: RESULT=b; b.add(new CommandScope(a.pos, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; +Scope ::= FOR NUMBER:a {: RESULT=new ArrayList(); RESULT.add(new CommandScope(a.pos, Pos.UNKNOWN, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; +Scope ::= FOR NUMBER:a BUT Typescopes:b {: RESULT=b; b.add(new CommandScope(a.pos, Pos.UNKNOWN, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; Scope ::= FOR Typescopes:b {: RESULT=b; :}; Scope ::= {: RESULT=new ArrayList(); :}; @@ -683,7 +680,7 @@ Typescopes ::= Typescopes:a COMMA Typescope:b {: RESULT=a; a.add(b); Typescope ::= TypeNumber:a Name:b {: nod(b); - RESULT = new CommandScope(a.pos.merge(b.pos), new PrimSig(b.label, AttrType.WHERE.make(a.pos.merge(b.pos))), a.isExact, a.startingScope, a.endingScope, a.increment); + RESULT = new CommandScope(a.pos.merge(b.pos), b.pos, new PrimSig(b.label, AttrType.WHERE.make(a.pos.merge(b.pos))), a.isExact, a.startingScope, a.endingScope, a.increment); :}; //[AM]: INT -> SIGINT @@ -691,31 +688,31 @@ Typescope ::= TypeNumber:a SIGINT:b {: Pos p = a.pos.merge(b); if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"Int\""); if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the integer bitwidth must be exact."); - RESULT = new CommandScope(p, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); + RESULT = new CommandScope(p, b, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); :}; Typescope ::= TypeNumber:a INT:b {: Pos p = a.pos.merge(b); if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"Int\""); if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the integer bitwidth must be exact."); - RESULT = new CommandScope(p, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); + RESULT = new CommandScope(p, b, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); :}; Typescope ::= TypeNumber:a SEQ:b {: Pos p = a.pos.merge(b); if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"seq\""); if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the number of sequence index has to be exact."); - RESULT = new CommandScope(p, new PrimSig("seq", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); + RESULT = new CommandScope(p, b, new PrimSig("seq", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); :}; Typescope ::= TypeNumber:e UNIV:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You cannot set a scope on univ."); :}; -Typescope ::= TypeNumber:a STRING:b {: RESULT = new CommandScope(a.pos.merge(b), new PrimSig("String", AttrType.WHERE.make(a.pos.merge(b))), a.isExact, a.startingScope, a.endingScope, a.increment); :}; +Typescope ::= TypeNumber:a STRING:b {: RESULT = new CommandScope(a.pos.merge(b), b, new PrimSig("String", AttrType.WHERE.make(a.pos.merge(b))), a.isExact, a.startingScope, a.endingScope, a.increment); :}; // [electrum] scope on Time Typescope ::= TypeNumber:a TIME:b {: Pos p = a.pos.merge(b); - RESULT = new CommandScope(p, new PrimSig("steps", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.endingScope, a.increment); + RESULT = new CommandScope(p, Pos.UNKNOWN, new PrimSig("steps", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.endingScope, a.increment); :}; //[AM] Typescope ::= TypeNumber:e SIGINT:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You can no longer set a scope on Int; the number of Int atoms is always exactly equal to 2^(integer bitwidth).\n"); :}; @@ -723,39 +720,39 @@ Typescope ::= TypeNumber:a TIME:b {: Typescope ::= TypeNumber:e NONE:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You cannot set a scope on none."); :}; // [electrum] distinguish between "n" and "n..n", the latter become exact; open ended scopes "n.." -TypeNumber ::= EXACTLY:e NUMBER:a {: RESULT = new CommandScope( e.merge(a.pos), Sig.NONE, true, a.num, a.num, 1 ); :}; -TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(b.pos), Sig.NONE, true, a.num, b.num, 1 ); :}; -TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e , Sig.NONE, true, a.num, Integer.MAX_VALUE, 1 ); :}; -TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Sig.NONE, true, a.num, b.num, i.num); :}; -TypeNumber ::= EXACTLY:e NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Sig.NONE, true, a.num, Integer.MAX_VALUE, i.num); :}; -TypeNumber ::= NUMBER:a {: RESULT = new CommandScope(a.pos , Sig.NONE, false, a.num, a.num, 1 ); :}; -TypeNumber ::= NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(b.pos), Sig.NONE, a.num == b.num, a.num, b.num, 1 ); :}; -TypeNumber ::= NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos , Sig.NONE, false, a.num, Integer.MAX_VALUE, 1 ); :}; -TypeNumber ::= NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Sig.NONE, a.num == b.num, a.num, b.num, i.num); :}; -TypeNumber ::= NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Sig.NONE, false, a.num, Integer.MAX_VALUE, i.num); :}; - -Macro ::= Vis:p LET:o Name:n LPAREN Names:d RPAREN MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.label, d , v); :}; -Macro ::= Vis:p LET:o Name:n LPAREN RPAREN MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.label, null , v); :}; -Macro ::= Vis:p LET:o Name:n LBRACKET Names:d RBRACKET MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.label, d , v); :}; -Macro ::= Vis:p LET:o Name:n LBRACKET RBRACKET MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.label, null , v); :}; -Macro ::= Vis:p LET:o Name:n MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.label, null , v); :}; +TypeNumber ::= EXACTLY:e NUMBER:a {: RESULT = new CommandScope( e.merge(a.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, a.num, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(b.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, b.num, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e , Pos.UNKNOWN, Sig.NONE, true, a.num, Integer.MAX_VALUE, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, b.num, i.num); :}; +TypeNumber ::= EXACTLY:e NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, Integer.MAX_VALUE, i.num); :}; +TypeNumber ::= NUMBER:a {: RESULT = new CommandScope(a.pos , Pos.UNKNOWN, Sig.NONE, false, a.num, a.num, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(b.pos), Pos.UNKNOWN, Sig.NONE, a.num == b.num, a.num, b.num, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos , Pos.UNKNOWN, Sig.NONE, false, a.num, Integer.MAX_VALUE, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Pos.UNKNOWN, Sig.NONE, a.num == b.num, a.num, b.num, i.num); :}; +TypeNumber ::= NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Pos.UNKNOWN, Sig.NONE, false, a.num, Integer.MAX_VALUE, i.num); :}; + +Macro ::= Vis:p LET:o Name:n LPAREN Names:d RPAREN MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.pos, n.label, d , v); :}; +Macro ::= Vis:p LET:o Name:n LPAREN RPAREN MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; +Macro ::= Vis:p LET:o Name:n LBRACKET Names:d RBRACKET MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.pos, n.label, d , v); :}; +Macro ::= Vis:p LET:o Name:n LBRACKET RBRACKET MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; +Macro ::= Vis:p LET:o Name:n MacroBody:v {: nod(n); parser.alloymodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; MacroBody ::= Super:a {: RESULT=a; :}; MacroBody ::= EQUALS Expr:a {: RESULT=a; :}; -Function ::= Vis:p FUN:o Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, d , mult(r), v); :}; -Function ::= Vis:p FUN:o Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, d , mult(r), v); :}; -Function ::= Vis:p FUN:o Name:n COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, null , mult(r), v); :}; -Function ::= Vis:p FUN:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , d , mult(r), v); :}; -Function ::= Vis:p FUN:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , d , mult(r), v); :}; -Function ::= Vis:p FUN:o SigRef:f DOT Name:n COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , null , mult(r), v); :}; +Function ::= Vis:p FUN:o Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, d , mult(r), v); :}; +Function ::= Vis:p FUN:o Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, d , mult(r), v); :}; +Function ::= Vis:p FUN:o Name:n COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, null , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , d , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , d , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n COLON Expr:r Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , null , mult(r), v); :}; -Predicate ::= Vis:p PRED:o Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, d , null, v); :}; -Predicate ::= Vis:p PRED:o Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, d , null, v); :}; -Predicate ::= Vis:p PRED:o Name:n Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, null, null , null, v); :}; -Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , d , null, v); :}; -Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , d , null, v); :}; -Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n.label, f , null , null, v); :}; +Predicate ::= Vis:p PRED:o Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, d , null, v); :}; +Predicate ::= Vis:p PRED:o Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, d , null, v); :}; +Predicate ::= Vis:p PRED:o Name:n Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, null, null , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , d , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , d , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n Super:v {: nod(n); parser.alloymodule.addFunc(o.merge(v.span()), p, n, f , null , null, v); :}; Vis ::= {: RESULT=null; :}; Vis ::= PRIVATE:p {: RESULT=p; :}; @@ -765,7 +762,7 @@ Sig ::= SigQuals:a Names:b SigIn:c LBRACE Decls:d RBRACE:o SuperOpt:e if (e==null) e = ExprConstant.Op.TRUE.make(o, 0); ExprVar cc = (c!=null && c.size()>0) ? c.remove(c.size()-1) : null; for(ExprVar bb:b) { - parser.alloymodule.addSig(bb.label, cc, c, d, e, + parser.alloymodule.addSig(bb.pos, bb.label, cc, c, d, e, AttrType.WHERE .makenull(bb.pos.merge(e==null ? o : e.span())), AttrType.ABSTRACT.makenull(a.get(0)), AttrType.LONE .makenull(a.get(1)), @@ -785,7 +782,7 @@ SigQual ::= PRIVATE:x {: RESULT=new ArrayList(6); RESULT.ad SigQual ::= VAR:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(x); :}; SigQuals ::= SIG {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); :}; -SigQuals ::= SigQual:a SigQuals:b {: RESULT=a; for(int i=0;i<6;i++) if (a.get(i)==null) a.set(i,b.get(i)); else if (b.get(i)!=null) throw new ErrorSyntax(b.get(i), "The same qualifer cannot be specified more than once for the same sig."); :}; +SigQuals ::= SigQual:a SigQuals:b {: RESULT=a; for(int i=0;i<6;i++) if (a.get(i)==null) a.set(i,b.get(i)); else if (b.get(i)!=null) throw new ErrorSyntax(b.get(i), "The same qualifier cannot be specified more than once for the same sig."); :}; SigIn ::= EXTENDS:a SigRef:x {: RESULT=new ArrayList(2); RESULT.add(x); RESULT.add(ExprVar.make(a, "extends")); :}; SigIn ::= IN:a SigRefu:x {: RESULT=x; x.add(ExprVar.make(a,"in")); :}; @@ -825,8 +822,6 @@ Namex ::= Namex:a COMMA Name:b {: nod(b); a.add(b); RESULT= Namex ::= Namex:a COMMA EXACTLY Name:b {: nod(b); a.add(null); a.add(b); RESULT=a; :}; // [electrum] additional parameter for variable declarations (for fields) -Decla ::= PART:k Names COLON Expr {: if (1==1) throw CompModule.hint(k, "part"); :}; -Decla ::= EXH:k Names COLON Expr {: if (1==1) throw CompModule.hint(k, "exh"); :}; Decla ::= DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(null, k, null, null, a, mult(b)); :}; Decla ::= PRIVATE:p DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(p, k, null, null, a, mult(b)); :}; Decla ::= PRIVATE:p Names:a COLON Expr:b {: RESULT=new Decl(p, null, null, null, a, mult(b)); :}; @@ -837,8 +832,6 @@ Decla ::= VAR:v PRIVATE:p DISJ:k Names:a COLON Expr:b {: RESULT Decla ::= VAR:v PRIVATE:p Names:a COLON Expr:b {: RESULT=new Decl(p, null, null, v, a, mult(b)); :}; Decla ::= VAR:v Names:a COLON Expr:b {: RESULT=new Decl(null, null, null, v, a, mult(b)); :}; -Decla ::= PART:k Names COLON DISJ Expr {: if (1==1) throw CompModule.hint(k, "part"); :}; -Decla ::= EXH:k Names COLON DISJ Expr {: if (1==1) throw CompModule.hint(k, "exh"); :}; Decla ::= DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(null, k, d, null, a, mult(b)); :}; Decla ::= PRIVATE:p DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, k, d, null, a, mult(b)); :}; Decla ::= PRIVATE:p Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, null, d, null, a, mult(b)); :}; @@ -851,15 +844,11 @@ Decla ::= VAR:v Names:a COLON DISJ:d Expr:b {: RESULT Declb ::= Decla:x {: RESULT=x; :}; -Declb ::= PART:k Names EQUALS Expr {: if (1==1) throw CompModule.hint(k, "part"); :}; -Declb ::= EXH:k Names EQUALS Expr {: if (1==1) throw CompModule.hint(k, "exh"); :}; Declb ::= DISJ:d Names EQUALS Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; Declb ::= PRIVATE DISJ:d Names EQUALS Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; Declb ::= PRIVATE:p Names:a EQUALS Expr:b {: RESULT=new Decl(p, null, null, null, a, ExprUnary.Op.EXACTLYOF.make(null, b)); :}; Declb ::= Names:a EQUALS Expr:b {: RESULT=new Decl(null, null, null, null, a, ExprUnary.Op.EXACTLYOF.make(null, b)); :}; -Declb ::= PART:k Names EQUALS DISJ Expr {: if (1==1) throw CompModule.hint(k, "part"); :}; -Declb ::= EXH:k Names EQUALS DISJ Expr {: if (1==1) throw CompModule.hint(k, "exh"); :}; Declb ::= DISJ Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; Declb ::= PRIVATE DISJ Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; Declb ::= PRIVATE Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; diff --git a/org.alloytools.alloy.core/parser/Alloy.lex b/org.alloytools.alloy.core/parser/Alloy.lex index 4ec7c4cac..f0f8f2a65 100644 --- a/org.alloytools.alloy.core/parser/Alloy.lex +++ b/org.alloytools.alloy.core/parser/Alloy.lex @@ -186,8 +186,6 @@ import java_cup.runtime.*; "else" { return alloy_sym(yytext(), CompSym.ELSE );} "enum" { return alloy_sym(yytext(), CompSym.ENUM );} "exactly" { return alloy_sym(yytext(), CompSym.EXACTLY );} -"exhaustive" { return alloy_sym(yytext(), CompSym.EXH );} -"exh" { return alloy_sym(yytext(), CompSym.EXH );} "expect" { return alloy_sym(yytext(), CompSym.EXPECT );} "extends" { return alloy_sym(yytext(), CompSym.EXTENDS );} "fact" { return alloy_sym(yytext(), CompSym.FACT );} @@ -208,8 +206,6 @@ import java_cup.runtime.*; "one" { return alloy_sym(yytext(), CompSym.ONE );} "open" { return alloy_sym(yytext(), CompSym.OPEN );} "or" { return alloy_sym(yytext(), CompSym.OR );} -"partition" { return alloy_sym(yytext(), CompSym.PART );} -"part" { return alloy_sym(yytext(), CompSym.PART );} "pred" { return alloy_sym(yytext(), CompSym.PRED );} "private" { return alloy_sym(yytext(), CompSym.PRIVATE );} "run" { return alloy_sym(yytext(), CompSym.RUN );} diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/A4Preferences.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/A4Preferences.java index 75365e8fc..52268d447 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/A4Preferences.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/A4Preferences.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.prefs.Preferences; import javax.swing.AbstractAction; @@ -572,6 +573,9 @@ public void actionPerformed(ActionEvent e) { /** The latest tab distance of the Alloy Analyzer. */ public static final IntChoicePref TabSize = IntChoicePref.range("TabSize", "Tab size", 1, 1, 16, 4); + /** The latest line-number mode selection of the Alloy Analyzer. */ + public static final BooleanPref LineNumbers = new BooleanPref("Line-numbers", "Show line numbers in editors"); + /** The latest welcome screen that the user has seen. */ public static final BooleanPref Welcome = new BooleanPref("Welcome", "Show welcome message at start up"); @@ -804,14 +808,28 @@ public final String toString() { return ans; } - // /** The visualization algorithm */ - // public static final StringChoicePref VisualizationAlgorithm = new - // StringChoicePref("VizAlg", "Visualization algorightm", - // Arrays.asList("Sugiyama", "Circle", "Grid"), "Sugiyama"); - // - // public static final IntPref GridLayoutRows = new - // IntPref("GridLayoutRows", 1, 5, 100); - // public static final IntPref GridLayoutCols = new - // IntPref("GridLayoutCols", 1, 5, 100); + /** + * Convenience method to set a value by string + * + * @param id the id of the preference + * @param value the value in string form + * @return an error message or null if all ok + */ + + public static String set(String id, String value) { + Optional> pref = allPrefs().stream().filter(p -> p.id.equals(id)).findAny(); + if (pref.isPresent()) { + try { + Pref p = (Pref) pref.get(); + T parsed = (T) pref.get().parse(value); + p.set(parsed); + } catch (Exception e) { + return e.getMessage(); + } + } else { + return "no such preference"; + } + return null; + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurLineNumberWidget.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurLineNumberWidget.java new file mode 100644 index 000000000..4301aaa10 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurLineNumberWidget.java @@ -0,0 +1,277 @@ +package edu.mit.csail.sdg.alloy4; + +import javax.swing.*; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.Utilities; +import java.awt.*; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.font.FontRenderContext; +import java.util.Collections; +import java.util.Objects; + +public class OurLineNumberWidget extends JComponent implements DocumentListener, CaretListener, ComponentListener { + + /** + * combine the two submitted objects with a new OurLineNumberWidget and return + * that widget. We assume that other code has already connected these components appropriately. + * + * While callers could send any fontName and size that they wanted, here in Allow in the context of + * the editor the assumption is that the font preference set by the user for the whole app is + * applying here as well, so OurSyntaxWidget will be sending the same font that it receives to use. + * + * @param textPane the text pane that has the lines we want to draw numbers for + * @param scrollPane the scroll pane we will set a header row for to draw the line numbers for textPane + * @param display line numbers should display if true, should not otherwise + * @param fontName the fontName to be used to draw line numbers. + * @return the OurLineNumberWidget linking the two components, with the display and font set. + */ + public static OurLineNumberWidget build(JTextPane textPane, JScrollPane scrollPane, boolean display, String fontName, int fontSize) { + Objects.requireNonNull(textPane); + Objects.requireNonNull(textPane.getDocument()); + Objects.requireNonNull(scrollPane); + Objects.requireNonNull(fontName); + if ( fontSize < 1 ) { + throw new IllegalArgumentException("Font size must be at least 1"); + } + + OurLineNumberWidget ourLineNumberWidget = new OurLineNumberWidget(textPane, display, fontName, fontSize); + scrollPane.setRowHeaderView(ourLineNumberWidget); + return ourLineNumberWidget; + } + + private static final boolean antiAlias = Util.onMac() || Util.onWindows(); + + private final JTextPane textPane; + private boolean display; + private String fontName; + private int fontSize; + private int width = 0; + private Font font; + /** assume we start showing 1 digit. */ + private int currentMaxDigits = 1; + private int descentAdjust; + + OurLineNumberWidget(JTextPane textPane, boolean display, String fontName, int fontSize) { + this.textPane = textPane; + this.display = display; + this.fontName = fontName; + this.fontSize = fontSize; + + // falls back to 'Dialog' on not being able to find. + this.font = new Font(this.fontName, Font.PLAIN, this.fontSize); + this.descentAdjust = makeDescentAdjust(); + + textPane.getDocument().addDocumentListener(this); + textPane.addComponentListener(this); + textPane.addCaretListener(this); + + update(); + } + + /** use current font to decide a width for the line-number view itself, + * based on how many digits are submitted. + * @param numberOfDigits + * @return + */ + private int calculateWidthForDigits(int numberOfDigits) { + if ( display ) { + String numberOfDigitsLong = String.join("", Collections.nCopies(numberOfDigits, "0")); + return (int)Math.ceil( + font.getStringBounds(numberOfDigitsLong, new FontRenderContext(null, false, false)).getWidth() * 1.2); + } else { + return 0; + } + } + + /** capture the descent of the current font, used to adjust (negative y) where the + * line number is drawn. Only needs to change when the font changes. + * @return + */ + private int makeDescentAdjust() { + return getFontMetrics(font).getDescent(); + } + + @Override + protected void paintComponent(final Graphics g) { + + if ( ! display ) { return; } + + if ( g instanceof Graphics2D && antiAlias ) { + ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + } + + super.paintComponent(g); + // antiAlias at some point + + Rectangle bounds = g.getClipBounds(); + final int startDocumentLocation = textPane.viewToModel(new Point(0, bounds.y)); + final int endDocumentLocation = textPane.viewToModel(new Point(0, bounds.y + bounds.height)); + + int docLoc = startDocumentLocation; + int maxDigits = 0; + + while ( docLoc <= endDocumentLocation ) { + try { + Element rootElement = textPane.getDocument().getDefaultRootElement(); + final int lineIndex = rootElement.getElementIndex(docLoc); + final Element line = rootElement.getElement(lineIndex); + if (line.getStartOffset() == docLoc) { + int x = niceX(); + int y = niceY(docLoc); + + String formattedLineNumber = formatLineNumberFromIndex(lineIndex); + if ( formattedLineNumber.length() > maxDigits ) { + maxDigits = formattedLineNumber.length(); + } + + g.setColor(Color.BLACK); + if (ifCaretOnSameLine(docLoc, rootElement)) { + Rectangle currentLineViewRec = textPane.modelToView(docLoc); + g.fillRect(0, currentLineViewRec.y, width, currentLineViewRec.height-1 ); + g.setColor(Color.YELLOW); + } + g.setFont(font); + g.drawString(formattedLineNumber, x, y); + } + docLoc = Utilities.getRowEnd(textPane, docLoc) + 1; + } catch (BadLocationException e) { + // what is the right thing to do here? + } + } + if ( maxDigits != currentMaxDigits ) { + currentMaxDigits = maxDigits; + update(); + } + } + + private boolean ifCaretOnSameLine(int docLoc, Element rootElement) { + return rootElement.getElementIndex(docLoc) == rootElement.getElementIndex(textPane.getCaretPosition()); + } + + /** a judgement about where in the x direction is good + * to start drawing the line number. + * @return + */ + private int niceX() { + return getInsets().left + 3; + } + + /** a judgement about where in the y direction is good + * to start drawing the line number for the given document location. + * @param docLoc + * @return + * @throws BadLocationException + */ + private int niceY(int docLoc) throws BadLocationException { + Rectangle viewRec = textPane.modelToView(docLoc); + return viewRec.y + viewRec.height - descentAdjust; + } + + private String formatLineNumberFromIndex(int lineIndex) { + return String.format("%d", (lineIndex + 1)); + } + + /** Make a new width value, set new current preferred size and size, + * and try to get this component repainted. + * Currently all listener events incur this, which might be more + * than strictly needed. + */ + private void update() { + width = calculateWidthForDigits(currentMaxDigits); + Dimension size = new Dimension(width, textPane.getHeight()); + setPreferredSize(size); + setSize(size); + SwingUtilities.invokeLater(this::repaint); + } + + // component listener events + @Override + public void componentResized(ComponentEvent e) { + update(); + } + + @Override + public void componentMoved(ComponentEvent e) { + update(); + } + + @Override + public void componentShown(ComponentEvent e) { + update(); + } + + @Override + public void componentHidden(ComponentEvent e) { + update(); + } + + // caret listener events + @Override + public void caretUpdate(CaretEvent e) { + update(); + } + + // document listener events + @Override + public void insertUpdate(DocumentEvent e) { + update(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + update(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + update(); + } + + /** + * Set whether this widget should display or not display line numbers, + * incur an update() call if there is a change. + * @param flag + */ + public void setDisplay(boolean flag) { + boolean oldDisplay = display; + this.display = flag; + if ( this.display != oldDisplay ) { + update(); + } + } + + /** + * Set the fontName and fontSize for this widget. If the + * submitted name and size amount to a change of the font itself, + * incur an update() call. + * @param fontName + * @param fontSize + */ + public void updateFontNameAndSize(String fontName, int fontSize) { + if ( fontSize < 1 ) { + if ( fontName == null || fontName.isEmpty() ) { + fontName = Font.MONOSPACED; + } + fontSize = 14; + } + String oldFontName = this.fontName; + int oldFontSize = this.fontSize; + + this.fontName = fontName; + this.fontSize = fontSize; + + if ( !this.fontName.equals(oldFontName) || this.fontSize != oldFontSize ) { + font = new Font(this.fontName, Font.PLAIN, this.fontSize); + descentAdjust = makeDescentAdjust(); + update(); + } + } + + +} diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurPDFWriter.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurPDFWriter.java index deccdd9e6..de3961c66 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurPDFWriter.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurPDFWriter.java @@ -226,7 +226,7 @@ public OurPDFWriter drawShape(Shape shape, boolean fillOrNot) { * given matrix; for example, [1 0 0 1 dx dy] means "translation to dx dy" $R $G * $B RG --> sets the stroke color (where 0 <= $R <= 1, etc) $R $G $B rg --> * sets the fill color (where 0 <= $R <= 1, etc) Q --> restores the current - * graphics state Page Object (3 because PAGE is #3) (4 beacuse PAGES is #4) (2 + * graphics state Page Object (3 because PAGE is #3) (4 because PAGES is #4) (2 * because CONTENTS is #2) * ========================================================= ================ * ============ 3 0 obj << /Type /Page /Parent 4 0 R /Contents 2 0 R >> diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxDocument.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxDocument.java index eeb66807e..24fedaf94 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxDocument.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxDocument.java @@ -577,7 +577,7 @@ else if (tabSize > 100) } /** - * Overriden to return the full text of the document. + * Overridden to return the full text of the document. * * @return the entire text */ diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxUndoableDocument.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxUndoableDocument.java index 11ca13341..11227e6fe 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxUndoableDocument.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxUndoableDocument.java @@ -60,7 +60,7 @@ final class OurSyntaxUndoableDocument extends OurSyntaxDocument { private int now; /** - * The number of undoable opeartions that are currently "undone". + * The number of undoable operations that are currently "undone". */ private int undone; @@ -219,7 +219,7 @@ public void replace(int offset, int length, String string, AttributeSet attrs) t } /** - * Overriden to return the full text of the document. + * Overridden to return the full text of the document. * * @return the entire text */ diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxWidget.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxWidget.java index 002607726..2723bf9eb 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxWidget.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurSyntaxWidget.java @@ -120,11 +120,13 @@ public final class OurSyntaxWidget { private volatile CompModule module; + private OurLineNumberWidget ourLineNumberWidget; + /** * Constructs a syntax-highlighting widget. */ public OurSyntaxWidget(OurTabbedSyntaxWidget parent) { - this(parent, true, "", "Monospaced", 14, 4, null, null); + this(parent, true, "", "Monospaced", 14, 4, false, null, null); } /** @@ -133,7 +135,7 @@ public OurSyntaxWidget(OurTabbedSyntaxWidget parent) { * @param parent */ @SuppressWarnings("serial" ) - public OurSyntaxWidget(OurTabbedSyntaxWidget parent, boolean enableSyntax, String text, String fontName, int fontSize, int tabSize, JComponent obj1, JComponent obj2) { + public OurSyntaxWidget(OurTabbedSyntaxWidget parent, boolean enableSyntax, String text, String fontName, int fontSize, int tabSize, boolean lineNumbers, JComponent obj1, JComponent obj2) { pane.addKeyListener(new KeyListener() { @Override @@ -327,6 +329,9 @@ public void focusGained(FocusEvent e) { component.setFocusable(false); component.setMinimumSize(new Dimension(50, 50)); component.setViewportView(pane); + + ourLineNumberWidget = OurLineNumberWidget.build(pane, component, lineNumbers, fontName, fontSize); + modified = false; } @@ -432,14 +437,14 @@ private void doComment() { if (s != null && s.length() > 0) { StringBuilder sb = new StringBuilder(s); int i = 0; - while (i < sb.length() - 1) { + while (i < sb.length()) { if (sb.charAt(i) == '/' && sb.charAt(i + 1) == '/') { sb.delete(i, i + 2); } else { sb.insert(i, "//"); i += 2; } - while (i < sb.length() - 1) { + while (i < sb.length()) { if (sb.charAt(i) == '\n') { i++; break; @@ -565,8 +570,10 @@ public boolean isFile() { * Changes the font name, font size, and tab size for the document. */ void setFont(String fontName, int fontSize, int tabSize) { - if (doc != null) + if (doc != null) { doc.do_setFont(fontName, fontSize, tabSize); + ourLineNumberWidget.updateFontNameAndSize(fontName, fontSize); + } } /** Enables or disables syntax highlighting. */ @@ -575,6 +582,10 @@ void enableSyntax(boolean flag) { doc.do_enableSyntax(flag); } + void enableLineNumbers(boolean flag) { + ourLineNumberWidget.setDisplay(flag); + } + /** * Return the number of lines represented by the current text (where partial * line counts as a line). @@ -865,4 +876,6 @@ public String getTooltip(MouseEvent event) { } return null; } + + } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurTabbedSyntaxWidget.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurTabbedSyntaxWidget.java index 5becd5587..b2cc396fd 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurTabbedSyntaxWidget.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/OurTabbedSyntaxWidget.java @@ -85,6 +85,11 @@ public final class OurTabbedSyntaxWidget { */ private boolean syntaxHighlighting; + /** + * Whether line numbers are currently enable to displayr or not. + */ + private boolean lineNumbers; + /** The list of clickable tabs. */ private final JPanel tabBar; @@ -157,7 +162,7 @@ public Object do_action(Object sender, Event e, Object arg) { private final JFrame parent; /** Constructs a tabbed editor pane. */ - public OurTabbedSyntaxWidget(String fontName, int fontSize, int tabSize, JFrame parent) { + public OurTabbedSyntaxWidget(String fontName, int fontSize, int tabSize, boolean lineNumbers, JFrame parent) { this.parent = parent; component.setBorder(null); component.setLayout(new BorderLayout()); @@ -174,6 +179,7 @@ public OurTabbedSyntaxWidget(String fontName, int fontSize, int tabSize, JFrame tabBarScroller.setFocusable(false); tabBarScroller.setBorder(null); setFont(fontName, fontSize, tabSize); + this.lineNumbers = lineNumbers; newtab(null); tabBarScroller.addComponentListener(new ComponentListener() { @@ -377,9 +383,18 @@ public void enableSyntax(boolean flag) { t.enableSyntax(flag); } + public void enableLineNumbers(boolean flag) { + lineNumbers = flag; + for ( OurSyntaxWidget t : tabs) { + t.enableLineNumbers(flag); + } + } + /** Returns the JTextArea of the current text buffer. */ public OurSyntaxWidget get() { - return (me >= 0 && me < tabs.size()) ? tabs.get(me) : new OurSyntaxWidget(this); + return (me >= 0 && me < tabs.size()) ? tabs.get(me) : + new OurSyntaxWidget(this, + syntaxHighlighting, "", fontName, fontSize, tabSize, lineNumbers, null, null); } /** @@ -438,7 +453,7 @@ public void mousePressed(MouseEvent e) { JPanel pan = Util.onMac() ? OurUtil.makeVL(null, 2, OurUtil.makeHB(h1, lb, h2)) : OurUtil.makeVL(null, 2, OurUtil.makeHB(h1, lb, h2, GRAY), GRAY); pan.setAlignmentX(0.0f); pan.setAlignmentY(1.0f); - OurSyntaxWidget text = new OurSyntaxWidget(this, syntaxHighlighting, "", fontName, fontSize, tabSize, lb, pan); + OurSyntaxWidget text = new OurSyntaxWidget(this, syntaxHighlighting, "", fontName, fontSize, tabSize, lineNumbers, lb, pan); tabBar.add(pan, tabs.size()); tabs.add(text); text.listeners.add(listener); // add listener AFTER we've updated diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Pos.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Pos.java index a82798858..07e6b84fa 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Pos.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Pos.java @@ -102,9 +102,9 @@ public Pos(String filename, int x, int y, int x2, int y2) { * @param that - the other position object */ public Pos merge(Pos that) { - if (that == null || that == UNKNOWN || that == this) + if (that == null || that.equals(UNKNOWN) || that == this) return this; - if (this == UNKNOWN) + if (this.equals(UNKNOWN)) return that; int x = this.x, y = this.y, x2 = that.x2, y2 = that.y2; if (that.y < y || (that.y == y && that.x < x)) { @@ -178,6 +178,11 @@ public String toString() { return "line " + y + ", column " + x + ", filename=" + filename; } + public String toRangeString() { + String filePart = filename.length() == 0 ? "" : ", filename=" + filename; + return "line " + y + ", column " + x + " to line " + y2 + ", column " + x2 + filePart; + } + int start() { return y * 500 + x; } @@ -194,6 +199,10 @@ public boolean contains(Pos pos) { int anchor = pos.start(); int ourStart = start(); int ourEnd = end(); + + if(!filename.equals(pos.filename) && !"".equals(pos.filename)) + return false; + if (ourStart > anchor) return false; @@ -308,4 +317,8 @@ public String substring(String text) { public boolean sameFile(Pos pos) { return this.filename.equals(pos.filename); } + + public Pos withFilename(String filename){ + return new Pos(filename, x, y, x2, y2); + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Runner.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Runner.java index 34aa02822..ed9f14c41 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Runner.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Runner.java @@ -45,14 +45,14 @@ public abstract class Runner extends AbstractAction implements Runnable, WindowL public Runner() {} /** - * This method should be overriden to provide the default action that this + * This method should be overridden to provide the default action that this * Runner would perform. */ @Override public abstract void run(); /** - * This method should be overriden to provide the default action that this + * This method should be overridden to provide the default action that this * Runner would perform given an argument. */ public abstract void run(Object arg); diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Util.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Util.java index 191bd54be..47d0ce2bd 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Util.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/alloy4/Util.java @@ -403,17 +403,17 @@ else if (b.equals("in")) } else if (b.startsWith("this/")) { return 1; } - int acount = 0, bcount = 0; + int account = 0, bcount = 0; for (int i = 0; i < a.length(); i++) { if (a.charAt(i) == '/') - acount++; + account++; } for (int i = 0; i < b.length(); i++) { if (b.charAt(i) == '/') bcount++; } - if (acount != bcount) - return (acount < bcount) ? -1 : 1; + if (account != bcount) + return (account < bcount) ? -1 : 1; int result = a.compareToIgnoreCase(b); return result != 0 ? result : a.compareTo(b); } @@ -821,7 +821,7 @@ public static int min(int bitwidth) { /** * Returns a mask of the form 000..0011..11 where the number of 1s is equal to - * the number of significant bits of the highest integer withing the given + * the number of significant bits of the highest integer within the given * bitwidth */ public static int shiftmask(int bitwidth) { diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Assert.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Assert.java new file mode 100644 index 000000000..a7431265e --- /dev/null +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Assert.java @@ -0,0 +1,64 @@ +package edu.mit.csail.sdg.ast; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorWarning; +import edu.mit.csail.sdg.alloy4.Pos; + +public final class Assert extends Expr implements Clause { + public final Expr expr; + public final Pos labelPos; + public final String label; + + public Assert(Pos pos, Pos labelPos, String label, Expr expr) { + super(pos, Type.FORMULA); + this.expr = expr; + this.labelPos = labelPos; + this.label = label; + } + + @Override + public String explain() { + return "assert " + label; + } + + @Override + public void toString(StringBuilder out, int indent) { + if (indent < 0) { + out.append(label); + } else { + for (int i = 0; i < indent; i++) { + out.append(' '); + } + out.append( "assert ").append(label).append('\n'); + } + } + + @Override + public T accept(VisitReturn visitor) throws Err { + return visitor.visit(this); + } + + @Override + public Expr resolve(Type t, Collection warnings) { + return this; + } + + @Override + public int getDepth() { + return 1; + } + + @Override + public String getHTML() { + return "assert " + label; + } + + @Override + public List< ? extends Browsable> getSubnodes() { + return Arrays.asList(expr); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Clause.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Clause.java index 10d951644..8a05d182d 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Clause.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Clause.java @@ -4,7 +4,7 @@ /** * Unfortunately not all objects are Expr. However, from the UI we want to be - * able to locae the clauses in the text file and what they refer to. + * able to locate the clauses in the text file and what they refer to. * * @author aqute * @@ -22,4 +22,25 @@ public interface Clause { * @return a string formatted like a set */ String explain(); + + public final class Custom implements Clause{ + final Pos pos; + final String explanation; + + public Custom(Pos pos, String explanation) { + this.pos = pos; + this.explanation = explanation; + } + + @Override + public Pos pos() { + return pos; + } + + @Override + public String explain() { + return explanation; + } + + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Command.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Command.java index 3e39158fc..033057377 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Command.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Command.java @@ -125,6 +125,11 @@ public final class Command extends Browsable { public final Expr nameExpr; + /** + * The 'check' or 'run' keyword + */ + public final ExprVar commandKeyword; + /** * Returns a human-readable string that summarizes this Run or Check command. */ @@ -170,6 +175,27 @@ else if (bitwidth >= 0 || maxseq >= 0 || scope.size() > 0 || minprefix >= 0 || m return sb.toString(); } + /** + * Constructs a new Command object. + * + * @param check - true if this is a "check"; false if this is a "run" + * @param overall - the overall scope (0 or higher) (-1 if no overall scope was + * specified) + * @param bitwidth - the integer bitwidth (0 or higher) (-1 if it was not + * specified) + * @param maxseq - the maximum sequence length (0 or higher) (-1 if it was not + * specified) + * @param mintime - the minimal trace length (0 or higher) (-1 if it was not + * specified) + * @param maxtime - the maximal trace length (0 or higher) (-1 if it was not + * specified) + * @param formula - the formula that must be satisfied by this command + */ + //extended with time scopes + public Command(boolean check, int overall, int bitwidth, int maxseq, int mintime, int maxtime, ExprVar commandKeyword, Expr formula) throws ErrorSyntax { + this(null, null, "", check, overall, bitwidth, maxseq, mintime, maxtime, -1, null, null, commandKeyword, formula, null); + } + /** * Constructs a new Command object. * @@ -182,8 +208,8 @@ else if (bitwidth >= 0 || maxseq >= 0 || scope.size() > 0 || minprefix >= 0 || m * specified) * @param formula - the formula that must be satisfied by this command */ - public Command(boolean check, int overall, int bitwidth, int maxseq, Expr formula) throws ErrorSyntax { - this(null, null, "", check, overall, bitwidth, maxseq, -1, -1, -1, null, null, formula, null); + public Command(boolean check, int overall, int bitwidth, int maxseq, ExprVar commandKeyword, Expr formula) throws ErrorSyntax { + this(null, null, "", check, overall, bitwidth, maxseq, -1, -1, -1, null, null, commandKeyword, formula, null); } /** @@ -210,10 +236,11 @@ public Command(boolean check, int overall, int bitwidth, int maxseq, Expr formul * exact though we may or may not know what the scope is yet * @param formula - the formula that must be satisfied by this command */ - public Command(Pos pos, Expr e, String label, boolean check, int overall, int bitwidth, int maxseq, int minprefix, int maxprefix, int expects, Iterable scope, Iterable additionalExactSig, Expr formula, Command parent) { + public Command(Pos pos, Expr e, String label, boolean check, int overall, int bitwidth, int maxseq, int minprefix, int maxprefix, int expects, Iterable scope, Iterable additionalExactSig, ExprVar commandKeyword, Expr formula, Command parent) { if (pos == null) pos = Pos.UNKNOWN; this.nameExpr = e; + this.commandKeyword = commandKeyword; this.formula = formula; this.pos = pos; this.label = (label == null ? "" : label); @@ -234,24 +261,27 @@ public Command(Pos pos, Expr e, String label, boolean check, int overall, int bi * Constructs a new Command object where it is the same as the current object, * except with a different formula. */ + //extended with time scopes public Command change(Expr newFormula) { - return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, additionalExactScopes, newFormula, parent); + return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, additionalExactScopes, commandKeyword, newFormula, parent); } /** * Constructs a new Command object where it is the same as the current object, * except with a different scope. */ + //extended with time scopes public Command change(ConstList scope) { - return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, additionalExactScopes, formula, parent); + return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, additionalExactScopes, commandKeyword, formula, parent); } /** * Constructs a new Command object where it is the same as the current object, * except with a different list of "additional exact sigs". */ + //extended with time scopes public Command change(Sig... additionalExactScopes) { - return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, Util.asList(additionalExactScopes), formula, parent); + return new Command(pos, nameExpr, label, check, overall, bitwidth, maxseq, minprefix, maxprefix, expects, scope, Util.asList(additionalExactScopes), commandKeyword, formula, parent); } /** @@ -269,10 +299,10 @@ public Command change(Sig sig, boolean isExact, int newScope) throws ErrorSyntax public Command change(Sig sig, boolean isExact, int startingScope, int endingScope, int increment) throws ErrorSyntax { for (int i = 0; i < scope.size(); i++) if (scope.get(i).sig == sig) { - CommandScope sc = new CommandScope(scope.get(i).pos, sig, isExact, startingScope, endingScope, increment); + CommandScope sc = new CommandScope(scope.get(i).pos, scope.get(i).sigPos, sig, isExact, startingScope, endingScope, increment); return change(new TempList(scope).set(i, sc).makeConst()); } - CommandScope sc = new CommandScope(Pos.UNKNOWN, sig, isExact, startingScope, endingScope, increment); + CommandScope sc = new CommandScope(Pos.UNKNOWN, Pos.UNKNOWN, sig, isExact, startingScope, endingScope, increment); return change(Util.append(scope, sc)); } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/CommandScope.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/CommandScope.java index 357be5bfb..408f88b82 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/CommandScope.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/CommandScope.java @@ -37,6 +37,10 @@ public class CommandScope { */ public final Pos pos; + /** + * The position of the sig reference + */ + public final Pos sigPos; /** * The sig whose scope is being given by this CommandScope object. */ @@ -69,7 +73,7 @@ public class CommandScope { * @throws ErrorSyntax if scope is less than zero */ public CommandScope(Sig sig, boolean isExact, int scope) throws ErrorSyntax { - this(null, sig, isExact, scope, scope, 1); + this(null, null, sig, isExact, scope, scope, 1); } /** @@ -87,7 +91,7 @@ public CommandScope(Sig sig, boolean isExact, int scope) throws ErrorSyntax { * @throws ErrorSyntax if endingScope is less than startingScope * @throws ErrorSyntax if increment is less than one */ - public CommandScope(Pos pos, Sig sig, boolean isExact, int startingScope, int endingScope, int increment) throws ErrorSyntax { + public CommandScope(Pos pos, Pos sigPos, Sig sig, boolean isExact, int startingScope, int endingScope, int increment) throws ErrorSyntax { if (pos == null) pos = Pos.UNKNOWN; if (sig == null) @@ -104,12 +108,18 @@ public CommandScope(Pos pos, Sig sig, boolean isExact, int startingScope, int en throw new ErrorSyntax(pos, "Sig " + sig + "'s increment value cannot be " + increment + ".\nThe increment must be 1 or greater."); this.pos = pos; this.sig = sig; + this.sigPos = sigPos; this.isExact = isExact; this.startingScope = startingScope; this.endingScope = endingScope; this.increment = increment; } + Expr sigRef = null; + public Expr sigRef(){ + if(sigRef == null) sigRef = ExprUnary.Op.NOOP.make(sigPos, sig, null, 0); + return sigRef; + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Decl.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Decl.java index 37c5b1d32..544a0148c 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Decl.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Decl.java @@ -29,7 +29,7 @@ * variable). */ -public final class Decl { +public class Decl { /** * If nonnull, then this decl is private (and this.isPrivate is the location of diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Expr.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Expr.java index 336c82466..2feb1531e 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Expr.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Expr.java @@ -125,7 +125,7 @@ public final Type type() { * @param errors - the list of errors associated with this Expr node (can be * null if there are none) */ - Expr(Pos pos, Pos closingBracket, boolean ambiguous, Type type, int mult, long weight, JoinableList errors) { + public Expr(Pos pos, Pos closingBracket, boolean ambiguous, Type type, int mult, long weight, JoinableList errors) { this.pos = (pos == null ? Pos.UNKNOWN : pos); this.closingBracket = (closingBracket == null ? Pos.UNKNOWN : closingBracket); this.ambiguous = ambiguous; @@ -140,7 +140,7 @@ public final Type type() { } /** This must only be called by Sig's constructor. */ - Expr(Pos pos, Type type) { + public Expr(Pos pos, Type type) { this.closingBracket = Pos.UNKNOWN; this.ambiguous = false; this.errors = emptyListOfErrors; @@ -240,7 +240,7 @@ public final Expr typecheck_as_set() { /** * Resolves this expression if ambiguous. (And if t.size()>0, it represents the - * set of tuples whose presence/absence is relevent to the parent expression) + * set of tuples whose presence/absence is relevant to the parent expression) * (Note: it's possible for t to be EMPTY, or even ambiguous!) *

* On success: the return value will be well-typed and unambiguous diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprCall.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprCall.java index 14c421bde..fc33446ca 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprCall.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprCall.java @@ -31,6 +31,7 @@ import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4.Util; import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.parser.Macro; /** * Immutable; represents a call. @@ -266,6 +267,21 @@ public Type visit(Sig x) { return x.type; } + @Override + public Type visit(Func x) throws Err { + return x.type; + } + + @Override + public Type visit(Assert x) throws Err { + return x.type; + } + + @Override + public Type visit(Macro x) throws Err { + return x.type(); + } + @Override public Type visit(Field x) { return x.type; diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprList.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprList.java index 52ddfaa80..8bb6c5b93 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprList.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/ExprList.java @@ -32,7 +32,7 @@ /** * Immutable; represents disjoint[] or pred/totalOrder[] or (... and ... and ..) - * and other similar list of arugments. + * and other similar list of arguments. *

* Invariant: type!=EMPTY => (all x:args | x.mult==0) */ diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Func.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Func.java index 6518c9d30..c8a4d3e0e 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Func.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Func.java @@ -18,13 +18,16 @@ import static edu.mit.csail.sdg.alloy4.TableView.clean; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; +import java.util.stream.Collectors; import edu.mit.csail.sdg.alloy4.ConstList; import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.alloy4.ErrorSyntax; import edu.mit.csail.sdg.alloy4.ErrorType; +import edu.mit.csail.sdg.alloy4.ErrorWarning; import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4.Util; @@ -40,7 +43,7 @@ * predicate/function call */ -public final class Func extends Browsable implements Clause { +public final class Func extends Expr implements Clause { /** * The location in the original file where this predicate/function is declared; @@ -59,6 +62,11 @@ public final class Func extends Browsable implements Clause { */ public final String label; + /** + * The position of the label + */ + public final Pos labelPos; + /** * True if this is a predicate; false if this is a function. */ @@ -133,8 +141,8 @@ public List params() { * @throws ErrorSyntax if this function's return type declaration contains a * predicate/function call */ - public Func(Pos pos, String label, List decls, Expr returnDecl, Expr body) throws Err { - this(pos, null, label, decls, returnDecl, body); + public Func(Pos pos, Pos labelPos, String label, List decls, Expr returnDecl, Expr body) throws Err { + this(pos, null, labelPos, label, decls, returnDecl, body); } /** @@ -167,12 +175,14 @@ public Func(Pos pos, String label, List decls, Expr returnDecl, Expr body) * @throws ErrorSyntax if this function's return type declaration contains a * predicate/function call */ - public Func(Pos pos, Pos isPrivate, String label, List decls, Expr returnDecl, Expr body) throws Err { + public Func(Pos pos, Pos isPrivate, Pos labelPos, String label, List decls, Expr returnDecl, Expr body) throws Err { + super(pos, Type.FORMULA); if (pos == null) pos = Pos.UNKNOWN; this.pos = pos; this.isPrivate = isPrivate; this.label = (label == null ? "" : label); + this.labelPos = labelPos; this.isPred = (returnDecl == null); if (returnDecl == null) returnDecl = ExprConstant.FALSE; @@ -252,12 +262,6 @@ public final String toString() { return (isPred ? "pred " : "fun ") + label; } - /** {@inheritDoc} */ - @Override - public final Pos pos() { - return pos; - } - /** {@inheritDoc} */ @Override public final Pos span() { @@ -270,6 +274,12 @@ public String getHTML() { return (isPred ? "pred " : "fun ") + label; } + ExprVar labelExpr = null; + public Expr labelExpr(){ + if(labelExpr == null) + labelExpr = ExprVar.make(labelPos, label); + return labelExpr; + } /** {@inheritDoc} */ @Override public List< ? extends Browsable> getSubnodes() { @@ -284,8 +294,7 @@ public String getHTML() { return ans; } - @Override - public String explain() { + public String explainOld() { if (clean(label).contains("run$")) { return null; } @@ -324,4 +333,54 @@ public String explain() { return sb.toString(); } + @Override + public String explain() { + StringBuilder sb = new StringBuilder(); + if (isPred) + sb.append("pred "); + else + sb.append("fun "); + + sb.append(clean(label)); + + if (decls.size() > 0 ) { + sb.append(" [\n"); + sb.append(decls.stream() + .flatMap(decl -> decl.names.stream().map(e -> " " + e + " : " + decl.expr.type)) + .collect(Collectors.joining(",\n"))); + sb.append("\n]"); + } + if (!isPred) { + sb.append(" ⟶ ").append(returnDecl.type.toString()); + } + return sb.toString(); + } + + @Override + public void toString(StringBuilder out, int indent) { + if (indent < 0) { + out.append("(").append(label).append(" <: ").append(label).append(")"); + } else { + for (int i = 0; i < indent; i++) { + out.append(' '); + } + out.append( isPred? "pred " : "field ").append(label).append('\n'); + } + } + + @Override + public T accept(VisitReturn visitor) throws Err { + return visitor.visit(this); + } + + @Override + public Expr resolve(Type t, Collection warnings) { + return this; + } + + @Override + public int getDepth() { + return 1; + } + } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Module.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Module.java index 07d768156..85f5b785e 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Module.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Module.java @@ -79,7 +79,7 @@ public interface Module extends Clause { /** * Return an unmodifiable list of all assertions in this module. */ - public ConstList> getAllAssertions(); + public ConstList getAllAssertions(); /** * Return an unmodifiable list of all facts in this module. @@ -110,7 +110,7 @@ public interface Module extends Clause { public JFrame showAsTree(Listener listener); /** - * Parse one expression by starting fromt this module as the root module. + * Parse one expression by starting from this module as the root module. */ public Expr parseOneExpressionFromString(String input) throws Err, FileNotFoundException, IOException; } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Sig.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Sig.java index 211040e65..e422f8752 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Sig.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/Sig.java @@ -20,6 +20,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import edu.mit.csail.sdg.alloy4.ConstList; import edu.mit.csail.sdg.alloy4.ConstList.TempList; @@ -33,6 +35,7 @@ import edu.mit.csail.sdg.alloy4.Util; import edu.mit.csail.sdg.alloy4.Version; import edu.mit.csail.sdg.ast.Attr.AttrType; +import org.alloytools.util.table.Table; /** * Mutable; represents a signature. @@ -45,26 +48,26 @@ public abstract class Sig extends Expr implements Clause { /** The built-in "univ" signature. */ - public static final PrimSig UNIV = new PrimSig("univ", null, true, false); + public static final PrimSig UNIV = new PrimSig("univ", null, null, false, false); /** The built-in "Int" signature. */ - public static final PrimSig SIGINT = new PrimSig("Int", UNIV, false, false); + public static final PrimSig SIGINT = new PrimSig("Int", Pos.UNKNOWN, UNIV, false, false); /** The built-in "seq/Int" signature. */ - public static final PrimSig SEQIDX = new PrimSig("seq/Int", SIGINT, false, true); + public static final PrimSig SEQIDX = new PrimSig("seq/Int", Pos.UNKNOWN, SIGINT, false, true); /** The built-in "String" signature. */ - public static final PrimSig STRING = new PrimSig("String", UNIV, false, true); + public static final PrimSig STRING = new PrimSig("String", Pos.UNKNOWN, UNIV, false, true); /** The built-in "none" signature. */ - public static final PrimSig NONE = new PrimSig("none", null, false, false); + public static final PrimSig NONE = new PrimSig("none", null, null, false, false); /** The built-in "none" signature. */ public static final PrimSig GHOST = mkGhostSig(); private static final PrimSig mkGhostSig() { try { - return new PrimSig("Univ", null, new Attr[0]); + return new PrimSig(null, "Univ", null, null, new Attr[0]); } catch (Err e) { return null; // never happens } @@ -226,6 +229,11 @@ public final T accept(VisitReturn visitor) throws Err { */ public final Pos isVariable; + /** + * The position of the sig label + */ + public final Pos labelPos; + /** * The label for this sig; this name does not need to be unique. */ @@ -268,11 +276,12 @@ private Sig(String label, boolean var) { this.isMeta = null; this.isEnum = null; this.isVariable = var ? Pos.UNKNOWN : null; + this.labelPos = null; this.attributes = ConstList.make(); } /** Constructs a new PrimSig or SubsetSig. */ - private Sig(Type type, String label, Attr... attributes) throws Err { + private Sig(Type type, Pos labelPos, String label, Attr... attributes) throws Err { super(AttrType.WHERE.find(attributes), type); this.attributes = Util.asList(attributes); Expr oneof = ExprUnary.Op.ONEOF.make(null, this); @@ -328,6 +337,7 @@ private Sig(Type type, String label, Attr... attributes) throws Err { this.isVariable = isVariable; this.label = label; this.builtin = false; + this.labelPos = labelPos; if (isLone != null && isOne != null) throw new ErrorSyntax(isLone.merge(isOne), "You cannot declare a sig to be both lone and one."); if (isLone != null && isSome != null) @@ -359,6 +369,13 @@ public boolean isSame(Expr obj) { /** Returns true iff "this is equal or subtype of that" */ public abstract boolean isSameOrDescendentOf(Sig that); + public boolean isEnumMember() { + if (this instanceof PrimSig) { + PrimSig _this = (PrimSig) this; + return _this.parent.isEnum != null; + } else + return false; + } /** {@inheritDoc} */ @Override public int getDepth() { @@ -469,10 +486,27 @@ public Iterable descendents() throws Err { */ public final PrimSig parent; + /** + * The position of the reference to the parent Sig. + * Can be null only if parent is null + */ + public final Pos parentRefPos; + + + private Expr parentRef; + public Expr parentRef(){ + if(parentRef == null ){ + parentRef = ExprUnary.Op.NOOP.make(parentRefPos , parent ); + } + return parentRef; + } + /** Constructs a builtin PrimSig. */ - private PrimSig(String label, PrimSig parent, boolean var, boolean add) { + private PrimSig(String label, Pos parentRefPos, PrimSig parent, boolean var, boolean add) { super(label, var); this.parent = parent; + assert parent == null ? parentRefPos == null : parentRefPos != null; + this.parentRefPos = parentRefPos ; if (add) this.parent.children.add(this); } @@ -488,8 +522,10 @@ private PrimSig(String label, PrimSig parent, boolean var, boolean add) { * @throws ErrorType if you attempt to extend the builtin sigs NONE, SIGINT, * SEQIDX, or STRING */ - public PrimSig(String label, PrimSig parent, Attr... attributes) throws Err { - super(((parent != null && parent.isEnum != null) ? parent.type : null), label, Util.append(attributes, Attr.SUBSIG)); + public PrimSig(Pos labelPos, String label, Pos parentRefPos, PrimSig parent, Attr... attributes) throws Err { + super(((parent != null && parent.isEnum != null) ? parent.type : null), labelPos, label, Util.append(attributes, Attr.SUBSIG)); + assert parent == null ? parentRefPos == null : parentRefPos != null; + if (parent == SIGINT) throw new ErrorSyntax(pos, "sig " + label + " cannot extend the builtin \"Int\" signature"); if (parent == SEQIDX) @@ -503,6 +539,8 @@ public PrimSig(String label, PrimSig parent, Attr... attributes) throws Err { else if (parent != UNIV) parent.children.add(this); this.parent = parent; + this.parentRefPos = parentRefPos; + if (isEnum != null && parent != UNIV) throw new ErrorType(pos, "sig " + label + " is not a toplevel sig, so it cannot be an enum."); for (; parent != null; parent = parent.parent) @@ -523,7 +561,7 @@ else if (parent != UNIV) * @throws ErrorSyntax if the signature has two or more multiplicities */ public PrimSig(String label, Attr... attributes) throws Err { - this(label, null, attributes); + this(null, label, null, null, attributes); } /** {@inheritDoc} */ @@ -611,6 +649,23 @@ private static Type getType(String label, Iterable parents) throws Err { return (ans != null) ? ans : (UNIV.type); } + /** + * The positions of references to parent Sigs (in parents field). + * Could be null + */ + public final ConstList parentRefPoss; + + private ConstList parentRefs; + public ConstList parentRefs(){ + if(parentRefs == null){ + TempList res = new TempList<>(); + for(int i = 0; i < parents.size(); i++){ + res.add(ExprUnary.Op.NOOP.make(parentRefPoss != null ? parentRefPoss.get(i) : Pos.UNKNOWN, parents.get(i) )); + } + parentRefs = res.makeConst(); + } + return parentRefs; + } /** * Constructs a subset sig. * @@ -622,8 +677,8 @@ private static Type getType(String label, Iterable parents) throws Err { * @throws ErrorSyntax if the signature has two or more multiplicities * @throws ErrorType if parents only contains NONE */ - public SubsetSig(String label, Collection parents, Attr... attributes) throws Err { - super(getType(label, parents), label, Util.append(attributes, Attr.SUBSET)); + public SubsetSig(Pos labelPos, String label, Collection parentRefPoss, Collection parents, Attr... attributes) throws Err { + super(getType(label, parents), labelPos, label, Util.append(attributes, Attr.SUBSET)); if (isEnum != null) throw new ErrorType(pos, "Subset signature cannot be an enum."); boolean exact = false; @@ -656,6 +711,7 @@ public SubsetSig(String label, Collection parents, Attr... attributes) thro if (temp.size() == 0) throw new ErrorType(pos, "Sig " + label + " must have at least one non-empty parent."); this.parents = temp.makeConst(); + this.parentRefPoss = parentRefPoss != null ? new TempList(parentRefPoss).makeConst() : null; } /** {@inheritDoc} */ @@ -696,13 +752,15 @@ public static final class Field extends ExprHasName implements Clause { /** The declaration that this field came from. */ private Decl decl; + public final Pos labelPos; + /** Return the declaration that this field came from. */ public Decl decl() { return decl; } /** Constructs a new Field object. */ - private Field(Pos pos, Pos isPrivate, Pos isMeta, Pos disjoint, Pos disjoint2, Pos isVar, Sig sig, String label, Expr bound) throws Err { + private Field(Pos pos, Pos isPrivate, Pos isMeta, Pos disjoint, Pos disjoint2, Pos isVar, Sig sig, Pos labelPos, String label, Expr bound) throws Err { super(pos, label, sig.type.product(bound.type)); this.defined = bound.mult() == ExprUnary.Op.EXACTLYOF; if (sig.builtin) @@ -717,6 +775,7 @@ private Field(Pos pos, Pos isPrivate, Pos isMeta, Pos disjoint, Pos disjoint2, P this.isMeta = (isMeta != null ? isMeta : sig.isMeta); this.isVariable = isVar; this.sig = sig; + this.labelPos = labelPos; } /** @@ -837,7 +896,7 @@ public final Field addField(String label, Expr bound) throws Err { // multiplicity // symbol, we assume // it's oneOf - final Field f = new Field(null, null, null, null, null, null, this, label, bound); + final Field f = new Field(null, null, null, null, null, null, this, null, label, bound); final Decl d = new Decl(null, null, null, null, Arrays.asList(f), bound); f.decl = d; fields.add(d); @@ -867,7 +926,7 @@ public final Field addField(String label, Expr bound) throws Err { * @throws ErrorType if the bound is not fully typechecked or is not a * set/relation */ - public final Field[] addTrickyField(Pos pos, Pos isPrivate, Pos isDisjoint, Pos isDisjoint2, Pos isMeta, Pos isVar, String[] labels, Expr bound) throws Err { + public final Field[] addTrickyField(Pos pos, Pos isPrivate, Pos isDisjoint, Pos isDisjoint2, Pos isMeta, Pos isVar, List labels, Expr bound) throws Err { bound = bound.typecheck_as_set(); if (bound.ambiguous) bound = bound.resolve_as_set(null); @@ -876,9 +935,9 @@ public final Field[] addTrickyField(Pos pos, Pos isPrivate, Pos isDisjoint, Pos // multiplicity // symbol, we assume // it's oneOf - final Field[] f = new Field[labels.length]; + final Field[] f = new Field[labels.size()]; for (int i = 0; i < f.length; i++) - f[i] = new Field(pos, isPrivate, isMeta, isDisjoint, isDisjoint2, isVar, this, labels[i], bound); + f[i] = new Field(pos, isPrivate, isMeta, isDisjoint, isDisjoint2, isVar, this, labels.get(i).pos, labels.get(i).label, bound); final Decl d = new Decl(isPrivate, isDisjoint, isDisjoint2, isVar, Arrays.asList(f), bound); for (int i = 0; i < f.length; i++) { f[i].decl = d; @@ -917,7 +976,7 @@ public final Field addDefinedField(Pos pos, Pos isPrivate, Pos isMeta, String la bound = bound.resolve_as_set(null); if (bound.mult() != ExprUnary.Op.EXACTLYOF) bound = ExprUnary.Op.EXACTLYOF.make(null, bound); - final Field f = new Field(pos, isPrivate, isMeta, null, null, null, this, label, bound); + final Field f = new Field(pos, isPrivate, isMeta, null, null, null, this, null, label, bound); final Decl d = new Decl(null, null, null, null, Arrays.asList(f), bound); f.decl = d; fields.add(d); @@ -925,8 +984,10 @@ public final Field addDefinedField(Pos pos, Pos isPrivate, Pos isMeta, String la return f; } - @Override - public String explain() { + // TODO remove at some point + public String explainOld() { + Table t = new Table(2, 1 + realFields.size(), 1); + StringBuilder sb = new StringBuilder(); if (builtin) sb.append("builtin "); @@ -956,6 +1017,44 @@ public String explain() { } sb.append(" }"); + //return sb.toString(); + + return t.transpose(0).toString(); + } + + @Override + public String explain() { + StringBuilder sb = new StringBuilder(); + if (builtin) + sb.append("builtin "); + if (isEnum != null) + sb.append("enum "); + if (isAbstract != null) + sb.append("abstract "); + if (isLone != null) + sb.append("lone "); + if (isOne != null) + sb.append("one "); + if (isMeta != null) + sb.append("meta "); + if (isSome != null) + sb.append("some "); + if (isSubsig != null) + sb.append("sig "); + if (isSubset != null) + sb.append("subset "); + + sb.append(clean(label)); + if(! realFields.isEmpty()){ + sb.append(" {\n"); + + sb.append(StreamSupport.stream(realFields.spliterator(), false) + .map(f -> " " + clean(f.label) + " : " + + clean(type.join(f.type).toString())) + .collect(Collectors.joining(",\n"))); + + sb.append("\n}"); + } return sb.toString(); } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQuery.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQuery.java index 5b91dfb86..f692968b8 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQuery.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQuery.java @@ -17,6 +17,7 @@ import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.parser.Macro; /** * This abstract class implements a Query visitor that walks over an Expr and @@ -149,6 +150,21 @@ public T visit(Sig x) throws Err { return null; } + @Override + public T visit(Func x) throws Err { + return null; + } + + @Override + public T visit(Assert x) throws Err { + return null; + } + + @Override + public T visit(Macro x) throws Err { + return null; + } + /** * Visits a Field node (this default implementation simply returns null) */ diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQueryOnce.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQueryOnce.java index e6a03242c..f51104442 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQueryOnce.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitQueryOnce.java @@ -4,6 +4,7 @@ import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.parser.Macro; /** * Acts like VisitQuery but never traverses a node more than once. @@ -144,4 +145,27 @@ protected boolean visited(Expr x) { return visited.put(x, x) != null; } + @Override + public T visit(Func x) throws Err { + if (visited(x)) + return null; + else + return super.visit(x); + } + + @Override + public T visit(Assert x) throws Err { + if (visited(x)) + return null; + else + return super.visit(x); + } + + @Override + public T visit(Macro x) throws Err { + if (visited(x)) + return null; + else + return super.visit(x); + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitReturn.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitReturn.java index 626e5ea87..c78f58890 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitReturn.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/ast/VisitReturn.java @@ -17,6 +17,7 @@ import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.parser.Macro; /** * This abstract class defines what a Return Visitor's interface needs to be. @@ -81,4 +82,13 @@ public T visit(ExprBadJoin x) throws Err { /** Visits a Field node. */ public abstract T visit(Field x) throws Err; + + /** Visits a Func node. */ + public abstract T visit(Func x) throws Err; + + /** Visists an Assert node. */ + public abstract T visit(Assert x) throws Err; + + /** Visits a Macro node. */ + public abstract T visit(Macro macro) throws Err; } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompFilter.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompFilter.java index 44e1491df..cfbab9411 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompFilter.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompFilter.java @@ -27,7 +27,6 @@ import static edu.mit.csail.sdg.parser.CompSym.DISJ; import static edu.mit.csail.sdg.parser.CompSym.EOF; import static edu.mit.csail.sdg.parser.CompSym.EQUALS; -import static edu.mit.csail.sdg.parser.CompSym.EXH; import static edu.mit.csail.sdg.parser.CompSym.FUN; import static edu.mit.csail.sdg.parser.CompSym.GT; import static edu.mit.csail.sdg.parser.CompSym.GTE; @@ -70,7 +69,6 @@ import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_LONE; import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_ONE; import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_SOME; -import static edu.mit.csail.sdg.parser.CompSym.PART; import static edu.mit.csail.sdg.parser.CompSym.PRED; import static edu.mit.csail.sdg.parser.CompSym.PRIVATE; import static edu.mit.csail.sdg.parser.CompSym.RBRACE; @@ -191,7 +189,7 @@ else if (a.sym == SOME) temp.add(b = myread()); if (b.sym == PRIVATE) temp.add(b = myread()); - if (b.sym == DISJ || b.sym == PART || b.sym == EXH) + if (b.sym == DISJ) temp.add(b = myread()); while (b.sym == ID) { temp.add(b = myread()); diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompModule.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompModule.java index 7fff7c4e0..adfea63e3 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompModule.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompModule.java @@ -40,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import edu.mit.csail.sdg.alloy4.A4Reporter; import edu.mit.csail.sdg.alloy4.ConstList; @@ -56,6 +57,7 @@ import edu.mit.csail.sdg.alloy4.SafeList; import edu.mit.csail.sdg.alloy4.Util; import edu.mit.csail.sdg.alloy4.Version; +import edu.mit.csail.sdg.ast.Assert; import edu.mit.csail.sdg.ast.Attr; import edu.mit.csail.sdg.ast.Browsable; import edu.mit.csail.sdg.ast.Clause; @@ -76,6 +78,7 @@ import edu.mit.csail.sdg.ast.ExprList; import edu.mit.csail.sdg.ast.ExprQt; import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.ExprUnary.Op; import edu.mit.csail.sdg.ast.ExprVar; import edu.mit.csail.sdg.ast.Func; import edu.mit.csail.sdg.ast.Module; @@ -114,7 +117,7 @@ * variable argument is passed */ -public final class CompModule extends Browsable implements Module { +public class CompModule extends Browsable implements Module { // These fields are shared by all Modules that point to each other @@ -191,7 +194,7 @@ public String path() { * The position of the "MODULE" line at the top of the file; Pos.UNKNOWN if the * line has not been parsed from the file yet. */ - private Pos modulePos = Pos.UNKNOWN; + public Pos modulePos = Pos.UNKNOWN; /** * The text of the "MODULE" line at the top of the file; "unknown" if the line @@ -202,7 +205,7 @@ public String path() { /** * Whether we have seen a name containing a dollar sign or not. */ - boolean seenDollar = false; + public boolean seenDollar = false; /** * Each param is mapped to its corresponding Sig (or null if we have not @@ -222,7 +225,7 @@ public String path() { private final Map opens = new LinkedHashMap(); /** Each sig name is mapped to its corresponding SigAST. */ - private final Map sigs = new LinkedHashMap(); + public final Map sigs = new LinkedHashMap(); /** * The list of params in this module whose scope shall be deemed "exact" @@ -232,7 +235,7 @@ public String path() { /** * The current name resolution mode (0=pure) (1=Alloy 4.1.3 and older) (2=new) */ - int resolution = 1; + public int resolution = 1; /** * Each func name is mapped to a nonempty list of FunAST objects. @@ -243,7 +246,7 @@ public String path() { private final Map macros = new LinkedHashMap(); /** Each assertion name is mapped to its Expr. */ - private final Map asserts = new LinkedHashMap(); + private final Map asserts = new LinkedHashMap(); /** * The list of facts; each fact is either an untypechecked Exp or a typechecked @@ -384,7 +387,7 @@ public Expr resolve(final Pos pos, final String name) { match = rootmodule.globals.get(name); if (match != null) { if (match instanceof Macro) - return ((Macro) match).changePos(pos); + return (match);//.changePos(pos); match = ExprUnary.Op.NOOP.make(pos, match); return ExprChoice.make(isIntsNotUsed, pos, asList(match), asList(name)); } @@ -486,9 +489,14 @@ public Expr visit(ExprITE x) throws Err { public Expr visit(ExprBadJoin x) throws Err { Expr left = visitThis(x.left); Expr right = visitThis(x.right); + Expr rightInner = ignoreNoops(right); // If it's a macro invocation, instantiate it - if (right instanceof Macro) - return ((Macro) right).addArg(left).instantiate(this, warns); + if (rightInner instanceof Macro){ + Expr instantiated = ((Macro) rightInner).addArg(left).instantiate(this, warns); + Expr res = ExprUnary.Op.NOOP.make(right.pos, instantiated); + res.setReferenced(right.referenced()); + return res; + } // check to see if it is the special builtin function "Int[]" if (left.type().is_int() && right.isSame(Sig.SIGINT)) return left; // [AM] .cast2sigint(); @@ -499,6 +507,15 @@ public Expr visit(ExprBadJoin x) throws Err { return process(x.pos, x.closingBracket, right.pos, ((ExprChoice) right).choices, ((ExprChoice) right).reasons, left); } + public static Expr ignoreNoops(Expr e){ + if (e instanceof ExprUnary){ + ExprUnary eu = (ExprUnary) e; + if( eu.op == Op.NOOP){ + return ignoreNoops(eu.sub); + } + } + return e; + } /** {@inheritDoc} */ @Override public Expr visit(ExprBinary x) throws Err { @@ -506,8 +523,13 @@ public Expr visit(ExprBinary x) throws Err { Expr right = visitThis(x.right); if (x.op == ExprBinary.Op.JOIN) { // If it's a macro invocation, instantiate it - if (right instanceof Macro) - return ((Macro) right).addArg(left).instantiate(this, warns); + Expr rightInner = ignoreNoops(right); + if (rightInner instanceof Macro){ + Expr instantiated = ((Macro) rightInner).addArg(left).instantiate(this, warns); + Expr res = ExprUnary.Op.NOOP.make(right.pos, instantiated); + res.setReferenced(right.referenced()); + return res; + } // check to see if it is the special builtin function "Int[]" if (left.type().is_int() && right.isSame(Sig.SIGINT)) return left; // [AM] .cast2sigint(); @@ -632,20 +654,9 @@ public Expr visit(ExprVar x) throws Err { if (obj instanceof Macro) { Macro macro = ((Macro) obj).copy(); Expr instantiated = macro.instantiate(this, warns); - instantiated.setReferenced(new Clause() { - - @Override - public Pos pos() { - return instantiated.pos; - } - - @Override - public String explain() { - return instantiated.toString(); - } - - }); - return instantiated; + Expr res = ExprUnary.Op.NOOP.make(x.pos, instantiated); + res.setReferenced(new Clause.Custom(macro.pos, macro.toString())); + return res; } else return obj; } @@ -674,6 +685,21 @@ public Expr visit(Sig x) { return x; } + @Override + public Expr visit(Func x) throws Err { + return x; + } + + @Override + public Expr visit(Assert x) throws Err { + return x; + } + + @Override + public Expr visit(Macro x) throws Err { + return x; + } + /** {@inheritDoc} */ @Override public Expr visit(Field x) { @@ -745,7 +771,7 @@ private Open(Pos pos, boolean isPrivate, String alias, ConstList args, S /** * Connect this OPEN statement to a module that it points to. */ - void connect(CompModule realModule) throws Err { + public void connect(CompModule realModule) throws Err { if (this.realModule != null && this.realModule != realModule) throw new ErrorFatal("Internal error (import mismatch)"); this.realModule = realModule; @@ -788,7 +814,7 @@ public String explain() { * @param filename - the filename corresponding to this module * @param path - one of the path pointing to this module */ - CompModule(CompModule world, String filename, String path) throws Err { + public CompModule(CompModule world, String filename, String path) throws Err { if (world == null) { if (path.length() > 0) throw new ErrorFatal("Root module misparsed by parser."); @@ -890,9 +916,9 @@ public String getHTML() { } if (asserts.size() > 0) { x = new ArrayList(asserts.size()); - for (Map.Entry e : asserts.entrySet()) { - Pos sp = e.getValue().span(); - x.add(make(sp, sp, "assert " + e.getKey(), e.getValue())); + for (Map.Entry e : asserts.entrySet()) { + Pos sp = e.getValue().expr.span(); + x.add(make(sp, sp, "assert " + e.getKey(), e.getValue().expr)); } ans.add(make("" + x.size() + (x.size() > 1 ? " asserts" : " assert"), x)); } @@ -925,7 +951,7 @@ private static String base(Sig sig) { /** * Generate an error message saying the given keyword is no longer supported. */ - static ErrorSyntax hint(Pos pos, String name) { + public static ErrorSyntax hint(Pos pos, String name) { String msg = "The name \"" + name + "\" cannot be found."; if ("exh".equals(name) || "exhaustive".equals(name) || "part".equals(name) || "partition".equals(name)) msg = msg + " If you are migrating from Alloy 3, please see Help->QuickGuide on how to translate models that use the \"" + name + "\" keyword."; @@ -933,7 +959,7 @@ static ErrorSyntax hint(Pos pos, String name) { } /** - * Parse one expression by starting fromt this module as the root module. + * Parse one expression by starting from this module as the root module. */ @Override public Expr parseOneExpressionFromString(String input) throws Err, FileNotFoundException, IOException { @@ -993,7 +1019,7 @@ private Object unique(Pos pos, String name, List objs) throws Err { } else if (x instanceof Func) { Func y = (Func) x; msg.append(y.isPred ? "pred " : "fun ").append(y.label).append("\n" + "at ").append(y.pos.toShortString()); - } else if (x instanceof Expr) { + } else if (x instanceof Assert) { Expr y = (Expr) x; msg.append("assertion at ").append(y.pos.toShortString()); } @@ -1095,7 +1121,7 @@ private List getRawNQS(CompModule start, final int r, String name) { ans.add(x); } if ((r & 2) != 0) { - Expr x = m.asserts.get(name); + Assert x = m.asserts.get(name); if (x != null) ans.add(x); } @@ -1130,7 +1156,7 @@ private List getRawQS(final int r, String name) { ans.add(x); } if ((r & 2) != 0) { - Expr x = u.asserts.get(name); + Assert x = u.asserts.get(name); if (x != null) ans.add(x); } @@ -1226,7 +1252,7 @@ public ConstList getOpens() { } /** Add the "MODULE" declaration. */ - void addModelName(Pos pos, String moduleName, List list) throws Err { + public void addModelName(Pos pos, String moduleName, List list) throws Err { if (status > 0) throw new ErrorSyntax(pos, "The \"module\" declaration must occur at the top,\n" + "and can occur at most once."); this.moduleName = moduleName; @@ -1241,7 +1267,7 @@ void addModelName(Pos pos, String moduleName, List list) throws Err { String name = expr.label; dup(expr.span(), name, true); if (path.length() == 0) { - Sig newSig = addSig(name, null, null, null, null, WHERE.make(expr.span())); + Sig newSig = addSig(null, name, null, null, null, null, WHERE.make(expr.span())); if (nextIsExact) exactSigs.add(newSig); } else { @@ -1256,7 +1282,7 @@ void addModelName(Pos pos, String moduleName, List list) throws Err { } /** Add util/sequniv to the list of declarations. */ - void addSeq(Pos pos) throws Err { + public void addSeq(Pos pos) throws Err { int oldStatus = status; status = 0; try { @@ -1267,7 +1293,7 @@ void addSeq(Pos pos) throws Err { } /** Add an OPEN declaration. */ - void addOpen(Pos pos, Pos isPrivate, ExprVar name, List args, ExprVar alias) throws Err { + public void addOpen(Pos pos, Pos isPrivate, ExprVar name, List args, ExprVar alias) throws Err { if (status > 2) throw new ErrorSyntax(pos, "The \"open\" declaration must occur before any\n" + "sig/pred/fun/fact/assert/check/run command."); String as = (alias == null ? "" : alias.label); @@ -1304,7 +1330,7 @@ void addOpen(Pos pos, Pos isPrivate, ExprVar name, List args, ExprVar a if (arg.label.length() == 0) throw new ErrorSyntax(arg.span(), "Argument cannot be empty."); if (arg.label.indexOf('@') >= 0) - throw new ErrorSyntax(arg.span(), "Argument cannot contain the \'@\' chracter."); + throw new ErrorSyntax(arg.span(), "Argument cannot contain the \'@\' character."); newlist.add(arg.label); } Open x = opens.get(as); @@ -1321,8 +1347,8 @@ void addOpen(Pos pos, Pos isPrivate, ExprVar name, List args, ExprVar a opens.put(as, x); } - /** Do any post-parsing processig. */ - void doneParsing() { + /** Do any post-parsing processing. */ + public void doneParsing() { status = 3; LinkedHashMap copy = new LinkedHashMap(opens); opens.clear(); @@ -1443,11 +1469,12 @@ private static void resolveModules(A4Reporter rep, List modules) { // ============================================================================================================================// /** Add a sig declaration. */ - void addGhostSig() throws Err { + public void addGhostSig() throws Err { sigs.put(Sig.GHOST.label, Sig.GHOST); } - Sig addSig(String name, ExprVar par, List parents, List fields, Expr fact, Attr... attributes) throws Err { + public Sig addSig(Pos namePos, String name, ExprVar par, List parents, List fields, Expr fact, Attr... attributes) throws Err { + Sig obj; Pos pos = Pos.UNKNOWN.merge(WHERE.find(attributes)); status = 3; @@ -1469,14 +1496,15 @@ Sig addSig(String name, ExprVar par, List parents, List fields, E if (subset != null) { attributes = Util.append(attributes, SUBSET.makenull(subset)); List newParents = new ArrayList(parents == null ? 0 : parents.size()); - if (parents != null) - for (ExprVar p : parents) - newParents.add(new PrimSig(p.label, WHERE.make(p.pos))); - obj = new SubsetSig(full, newParents, attributes); + if (parents == null) parents = Arrays.asList(); + for (ExprVar p : parents) + newParents.add(new PrimSig(p.label, WHERE.make(p.pos))); + obj = new SubsetSig(namePos, full, parents.stream().map(p -> p.pos).collect(Collectors.toList()), newParents, attributes); } else { attributes = Util.append(attributes, SUBSIG.makenull(subsig)); PrimSig newParent = (parents != null && parents.size() > 0) ? (new PrimSig(parents.get(0).label, WHERE.make(parents.get(0).pos))) : UNIV; - obj = new PrimSig(full, newParent, attributes); + Pos parentPos = (parents != null && parents.size() > 0) ? parents.get(0).pos : Pos.UNKNOWN; + obj = new PrimSig(namePos, full, parentPos, newParent, attributes); } sigs.put(name, obj); old2fields.put(obj, fields); @@ -1485,15 +1513,15 @@ Sig addSig(String name, ExprVar par, List parents, List fields, E } /** Add an enumeration. */ - void addEnum(Pos pos, Pos priv, ExprVar name, List atoms, Pos closingBracket) throws Err { + public void addEnum(Pos pos, Pos priv, ExprVar name, List atoms, Pos closingBracket) throws Err { ExprVar EXTENDS = ExprVar.make(null, "extends"); ExprVar THIS = ExprVar.make(null, "this/" + name); List THESE = Arrays.asList(THIS); if (atoms == null || atoms.size() == 0) throw new ErrorSyntax(pos, "Enumeration must contain at least one name."); - addSig(name.label, null, null, null, null, WHERE.make(name.pos), ABSTRACT.make(name.pos), PRIVATE.makenull(priv), Attr.ENUM); + addSig(null, name.label, null, null, null, null, WHERE.make(name.pos), ABSTRACT.make(name.pos), PRIVATE.makenull(priv), Attr.ENUM); for (ExprVar a : atoms) - addSig(a.label, EXTENDS, THESE, null, null, WHERE.make(a.pos), ONE.make(a.pos), PRIVATE.makenull(priv)); + addSig(null, a.label, EXTENDS, THESE, null, null, WHERE.make(a.pos), ONE.make(a.pos), PRIVATE.makenull(priv)); int oldStatus = status; status = 0; try { @@ -1520,18 +1548,20 @@ private static Sig resolveSig(CompModule res, Set topo, Sig oldS, final throw new ErrorType(pos, "Sig " + oldS + " is involved in a cyclic inheritance."); if (oldS instanceof SubsetSig) { List parents = new ArrayList(); - for (Sig n : ((SubsetSig) oldS).parents) { + SubsetSig oldSS = (SubsetSig) oldS; + for (Sig n : oldSS.parents) { Sig parentAST = u.getRawSIG(n.pos, n.label); if (parentAST == null) throw new ErrorSyntax(n.pos, "The sig \"" + n.label + "\" cannot be found."); parents.add(resolveSig(res, topo, parentAST, warns)); } - realSig = new SubsetSig(fullname, parents, oldS.attributes.toArray(new Attr[0])); + realSig = new SubsetSig(oldSS.pos, fullname, oldSS.parentRefPoss, parents, oldS.attributes.toArray(new Attr[0])); for (Sig n : parents) if (n != UNIV && n.isVariable != null && realSig.isVariable == null) warns.add(new ErrorWarning(realSig.isSubset, "Part of " + n.label + " is static.\n" + "Sig " + realSig.label + " is static but " + n.label + " is variable.")); } else { - Sig sup = ((PrimSig) oldS).parent; + PrimSig oldSP = (PrimSig) oldS; + Sig sup = oldSP.parent; Sig parentAST = u.getRawSIG(sup.pos, sup.label); if (parentAST == null) throw new ErrorSyntax(sup.pos, "The sig \"" + sup.label + "\" cannot be found."); @@ -1539,7 +1569,7 @@ private static Sig resolveSig(CompModule res, Set topo, Sig oldS, final if (!(parent instanceof PrimSig)) throw new ErrorSyntax(sup.pos, "Cannot extend the subset signature \"" + parent + "\".\n" + "A signature can only extend a toplevel signature or a subsignature."); PrimSig p = (PrimSig) parent; - realSig = new PrimSig(fullname, p, oldS.attributes.toArray(new Attr[0])); + realSig = new PrimSig(oldSP.labelPos, fullname, oldSP.parentRefPos, p, oldS.attributes.toArray(new Attr[0])); if (parent != UNIV && parent.isVariable != null && realSig.isVariable == null) warns.add(new ErrorWarning(realSig.isSubsig, "Part of " + parent.label + " is static.\n" + "Sig " + realSig.label + " is static but " + parent.label + " is variable.")); if (parent != UNIV && parent.isVariable == null && realSig.isVariable != null) @@ -1573,26 +1603,30 @@ public SafeList getAllSigs() { // ============================================================================================================================// /** Add a MACRO declaration. */ - void addMacro(Pos p, Pos isPrivate, String n, List decls, Expr v) throws Err { + public void addMacro(Pos p, Pos isPrivate, Pos labelPos, String label, List decls, Expr v) throws Err { if (!Version.experimental) throw new ErrorSyntax(p, "LET declaration is allowed only inside a toplevel paragraph."); ConstList ds = ConstList.make(decls); status = 3; - dup(p, n, false); + dup(p, label, false); for (int i = 0; i < ds.size(); i++) for (int j = i + 1; j < ds.size(); j++) if (ds.get(i).label.equals(ds.get(j).label)) throw new ErrorSyntax(ds.get(j).span(), "The parameter name \"" + ds.get(j).label + "\" cannot appear more than once."); - Macro ans = new Macro(p, isPrivate, this, n, ds, v); - Macro old = macros.put(n, ans); + Macro ans = new Macro(p, isPrivate, this, labelPos, label, ds, v); + Macro old = macros.put(label, ans); if (old != null) { - macros.put(n, old); - throw new ErrorSyntax(p, "You cannot declare more than one macro with the same name \"" + n + "\" in the same file."); + macros.put(label, old); + throw new ErrorSyntax(p, "You cannot declare more than one macro with the same name \"" + label + "\" in the same file."); } } + public SafeList getAllMacros() { + return new SafeList(macros.values()); + } + /** Add a FUN or PRED declaration. */ - void addFunc(Pos p, Pos isPrivate, String n, Expr f, List decls, Expr t, Expr v) throws Err { + public void addFunc(Pos p, Pos isPrivate, ExprVar n, Expr f, List decls, Expr t, Expr v) throws Err { if (decls == null) decls = new ArrayList(); else @@ -1610,15 +1644,15 @@ void addFunc(Pos p, Pos isPrivate, String n, Expr f, List decls, Expr t, E } } status = 3; - dup(p, n, false); + dup(p, n.label, false); ExprHasName dup = Decl.findDuplicateName(decls); if (dup != null) throw new ErrorSyntax(dup.span(), "The parameter name \"" + dup.label + "\" cannot appear more than once."); - Func ans = new Func(p, isPrivate, n, decls, t, v); - ArrayList list = funcs.get(n); + Func ans = new Func(p, isPrivate, n.pos, n.label, decls, t, v); + ArrayList list = funcs.get(n.label); if (list == null) { list = new ArrayList(); - funcs.put(n, list); + funcs.put(n.label, list); } list.add(ans); } @@ -1663,7 +1697,7 @@ private JoinableList resolveFuncDecls(A4Reporter rep, JoinableList err if (err) continue; try { - f = new Func(f.pos, f.isPrivate, fullname, tmpdecls.makeConst(), ret, f.getBody()); + f = new Func(f.pos, f.isPrivate, f.labelPos, fullname, tmpdecls.makeConst(), ret, f.getBody()); list.set(listi, f); rep.typecheck("" + f + ", RETURN: " + f.returnDecl.type() + "\n"); } catch (Err ex) { @@ -1727,12 +1761,12 @@ public SafeList getAllFunc() { // ============================================================================================================================// /** Add an ASSERT declaration. */ - String addAssertion(Pos pos, String name, Expr value) throws Err { + public String addAssertion(Pos pos, Pos labelPos, String name, Expr value) throws Err { status = 3; if (name == null || name.length() == 0) name = "assert$" + (1 + asserts.size()); dup(pos, name, false); - Expr old = asserts.put(name, ExprUnary.Op.NOOP.make(value.span().merge(pos), value)); + Assert old = asserts.put(name, new Assert(pos.merge(value.span()), labelPos, name, ExprUnary.Op.NOOP.make(value.span(), value))); if (old != null) { asserts.put(name, old); throw new ErrorSyntax(pos, "\"" + name + "\" is already the name of an assertion in this module."); @@ -1746,11 +1780,12 @@ String addAssertion(Pos pos, String name, Expr value) throws Err { */ private JoinableList resolveAssertions(A4Reporter rep, JoinableList errors, List warns) throws Err { Context cx = new Context(this, warns); - for (Map.Entry e : asserts.entrySet()) { - Expr expr = e.getValue(); + for (Map.Entry e : asserts.entrySet()) { + Assert _assert = e.getValue(); + Expr expr = _assert.expr; expr = cx.check(expr).resolve_as_formula(warns); if (expr.errors.isEmpty()) { - e.setValue(expr); + e.setValue(new Assert(_assert.pos, _assert.labelPos, _assert.label, expr)); rep.typecheck("Assertion " + e.getKey() + ": " + expr.type() + "\n"); } else errors = errors.make(expr.errors); @@ -1762,10 +1797,10 @@ private JoinableList resolveAssertions(A4Reporter rep, JoinableList er * Return an unmodifiable list of all assertions in this module. */ @Override - public ConstList> getAllAssertions() { - TempList> ans = new TempList>(asserts.size()); - for (Map.Entry e : asserts.entrySet()) { - ans.add(new Pair(e.getKey(), e.getValue())); + public ConstList getAllAssertions() { + TempList ans = new TempList(asserts.size()); + for (Assert a : asserts.values()) { + ans.add(a); } return ans.makeConst(); } @@ -1773,7 +1808,7 @@ public ConstList> getAllAssertions() { // ============================================================================================================================// /** Add a FACT declaration. */ - void addFact(Pos pos, String name, Expr value) throws Err { + public void addFact(Pos pos, String name, Expr value) throws Err { status = 3; if (name == null || name.length() == 0) name = "fact$" + (1 + facts.size()); @@ -1851,7 +1886,8 @@ public Expr getAllReachableFacts() { // ============================================================================================================================// /** Add a COMMAND declaration. */ - void addCommand(boolean followUp, Pos pos, ExprVar name, boolean check, int overall, int bitwidth, int seq, int tmn, int tmx, int exp, List scopes, ExprVar label) throws Err { + public void addCommand(boolean followUp, Pos pos, ExprVar name, ExprVar commandKeyword, int overall, int bitwidth, int seq, int tmn, int tmx, int exp, List scopes, ExprVar label) throws Err { + boolean check = commandKeyword.label.equals("c"); if (followUp && !Version.experimental) throw new ErrorSyntax(pos, "Syntax error encountering => symbol."); if (label != null) @@ -1863,7 +1899,7 @@ void addCommand(boolean followUp, Pos pos, ExprVar name, boolean check, int over throw new ErrorSyntax(pos, "Predicate/assertion name cannot contain \'@\'"); String labelName = (label == null || label.label.length() == 0) ? name.label : label.label; Command parent = followUp ? commands.get(commands.size() - 1) : null; - Command newcommand = new Command(pos, name, labelName, check, overall, bitwidth, seq, tmn, tmx, exp, scopes, null, name, parent); + Command newcommand = new Command(pos, name, labelName, check, overall, bitwidth, seq, tmn, tmx, exp, scopes, null, commandKeyword, name, parent); if (parent != null) commands.set(commands.size() - 1, newcommand); else @@ -1871,8 +1907,8 @@ void addCommand(boolean followUp, Pos pos, ExprVar name, boolean check, int over } /** Add a COMMAND declaration. */ - void addCommand(boolean followUp, Pos pos, Expr e, boolean check, int overall, int bitwidth, int seq, int tmn, int tmx, int expects, List scopes, ExprVar label) throws Err { - + public void addCommand(boolean followUp, Pos pos, Expr e, ExprVar commandKeyword, int overall, int bitwidth, int seq, int tmn, int tmx, int expects, List scopes, ExprVar label) throws Err { + boolean check = commandKeyword.label.equals("c"); if (followUp && !Version.experimental) throw new ErrorSyntax(pos, "Syntax error encountering => symbol."); @@ -1882,12 +1918,12 @@ void addCommand(boolean followUp, Pos pos, Expr e, boolean check, int overall, i status = 3; String n; if (check) - n = addAssertion(pos, "check$" + (1 + commands.size()), e); + n = addAssertion(pos, null, "check$" + (1 + commands.size()), e); else - addFunc(e.span().merge(pos), Pos.UNKNOWN, n = "run$" + (1 + commands.size()), null, new ArrayList(), null, e); + addFunc(e.span().merge(pos), Pos.UNKNOWN, ExprVar.make( Pos.UNKNOWN, n = "run$" + (1 + commands.size())), null, new ArrayList(), null, e); String labelName = (label == null || label.label.length() == 0) ? n : label.label; Command parent = followUp ? commands.get(commands.size() - 1) : null; - Command newcommand = new Command(e.span().merge(pos), e, labelName, check, overall, bitwidth, seq, tmn, tmx, expects, scopes, null, ExprVar.make(null, n), parent); + Command newcommand = new Command(e.span().merge(pos), e, labelName, check, overall, bitwidth, seq, tmn, tmx, expects, scopes, null, commandKeyword, ExprVar.make(null, n), parent); if (parent != null) commands.set(commands.size() - 1, newcommand); else @@ -1896,8 +1932,9 @@ void addCommand(boolean followUp, Pos pos, Expr e, boolean check, int overall, i public void addDefaultCommand() { if (commands.isEmpty()) { - addFunc(Pos.UNKNOWN, Pos.UNKNOWN, "$$Default", null, new ArrayList(), null, ExprConstant.TRUE); - commands.add(new Command(Pos.UNKNOWN, ExprConstant.TRUE, "Default", false, 4, 4, 4, -1, -1, 1, null, null, ExprVar.make(null, "$$Default"), null)); + addFunc(Pos.UNKNOWN, Pos.UNKNOWN, ExprVar.make(Pos.UNKNOWN, "$$Default"), null, new ArrayList(), null, ExprConstant.TRUE); + ExprVar check = ExprVar.make(Pos.UNKNOWN, "check"); + commands.add(new Command(Pos.UNKNOWN, ExprConstant.TRUE, "Default", false, 4, 4, 4, -1, -1, 1, null, null, check, ExprVar.make(null, "$$Default"), null)); } } @@ -1917,7 +1954,14 @@ private Command resolveCommand(Command cmd, ConstList exactSigs, Expr globa if (m.size() < 1) throw new ErrorSyntax(cmd.pos, "The assertion \"" + cname + "\" cannot be found."); - Expr expr = (Expr) (m.get(0)); + Expr expr; + if (m.get(0) instanceof Assert){ + Assert _assert = (Assert) m.get(0); + expr = _assert.expr; + declaringClause = _assert; + }else{ + expr = (Expr) m.get(0); + } e = expr.not(); } else { List m = getRawQS(4, cname); // We prefer fun/pred in the @@ -1947,13 +1991,13 @@ private Command resolveCommand(Command cmd, ConstList exactSigs, Expr globa throw new ErrorSyntax(cmd.pos, "Mutable sig " + et.sig + " is not top-level thus cannot have scopes assigned."); if (et.isExact && s.isVariable != null) throw new ErrorSyntax(cmd.pos, "Sig " + et.sig + " is variable thus scope cannot be exact."); - sc.add(new CommandScope(null, s, et.isExact, et.startingScope, et.endingScope, et.increment)); + sc.add(new CommandScope(et.pos, et.sigPos, s, et.isExact, et.startingScope, et.endingScope, et.increment)); } if (cmd.nameExpr != null) { cmd.nameExpr.setReferenced(declaringClause); } - return new Command(cmd.pos, cmd.nameExpr, cmd.label, cmd.check, cmd.overall, cmd.bitwidth, cmd.maxseq, cmd.minprefix, cmd.maxprefix, cmd.expects, sc.makeConst(), exactSigs, globalFacts.and(e), parent); + return new Command(cmd.pos, cmd.nameExpr, cmd.label, cmd.check, cmd.overall, cmd.bitwidth, cmd.maxseq, cmd.minprefix, cmd.maxprefix, cmd.expects, sc.makeConst(), exactSigs, cmd.commandKeyword, globalFacts.and(e), parent); } @@ -2024,10 +2068,10 @@ private static void resolveFieldDecl(CompModule res, final A4Reporter rep, final cx.put("this", s.decl.get()); Expr bound = cx.check(d.expr).resolve_as_set(warns); cx.remove("this"); - String[] names = new String[d.names.size()]; - for (int i = 0; i < names.length; i++) - names[i] = d.names.get(i).label; - Field[] fields = s.addTrickyField(d.span(), d.isPrivate, d.disjoint, d.disjoint2, null, d.isVar, names, bound); + // String[] names = new String[d.names.size()]; + // for (int i = 0; i < names.length; i++) + // names[i] = d.names.get(i).label; + Field[] fields = s.addTrickyField(d.span(), d.isPrivate, d.disjoint, d.disjoint2, null, d.isVar, d.names, bound); final VisitQuery q = new VisitQuery() { @Override @@ -2039,9 +2083,9 @@ public final Sig visit(Sig x) { } }; Sig qr = q.visitThis(bound); - if (d.isVar == null && qr != null) + if (d.isVar == null && qr != null) warns.add(new ErrorWarning(d.span(), "Static field types with variable bound.\n" + "Field " + d.names.get(0) + " is static but " + qr.label + " is variable.")); - if (d.isVar == null && s.isVariable != null) + if (d.isVar == null && s.isVariable != null) warns.add(new ErrorWarning(d.span(), "Static field inside variable sig.\n" + "Field " + d.names.get(0) + " is static but " + s.label + " is variable.")); for (Field f : fields) { rep.typecheck("Sig " + s + ", Field " + f.label + ": " + f.type() + "\n"); @@ -2088,7 +2132,7 @@ private static void resolveMeta(final CompModule root) throws Err { for (CompModule m : root.allModules) for (Sig s : new ArrayList(m.sigs.values())) if (m != root || (s != root.metaSig && s != root.metaField)) { - PrimSig ka = new PrimSig(s.label + "$", root.metaSig, Attr.ONE, PRIVATE.makenull(s.isPrivate), Attr.META); + PrimSig ka = new PrimSig(Pos.UNKNOWN, s.label + "$", Pos.UNKNOWN, root.metaSig, Attr.ONE, PRIVATE.makenull(s.isPrivate), Attr.META); sig2meta.put(s, ka); ka.addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "value", s); m.new2old.put(ka, ka); @@ -2099,7 +2143,7 @@ private static void resolveMeta(final CompModule root) throws Err { Pos priv = field.isPrivate; if (priv == null) priv = s.isPrivate; - PrimSig kb = new PrimSig(s.label + "$" + field.label, root.metaField, Attr.ONE, PRIVATE.makenull(priv), Attr.META); + PrimSig kb = new PrimSig(Pos.UNKNOWN, s.label + "$" + field.label, Pos.UNKNOWN, root.metaField, Attr.ONE, PRIVATE.makenull(priv), Attr.META); field2meta.put(field, kb); m.new2old.put(kb, kb); m.sigs.put(base(kb), kb); @@ -2155,7 +2199,7 @@ else if (hasMetaField == false) * This method resolves the entire world; NOTE: if it throws an exception, it * may leave the world in an inconsistent state! */ - static CompModule resolveAll(final A4Reporter rep, final CompModule root) throws Err { + public static CompModule resolveAll(final A4Reporter rep, final CompModule root) throws Err { final List warns = new ArrayList(); for (CompModule m : root.getAllReachableModules()) root.allModules.add(m); @@ -2413,6 +2457,14 @@ public T visitExpressions(VisitReturn visitor) { d.expr.accept(visitor); }); s.getFacts().forEach(f -> f.accept(visitor)); + + if(s instanceof SubsetSig){ + SubsetSig ss = (SubsetSig) s; + ss.parentRefs().forEach( p -> p.accept(visitor)); + }else{ + PrimSig ps = (PrimSig) s; + ps.parentRef().accept(visitor); + } }); funcs.values().forEach(funs -> { @@ -2430,6 +2482,7 @@ public T visitExpressions(VisitReturn visitor) { }); asserts.values().forEach(assrt -> { assrt.accept(visitor); + assrt.expr.accept(visitor); }); commands.forEach(cmd -> { if (cmd.nameExpr != null) @@ -2445,13 +2498,81 @@ public T visitExpressions(VisitReturn visitor) { if (open.expressions != null) open.expressions.stream().filter(x -> x != null).forEach(ex -> ex.accept(visitor)); }); + + // macros are not visitable for now ( accept() throws an exception) macros.values().forEach(macro -> { - macro.accept(visitor); + macro.accept(visitor); }); params.values().forEach(x -> x.accept(visitor)); return null; } + interface Action{ void call();} + private void tryIgnore(Action action) {try { action.call();} catch(Exception ex) {}} + + public void visitExpressionsResilient(VisitReturn visitor) { + sigs.values().forEach(s -> { + s.accept(visitor); + s.getFieldDecls().forEach(d -> { + d.names.forEach(x -> tryIgnore(() -> x.accept(visitor))); + tryIgnore( () -> d.expr.accept(visitor)); + }); + s.getFacts().forEach(f -> tryIgnore(() -> f.accept(visitor))); + + if(s instanceof SubsetSig){ + SubsetSig ss = (SubsetSig) s; + ss.parentRefs().forEach( p -> tryIgnore( () -> p.accept(visitor))); + }else { + PrimSig ps = (PrimSig) s; + tryIgnore ( () -> ps.parentRef().accept(visitor)); + } + + }); + + funcs.values().forEach(funs -> { + funs.forEach(fun -> { + + //System.out.println("visiting func " + fun.label + ". label pos: " + fun.labelExpr().pos); + //tryIgnore ( () -> fun.labelExpr().accept(visitor)); + fun.accept(visitor); + fun.getBody().accept(visitor); + fun.decls.forEach(d -> { + tryIgnore( () -> d.expr.accept(visitor)); + d.names.forEach(n -> tryIgnore ( () -> n.accept(visitor))); + }); + tryIgnore( () -> fun.returnDecl.accept(visitor)); + }); + }); + facts.forEach(fact -> { + tryIgnore ( () -> fact.b.accept(visitor)); + }); + asserts.values().forEach(assrt -> { + tryIgnore ( () -> assrt.accept(visitor)); + tryIgnore ( () -> assrt.expr.accept(visitor)); + }); + commands.forEach(cmd -> { + if (cmd.nameExpr != null) + tryIgnore ( () -> cmd.nameExpr.accept(visitor)); + + cmd.additionalExactScopes.forEach(sig -> tryIgnore( () -> sig.accept(visitor))); + tryIgnore( () -> cmd.formula.accept(visitor)); + cmd.scope.forEach(scope -> { + tryIgnore( () -> scope.sigRef().accept(visitor)); + }); + }); + opens.values().forEach(open -> { + if (open.expressions != null) + open.expressions.stream().filter(x -> x != null).forEach(ex -> tryIgnore( () -> ex.accept(visitor))); + }); + + // macros are not visitable for now ( accept() throws an exception) + macros.values().forEach(macro -> { + tryIgnore( () -> macro.accept(visitor)); + }); + params.values().forEach(x -> tryIgnore( () -> x.accept(visitor))); + } + + public Expr find(Pos pos) { if (pos == null) return null; @@ -2463,7 +2584,7 @@ class Holder { } Holder holder = new Holder(); - visitExpressions(new VisitQueryOnce() { + visitExpressionsResilient(new VisitQueryOnce() { @Override public boolean visited(Expr expr) { diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompUtil.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompUtil.java index 65f04d3e1..d068a7db7 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompUtil.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/CompUtil.java @@ -70,7 +70,7 @@ private CompUtil() { // =============================================================================================================// /** - * Go up the directory hierachy 0 or more times.
+ * Go up the directory hierarchy 0 or more times.
* For example, on a UNIX machine, goUp("/home/abc/def",1) will return * "/home/abc"
* For example, on a UNIX machine, goUp("/home/abc/def",2) will return "/home" @@ -498,4 +498,8 @@ static CompModule parse(List seenDollar, Map loaded, Map< module.addDefaultCommand(); return module; } + + public static CompModule nullModule() { + return new CompModule(null, "", ""); + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/Macro.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/Macro.java index 5dc8fa7b1..1f8689ade 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/Macro.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/Macro.java @@ -30,11 +30,12 @@ import edu.mit.csail.sdg.ast.ExprBad; import edu.mit.csail.sdg.ast.ExprCustom; import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.VisitReturn; import edu.mit.csail.sdg.parser.CompModule.Context; /** Immutable; this class represents a macro. */ -final class Macro extends ExprCustom { +public final class Macro extends ExprCustom { /** If nonnull, this is a private macro. */ final Pos isPrivate; @@ -43,7 +44,9 @@ final class Macro extends ExprCustom { private final CompModule realModule; /** The name of the macro. */ - private final String name; + public final String name; + + public final Pos namePos; /** The list of parameters (can be an empty list) */ private final ConstList params; @@ -52,33 +55,34 @@ final class Macro extends ExprCustom { * The list of arguments (can be an empty list) (must be equal or shorter than * this.params) */ - private final ConstList args; + public final ConstList args; /** The macro body. */ - private final Expr body; + public final Expr body; /** Construct a new Macro object. */ - private Macro(Pos pos, Pos isPrivate, CompModule realModule, String name, List params, List args, Expr body) { + private Macro(Pos pos, Pos isPrivate, CompModule realModule, Pos namePos, String name, List params, List args, Expr body) { super(pos, new ErrorFatal(pos, "Incomplete call on the macro \"" + name + "\"")); this.realModule = realModule; this.isPrivate = isPrivate; this.name = name; + this.namePos = namePos; this.params = ConstList.make(params); this.args = ConstList.make(args); this.body = body; } /** Construct a new Macro object. */ - Macro(Pos pos, Pos isPrivate, CompModule realModule, String name, List params, Expr body) { - this(pos, isPrivate, realModule, name, params, null, body); + Macro(Pos pos, Pos isPrivate, CompModule realModule, Pos namePos, String name, List params, Expr body) { + this(pos, isPrivate, realModule, namePos, name, params, null, body); } Macro addArg(Expr arg) { - return new Macro(pos, isPrivate, realModule, name, params, Util.append(args, arg), body); + return new Macro(pos, isPrivate, realModule, namePos, name, params, Util.append(args, arg), body); } Expr changePos(Pos pos) { - return new Macro(pos, isPrivate, realModule, name, params, args, body); + return new Macro(pos, isPrivate, realModule, namePos, name, params, args, body); } /** @@ -132,7 +136,16 @@ public int getDepth() { /** {@inheritDoc} */ @Override public String toString() { - return name; + StringBuilder sb = new StringBuilder(); + sb.append(name); + if (! this.params.isEmpty()){ + sb.append("["); + sb.append( String.join(", ", this.params.stream().map(p -> p.label).toArray(String[]::new)) ); + sb.append("]"); + } + sb.append(" = "); + sb.append(this.body.toString()); + return sb.toString(); } /** {@inheritDoc} */ @@ -148,7 +161,12 @@ public String getHTML() { } public Macro copy() { - return new Macro(pos, isPrivate, realModule, name, params, args, body); + return new Macro(pos, isPrivate, realModule, namePos, name, params, args, body); } + + @Override + public T accept(VisitReturn visitor) throws Err { + return visitor.visit(this); + } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/MarkdownHandler.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/MarkdownHandler.java index a25f751b4..02ffc92ad 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/MarkdownHandler.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/MarkdownHandler.java @@ -78,7 +78,7 @@ public static String strip(String content) { while ((line = br.readLine()) != null) { state = state.process(line, yaml, alloy); if (state == null) - return content; + return ""; } } return alloy.toString(); diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/sim/SimInstance.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/sim/SimInstance.java index 407e6b710..66b87bbae 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/sim/SimInstance.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/sim/SimInstance.java @@ -37,6 +37,7 @@ import edu.mit.csail.sdg.alloy4.ErrorType; import edu.mit.csail.sdg.alloy4.Pair; import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.ast.Assert; import edu.mit.csail.sdg.ast.Decl; import edu.mit.csail.sdg.ast.Expr; import edu.mit.csail.sdg.ast.ExprBinary; @@ -56,6 +57,7 @@ import edu.mit.csail.sdg.ast.Sig.PrimSig; import edu.mit.csail.sdg.ast.Sig.SubsetSig; import edu.mit.csail.sdg.ast.VisitReturn; +import edu.mit.csail.sdg.parser.Macro; /** Mutable; represents an instance. */ @@ -520,7 +522,7 @@ private int trunc(int i) { } /** - * Convenience method that evalutes x and casts the result to be a boolean. + * Convenience method that evaluates x and casts the result to be a boolean. * * @return the boolean - if x evaluates to a boolean * @throws ErrorFatal - if x does not evaluate to a boolean @@ -535,7 +537,7 @@ public boolean cform(Expr x) throws Err { } /** - * Convenience method that evalutes x and cast the result to be a int. + * Convenience method that evaluates x and cast the result to be a int. * * @return the int - if x evaluates to an int * @throws ErrorFatal - if x does not evaluate to an int @@ -552,7 +554,7 @@ public int cint(Expr x) throws Err { } /** - * Convenience method that evalutes x and cast the result to be a tupleset + * Convenience method that evaluates x and cast the result to be a tupleset * * @return the tupleset - if x evaluates to a tupleset * @throws ErrorFatal - if x does not evaluate to a tupleset @@ -912,6 +914,21 @@ public SimTupleset visit(Sig x) throws Err { throw new ErrorFatal("Unknown sig " + x + " encountered during evaluation."); } + @Override + public Object visit(Func x) throws Err { + return null; + } + + @Override + public Object visit(Assert x) throws Err { + return null; + } + + @Override + public Object visit(Macro x) throws Err { + return null; + } + /** {@inheritDoc} */ @Override public SimTupleset visit(Field x) throws Err { @@ -944,7 +961,7 @@ public SimTupleset visit(Field x) throws Err { } /** - * Helper method for enumerating all possibilties for a + * Helper method for enumerating all possibilities for a * quantification-expression. */ private int enumerate(final TempList store, int sum, final ExprQt x, final Expr body, final int i) throws Err { // if op is ALL NO SOME ONE LONE then it always returns @@ -1324,7 +1341,7 @@ public String validate(Module world) { } return ""; } catch (Err ex) { - return "An internal error has occured:\n" + ex.dump(); + return "An internal error has occurred:\n" + ex.dump(); } } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4Solution.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4Solution.java index 3ca5e1ae0..15df281fd 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4Solution.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4Solution.java @@ -1698,7 +1698,7 @@ public synchronized void solvingCNF(int step, int primaryVars, int vars, int cla inst = new TemporalInstance(Arrays.asList(inst), 0, 1); // To ensure no more output during SolutionEnumeration solver.options().setReporter(oldReporter); - // If unsatisfiable, then retreive the unsat core if desired + // If unsatisfiable, then retrieve the unsat core if desired if (inst == null && solver.options().solver() == SATFactory.MiniSatProver) { try { lCore = new LinkedHashSet(); diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4SolutionReader.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4SolutionReader.java index ce191c022..772230ffe 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4SolutionReader.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4SolutionReader.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -39,6 +40,7 @@ import edu.mit.csail.sdg.alloy4.XMLNode; import edu.mit.csail.sdg.ast.Attr; import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprHasName; import edu.mit.csail.sdg.ast.ExprVar; import edu.mit.csail.sdg.ast.Sig; import edu.mit.csail.sdg.ast.Sig.Field; @@ -217,7 +219,7 @@ private Sig parseSig(String id, int depth) throws IOException, Err { break; } if (ans == null) { - ans = new PrimSig(label, (PrimSig) parent, isAbstract, isLone, isOne, isSome, isPrivate, isMeta, isEnum, isVar); + ans = new PrimSig(null, label, Pos.UNKNOWN, (PrimSig) parent, isAbstract, isLone, isOne, isSome, isPrivate, isMeta, isEnum, isVar); allsigs.add(ans); } } else { @@ -228,7 +230,7 @@ private Sig parseSig(String id, int depth) throws IOException, Err { break; } if (ans == null) { - ans = new SubsetSig(label, parents, isExact, isLone, isOne, isSome, isPrivate, isMeta, isVar); + ans = new SubsetSig(null, label, null, parents, isExact, isLone, isOne, isSome, isPrivate, isMeta, isVar); allsigs.add(ans); } } @@ -302,10 +304,11 @@ private Field parseField(String id) throws IOException, Err { choices.remove(f); break; } - if (field == null) - field = parent.addTrickyField(Pos.UNKNOWN, isPrivate, null, null, isMeta, isVar, new String[] { - label - }, UNIV.join(type))[0]; + if (field == null){ + ExprHasName labelExpr = ExprVar.make(null, label); + field = parent.addTrickyField(Pos.UNKNOWN, isPrivate, null, null, isMeta, isVar, Arrays.asList(labelExpr) + , UNIV.join(type))[0]; + } TupleSet ts = parseTuples(node, arity); expr2ts.put(field, ts); return field; @@ -515,7 +518,7 @@ public static A4Solution read(Iterable sigs, XMLNode xml) throws Err { if (ex instanceof Err) throw ((Err) ex); else - throw new ErrorFatal("Fatal error occured: " + ex, ex); + throw new ErrorFatal("Fatal error occurred: " + ex, ex); } } } diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/ConvToConjunction.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/ConvToConjunction.java index 6ca1362d4..b090d65cf 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/ConvToConjunction.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/ConvToConjunction.java @@ -17,6 +17,7 @@ import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Assert; import edu.mit.csail.sdg.ast.Expr; import edu.mit.csail.sdg.ast.ExprBinary; import edu.mit.csail.sdg.ast.ExprCall; @@ -27,9 +28,11 @@ import edu.mit.csail.sdg.ast.ExprQt; import edu.mit.csail.sdg.ast.ExprUnary; import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Func; import edu.mit.csail.sdg.ast.Sig; import edu.mit.csail.sdg.ast.Sig.Field; import edu.mit.csail.sdg.ast.VisitReturn; +import edu.mit.csail.sdg.parser.Macro; /** * Immutable; this class rearranges the AST to promote as many clauses up to the @@ -122,6 +125,21 @@ public Expr visit(Sig x) { return x; } + @Override + public Expr visit(Func x) throws Err { + return x; + } + + @Override + public Expr visit(Assert x) throws Err { + return x; + } + + @Override + public Expr visit(Macro x) throws Err { + return x; + } + /** {@inheritDoc} */ @Override public Expr visit(Field x) { diff --git a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/TranslateAlloyToKodkod.java b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/TranslateAlloyToKodkod.java index 5f7825f8e..b1cad7bda 100644 --- a/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/TranslateAlloyToKodkod.java +++ b/org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/TranslateAlloyToKodkod.java @@ -36,6 +36,7 @@ import edu.mit.csail.sdg.alloy4.Pair; import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.ast.Assert; import edu.mit.csail.sdg.ast.Command; import edu.mit.csail.sdg.ast.CommandScope; import edu.mit.csail.sdg.ast.Decl; @@ -55,6 +56,7 @@ import edu.mit.csail.sdg.ast.Sig.Field; import edu.mit.csail.sdg.ast.Type; import edu.mit.csail.sdg.ast.VisitReturn; +import edu.mit.csail.sdg.parser.Macro; import kodkod.ast.BinaryExpression; import kodkod.ast.Decls; import kodkod.ast.ExprToIntCast; @@ -658,7 +660,7 @@ public static Object alloy2kodkod(A4Solution sol, Expr expr) throws Err { // ==============================================================================================================// /** - * Convenience method that evalutes x and casts the result to be a Kodkod + * Convenience method that evaluates x and casts the result to be a Kodkod * Formula. * * @return the formula - if x evaluates to a Formula @@ -674,7 +676,7 @@ private Formula cform(Expr x) throws Err { } /** - * Convenience method that evalutes x and cast the result to be a Kodkod + * Convenience method that evaluates x and cast the result to be a Kodkod * IntExpression. * * @return the integer expression - if x evaluates to an IntExpression @@ -821,7 +823,7 @@ public Object visit(ExprConstant x) throws Err { case EMPTYNESS : return Expression.NONE; case IDEN : - return Expression.IDEN.intersection(a2k(UNIV).product(Expression.UNIV)); + return Expression.IDEN.intersection(a2k(UNIV).product(Expression.UNIV)); //this makes bad decompositions, makes static expressions variable case STRING : Expression ans = s2k(x.string); if (ans == null) @@ -890,7 +892,7 @@ public Object visit(ExprUnary x) throws Err { case CAST2INT : return sum(cset(x.sub)); case RCLOSURE : - Expression iden = Expression.IDEN.intersection(a2k(UNIV).product(Expression.UNIV)); + Expression iden = Expression.IDEN.intersection(a2k(UNIV).product(Expression.UNIV)); //this makes bad decompositions, makes static expressions variable return cset(x.sub).closure().union(iden); case CLOSURE : return cset(x.sub).closure(); @@ -950,6 +952,21 @@ public Object visit(Sig x) throws Err { return ans; } + @Override + public Object visit(Func x) throws Err { + return null; + } + + @Override + public Object visit(Assert x) throws Err { + return null; + } + + @Override + public Object visit(Macro x) throws Err { + return null; + } + /* ============================= */ /* Evaluates an ExprCall node. */ /* ============================= */ diff --git a/org.alloytools.alloy.core/src/main/java/java_cup/runtime/lr_parser.java b/org.alloytools.alloy.core/src/main/java/java_cup/runtime/lr_parser.java index 3429b6ee5..7de344de4 100644 --- a/org.alloytools.alloy.core/src/main/java/java_cup/runtime/lr_parser.java +++ b/org.alloytools.alloy.core/src/main/java/java_cup/runtime/lr_parser.java @@ -397,7 +397,7 @@ public void user_init() throws java.lang.Exception {} * Get the next Symbol from the input (supplied by generated subclass). Once end * of file has been reached, all subsequent calls to scan should return an EOF * Symbol (which is Symbol number 0). By default this method returns - * getScanner().next_token(); this implementation can be overriden by the + * getScanner().next_token(); this implementation can be overridden by the * generated parser using the code declared in the "scan with" clause. Do not * recycle objects; every call to scan() should return a fresh object. */ diff --git a/org.alloytools.alloy.core/src/main/java/java_cup/runtime/virtual_parse_stack.java b/org.alloytools.alloy.core/src/main/java/java_cup/runtime/virtual_parse_stack.java index 8dc9fb1e0..0a0b2913c 100644 --- a/org.alloytools.alloy.core/src/main/java/java_cup/runtime/virtual_parse_stack.java +++ b/org.alloytools.alloy.core/src/main/java/java_cup/runtime/virtual_parse_stack.java @@ -91,7 +91,7 @@ protected void get_from_real() { if (real_next >= real_stack.size()) return; - /* get a copy of the first Symbol we have not transfered */ + /* get a copy of the first Symbol we have not transferred */ stack_sym = (Symbol) real_stack.elementAt(real_stack.size() - 1 - real_next); /* record the transfer */ diff --git a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/Alloy.java b/org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/Alloy.java similarity index 71% rename from org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/Alloy.java rename to org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/Alloy.java index 191d56ef8..bb105ce54 100644 --- a/org.alloytools.alloy.application/src/main/java/edu/mit/csail/sdg/alloy4whole/Alloy.java +++ b/org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/Alloy.java @@ -1,4 +1,4 @@ -package edu.mit.csail.sdg.alloy4whole; +package org.alloytools.alloy.core.infra; import java.io.File; import java.io.IOException; @@ -8,6 +8,16 @@ import aQute.lib.io.IO; +/** + * This class is the main class for the JAR. Its name is the name shown in the + * GUI on MacOS, so do not change it. + *

+ * This class is an entry point and should not be renamed. It should also _NOT_ + * touch any other classes. We're creating a special class loader to allow the + * dynamic libraries to be found. If you link this class to any other class + * you're bound to create trouble. + * + */ public class Alloy { static ClassLoader old = Alloy.class.getClassLoader(); @@ -54,8 +64,8 @@ protected String findLibrary(String libname) { public static void main(String args[]) throws Exception { AlloyClassLoader l1 = new AlloyClassLoader(); - Class< ? > simpleGui = l1.loadClass("edu.mit.csail.sdg.alloy4whole.SimpleGUI"); - Method main = simpleGui.getMethod("main", String[].class); + Class< ? > dispatcher = l1.loadClass("org.alloytools.alloy.core.infra.AlloyDispatcher"); + Method main = dispatcher.getMethod("main", String[].class); main.invoke(null, (Object) args); } } diff --git a/org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/AlloyDispatcher.java b/org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/AlloyDispatcher.java new file mode 100644 index 000000000..1f88a806d --- /dev/null +++ b/org.alloytools.alloy.core/src/main/java/org/alloytools/alloy/core/infra/AlloyDispatcher.java @@ -0,0 +1,418 @@ +package org.alloytools.alloy.core.infra; + + +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Arrays; +import java.util.Formatter; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.TreeMap; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.alloytools.alloy.context.api.AlloyContext; +import org.alloytools.alloy.infrastructure.api.AlloyMain; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import aQute.lib.getopt.Arguments; +import aQute.lib.getopt.CommandLine; +import aQute.lib.getopt.Description; +import aQute.lib.getopt.Options; +import aQute.lib.io.IO; +import aQute.lib.justif.Justif; +import aQute.lib.strings.Strings; +import aQute.libg.parameters.Attributes; +import aQute.libg.parameters.ParameterMap; +import aQute.libg.reporter.ReporterAdapter; +import edu.mit.csail.sdg.alloy4.A4Preferences; +import edu.mit.csail.sdg.alloy4.A4Preferences.Pref; +import edu.mit.csail.sdg.translator.A4Options; +import edu.mit.csail.sdg.translator.A4Options.SatSolver; + +/** + * Since the Alloy code is used for many different situations, we do not assume + * we know how the world looks like. This class uses the AlloyMain annotation to + * find any class that can be called from the command line that was added to the + * distribution jar. + * + */ +public class AlloyDispatcher extends ReporterAdapter { + + final static Logger log = LoggerFactory.getLogger(AlloyDispatcher.class); + PrintStream out = System.out; + PrintStream err = System.err; + AlloyContext context; + Optional manifest; + + + + static class MainDef implements AutoCloseable { + + public final String name; + public final Object instance; + public final boolean deflt; + + public MainDef(Object instance, String name, boolean deflt) { + this.instance = instance; + this.name = name; + this.deflt = deflt; + } + + @Override + public String toString() { + return "MainDef [name=" + name + ", instance=" + instance + "]"; + } + + @Override + public void close() throws Exception { + if (instance instanceof AutoCloseable) + IO.close((AutoCloseable) instance); + } + } + + enum Levels { + off, + trace, + debug, + info, + warn, + error; + } + + + + @Description("The Alloy command line" ) + @Arguments( + arg = { + "[sub-cmd]", "..." + } ) + interface BaseOptions extends Options { + + @Description("Activate debugging mode" ) + boolean debug(); + + @Description("Set the default log level: off, trace, debug, info, warn, error. If not set, defaults to error" ) + Levels defaultLevel(Levels deflt); + + @Description("Set per logger log level. The syntax is =, where level is off, trace, debug, info, warn, error" ) + String[] log(); + + @Description("A comma separated string with Alloy preferences. Preference id's (and their values) can be found with the `prefs` sub command. Usually enclosed in quotes to prevent the shell from breaking them up. Preferences are stored persistently." ) + String preferences(); + } + + public static void main(String[] args) { + AlloyDispatcher dispatcher = new AlloyDispatcher(); + CommandLine cl = new CommandLine(dispatcher); + try { + String help = cl.execute(dispatcher, "alloy", Arrays.asList(args)); + if (help != null) { + System.err.println(help); + } + } catch (Exception e) { + dispatcher.exception(e, "invocation failed %s", e.getMessage()); + } + dispatcher.report(System.out); + } + + public void _alloy(BaseOptions options) throws Exception { + if (options.debug()) + System.setProperty("debug", "yes"); + + setslf4j(options.defaultLevel(Levels.error), options.log()); + + CommandLine cl = options._command(); + AlloyContext context = getContext(options); + Map mains = getMains(context, cl); + + doPreferences(options.preferences()); + + try { + + + List arguments = options._arguments(); + + MainDef selected; + if (arguments.isEmpty()) { + selected = mains.entrySet().stream().filter(e -> e.getValue().deflt).map(e -> e.getValue()).findAny().orElse(null); + if (selected == null) { + error("invalid JAR, could not find a main that is the default and no command was given. Main classes found %s", mains); + return; + } + } else { + String _name = arguments.remove(0); + String name = _name.equals("help") ? "_help" : _name; // 'help' is built in but we override it + selected = mains.entrySet().stream().filter(e -> e.getValue().name.equals(name)).map(e -> e.getValue()).findAny().orElse(null); + if (selected == null) { + error("No such command: %s, available commands are %s", name, mains.keySet()); + return; + } + } + + if (!isOk()) { + return; + } + + log.debug("selected main {} is with arguments {}", selected, arguments); + + String execute = cl.execute(selected.instance, selected.name, arguments); + if (execute != null) { + err.println(execute); + } + + } finally { + mains.values().forEach(IO::close); + } + } + + + @Arguments( + arg = {} ) + @Description("Display the current version" ) + interface VersionOptions extends Options { + + @Description("Show the full major.minor.micro.qualifier version, normal it does not print the qualifier" ) + boolean full(); + } + + public void _version(VersionOptions options) { + String version = getVersion(); + if (!options.full()) { + int n = version.lastIndexOf('.'); + if (n > 0) + version = version.substring(0, n); + } + out.println(version); + } + + private AlloyContext getContext(BaseOptions options) { + if (context == null) { + context = new AlloyContext() { + + @Override + public boolean isDebug() { + return options.debug(); + } + }; + } + return context; + } + + + @Description("Show the preferences or modify them" ) + @Arguments( + arg = {} ) + interface PreferencesOptions extends Options { + + @Description("Show the preferences in a comma separated format as used by the alloy `-p` preferences option. You can then copy the output and paste it in the -p option" ) + boolean cli(); + } + + + public void _prefs(PreferencesOptions options) { + if (options.cli()) { + StringBuilder sb = new StringBuilder(); + sb.append("\""); + String del = ""; + for (Pref< ? > pref : A4Preferences.allUserPrefs()) { + sb.append(del).append(pref.id).append("=").append(pref.get()); + del = ","; + } + sb.append("\""); + out.println(sb); + } else { + for (Pref< ? > pref : A4Preferences.allPrefs()) { + out.printf("%-30s %-50s %s%n", pref.id, pref.title, pref.get()); + } + } + } + + + + @Description("Show the list of solvers" ) + @Arguments( + arg = {} ) + interface SolverOptions extends Options { + } + + + public void _solvers(SolverOptions options) { + StringBuilder sb = new StringBuilder(); + for (SatSolver o : A4Options.SatSolver.values()) { + out.printf("%s%n", o); + } + } + + + + @Description("Show help information about the available sub commands" ) + @Arguments( + arg = { + "[sub-cmd]" + } ) + interface HelpOptions extends Options { + + } + + public void __help(HelpOptions options) { + List arguments = options._arguments(); + CommandLine cl = options._command(); + Map mains = getMains(context, cl); + Justif j = new Justif(80); + try (Formatter f = j.formatter()) { + + if (arguments.isEmpty()) { + cl.help(f, this, "alloy"); + f.format("Sub commands are: %s%n", mains.keySet().stream().collect(Collectors.joining(", ")).replace("_help", "help")); + f.format("Do 'help to get more information about a particular sub command%n", mains.keySet().stream().collect(Collectors.joining(", "))); + } else { + for (Map.Entry e : mains.entrySet()) { + String name = e.getKey(); + if (!arguments.contains(name)) + continue; + + MainDef main = e.getValue(); + if (main.deflt) + f.format("[default]"); + cl.help(f, main.instance, name); + } + } + out.println(j.wrap()); + } + } + + + private Map getMains(AlloyContext context, CommandLine cl) { + Map result = new TreeMap<>(); + localCommands(cl, result); + globalCommands(context, result); + return result; + } + + private void globalCommands(AlloyContext context, Map result) { + ParameterMap header = getHeader("Provide-Capability"); + + header.entrySet().stream().filter(e -> e.getKey().startsWith(AlloyMain.NAMESPACE)).forEach(e -> { + try { + Attributes attrs = e.getValue(); + String fqn = attrs.get(AlloyMain.FQN); + if (fqn == null) + throw new RuntimeException("Expected a fqn in the capability " + e); + + Class< ? > mainClass = AlloyDispatcher.class.getClassLoader().loadClass(fqn); + AlloyMain mainAnn = mainClass.getAnnotation(AlloyMain.class); + if (mainAnn != null) { + Object instance = getInstance(context, e, mainClass); + MainDef main = new MainDef(instance, mainAnn.name(), mainAnn.isDefault()); + result.put(main.name, main); + log.debug("found main class {}", main); + } else { + throw new RuntimeException("Main class " + mainClass + " is listed in capability " + e + " but does not have an AlloyMain annotation"); + } + } catch (ClassNotFoundException e1) { + throw new RuntimeException("In capability " + e + ", the fqn cannot be located as class in the current JAR: " + e1); + } + }); + } + + private void localCommands(CommandLine cl, Map result) { + Map commands = cl.getCommands(this); + for (Map.Entry e : commands.entrySet()) { + String cmd = e.getKey(); + if (cmd.equals("alloy")) + continue; + + MainDef md = new MainDef(this, cmd, false); + result.put(cmd, md); + } + } + + private Object getInstance(AlloyContext context, Entry e, Class< ? > mainClass) { + try { + return mainClass.getConstructor(AlloyContext.class).newInstance(context); + } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { + try { + return mainClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e2) { + throw new RuntimeException("Capability " + e + " specifies class " + mainClass + " but that class has no default constructor nor one that takes AlloyContext"); + } + } + } + + final static Pattern PREF_P = Pattern.compile("\\s*(?[^=]+)\\s*(=\\s*(?.*)\\s*)"); + + private void doPreferences(String preferences) { + if (preferences == null) + return; + + for (String pref : Strings.splitQuoted(preferences)) { + Matcher m = PREF_P.matcher(pref); + if (!m.matches()) { + error("cannot match preferences '%s', particularly `%s`", preferences, pref); + } else { + String id = m.group("id"); + String value = m.group("value"); + if (value == null) + value = "true"; + + String result = A4Preferences.set(id, value); + if (result != null) { + error("Setting pref %s failed: %s", id, result); + } + } + } + + } + + private ParameterMap getHeader(String name) { + return getManifest().map(m -> new ParameterMap(m.getMainAttributes().getValue(name))).orElse(new ParameterMap()); + } + + private String getVersion() { + return getManifest().map(m -> m.getMainAttributes().getValue("Bundle-Version")).orElse("0.0.0.unknown"); + } + + private Optional getManifest() { + if (manifest != null) + return manifest; + + try { + URL resource = AlloyDispatcher.class.getResource("/META-INF/MANIFEST.MF"); + if (resource == null) + return Optional.empty(); + + Manifest manifest = new Manifest(resource.openStream()); + return this.manifest = Optional.of(manifest); + } catch (IOException e) { + log.error("No Manifest found {}", e, e); + return Optional.empty(); + } + } + + + static final Pattern TARGET_P = Pattern.compile("\\s*(?[^=]+)\\s*=\\s*(?off|trace|debug|info|warn|error)\\s*"); + + public static void setslf4j(Levels deflt, String... targets) { + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", deflt.toString()); + if (targets != null) + for (String target : targets) { + Matcher m = TARGET_P.matcher(target); + if (m.matches()) { + String key = m.group("name"); + Levels level = Levels.valueOf(m.group("level")); + System.setProperty("org.slf4j.simpleLogger.log." + key, level.toString()); + } else { + System.err.println("invalid slf4j target definition " + target + ", expect " + TARGET_P); + } + } + } +} diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/buffer.als b/org.alloytools.alloy.core/src/main/resources/models/util/buffer.als new file mode 100644 index 000000000..b25c7a87c --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/buffer.als @@ -0,0 +1,68 @@ +module util/buffer[BufIdx, elem] + +open util/ordering[BufIdx] as ord + +/** returns all the elements in this sequence */ +fun elems [R: BufIdx->elem]: set elem { BufIdx.(R) } + +/** returns the first element in the sequence */ +fun firstElem [R: BufIdx->elem]: lone elem { ord/first.R } + +/** returns the last element in the sequence */ +fun lastElem [R: BufIdx->elem]: lone elem { R.at[R.lastIdx] } + +/** true if the sequence is empty */ +pred isEmpty [R: BufIdx -> elem] { no R} + +/** returns last index occupied by this sequence */ +fun lastIdx [R: BufIdx->elem] : lone BufIdx { ord/max[R.elem] } + +/** returns all the indices occupied by this sequence */ +fun inds [R: BufIdx->elem] : set BufIdx { elem.~(R) } + +/** returns element at the given index */ +fun at [R: BufIdx->elem, i: BufIdx]: lone elem { i.(R) } + +/** + * returns the index after the last index + * if this sequence is empty, returns the first index, + * if this sequence is full, returns empty set + */ +fun afterLastIdx [R: BufIdx->elem] : lone BufIdx { + ord/min[BufIdx - R.inds] +} + +/** true if this sequence has duplicates */ +pred hasDups [R: BufIdx->elem] { # elems[R] < # inds[R] } + +/** added is the result of appending e to the end of R */ +pred add [R: BufIdx->elem, R_next: BufIdx->elem, e: elem] { + R_next = R + (R.afterLastIdx -> e) +} + +/** + * Set the first element in R_next + * Copy over the remaning elements from R to R_next +*/ +pred addFirst [R: BufIdx->elem, R_next: BufIdx->elem, e: elem] { + R_next.firstElem = e + some R => { (all i: R.inds - firstIdx | R_next.at[i] = R.at[ord/prev[i]]) and R_next.at[R.afterLastIdx] = R.lastElem } +} + +/** Substract the relation (lastIndex -> lastElem) from the set of relations in R */ +pred remove [R: BufIdx->elem, R_next: BufIdx->elem] { + R_next = R - (lastIdx[R] -> lastElem[R]) +} + +/** + * R_next[index - 1] = R[index] for each index > 0 in R. The first index is not copied since we are removing it + * The lastIndex in R_next is equal to (lastIndex - 1) in R +*/ +pred removeFirst [R: BufIdx->elem, R_next: BufIdx->elem] { + one R.inds => (no R_next.inds) else { + (all i: R.inds - ord/first | R_next.at[ord/prev[i]] = R.at[i]) + lastIdx[R_next] = ord/prev[lastIdx[R]] + } +} + +fun firstIdx: BufIdx { ord/first } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/graph.als b/org.alloytools.alloy.core/src/main/resources/models/util/graph.als index 712dfd14c..52fed9137 100644 --- a/org.alloytools.alloy.core/src/main/resources/models/util/graph.als +++ b/org.alloytools.alloy.core/src/main/resources/models/util/graph.als @@ -1,7 +1,7 @@ module util/graph[node] /* - * Utilities for some common operations and contraints + * Utilities for some common operations and constraints * on graphs. * * author: Greg Dennis diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/ring.als b/org.alloytools.alloy.core/src/main/resources/models/util/ring.als new file mode 100644 index 000000000..857a236f1 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/ring.als @@ -0,0 +1,8 @@ +module util/ring[exactly elem] +open util/ordering[elem] as order + +fun nextRing [ie: elem] : lone elem { + {m: elem | no order/next[ie] implies m = order/first + else m = order/next[ie] + } +} diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/sequniv.als b/org.alloytools.alloy.core/src/main/resources/models/util/sequniv.als index cd2a3cba5..0f91e398e 100644 --- a/org.alloytools.alloy.core/src/main/resources/models/util/sequniv.als +++ b/org.alloytools.alloy.core/src/main/resources/models/util/sequniv.als @@ -131,7 +131,7 @@ fun append [s1, s2: Int -> univ] : s1+s2 { * returns the subsequence of s between from and to, inclusive * Precondition: 0 <= from <= to < #s */ -fun subseq [s: Int -> univ, from, to: Int] : s { - let shift = {i", i: seq/Int | int[i"] = ui/sub[int[i], int[from]] } | +fun subseq [s: Int -> univ, frm, to: Int] : s { + let shift = {i", i: seq/Int | int[i"] = ui/sub[int[i], int[frm]] } | shift.((seq/Int - ui/nexts[to]) <: s) } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmc.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc.als new file mode 100644 index 000000000..a71feb674 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc.als @@ -0,0 +1,94 @@ +/* +/* + * Copyright (c) 2012, Amirhossein Vakili + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module util/tcmc[S] + +//********************KRIPKE STRUCTURE DEF*************************// + +one sig TS{ + S0: some S, + sigma: S -> S, +} + +//********************MODEL SET UP FUNCTIONS*************************// +// set by users in their model files + +fun ks_s0: some S {TS.S0} + +fun ks_sigma: S -> S {TS.sigma} + +//********************HELPER FUNCTIONS*************************// + +private fun bound[R: S -> S, X: S]: S -> S {X <: R} +private fun id[X:S]: S->S{bound[iden,X]} +private fun loop[R: S -> S]: S {S.(^R & id[S])} +--private fun loop[R: S -> S]: S {{a:S | (a->a) in ^R}} + +//********************LOGICAL OPERATORS*************************// + +fun not_ctl[phi: S]: S {S - phi} +fun and_ctl[phi, si: S]: S {phi & si} +fun or_ctl[phi, si: S]: S {phi + si} +fun imp_ctl[phi, si: S]: S {not_ctl[phi] + si} + +//********************TEMPORAL OPERATORS*************************// + +fun ex[phi: S]: S {TS.sigma.phi} + +fun ax[phi:S]:S {not_ctl[ex[not_ctl[phi]]]} + +fun ef[phi: S]: S {(*(TS.sigma)).phi } + +fun eg[phi: S]: S { + let R= bound[TS.sigma,phi]| + let Loop = loop[R]| + (*R).Loop +} + +fun af[phi: S]: S {not_ctl[eg[not_ctl[phi]]]} + +fun ag[phi: S]: S {not_ctl[ef[not_ctl[phi]]]} + +fun eu[phi, si: S]: S {(*(bound[TS.sigma, phi])).si} + +fun au[phi, si: S]: S { + not_ctl[ + or_ctl[ + eg[not_ctl[si]], + eu[ + not_ctl[si], + not_ctl[or_ctl[phi, si]] + ] + ] + ] +} + +//********************MODEL CHECKING CONSTRAINT*************************// +// called by users for mc in their model file +pred ctl_mc[phi: S]{TS.S0 in phi} diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_path.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_path.als new file mode 100755 index 000000000..025e55491 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_path.als @@ -0,0 +1,101 @@ +/* + * Original work Copyright (c) 2017, Amirhossein Vakili, Sabria Farheen, + * Nancy A. Day, Ali Abbassi + * Modified work Copyright (c) 2019, Mitchell Kember, Thi My Linh Tran, + * Yuezhou Gao, Nancy A. Day + * This file is part of the TCMC-Path project, which is released under the + * FreeBSD License. See LICENSE.txt for full license details, or visit + * https://opensource.org/licenses/BSD-2-Clause. + */ + +module tcmc_path[S] + +// ********** Kripke structure ************************************************* + +one sig TS { + S0: some S, + sigma: S -> S, +} + +// ********* Path definition *************************************************** + +// The path is a linked list of nodes. +sig PathNode { + // Each node has 0 or 1 successor. + nextNode: lone PathNode, + // Each node points to a different state. + nodeState: disj one S +} + +// The path has a start node. +one sig P0 in PathNode {} + +// We can project PathNode onto the transition system. +fun pathState: S { PathNode.nodeState } +fun pathSigma: S -> S { ~nodeState.nextNode.nodeState } + +fact { + // The path respects transitions. + pathSigma in TS.sigma + // The start node is in an initial state. + P0.nodeState in TS.S0 + // The path is connected. + P0.*nextNode = PathNode +} + +// Allow the user to optionally enforce a finite path. +pred finitePath { + some p : PathNode | no p.nextNode +} + +// ********** Model setup functions ******************************************** + +// Set by users in their model files. + +fun ks_s0: S { TS.S0 } + +fun ks_sigma: S -> S { TS.sigma } + +// ********** Helper functions ************************************************* + +private fun domainRes[R: S -> S, X: S]: S -> S { X <: R } +private fun id[X:S]: S -> S { domainRes[iden,X] } + +// ********** Logical operators ************************************************ + +fun not_[phi: S]: S { S - phi } +fun and_[phi, si: S]: S { phi & si } +fun or_[phi, si: S]: S { phi + si } +fun imp_[phi, si: S]: S { not_[phi] + si } + +// ********** Temporal operators *********************************************** + +fun ex[phi: S]: S { pathSigma.phi } + +fun ax[phi:S]: S { not_[ex[not_[phi]]] } + +fun ef[phi: S]: S { (*(pathSigma)).phi } + +fun eg[phi:S]: S { + let R = domainRes[pathSigma, phi] | + *R.((^R & id[S]).S) +} + +fun af[phi: S]: S { not_[eg[not_[phi]]] } + +fun ag[phi: S]: S { not_[ef[not_[phi]]] } + +fun eu[phi, si: S]: S { + (*(domainRes[pathSigma, phi])).si +} + +// TODO: Why was this only defined in ctlfc.als and not ctl.als? +fun au[phi, si: S]: S { + not_[or_[eg[not_[si]], + eu[not_[si], not_[or_[phi, si]]]]] +} + +// ********** Model checking constraint **************************************** + +// Called by users for model checking in their model file. +pred ctl_mc[phi: S] { TS.S0 in phi } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_subgraph.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_subgraph.als new file mode 100755 index 000000000..511e7b924 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmc_subgraph.als @@ -0,0 +1,92 @@ +/* + * Original work Copyright (c) 2017, Amirhossein Vakili, Sabria Farheen, + * Nancy A. Day, Ali Abbassi + * Modified work Copyright (c) 2019, Mitchell Kember, Thi My Linh Tran, + * Yuezhou Gao, Nancy A. Day + * This file is part of the TCMC-Path project, which is released under the + * FreeBSD License. See LICENSE.txt for full license details, or visit + * https://opensource.org/licenses/BSD-2-Clause. + */ + +module tcmc_subgraph[S] + +// ********** Kripke structure ************************************************* + +one sig TS { + S0: some S, + sigma: S -> S, +} + +// ********* Subgraph definition *********************************************** + +// Reify the transition relation as a signature. +sig Transition { + transFrom: S, + transTo: S +} + +// We can project Transition onto the transition system. +fun subState: S { Transition.(transFrom + transTo) } +fun subSigma: S -> S { ~transFrom.transTo } + +fact { + // The subgraph respects transitions. + subSigma in TS.sigma + // There are no duplicate Transition elements. + all t, t': Transition | + t.transFrom = t'.transFrom && t.transTo = t'.transTo => t = t' + // The subgraph is connected. + some s: S | s.~transFrom.(*(transTo.~transFrom)) = Transition +} + +// ********** Model setup functions ******************************************** + +// Set by users in their model files. + +fun initialState: S { TS.S0 } + +fun nextState: S -> S { TS.sigma } + +// ********** Helper functions ************************************************* + +private fun domainRes[R: S -> S, X: S]: S -> S { X <: R } +private fun id[X:S]: S -> S { domainRes[iden,X] } + +// ********** Logical operators ************************************************ + +fun not_[phi: S]: S { S - phi } +fun and_[phi, si: S]: S { phi & si } +fun or_[phi, si: S]: S { phi + si } +fun imp_[phi, si: S]: S { not_[phi] + si } + +// ********** Temporal operators *********************************************** + +fun ex[phi: S]: S { subSigma.phi } + +fun ax[phi:S]: S { not_[ex[not_[phi]]] } + +fun ef[phi: S]: S { (*(subSigma)).phi } + +fun eg[phi:S]: S { + let R = domainRes[subSigma, phi] | + *R.((^R & id[S]).S) +} + +fun af[phi: S]: S { not_[eg[not_[phi]]] } + +fun ag[phi: S]: S { not_[ef[not_[phi]]] } + +fun eu[phi, si: S]: S { + (*(domainRes[subSigma, phi])).si +} + +// TODO: Why was this only defined in ctlfc.als and not ctl.als? +fun au[phi, si: S]: S { + not_[or_[eg[not_[si]], + eu[not_[si], not_[or_[phi, si]]]]] +} + +// ********** Model checking constraint **************************************** + +// Called by users for model checking in their model file. +pred ctl_mc[phi: S] { TS.S0 in phi } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc.als new file mode 100755 index 000000000..cf9cb250d --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc.als @@ -0,0 +1,81 @@ +/* + * Original work Copyright (c) 2017, Amirhossein Vakili, Sabria Farheen, + * Nancy A. Day, Ali Abbassi + * Modified work Copyright (c) 2019, Mitchell Kember, Thi My Linh Tran, + * Yuezhou Gao, Nancy A. Day + * This file is part of the TCMC-Path project, which is released under the + * FreeBSD License. See LICENSE.txt for full license details, or visit + * https://opensource.org/licenses/BSD-2-Clause. + */ + +module tcmcfc[S] + +// ********** Kripke structure ************************************************* + +one sig TS { + S0: some S, + sigma: S -> S, + FC: set S +} + +// ********** Model setup functions ******************************************** + +// Set by users in their model files. + +fun initialState: S { TS.S0 } + +fun nextState: S -> S { TS.sigma } + +fun fc: S { TS.FC } + +// ********** Helper functions ************************************************* + +private fun domainRes[R: S -> S, X: S]: S -> S { X <: R } +private fun id[X:S]: S -> S { domainRes[iden,X] } + +// ********** Fair states definition ******************************************* + +// Fair is EcG true. +private fun Fair: S { + let R = TS.sigma | + *R.((^R & id[S]).S & TS.FC) +} + +// ********** Logical operators ************************************************ + +fun not_[phi: S]: S { S - phi } +fun and_[phi, si: S]: S { phi & si } +fun or_[phi, si: S]: S { phi + si } +fun imp_[phi, si: S]: S { not_[phi] + si } + +// ********** Temporal operators *********************************************** + +fun ex[phi: S]: S { TS.sigma.(phi & Fair) } + +fun ax[phi:S]: S { not_[ex[not_[phi]]] } + +fun ef[phi: S]: S { (*(TS.sigma)).(phi & Fair) } + +fun eg[phi:S]: S { + let R = domainRes[TS.sigma, phi] | + *R.(((^R & id[S]).S & TS.FC)) +} + +fun af[phi: S]: S { not_[eg[not_[phi]]] } + +fun ag[phi: S]: S { not_[ef[not_[phi]]] } + +fun eu[phi, si: S]: S { + (*(domainRes[TS.sigma, phi])).(si & Fair) +} + +// TODO: Why was this only defined in ctlfc.als and not ctl.als? +fun au[phi, si: S]: S { + not_[or_[eg[not_[si]], + eu[not_[si], not_[or_[phi, si]]]]] +} + +// ********** Model checking constraint **************************************** + +// Called by users for model checking in their model file. +pred ctlfc_mc[phi: S] { TS.S0 in phi } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_path.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_path.als new file mode 100755 index 000000000..70b0dcdf9 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_path.als @@ -0,0 +1,112 @@ +/* + * Original work Copyright (c) 2017, Amirhossein Vakili, Sabria Farheen, + * Nancy A. Day, Ali Abbassi + * Modified work Copyright (c) 2019, Mitchell Kember, Thi My Linh Tran, + * Yuezhou Gao, Nancy A. Day + * This file is part of the TCMC-Path project, which is released under the + * FreeBSD License. See LICENSE.txt for full license details, or visit + * https://opensource.org/licenses/BSD-2-Clause. + */ + +module tcmcfc_path[S] + +// ********** Kripke structure ************************************************* + +one sig TS { + S0: some S, + sigma: S -> S, + FC: set S +} + +// ********* Path definition *************************************************** + +// The path is a linked list of nodes. +sig PathNode { + // Each node has 0 or 1 successor. + nextNode: lone PathNode, + // Each node points to a different state. + nodeState: disj one S +} + +// The path has a start node. +one sig P0 in PathNode {} + +// We can project PathNode onto the transition system. +fun pathState: S { PathNode.nodeState } +fun pathSigma: S -> S { ~nodeState.nextNode.nodeState } + +fact { + // The path respects transitions. + pathSigma in TS.sigma + // The start node is in an initial state. + P0.nodeState in TS.S0 + // The path is connected. + P0.*nextNode = PathNode +} + +// Allow the user to optionally enforce a finite path. +pred finitePath { + some p : PathNode | no p.nextNode +} + +// ********** Model setup functions ******************************************** + +// Set by users in their model files. + +fun initialState: S { TS.S0 } + +fun nextState: S -> S { TS.sigma } + +fun fc: S { TS.FC } + +// ********** Helper functions ************************************************* + +private fun domainRes[R: S -> S, X: S]: S -> S { X <: R } +private fun id[X:S]: S -> S { domainRes[iden,X] } + +// ********** Fair states definition ******************************************* + +// Fair is EcG true. +private fun Fair: S { + let R = pathSigma | + *R.((^R & id[S]).S & TS.FC) +} + +// ********** Logical operators ************************************************ + +fun not_[phi: S]: S { S - phi } +fun and_[phi, si: S]: S { phi & si } +fun or_[phi, si: S]: S { phi + si } +fun imp_[phi, si: S]: S { not_[phi] + si } + +// ********** Temporal operators *********************************************** + +fun ex[phi: S]: S { pathSigma.(phi & Fair) } + +fun ax[phi:S]: S { not_[ex[not_[phi]]] } + +fun ef[phi: S]: S { (*(pathSigma)).(phi & Fair) } + +fun eg[phi:S]: S { + let R = domainRes[pathSigma, phi] | + *R.(((^R & id[S]).S & TS.FC)) +} + +fun af[phi: S]: S { not_[eg[not_[phi]]] } + +fun ag[phi: S]: S { not_[ef[not_[phi]]] } + +fun eu[phi, si: S]: S { + (*(domainRes[pathSigma, phi])).(si & Fair) +} + +// TODO: Why was this only defined in ctlfc.als and not ctl.als? +fun au[phi, si: S]: S { + not_[or_[eg[not_[si]], + eu[not_[si], not_[or_[phi, si]]]]] +} + +// ********** Model checking constraint **************************************** + +// Called by users for model checking in their model file. +pred ctlfc_mc[phi: S] { TS.S0 in phi } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_subgraph.als b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_subgraph.als new file mode 100755 index 000000000..c8f03647f --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/tcmcfc_subgraph.als @@ -0,0 +1,103 @@ +/* + * Original work Copyright (c) 2017, Amirhossein Vakili, Sabria Farheen, + * Nancy A. Day, Ali Abbassi + * Modified work Copyright (c) 2019, Mitchell Kember, Thi My Linh Tran, + * Yuezhou Gao, Nancy A. Day + * This file is part of the TCMC-Path project, which is released under the + * FreeBSD License. See LICENSE.txt for full license details, or visit + * https://opensource.org/licenses/BSD-2-Clause. + */ + +module tcmcfc_subgraph[S] + +// ********** Kripke structure ************************************************* + +one sig TS { + S0: some S, + sigma: S -> S, + FC: set S +} + +// ********* Subgraph definition *********************************************** + +// Reify the transition relation as a signature. +sig Transition { + transFrom: S, + transTo: S +} + +// We can project Transition onto the transition system. +fun subState: S { Transition.(transFrom + transTo) } +fun subSigma: S -> S { ~transFrom.transTo } + +fact { + // The subgraph respects transitions. + subSigma in TS.sigma + // There are no duplicate Transition elements. + all t, t': Transition | + t.transFrom = t'.transFrom && t.transTo = t'.transTo => t = t' + // The subgraph is connected. + some s: S | s.~transFrom.(*(transTo.~transFrom)) = Transition +} + +// ********** Model setup functions ******************************************** + +// Set by users in their model files. + +fun initialState: S { TS.S0 } + +fun nextState: S -> S { TS.sigma } + +fun fc: S { TS.FC } + +// ********** Helper functions ************************************************* + +private fun domainRes[R: S -> S, X: S]: S -> S { X <: R } +private fun id[X:S]: S -> S { domainRes[iden,X] } + +// ********** Fair states definition ******************************************* + +// Fair is EcG true. +private fun Fair: S { + let R = subSigma | + *R.((^R & id[S]).S & TS.FC) +} + +// ********** Logical operators ************************************************ + +fun not_[phi: S]: S { S - phi } +fun and_[phi, si: S]: S { phi & si } +fun or_[phi, si: S]: S { phi + si } +fun imp_[phi, si: S]: S { not_[phi] + si } + +// ********** Temporal operators *********************************************** + +fun ex[phi: S]: S { subSigma.(phi & Fair) } + +fun ax[phi:S]: S { not_[ex[not_[phi]]] } + +fun ef[phi: S]: S { (*(subSigma)).(phi & Fair) } + +fun eg[phi:S]: S { + let R = domainRes[subSigma, phi] | + *R.(((^R & id[S]).S & TS.FC)) +} + +fun af[phi: S]: S { not_[eg[not_[phi]]] } + +fun ag[phi: S]: S { not_[ef[not_[phi]]] } + +fun eu[phi, si: S]: S { + (*(domainRes[subSigma, phi])).(si & Fair) +} + +// TODO: Why was this only defined in ctlfc.als and not ctl.als? +fun au[phi, si: S]: S { + not_[or_[eg[not_[si]], + eu[not_[si], not_[or_[phi, si]]]]] +} + +// ********** Model checking constraint **************************************** + +// Called by users for model checking in their model file. +pred ctlfc_mc[phi: S] { TS.S0 in phi } diff --git a/org.alloytools.alloy.core/src/main/resources/models/util/traces.als b/org.alloytools.alloy.core/src/main/resources/models/util/traces.als new file mode 100644 index 000000000..1a2f20636 --- /dev/null +++ b/org.alloytools.alloy.core/src/main/resources/models/util/traces.als @@ -0,0 +1,47 @@ +/* + Src: Bounded Model Checking of Temporal Formulas with Alloy by Alcino Cunha + Modified to change s' to s_next for Alloy 6 +*/ +module util/traces[exactly elem] + +private one sig Ord { + First: set elem, + Next: elem -> elem +} { + pred/totalOrder[elem,First,Next] +} + +lone sig back in elem {} + +fun loop : elem -> elem { + last -> back +} + +fun first: one elem { Ord.First } + +fun last: one elem { elem - ((Ord.Next).elem) } + +fun next : elem->elem { Ord.Next + loop } + +fun prev : elem->elem { ~this/next } + +fun past : elem->elem { ^(~this/next) } + +fun future : elem -> elem { elem <: *this/next } + +fun upto[s,s_next : elem] : set elem { + (s_next in s.*(Ord.Next) or finite) implies s.future & ^(Ord.Next).s_next else s.*(Ord.Next) + (^(Ord.Next).s_next & back.*(Ord.Next)) +} + + +pred finite { + no loop +} + +pred infinite { + some loop +} + +check total { + finite implies pred/totalOrder[elem,first,next] +} diff --git a/org.alloytools.alloy.core/src/test/java/org/alloytools/alloy/core/AlloyModelsTest.java b/org.alloytools.alloy.core/src/test/java/org/alloytools/alloy/core/AlloyModelsTest.java index a2a367cf0..8362fac9d 100644 --- a/org.alloytools.alloy.core/src/test/java/org/alloytools/alloy/core/AlloyModelsTest.java +++ b/org.alloytools.alloy.core/src/test/java/org/alloytools/alloy/core/AlloyModelsTest.java @@ -6,6 +6,8 @@ import edu.mit.csail.sdg.alloy4.A4Reporter; import edu.mit.csail.sdg.ast.Command; import edu.mit.csail.sdg.ast.Module; +import edu.mit.csail.sdg.ast.VisitQuery; +import edu.mit.csail.sdg.ast.VisitReturn; import edu.mit.csail.sdg.parser.CompModule; import edu.mit.csail.sdg.parser.CompUtil; import edu.mit.csail.sdg.translator.A4Options; @@ -48,4 +50,40 @@ public void minimalAlloyDoc() throws Exception { return; } } + + + @Test + public void minimalAlloyDoc2() throws Exception { + CompModule world = CompUtil.parseEverything_fromString(A4Reporter.NOP, + //" \n" + + "let nx[foo] { foo.next }\n" + + "sig Foo { next: Foo} \n" + + "check TT{ some foo : Foo | some foo.next }\n"); + + + + VisitReturn visitor = new VisitQuery() {}; + world.getAllSigs().forEach(sig -> sig.accept(visitor)); + //world.getAllMacros().forEach(macro -> {macro.toString();}); + //world.getAllMacros().forEach(macro -> macro.accept(visitor)); + world.getAllCommands().forEach(cmd -> { + System.out.println("nameExpr:" + cmd.nameExpr.toString()); + System.out.println("formula: " + cmd.formula.toString()); + System.out.println("label: " + cmd.label); +// if (cmd.nameExpr != null) +// cmd.nameExpr.accept(visitor); + + //cmd.additionalExactScopes.forEach(sig -> sig.accept(visitor)); + cmd.formula.accept(visitor); +// cmd.scope.forEach(scope -> { +// scope.sig.accept(visitor); +// }); + + }); + //world.visitExpressions(new VisitQuery() {}); + + //Expr expr = world.find(new Pos(null, 12, 3, 15, 3)); + + } + } diff --git a/org.alloytools.alloy.dash/.classpath b/org.alloytools.alloy.dash/.classpath new file mode 100644 index 000000000..d0ac3bda3 --- /dev/null +++ b/org.alloytools.alloy.dash/.classpath @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.alloytools.alloy.dash/.project b/org.alloytools.alloy.dash/.project new file mode 100644 index 000000000..43454e74a --- /dev/null +++ b/org.alloytools.alloy.dash/.project @@ -0,0 +1,40 @@ + + + org.alloytools.alloy.dash + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + org.eclipse.buildship.core.gradleprojectnature + + + + 1687449709202 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/org.alloytools.alloy.dash/bnd.bnd b/org.alloytools.alloy.dash/bnd.bnd new file mode 100644 index 000000000..2c833e04e --- /dev/null +++ b/org.alloytools.alloy.dash/bnd.bnd @@ -0,0 +1,46 @@ +-dependson org.alloytools.alloy.wrappers + +-includeresource: \ + src/main/resources, \ + @${repo;slf4j.api}, \ + +-buildpath: \ + org.alloytools:pardinus.core;version='1.3.0',\ + org.alloytools:pardinus.nativesat;version='1.3.0',\ + org.eclipse.jdt.annotation,\ + org.alloytools.alloy.core;version=latest, \ + com.io7m.jpplib.io7m-jpplib-core;version=0.7.4,\ + org.apache.commons.io,\ + +-testpath: \ + biz.aQute.wrapper.junit, \ + biz.aQute.wrapper.hamcrest, \ + src/main/resources;version=file, \ + slf4j.api, \ + org.sat4j.core, \ + +Export-Package: \ + ca.uwaterloo.watform.alloyasthelper,\ + ca.uwaterloo.watform.core,\ + ca.uwaterloo.watform.ast,\ + ca.uwaterloo.watform.parser,\ + ca.uwaterloo.watform.dashtoalloy,\ + ca.uwaterloo.watform.mainfunctions,\ + + + +Private-Package: \ + java_cup.runtime + + +src=${^src},gen/java + +-generate: \ + parser/; \ + output=gen/java/; \ + workingdir=gen/java/ca/uwaterloo/watform/parser; \ + generate= \ + "JFlex.Main -d . -nobak ./parser/Dash.lex; \ + java_cup.Main -dump -parser DashParser -symbols DashSym -compact_red <./parser/Dash.cup 2>target/report" + +-fixupmessages: "Export ca.uwaterloo.watform.parser" diff --git a/org.alloytools.alloy.dash/parser/Dash-cup-grammar.txt b/org.alloytools.alloy.dash/parser/Dash-cup-grammar.txt new file mode 100644 index 000000000..e7f6a6c9f --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-cup-grammar.txt @@ -0,0 +1,341 @@ + + +//DASH grammar ------------------------------------------------------------------------ + +// besides creating a DashState; the parsing also has count buffers and create indexes +// for those buffers in order to have the correct open statements + +// a few Dash errors here + +// adding a case for the Spec +Spec ::= Spec StateRoot:o ; + +// Root State Declaration +StateRoot ::= STATE:o Name:n LBRACE RBRACE:e // empty state + {: + // first line in file is line 1 + parser.dashmodule.rootStartLine = o.y; + parser.dashmodule.rootEndLine = e.y; + parser.dashmodule.addRoot( + new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates())); + :}; +StateRoot ::= STATE:o Name:n LBRACE StateItemList:c RBRACE:e + {: + parser.dashmodule.rootStartLine = o.y; + parser.dashmodule.rootEndLine = e.y; + parser.dashmodule.addRoot( + new DashState(o, + n.label, + null, + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + c)); + :}; + +StateItemList ::= StateItem:x + {: List xList = new ArrayList(); xList.add(x); RESULT= xList; :}; +StateItemList ::= StateItemList:c StateItem:s + {: c.add(s); RESULT = c; :}; + +// or-state, non-default, empty +StateItem ::= STATE:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates() ); + :}; + +// or-state, non-default, substates +StateItem ::= STATE:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// or-state, default, empty state +StateItem ::= DEF STATE:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates()); + :}; + +// or-state, default, substates +StateItem ::= DEF STATE:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// conc state, non-default, empty +StateItem ::= CONC:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates()); + :}; + +// conc state, non-default, substates +StateItem ::= CONC:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// conc state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates() ); + :}; + +// conc state, default, substates +StateItem ::= DEF CONC:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// parametrized state, non-default, empty +StateItem ::= CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates()); + :}; + +// parametrized state, non-default, substates +StateItem ::= CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// parametrized state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates()); + :}; + +// parametrized state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// event decls +StateItem ::= EVENT:o Names:n LBRACE RBRACE + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashEventDecls(o, ll, DashStrings.IntEnvKind.INT); :}; +StateItem ::= ENV EVENT:o Names:n LBRACE RBRACE + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashEventDecls(o, ll, DashStrings.IntEnvKind.ENV); :}; + +// var decls +StateItem ::= + // we don't support the full variations of declarations here + // don't know what the pos should be for this one + Names:n COLON:o Expr:b + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashVarDecls(o, ll ,b, DashStrings.IntEnvKind.INT); :}; +StateItem ::= ENV:o Names:n COLON Expr:b + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashVarDecls(o, ll, b, DashStrings.IntEnvKind.ENV); :}; + +//buffer decls +//we have to know the number of buffers for the open statements, +//which have to be loaded at the beginning of parsing +//Soln: parse twice +//first time stores buffer names, element types in DashSituation +//second time includes the appropriate opens (based on values in DashSituation) +//when do new DashModule() before start parsing +//collection here is the same regardless of parsing pass +StateItem ::= Names:n COLON:o BUF LBRACKET Name:m RBRACKET + {: + ArrayList ll = new ArrayList(); + Integer startIndex = DashSituation.bufferIndex; + for (ExprVar x: n) { + ll.add(x.label); + // it will do this the same way both passes through parsing + DashSituation.bufferElements.add(m.label); + DashSituation.bufferNames.add(x.label); + DashSituation.bufferIndex++; + } + // endIndex is inclusive + Integer endIndex = DashSituation.bufferIndex - 1; + RESULT = new DashBufferDecls(o, ll, m.label, DashStrings.IntEnvKind.INT, startIndex, endIndex); + :}; +StateItem ::= Names:n COLON:o BUF LBRACKET SIGINT RBRACKET + {: + ArrayList ll = new ArrayList(); + Integer startIndex = DashSituation.bufferIndex; + for (ExprVar x: n) { + ll.add(x.label); + // it will do this the same way both passes through parsing + DashSituation.bufferElements.add(DashStrings.intName); + DashSituation.bufferNames.add(x.label); + DashSituation.bufferIndex++; + } + // endIndex is inclusive + Integer endIndex = DashSituation.bufferIndex - 1; + RESULT = new DashBufferDecls(o, ll, DashStrings.intName, DashStrings.IntEnvKind.INT, startIndex, endIndex); + :}; + +// init +// Super is a list of expressions joined by conjunction +StateItem ::= INIT:o Super:v + {: RESULT = new DashInit(o, v); :}; + +// invariant +StateItem ::= INVARIANT:o Super:v + {: RESULT = new DashInv(o, v); :}; + +// invariant +StateItem ::= INVARIANT:o Name: n Super:v + {: RESULT = new DashInv(o, n.label, v); :}; + +// entered +StateItem ::= ENTER:o Super:v + {: RESULT = new DashEntered(o, v); :}; + +// exited +StateItem ::= EXIT:o Super:v + {: RESULT = new DashExited(o, v); :}; + +//StateItem ::= INVARIANT:o Name:n Super:v +// {: RESULT = new DashInv(o, n.label, v); :}; + +// action +//StateItem ::= ACTION:o Name:n LBRACKET Expr:e RBRACKET LBRACE RBRACE +// {: RESULT = new DashAction(o, n.label, e); :}; + +// condition +//StateItem ::= CONDITION:o Name:n LBRACKET Expr:e RBRACKET LBRACE RBRACE +// {: RESULT = new DashCondition(o, n.label, e); :}; + +// named expression +StateItem ::= PRED:o Name:n LBRACE Expr:e RBRACE + {: RESULT = new DashPred(o, n.label, e); :}; + +// transition +StateItem ::= TRANS:o Name:n LBRACE TransItemList:c RBRACE + {: RESULT = new DashTrans(o, n.label, c); :}; +// transition +StateItem ::= TRANS:o Name:n LBRACE RBRACE + {: RESULT = new DashTrans(o, n.label, new ArrayList()); :}; + +TransItemList ::= TransItem:x + {: RESULT = new ArrayList(); RESULT.add(x); :}; +TransItemList ::= TransItemList:c TransItem:x + {: c.add(x); RESULT = c; :}; + +//Exprp is non-empty list of comma-separated Expr +//Exprs could be empty ist of comma-separated Expr + +// src/dest --------------------- +TransItem ::= FROM:o Name:n + {: RESULT = new DashFrom(o, DashRef.createStateDashRef(o, n.label,DashRef.emptyParamValuesList())); :}; + +TransItem ::= FROM Name:n LBRACKET:o Exprp:e RBRACKET + {: RESULT = new DashFrom(o, DashRef.createStateDashRef(o,n.label,e)); :}; + +TransItem ::= GOTO:o Name:n + {: RESULT = new DashGoto(o, DashRef.createStateDashRef(o,n.label,DashRef.emptyParamValuesList())); :}; + +TransItem ::= GOTO Name:n LBRACKET:o Exprp:e RBRACKET + {: RESULT = new DashGoto(o, DashRef.createStateDashRef(o, n.label,e)); :}; + +// events A/B[a1]/ev1 --------------------------- + +TransItem ::= ON:o Name:n + {: RESULT = new DashOn(o, DashRef.createEventDashRef(o, n.label,DashRef.emptyParamValuesList()) ); :}; + +TransItem ::= ON Name:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: RESULT = new DashOn(o, DashRef.createEventDashRef(o, a.toString() + '/' + e.label, b)); :}; + +TransItem ::= SEND:o Name:n + {: RESULT = new DashSend(o, DashRef.createEventDashRef(o, n.label,DashRef.emptyParamValuesList()) ); :}; + +TransItem ::= SEND Name:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: RESULT = new DashSend(o, DashRef.createEventDashRef(o, a.toString() + '/' + e.label, DashRef.emptyParamValuesList()) ); :}; + + +// actions/guards +TransItem ::= WHEN:o Expr:v + {: RESULT = new DashWhen(o, v); :}; + +TransItem ::= DO:o Expr:v + {: RESULT = new DashDo(o, v); :}; + +// DASH PLUS REFERENCE +// in Alloy can't have a "/Variable" in the following as a regular +// expression so we need more syntax +// and this distinguishes it from other Alloy expressions +// A/B/C[ParamValue1, ParamValue2]/Variable +// note PRIME is a special token in grammar and we want to support v' + +BracketExprB ::= BracketExprB:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: + // have to find the error here + // because if put Name:a in rule above, get shift/reduce conflict + // and DashRef expects a String + if (!ExprHelper.isExprVar(a)) DashErrors.notVarBeforeDashRef(o,a.toString()); + else { + String r = a.toString() + '/' + e.label; + RESULT = DashRef.createVarDashRef(o, r, b); + } + :}; +BracketExprB ::= BracketExprB:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e PRIME + {: + if (!ExprHelper.isExprVar(a)) DashErrors.notVarBeforeDashRef(o,a.toString()); + else { + String r = a.toString() + '/' + e.label + "'"; + RESULT = DashRef.createVarDashRef(o,r, b); + } + :}; + +//DASH end grammar --------------------------------------------------------------------- + diff --git a/org.alloytools.alloy.dash/parser/Dash-cup-imports.txt b/org.alloytools.alloy.dash/parser/Dash-cup-imports.txt new file mode 100644 index 000000000..e87f115bf --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-cup-imports.txt @@ -0,0 +1,12 @@ +import java.util.Arrays; +import edu.mit.csail.sdg.alloy4.Pair; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.parser.MarkdownHandler; + +import ca.uwaterloo.watform.ast.*; +import ca.uwaterloo.watform.core.*; +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; diff --git a/org.alloytools.alloy.dash/parser/Dash-cup-nonterminals.txt b/org.alloytools.alloy.dash/parser/Dash-cup-nonterminals.txt new file mode 100644 index 000000000..0910f094e --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-cup-nonterminals.txt @@ -0,0 +1,15 @@ + + +//DASH nonterminals -------------------------------------------- + +nonterminal StateRoot; + +nonterminal Object StateItem; +nonterminal List StateItemList; + +nonterminal Object TransItem; +nonterminal List TransItemList; + + +//DASH end nonterminals ------------------------------------------ + diff --git a/org.alloytools.alloy.dash/parser/Dash-cup-symbols.txt b/org.alloytools.alloy.dash/parser/Dash-cup-symbols.txt new file mode 100644 index 000000000..83bc72e55 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-cup-symbols.txt @@ -0,0 +1,32 @@ + + + //DASH syntax --------------------------------- + + // must match DASH terminals + + ch.put(DashSym.STATE, "state"); + ch.put(DashSym.CONC, "conc"); + ch.put(DashSym.DEF, "default"); + + ch.put(DashSym.EVENT, "event"); + ch.put(DashSym.ENV, "env"); + ch.put(DashSym.BUF, "buf"); + + ch.put(DashSym.INIT, "init"); + ch.put(DashSym.INVARIANT, "invariant"); + ch.put(DashSym.ENTER, "enter"); + ch.put(DashSym.EXIT, "exit"); + //ch.put(DashSym.ACTION, "action"); + //ch.put(DashSym.CONDITION, "condition"); + + ch.put(DashSym.TRANS, "trans"); + + ch.put(DashSym.FROM, "from"); + ch.put(DashSym.ON, "on"); + ch.put(DashSym.WHEN, "when"); + ch.put(DashSym.DO, "do"); + ch.put(DashSym.GOTO, "goto"); + ch.put(DashSym.SEND, "send"); + + //DASH end syntax ------------------------------ + diff --git a/org.alloytools.alloy.dash/parser/Dash-cup-terminals.txt b/org.alloytools.alloy.dash/parser/Dash-cup-terminals.txt new file mode 100644 index 000000000..47094a0a4 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-cup-terminals.txt @@ -0,0 +1,32 @@ + + +//DASH terminals ----------------------------------- + +// must match DASH symbols + +terminal Pos STATE; +terminal Pos CONC; +terminal Pos DEF; + +terminal Pos EVENT; +terminal Pos ENV; +terminal Pos BUF; + +terminal Pos INIT; +terminal Pos INVARIANT; +terminal Pos ENTER; +terminal Pos EXIT; +//terminal Pos ACTION; +//terminal Pos CONDITION; + +terminal Pos TRANS; + +terminal Pos FROM; +terminal Pos ON; +terminal Pos WHEN; +terminal Pos DO; +terminal Pos GOTO; +terminal Pos SEND; + +//DASH end terminals --------------------------------- + diff --git a/org.alloytools.alloy.dash/parser/Dash-lex-addition.txt b/org.alloytools.alloy.dash/parser/Dash-lex-addition.txt new file mode 100644 index 000000000..43691b77c --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-lex-addition.txt @@ -0,0 +1,29 @@ +//DASH SYNTAX ADDITIONS + +"state" { return alloy_sym(yytext(), DashSym.STATE );} +"conc" { return alloy_sym(yytext(), DashSym.CONC );} +"default" { return alloy_sym(yytext(), DashSym.DEF );} + +"event" { return alloy_sym(yytext(), DashSym.EVENT );} +"env" { return alloy_sym(yytext(), DashSym.ENV );} +"buf" { return alloy_sym(yytext(), DashSym.BUF );} + +"init" { return alloy_sym(yytext(), DashSym.INIT );} +"invariant" { return alloy_sym(yytext(), DashSym.INVARIANT );} +"enter" { return alloy_sym(yytext(), DashSym.ENTER );} +"exit" { return alloy_sym(yytext(), DashSym.EXIT );} +//"action" { return alloy_sym(yytext(), DashSym.ACTION );} +//"condition" { return alloy_sym(yytext(), DashSym.CONDITION );} + +"trans" { return alloy_sym(yytext(), DashSym.TRANS );} + +"from" { return alloy_sym(yytext(), DashSym.FROM );} +"on" { return alloy_sym(yytext(), DashSym.ON );} +"when" { return alloy_sym(yytext(), DashSym.WHEN );} +"do" { return alloy_sym(yytext(), DashSym.DO );} +"goto" { return alloy_sym(yytext(), DashSym.GOTO );} +"send" { return alloy_sym(yytext(), DashSym.SEND );} + + +//END DASH SYNTAX ADDITIONS + diff --git a/org.alloytools.alloy.dash/parser/Dash-lex-imports.txt b/org.alloytools.alloy.dash/parser/Dash-lex-imports.txt new file mode 100644 index 000000000..09432174f --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash-lex-imports.txt @@ -0,0 +1,2 @@ +import edu.mit.csail.sdg.parser.CompModule; + diff --git a/org.alloytools.alloy.dash/parser/Dash.cup b/org.alloytools.alloy.dash/parser/Dash.cup new file mode 100644 index 000000000..95ed2fa21 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash.cup @@ -0,0 +1,1599 @@ +/* + * DO NOT EDIT THIS FILE + * DASH: file copied from Alloy src with replacements for Dash - see install-alloy-files.sh + */ + + +/* Alloy Analyzer 4 -- Copyright (c) 2006-2008, Felix Chang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Warning: this file alone is not enough to correctly parse Alloy4 since the actual + * language is not LALR(1); instead, we have to pre-process the token stream + * using DashFilter.java to rearrange/transform the token stream, and then we can + * parse the transformed token stream using this LALR(1) grammar. For more information, + * please refer to DashFilter.java + */ + +package ca.uwaterloo.watform.parser; + +import java.util.Stack; +import java.util.List; +import java.util.ArrayList; +import java.util.Locale; +import java.util.TreeSet; +import java.util.Map; +import java.util.LinkedHashMap; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.Reader; +import java.io.IOException; +import java.io.StringReader; +import java_cup.runtime.*; +import org.alloytools.alloy.core.AlloyCore; +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Pair; +import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.alloy4.Version; +import edu.mit.csail.sdg.ast.Attr.AttrType; +import edu.mit.csail.sdg.ast.CommandScope; +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprBadJoin; +import edu.mit.csail.sdg.ast.ExprITE; +import edu.mit.csail.sdg.ast.ExprLet; +import edu.mit.csail.sdg.ast.ExprBinary; +import edu.mit.csail.sdg.ast.ExprList; +import edu.mit.csail.sdg.ast.ExprConstant; +import edu.mit.csail.sdg.ast.ExprQt; +import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Sig; +import edu.mit.csail.sdg.ast.Sig.PrimSig; +import java.util.Arrays; +import edu.mit.csail.sdg.alloy4.Pair; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.parser.MarkdownHandler; + +import ca.uwaterloo.watform.ast.*; +import ca.uwaterloo.watform.core.*; +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; + +// @modified [electrum] added temporal operators to the AST (unary temporal operators +// have the same precedence as other unary operators, binary ones have the +// highest precedence); also added a trace sequence operator which has the +// lowest precedence (not actually translated into AST but expanded during +// parsing) added time scopes to commands (reused scope ranges but extended +// to open ranges); support for open ended time scopes; additional syntax +// errors: trace scope increments must be 1; trace scope must be larger than +// 0; open ended trace scopes must start at 1 + +//===========================================================================// + +parser code {: + + public DashModule dashmodule=null; + + @Override public Symbol parse() throws java.lang.Exception { + int act; // current action code + Symbol lhs_sym = null; // the Symbol/stack element returned by a reduce + short handle_size, lhs_sym_num; // information about production being reduced with + boolean logging = AlloyCore.isDebug(); + production_tab = production_table(); + action_tab = action_table(); + reduce_tab = reduce_table(); + init_actions(); + user_init(); + // start + cur_token = scan(); + stack.removeAllElements(); + stack.push(getSymbolFactory().startSymbol("START", 0, start_state())); + tos = 0; + for (_done_parsing = false; !_done_parsing; ) { + act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym); + if (act > 0) { // "shift"; thus, we shift to the encoded state by pushing it on the stack + // if (logging) System.out.println("shift " + cur_token.sym); + cur_token.parse_state = act-1; + stack.push(cur_token); + tos++; + cur_token = scan(); + } else if (act<0) { // "reduce" + // if (logging) System.out.println("reduce " + ((-act)-1)); + lhs_sym = do_action((-act)-1, this, stack, tos); + lhs_sym_num = production_tab[(-act)-1][0]; + handle_size = production_tab[(-act)-1][1]; + for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } + act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num); + lhs_sym.parse_state = act; + stack.push(lhs_sym); + tos++; + } else { // "error" + if (logging) System.out.println("error"); + syntax_error(cur_token); + done_parsing(); + } + } + return lhs_sym; + } + + public void syntax_error(Symbol x) throws Err { + Map ch = new LinkedHashMap(); + ch.put(DashSym.ARROW, "->"); + ch.put(DashSym.ANY_ARROW_SOME, "->"); + ch.put(DashSym.ANY_ARROW_ONE, "->"); + ch.put(DashSym.ANY_ARROW_LONE, "->"); + ch.put(DashSym.SOME_ARROW_ANY, "some"); + ch.put(DashSym.SOME_ARROW_SOME, "some"); + ch.put(DashSym.SOME_ARROW_ONE, "some"); + ch.put(DashSym.SOME_ARROW_LONE, "some"); + ch.put(DashSym.ONE_ARROW_ANY, "one"); + ch.put(DashSym.ONE_ARROW_SOME, "one"); + ch.put(DashSym.ONE_ARROW_ONE, "one"); + ch.put(DashSym.ONE_ARROW_LONE, "one"); + ch.put(DashSym.LONE_ARROW_ANY, "lone"); + ch.put(DashSym.LONE_ARROW_SOME, "lone"); + ch.put(DashSym.LONE_ARROW_ONE, "lone"); + ch.put(DashSym.LONE_ARROW_LONE, "lone"); + ch.put(DashSym.INTADD, "fun"); + ch.put(DashSym.INTSUB, "fun"); + ch.put(DashSym.INTMUL, "fun"); + ch.put(DashSym.INTDIV, "fun"); + ch.put(DashSym.INTREM, "fun"); + ch.put(DashSym.INTMIN, "fun"); + ch.put(DashSym.INTMAX, "fun"); + ch.put(DashSym.INTNEXT, "fun"); + ch.put(DashSym.TOTALORDER, "pred"); + ch.put(DashSym.ABSTRACT, "abstract"); + ch.put(DashSym.ALL, "all"); + ch.put(DashSym.ALL2, "all"); + ch.put(DashSym.AMPERSAND, "&"); + ch.put(DashSym.AND, "&&"); + ch.put(DashSym.AS, "as"); + ch.put(DashSym.ASSERT, "assert"); + ch.put(DashSym.AT, "@"); + ch.put(DashSym.BAR, "|"); + ch.put(DashSym.BUT, "but"); + ch.put(DashSym.CARET, "^"); + ch.put(DashSym.CHECK, "check"); + ch.put(DashSym.COLON, ":"); + ch.put(DashSym.COMMA, ", "); + ch.put(DashSym.DISJ, "disj"); + ch.put(DashSym.DOMAIN, "<:"); + ch.put(DashSym.DOT, "."); + ch.put(DashSym.ELSE, "else"); + ch.put(DashSym.ENUM, "enum"); + ch.put(DashSym.EQUALS, "="); + ch.put(DashSym.EXACTLY, "exactly"); + ch.put(DashSym.EXPECT, "expect"); + ch.put(DashSym.EXTENDS, "extends"); + ch.put(DashSym.FACT, "fact"); + ch.put(DashSym.FOR, "for"); + ch.put(DashSym.FUN, "fun"); + ch.put(DashSym.GT, ">"); + ch.put(DashSym.GTE, ">="); + ch.put(DashSym.HASH, "#"); + ch.put(DashSym.IDEN, "iden"); + ch.put(DashSym.IFF, "iff"); + ch.put(DashSym.IMPLIES, "=>"); + ch.put(DashSym.IN, "in"); + ch.put(DashSym.INT, "int"); + ch.put(DashSym.LBRACE, "{"); + ch.put(DashSym.LBRACKET, "["); + ch.put(DashSym.LET, "let"); + ch.put(DashSym.LONE2, "lone"); + ch.put(DashSym.LONE, "lone"); + ch.put(DashSym.LPAREN, "("); + ch.put(DashSym.LT, "<"); + ch.put(DashSym.LTE, "<="); + ch.put(DashSym.MINUS, "-"); + ch.put(DashSym.MODULE, "module"); + ch.put(DashSym.NO2, "no"); + ch.put(DashSym.NO, "no"); + ch.put(DashSym.NONE, "none"); + ch.put(DashSym.NOT, "!"); + ch.put(DashSym.NOTEQUALS, "!"); + ch.put(DashSym.NOTGT, "!"); + ch.put(DashSym.NOTGTE, "!"); + ch.put(DashSym.NOTIN, "!"); + ch.put(DashSym.NOTLT, "!"); + ch.put(DashSym.NOTLTE, "!"); + ch.put(DashSym.ONE2, "one"); + ch.put(DashSym.ONE, "one"); + ch.put(DashSym.OPEN, "open"); + ch.put(DashSym.OR, "||"); + ch.put(DashSym.PLUS, "+"); + ch.put(DashSym.PLUSPLUS, "++"); + ch.put(DashSym.PRED, "pred"); + ch.put(DashSym.PRIVATE, "private"); + ch.put(DashSym.RANGE, ":>"); + ch.put(DashSym.RBRACE, "}"); + ch.put(DashSym.RBRACKET, "]"); + ch.put(DashSym.RPAREN, ")"); + ch.put(DashSym.RUN, "run"); + ch.put(DashSym.SEQ, "seq"); + ch.put(DashSym.SET, "set"); + ch.put(DashSym.SHL, "<<"); + ch.put(DashSym.SHR, ">>>"); + ch.put(DashSym.SHA, ">>"); + ch.put(DashSym.SIG, "sig"); + ch.put(DashSym.SIGINT, "Int"); + ch.put(DashSym.SLASH, "/"); + ch.put(DashSym.SOME2, "some"); + ch.put(DashSym.SOME, "some"); + ch.put(DashSym.STAR, "*"); + ch.put(DashSym.STRING, "String"); + ch.put(DashSym.SUM2, "sum"); + ch.put(DashSym.SUM, "sum"); + ch.put(DashSym.THIS, "this"); + ch.put(DashSym.TILDE, "~"); + ch.put(DashSym.UNIV, "univ"); + ch.put(DashSym.ID, "NAME"); + ch.put(DashSym.NUMBER, "NUMBER"); + ch.put(DashSym.STR, "STRING"); + ch.put(DashSym.VAR, "var"); + ch.put(DashSym.ALWAYS, "always"); + ch.put(DashSym.EVENTUALLY, "eventually"); + ch.put(DashSym.AFTER, "after"); + ch.put(DashSym.BEFORE, "before"); + ch.put(DashSym.HISTORICALLY, "historically"); + ch.put(DashSym.ONCE, "once"); + ch.put(DashSym.RELEASES, "releases"); + ch.put(DashSym.UNTIL, "until"); + ch.put(DashSym.SINCE, "since"); + ch.put(DashSym.TRIGGERED, "triggered"); + ch.put(DashSym.TRCSEQ, ";"); + ch.put(DashSym.PRIME, "'"); + ch.put(DashSym.TIME, "steps"); + + + //DASH syntax --------------------------------- + + // must match DASH terminals + + ch.put(DashSym.STATE, "state"); + ch.put(DashSym.CONC, "conc"); + ch.put(DashSym.DEF, "default"); + + ch.put(DashSym.EVENT, "event"); + ch.put(DashSym.ENV, "env"); + ch.put(DashSym.BUF, "buf"); + + ch.put(DashSym.INIT, "init"); + ch.put(DashSym.INVARIANT, "invariant"); + ch.put(DashSym.ENTER, "enter"); + ch.put(DashSym.EXIT, "exit"); + //ch.put(DashSym.ACTION, "action"); + //ch.put(DashSym.CONDITION, "condition"); + + ch.put(DashSym.TRANS, "trans"); + + ch.put(DashSym.FROM, "from"); + ch.put(DashSym.ON, "on"); + ch.put(DashSym.WHEN, "when"); + ch.put(DashSym.DO, "do"); + ch.put(DashSym.GOTO, "goto"); + ch.put(DashSym.SEND, "send"); + + //DASH end syntax ------------------------------ + + TreeSet list = new TreeSet(); + Pos p=Pos.UNKNOWN; + if (x!=null && x.value instanceof Pos) p=(Pos)(x.value); + else if (x!=null && x.value instanceof Expr) p=((Expr)(x.value)).pos; + else if (x!=null) p=x.pos; + if (!stack.empty()) for(Map.Entry e:ch.entrySet()) { + int key=e.getKey(), act=get_action(((Symbol)stack.peek()).parse_state, key); + if (act==0) continue; + try { + if (act>0 || alloy_confirm(key)) list.add(e.getValue()); + } catch(Throwable ex) { + // If the parser is really really confused, alloy_confirm() could fail with array out-of-bound exception, etc. + } + } + String result="There are "+list.size()+" possible tokens that can appear here:\n"; + for(String item:list) result=result+item+" "; + throw new ErrorSyntax(p, (list.size()!=0)?result:""); + } + + private boolean alloy_confirm(int key) { + int state = ((Symbol)stack.peek()).parse_state; + Stack newstack=new Stack(); for(Object x:stack) newstack.push(x); + while(true) { + int act = get_action(state, key); + if (act>0) return true; + if (act==0) return false; + int lhs_sym_num = production_tab[(-act)-1][0]; + int handle_size = production_tab[(-act)-1][1]; + for (int i = 0; i < handle_size; i++) { if (newstack.empty()) return false; newstack.pop(); } + if (newstack.empty()) return false; + if (newstack.peek() instanceof Symbol) state=((Symbol)newstack.peek()).parse_state; + state=get_reduce(state, lhs_sym_num); + newstack.push(null); + } + } + + static final String INT_LIB_NAME = "util" + java.io.File.separator + "integer"; + static DashModule alloy_parseStream (List seenDollar, + Map loaded, Map fc, CompModule root, + int lineOffset, String filename, String prefix, int initialResolutionMode) throws Err, FileNotFoundException, IOException { + Reader isr=null; + try { + if (root==null && prefix.length()!=0) throw new ErrorFatal("Internal error (parse subfile with root==null)"); + if (root!=null && prefix.length()==0) throw new ErrorFatal("Internal error (parse topfile with root!=null)"); + DashModule u = new DashModule(root, filename, prefix); + if (!filename.endsWith(INT_LIB_NAME + ".als")) + u.addOpen(null, null, ExprVar.make(null, INT_LIB_NAME), null, ExprVar.make(null, "integer")); + u.resolution = initialResolutionMode; + String content = fc!=null ? fc.get(filename) : null; + if (content==null && loaded!=null) content = loaded.get(filename); + if (content==null) content = Util.readAll(filename); + if (loaded!=null) loaded.put(filename,content); + if (content.startsWith("---") || filename.toLowerCase(Locale.ROOT).endsWith(".md")) content = MarkdownHandler.strip(content); + content = Util.convertLineBreak(content); + isr = new StringReader(content); + DashFilter s = new DashFilter(u, seenDollar, filename, lineOffset, new BufferedReader(isr)); + DashParser p = new DashParser(s); + p.dashmodule=u; + try {p.parse();} catch(Throwable ex) {if (ex instanceof Err) throw (Err)ex; throw new ErrorFatal("Parser Exception", ex);} + return u; + } finally { + Util.close(isr); + } + } + +:}; + +action code {: + /** This function is needed to handle a difficult parsing ambiguity. + * + *

+ * "some EXPR", "one EXPR", and "lone EXPR" + * can be either formulas (saying the EXPR has at least 1, exactly 1, or at most 1 tuple), + * or multiplicity constraints (saying something else has this multiplicity). + * + *

+ * So we let the parser generate the former by default. + * And whenever we construct a Decl "x: y" object, + * or an binary expression "x in y", or a function return type, + * we call this method on y to convert it into a multiplicity constraint. + * + *

+ * This is safe, because in all 3 cases, a formula would be illegal. + * So the first form is always wrong. + * + *

+ * And this is sufficient, because those are the only 3 places + * where a mulitplicity constraint is allowed to appear. + * + * @return a newly formed multiplciity constraint (if this.op==SOME or LONE or ONE), + * otherwise it just returns the original node. + */ + private Expr mult(Expr x) throws Err { + if (x instanceof ExprUnary) { + ExprUnary y=(ExprUnary)x; + if (y.op==ExprUnary.Op.SOME) return ExprUnary.Op.SOMEOF.make(y.pos, y.sub); + if (y.op==ExprUnary.Op.LONE) return ExprUnary.Op.LONEOF.make(y.pos, y.sub); + if (y.op==ExprUnary.Op.ONE) return ExprUnary.Op.ONEOF.make(y.pos, y.sub); + } + return x; + } + private void nod(ExprVar name) throws Err { + if (name.label.indexOf('$')>=0) throw new ErrorSyntax(name.pos, "The name cannot contain the '$' symbol."); + } + private void nod(List names) throws Err { + if (names!=null) for(ExprVar n:names) if (n!=null && n.label.indexOf('$')>=0) throw new ErrorSyntax(n.pos, "The name cannot contain the '$' symbol."); + } + private void c(boolean follow, ExprVar o, ExprVar x, ExprVar n, Expr e, List s, ExprConstant c) throws Err { + if (n!=null) nod(n); + int bitwidth=(-1), maxseq=(-1), overall=(-1), expects=(c==null ? -1 : c.num); + int maxtime = (-1), mintime = (-1); + Pos p = o.pos.merge(n!=null ? n.span() : e.span()); + for(int i=s.size()-1; i>=0; i--) { + Sig j=s.get(i).sig; int k=s.get(i).startingScope; + p=p.merge(j.pos); + if (j.label.equals("univ")) { overall=k; s.remove(i); continue; } + if (j.label.equals("int")) { if (bitwidth>=0) throw new ErrorSyntax(j.pos, "The bitwidth cannot be specified more than once."); bitwidth=k; s.remove(i); continue; } + if (j.label.equals("seq")) { if (maxseq>=0) throw new ErrorSyntax(j.pos, "The maximum sequence length cannot be specified more than once."); maxseq=k; s.remove(i); continue; } + // [electrum] process time scopes + if (j.label.equals("steps")) { + if (s.get(i).endingScope == Integer.MAX_VALUE && s.get(i).startingScope != 1) throw new ErrorSyntax(j.pos, "Unbounded time scope must start at 1."); + if (s.get(i).increment != 1) throw new ErrorSyntax(j.pos, "Step scopes must be incremented by 1."); + if (k<1) throw new ErrorSyntax(j.pos, "Trace solutions must contain at least one step."); + if (maxtime>=0) throw new ErrorSyntax(j.pos, "Steps scope cannot be specified more than once."); + maxtime=k; + if (s.get(i).isExact) mintime = k; + else if (s.get(i).endingScope != s.get(i).startingScope) { + maxtime = s.get(i).endingScope; mintime = s.get(i).startingScope; } + s.remove(i); continue; + } + } + if (n!=null) + parser.dashmodule.addCommand(follow, p, n, o, overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); + else + parser.dashmodule.addCommand(follow, p, e, o, overall, bitwidth, maxseq, mintime, maxtime, expects, s, x); + } + private Expr t(Pos pos, Pos oldClosing, Expr left, Expr right, Pos close) throws Err { + if (right instanceof ExprVar) { + String n = ((ExprVar)right).label; + if (n.equals("int")) return ExprUnary.Op.CAST2INT.make(pos, left); + if (n.equals("disj")) return ExprList.makeDISJOINT(pos, close, Util.asList(left)); + if (n.equals("pred/totalOrder")) return ExprList.makeTOTALORDER(pos, close, Util.asList(left)); + } + else if (right instanceof ExprList) { + return ((ExprList)right).addArg(left); + } + return ExprBadJoin.make(pos, oldClosing, left, right); + } +:}; + +//===========================================================================// + +terminal Pos ARROW; // -> +terminal Pos ANY_ARROW_SOME; // ->some // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ANY_ARROW_ONE; // ->one // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ANY_ARROW_LONE; // ->lone // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos SOME_ARROW_ANY; // some-> // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos SOME_ARROW_SOME; // some->some // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos SOME_ARROW_ONE; // some->one // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos SOME_ARROW_LONE; // some->lone // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ONE_ARROW_ANY; // one-> // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ONE_ARROW_SOME; // one->some // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ONE_ARROW_ONE; // one->one // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos ONE_ARROW_LONE; // one->lone // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos LONE_ARROW_ANY; // lone->any // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos LONE_ARROW_SOME; // lone->some // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos LONE_ARROW_ONE; // lone->one // The filter allows whitespace/comment in these 15 "*->*" tokens +terminal Pos LONE_ARROW_LONE; // lone->lone // The filter allows whitespace/comment in these 15 "*->*" tokens + +terminal Pos INTADD; +terminal Pos INTSUB; +terminal Pos INTMUL; +terminal Pos INTDIV; +terminal Pos INTREM; +terminal Pos INTMIN; +terminal Pos INTMAX; +terminal Pos INTNEXT; +terminal Pos TOTALORDER; + +terminal Pos ABSTRACT; // abstract +terminal Pos ALL; // all // The filter enables us to disambiguate +terminal Pos ALL2; // all // The filter enables us to disambiguate +terminal Pos AMPERSAND; // & +terminal Pos AND; // && and +terminal Pos AS; // as +terminal Pos ASSERT; // assert +terminal Pos AT; // @ +terminal Pos BAR; // | +terminal Pos BUT; // but +terminal Pos CARET; // ^ +terminal Pos CHECK; // check +terminal Pos COLON; // : +terminal Pos COMMA; // , +terminal Pos DISJ; // disj disjoint +terminal Pos DOMAIN; // <: +terminal Pos DOT; // . +terminal Pos ELSE; // else +terminal Pos ENUM; // enum +terminal Pos EQUALS; // = == +terminal Pos EXACTLY; // exactly +terminal Pos EXPECT; // expect +terminal Pos EXTENDS; // extends +terminal Pos FACT; // fact +terminal Pos FOR; // for +terminal Pos FUN; // fun +terminal Pos GT; // > +terminal Pos GTE; // >= +terminal Pos HASH; // # +terminal Pos IDEN; // iden +terminal Pos IFF; // <=> iff +terminal Pos IMPLIES; // => implies +terminal Pos IN; // in +terminal Pos INT; // int +terminal Pos LBRACE; // { +terminal Pos LBRACKET; // [ +terminal Pos LET; // let +terminal Pos LONE2; // lone // The filter enables us to disambiguate +terminal Pos LONE; // lone // The filter enables us to disambiguate +terminal Pos LPAREN; // ( +terminal Pos LT; // < +terminal Pos LTE; // <= =< +terminal Pos MINUS; // - +terminal Pos MODULE; // module +terminal Pos NO2; // no // The filter enables us to disambiguate +terminal Pos NO; // no // The filter enables us to disambiguate +terminal Pos NONE; // none +terminal Pos NOT; // ! not +terminal Pos NOTEQUALS; // != not= // The filter allows whitespace/comment in between +terminal Pos NOTGT; // !> not> // The filter allows whitespace/comment in between +terminal Pos NOTGTE; // !>= not>= // The filter allows whitespace/comment in between +terminal Pos NOTIN; // !in notin // The filter allows whitespace/comment in between +terminal Pos NOTLT; // !< not< // The filter allows whitespace/comment in between +terminal Pos NOTLTE; // !=< not=< // The filter allows whitespace/comment in between +terminal Pos ONE2; // one // The filter enables us to disambiguate +terminal Pos ONE; // one // The filter enables us to disambiguate +terminal Pos OPEN; // open +terminal Pos OR; // || or +terminal Pos PLUS; // + +terminal Pos PLUSPLUS; // ++ +terminal Pos PRED; // pred +terminal Pos PRIVATE; // private +terminal Pos RANGE; // :> +terminal Pos RBRACE; // } +terminal Pos RBRACKET; // ] +terminal Pos RPAREN; // ) +terminal Pos RUN; // run +terminal Pos SEQ; // seq +terminal Pos SET; // set +terminal Pos SHL; // << +terminal Pos SHR; // >>> +terminal Pos SHA; // >> +terminal Pos SIG; // sig +terminal Pos SIGINT; // Int +terminal Pos SLASH; // / +terminal Pos SOME2; // some // The filter enables us to disambiguate +terminal Pos SOME; // some // The filter enables us to disambiguate +terminal Pos STAR; // * +terminal Pos STRING; // String +terminal Pos SUM2; // sum // The filter enables us to disambiguate +terminal Pos SUM; // sum // The filter enables us to disambiguate +terminal Pos THIS; // this +terminal Pos TILDE; // ~ +terminal Pos UNIV; // univ + +terminal Pos VAR; // var +terminal Pos ALWAYS; // always +terminal Pos EVENTUALLY; // eventually +terminal Pos AFTER; // after +terminal Pos ONCE; // once +terminal Pos HISTORICALLY; // historically +terminal Pos BEFORE; // before +terminal Pos RELEASES; // releases +terminal Pos UNTIL; // until +terminal Pos SINCE; // since +terminal Pos TRIGGERED; // triggered +terminal Pos TRCSEQ; // trace seq +terminal Pos TIME; // steps +terminal Pos PRIME; // ' + +terminal ExprVar ID; + +terminal ExprConstant NUMBER, STR; + + +//DASH terminals ----------------------------------- + +// must match DASH symbols + +terminal Pos STATE; +terminal Pos CONC; +terminal Pos DEF; + +terminal Pos EVENT; +terminal Pos ENV; +terminal Pos BUF; + +terminal Pos INIT; +terminal Pos INVARIANT; +terminal Pos ENTER; +terminal Pos EXIT; +//terminal Pos ACTION; +//terminal Pos CONDITION; + +terminal Pos TRANS; + +terminal Pos FROM; +terminal Pos ON; +terminal Pos WHEN; +terminal Pos DO; +terminal Pos GOTO; +terminal Pos SEND; + +//DASH end terminals --------------------------------- + + +//===========================================================================// + +nonterminal Expr AndExprA; +nonterminal Expr AndExprB; +nonterminal Expr BaseExpr; +nonterminal Expr Bind; +nonterminal Expr BracketExprA; +nonterminal Expr BracketExprB; +nonterminal Expr CompareExprA; +nonterminal Expr CompareExprB; +nonterminal Command; +nonterminal ExprVar CommandPrefix; +nonterminal Decl Decla; +nonterminal Decl Declb; +nonterminal List Declp; +nonterminal List Decls; +nonterminal List Declz; +nonterminal Expr DomainExprA; +nonterminal Expr DomainExprB; +nonterminal Expr DotExprA; +nonterminal Expr DotExprB; +nonterminal Expr EquivExprA; +nonterminal Expr EquivExprB; +nonterminal ExprConstant Expects; +nonterminal Expr Expr; +nonterminal Expr Super; +nonterminal Expr SuperOpt; +nonterminal Expr SuperP; +nonterminal Expr SuperOrBar; +nonterminal List Exprs; +nonterminal List Exprp; +nonterminal Function; +nonterminal Expr ImpliesExprA; +nonterminal Expr ImpliesExprB; +nonterminal Expr ImpliesExprCloseA; +nonterminal Expr ImpliesExprCloseB; +nonterminal Expr ImpliesExprOpenA; +nonterminal Expr ImpliesExprOpenB; +nonterminal Expr IntersectExprA; +nonterminal Expr IntersectExprB; +nonterminal Expr Let; +nonterminal Macro; +nonterminal Expr MacroBody; +nonterminal ExprVar Name; +nonterminal ExprVar NameHelper; +nonterminal List Names; +nonterminal List Namex; +nonterminal Expr UnaryExprA; +nonterminal Expr UnaryExprB; +nonterminal Expr NumUnopExprA; +nonterminal Expr NumUnopExprB; +nonterminal Expr OrExprA; +nonterminal Expr OrExprB; +nonterminal Expr OverrideExprA; +nonterminal Expr OverrideExprB; +nonterminal Predicate; +nonterminal Expr RangeExprA; +nonterminal Expr RangeExprB; +nonterminal Pair RelOp; +nonterminal Expr RelationExprA; +nonterminal Expr RelationExprB; +nonterminal List Scope; +nonterminal Sig; +nonterminal List SigIn; +nonterminal List SigQual; +nonterminal List SigQuals; +nonterminal ExprVar SigRef; +nonterminal List SigRefp; +nonterminal List SigRefs; +nonterminal List SigRefu; +nonterminal File; +nonterminal Spec; +nonterminal CommandScope TypeNumber; +nonterminal CommandScope Typescope; +nonterminal List Typescopes; +nonterminal Expr ShiftExprA; +nonterminal Expr ShiftExprB; +nonterminal Expr MulExprA; +nonterminal Expr MulExprB; +nonterminal Expr UnionDiffExprA; +nonterminal Expr UnionDiffExprB; +nonterminal Expr UnopExprA; +nonterminal Expr UnopExprB; +nonterminal Pos Vis; +nonterminal Expr TempBinaryA; +nonterminal Expr TempBinaryB; +nonterminal Expr ExprNoSeq; + + +//DASH nonterminals -------------------------------------------- + +nonterminal StateRoot; + +nonterminal Object StateItem; +nonterminal List StateItemList; + +nonterminal Object TransItem; +nonterminal List TransItemList; + + +//DASH end nonterminals ------------------------------------------ + + +precedence right TRCSEQ; +precedence nonassoc BAR; +precedence left OR; +precedence left IFF; +precedence right IMPLIES; +precedence left AND; +precedence nonassoc RELEASES, SINCE, UNTIL, TRIGGERED; +precedence nonassoc AFTER, ALWAYS, EVENTUALLY, BEFORE, HISTORICALLY, ONCE; +precedence nonassoc NOT; +precedence nonassoc EQUALS, NOTEQUALS, IN, NOTIN; +precedence nonassoc NO, SOME, LONE, ONE; +precedence nonassoc PRIME; +precedence nonassoc TILDE, CARET, STAR; + +//===========================================================================// + +File ::= Spec {: parser.dashmodule.doneParsing(); :}; + +Spec ::= Spec MODULE:o Name:n {: nod(n); parser.dashmodule.addModelName(o.merge(n.pos) , n.label , new ArrayList()); :}; +Spec ::= Spec MODULE:o Name:n LBRACKET Namex:b RBRACKET:r {: nod(n); nod(b); parser.dashmodule.addModelName(o.merge(r) , n.label , b ); :}; +Spec ::= Spec Vis:p OPEN:o Name:a {: nod(a); parser.dashmodule.addOpen(o.merge(a.pos), p, a, null, null); :}; +Spec ::= Spec Vis:p OPEN:o Name:a AS Name:c {: nod(a); nod(c); parser.dashmodule.addOpen(o.merge(c.pos), p, a, null, c); :}; +Spec ::= Spec Vis:p OPEN:o Name:a LBRACKET SigRefs:b RBRACKET:c {: nod(a); parser.dashmodule.addOpen(o.merge(c), p, a, b, null); :}; +Spec ::= Spec Vis:p OPEN:o Name:a LBRACKET SigRefs:b RBRACKET AS Name:c {: nod(a); nod(c); parser.dashmodule.addOpen(o.merge(c.pos), p, a, b, c); :}; +Spec ::= Spec Vis:p ENUM:o Name:a LBRACE Names:n RBRACE:c {: nod(a); parser.dashmodule.addEnum(o.merge(c), p, a, n, c); :}; +Spec ::= Spec Vis:p ENUM:o Name:a LBRACE RBRACE:c {: nod(a); parser.dashmodule.addEnum(o.merge(c), p, a, null, c); :}; +Spec ::= Spec FACT:o Super:e {: parser.dashmodule.addFact (o , "" , e); :}; +Spec ::= Spec FACT:o Name:n Super:e {: nod(n); parser.dashmodule.addFact (o , n.label , e); :}; +Spec ::= Spec FACT:o STR:n Super:e {: parser.dashmodule.addFact (o , n.string , e); :}; +Spec ::= Spec ASSERT:o Super:e {: parser.dashmodule.addAssertion (o , null , "" , e); :}; +Spec ::= Spec ASSERT:o Name:n Super:e {: nod(n); parser.dashmodule.addAssertion (o , n.pos, n.label , e); :}; +Spec ::= Spec ASSERT:o STR:n Super:e {: parser.dashmodule.addAssertion (o , null, n.string , e); :}; +Spec ::= Spec Sig ; +Spec ::= Spec Function ; +Spec ::= Spec Predicate ; +Spec ::= Spec Macro ; +Spec ::= Spec Command ; +Spec ::= ; + +CommandPrefix ::= CHECK:c {: RESULT = ExprVar.make(c, "c"); :}; +CommandPrefix ::= RUN:r {: RESULT = ExprVar.make(r, "r"); :}; + +Command ::= CommandPrefix:o Name:x Super:e Scope:s Expects:c {: c(false,o,x ,null,e ,s,c); :}; +Command ::= CommandPrefix:o Super:e Scope:s Expects:c {: c(false,o,null,null,e ,s,c); :}; +Command ::= Command IMPLIES CommandPrefix:o Name:x Super:e Scope:s Expects:c {: c(true ,o,x ,null,e ,s,c); :}; +Command ::= Command IMPLIES CommandPrefix:o Super:e Scope:s Expects:c {: c(true ,o,null,null,e ,s,c); :}; +Command ::= CommandPrefix:o Name:x Name:n Scope:s Expects:c {: c(false,o,x ,n ,null,s,c); :}; +Command ::= CommandPrefix:o Name:n Scope:s Expects:c {: c(false,o,null,n ,null,s,c); :}; +Command ::= Command IMPLIES CommandPrefix:o Name:x Name:n Scope:s Expects:c {: c(true ,o,x ,n ,null,s,c); :}; +Command ::= Command IMPLIES CommandPrefix:o Name:n Scope:s Expects:c {: c(true ,o,null,n ,null,s,c); :}; + +Expects ::= {: RESULT=null; :}; +Expects ::= EXPECT NUMBER:a {: RESULT=a; :}; + +Scope ::= FOR NUMBER:a {: RESULT=new ArrayList(); RESULT.add(new CommandScope(a.pos, Pos.UNKNOWN, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; +Scope ::= FOR NUMBER:a BUT Typescopes:b {: RESULT=b; b.add(new CommandScope(a.pos, Pos.UNKNOWN, new PrimSig("univ", AttrType.WHERE.make(a.pos)), true, a.num, a.num, 1)); :}; +Scope ::= FOR Typescopes:b {: RESULT=b; :}; +Scope ::= {: RESULT=new ArrayList(); :}; + +Typescopes ::= Typescope:a {: RESULT=new ArrayList(); RESULT.add(a); :}; +Typescopes ::= Typescopes:a COMMA Typescope:b {: RESULT=a; a.add(b); :}; + +Typescope ::= TypeNumber:a Name:b {: + nod(b); + RESULT = new CommandScope(a.pos.merge(b.pos), b.pos, new PrimSig(b.label, AttrType.WHERE.make(a.pos.merge(b.pos))), a.isExact, a.startingScope, a.endingScope, a.increment); +:}; + +//[AM]: INT -> SIGINT +Typescope ::= TypeNumber:a SIGINT:b {: + Pos p = a.pos.merge(b); + if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"Int\""); + if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the integer bitwidth must be exact."); + RESULT = new CommandScope(p, b, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); +:}; + +Typescope ::= TypeNumber:a INT:b {: + Pos p = a.pos.merge(b); + if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"Int\""); + if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the integer bitwidth must be exact."); + RESULT = new CommandScope(p, b, new PrimSig("int", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); +:}; + +Typescope ::= TypeNumber:a SEQ:b {: + Pos p = a.pos.merge(b); + if (a.endingScope>a.startingScope) throw new ErrorSyntax(p, "Cannot specify a growing scope for \"seq\""); + if (a.isExact) throw new ErrorSyntax(p, "The exactly keyword is redundant here since the number of sequence index has to be exact."); + RESULT = new CommandScope(p, b, new PrimSig("seq", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.startingScope, 1); +:}; + +Typescope ::= TypeNumber:e UNIV:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You cannot set a scope on univ."); :}; + +Typescope ::= TypeNumber:a STRING:b {: RESULT = new CommandScope(a.pos.merge(b), b, new PrimSig("String", AttrType.WHERE.make(a.pos.merge(b))), a.isExact, a.startingScope, a.endingScope, a.increment); :}; + +// [electrum] scope on Time +Typescope ::= TypeNumber:a TIME:b {: + Pos p = a.pos.merge(b); + RESULT = new CommandScope(p, Pos.UNKNOWN, new PrimSig("steps", AttrType.WHERE.make(p)), a.isExact, a.startingScope, a.endingScope, a.increment); +:}; + +//[AM] Typescope ::= TypeNumber:e SIGINT:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You can no longer set a scope on Int; the number of Int atoms is always exactly equal to 2^(integer bitwidth).\n"); :}; + +Typescope ::= TypeNumber:e NONE:f {: if (1==1) throw new ErrorSyntax(e.pos.merge(f), "You cannot set a scope on none."); :}; + +// [electrum] distinguish between "n" and "n..n", the latter become exact; open ended scopes "n.." +TypeNumber ::= EXACTLY:e NUMBER:a {: RESULT = new CommandScope( e.merge(a.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, a.num, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(b.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, b.num, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e , Pos.UNKNOWN, Sig.NONE, true, a.num, Integer.MAX_VALUE, 1 ); :}; +TypeNumber ::= EXACTLY:e NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, b.num, i.num); :}; +TypeNumber ::= EXACTLY:e NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope( e.merge(i.pos), Pos.UNKNOWN, Sig.NONE, true, a.num, Integer.MAX_VALUE, i.num); :}; +TypeNumber ::= NUMBER:a {: RESULT = new CommandScope(a.pos , Pos.UNKNOWN, Sig.NONE, false, a.num, a.num, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT NUMBER:b {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(b.pos), Pos.UNKNOWN, Sig.NONE, a.num == b.num, a.num, b.num, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos , Pos.UNKNOWN, Sig.NONE, false, a.num, Integer.MAX_VALUE, 1 ); :}; +TypeNumber ::= NUMBER:a DOT DOT NUMBER:b COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Pos.UNKNOWN, Sig.NONE, a.num == b.num, a.num, b.num, i.num); :}; +TypeNumber ::= NUMBER:a COLON NUMBER:i {: if (!Version.experimental) throw new ErrorSyntax(a.pos, "Syntax error here."); RESULT = new CommandScope(a.pos.merge(i.pos), Pos.UNKNOWN, Sig.NONE, false, a.num, Integer.MAX_VALUE, i.num); :}; + +Macro ::= Vis:p LET:o Name:n LPAREN Names:d RPAREN MacroBody:v {: nod(n); parser.dashmodule.addMacro(o.merge(v.span()), p, n.pos, n.label, d , v); :}; +Macro ::= Vis:p LET:o Name:n LPAREN RPAREN MacroBody:v {: nod(n); parser.dashmodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; +Macro ::= Vis:p LET:o Name:n LBRACKET Names:d RBRACKET MacroBody:v {: nod(n); parser.dashmodule.addMacro(o.merge(v.span()), p, n.pos, n.label, d , v); :}; +Macro ::= Vis:p LET:o Name:n LBRACKET RBRACKET MacroBody:v {: nod(n); parser.dashmodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; +Macro ::= Vis:p LET:o Name:n MacroBody:v {: nod(n); parser.dashmodule.addMacro(o.merge(v.span()), p, n.pos, n.label, null , v); :}; + +MacroBody ::= Super:a {: RESULT=a; :}; +MacroBody ::= EQUALS Expr:a {: RESULT=a; :}; + +Function ::= Vis:p FUN:o Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, d , mult(r), v); :}; +Function ::= Vis:p FUN:o Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, d , mult(r), v); :}; +Function ::= Vis:p FUN:o Name:n COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, null , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , d , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , d , mult(r), v); :}; +Function ::= Vis:p FUN:o SigRef:f DOT Name:n COLON Expr:r Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , null , mult(r), v); :}; + +Predicate ::= Vis:p PRED:o Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, d , null, v); :}; +Predicate ::= Vis:p PRED:o Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, d , null, v); :}; +Predicate ::= Vis:p PRED:o Name:n Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, null, null , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LPAREN Decls:d RPAREN Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , d , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n LBRACKET Decls:d RBRACKET Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , d , null, v); :}; +Predicate ::= Vis:p PRED:o SigRef:f DOT Name:n Super:v {: nod(n); parser.dashmodule.addFunc(o.merge(v.span()), p, n, f , null , null, v); :}; + +Vis ::= {: RESULT=null; :}; +Vis ::= PRIVATE:p {: RESULT=p; :}; + +Sig ::= SigQuals:a Names:b SigIn:c LBRACE Decls:d RBRACE:o SuperOpt:e + {: + if (e==null) e = ExprConstant.Op.TRUE.make(o, 0); + ExprVar cc = (c!=null && c.size()>0) ? c.remove(c.size()-1) : null; + for(ExprVar bb:b) { + parser.dashmodule.addSig(bb.pos, bb.label, cc, c, d, e, + AttrType.WHERE .makenull(bb.pos.merge(e==null ? o : e.span())), + AttrType.ABSTRACT.makenull(a.get(0)), + AttrType.LONE .makenull(a.get(1)), + AttrType.ONE .makenull(a.get(2)), + AttrType.SOME .makenull(a.get(3)), + AttrType.PRIVATE .makenull(a.get(4)), + AttrType.VARIABLE.makenull(a.get(5))); + } + :}; + +// [electrum] additional attribute for variable sigs +SigQual ::= ABSTRACT:x {: RESULT=new ArrayList(6); RESULT.add(x); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); :}; +SigQual ::= LONE:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(x); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); :}; +SigQual ::= ONE:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(x); RESULT.add(null); RESULT.add(null); RESULT.add(null); :}; +SigQual ::= SOME:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(x); RESULT.add(null); RESULT.add(null); :}; +SigQual ::= PRIVATE:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(x); RESULT.add(null); :}; +SigQual ::= VAR:x {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(x); :}; + +SigQuals ::= SIG {: RESULT=new ArrayList(6); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); RESULT.add(null); :}; +SigQuals ::= SigQual:a SigQuals:b {: RESULT=a; for(int i=0;i<6;i++) if (a.get(i)==null) a.set(i,b.get(i)); else if (b.get(i)!=null) throw new ErrorSyntax(b.get(i), "The same qualifier cannot be specified more than once for the same sig."); :}; + +SigIn ::= EXTENDS:a SigRef:x {: RESULT=new ArrayList(2); RESULT.add(x); RESULT.add(ExprVar.make(a, "extends")); :}; +SigIn ::= IN:a SigRefu:x {: RESULT=x; x.add(ExprVar.make(a,"in")); :}; +SigIn ::= EQUALS:a SigRefu:x {: RESULT=x; x.add(ExprVar.make(a,"=")); :}; +SigIn ::= {: RESULT=null; :}; + +SigRef ::= Name:x {: RESULT=x; :}; +SigRef ::= UNIV:x {: RESULT=ExprVar.make(x, "univ"); :}; +SigRef ::= STRING:x {: RESULT=ExprVar.make(x, "String"); :}; +SigRef ::= TIME:x {: RESULT=ExprVar.make(x, "steps"); :}; +SigRef ::= SIGINT:x {: RESULT=ExprVar.make(x, "Int"); :}; +SigRef ::= SEQ:a SLASH SIGINT:b {: RESULT=ExprVar.make(a.merge(b), "seq/Int"); :}; +SigRef ::= NONE:x {: RESULT=ExprVar.make(x, "none"); :}; + +SigRefs ::= {: RESULT=new ArrayList(); :}; +SigRefs ::= SigRefp:x {: RESULT=x; :}; + +SigRefp ::= SigRef:x {: RESULT=new ArrayList(); RESULT.add(x); :}; +SigRefp ::= SigRefp:a COMMA SigRef:b {: a.add(b); RESULT=a; :}; + +SigRefu ::= SigRef:x {: RESULT=new ArrayList(); RESULT.add(x); :}; +SigRefu ::= SigRefu:a PLUS SigRef:b {: a.add(b); RESULT=a; :}; + +Name ::= NameHelper:x {: RESULT=x; :}; +Name ::= THIS:a SLASH NameHelper:b {: RESULT=ExprVar.make(a.merge(b.pos), "this/"+b.label); :}; +Name ::= SEQ:a SLASH NameHelper:b {: RESULT=ExprVar.make(a.merge(b.pos), "seq/"+b.label); :}; + +NameHelper ::= ID:x {: RESULT=x; :}; +NameHelper ::= NameHelper:a SLASH ID:b {: RESULT=ExprVar.make(a.pos.merge(b.pos), a.label+"/"+b.label); :}; + +Names ::= Name:x {: nod(x); RESULT=new ArrayList(); RESULT.add(x); :}; +Names ::= Names:a COMMA Name:b {: nod(b); a.add(b); RESULT=a; :}; + +Namex ::= Name:x {: nod(x); RESULT=new ArrayList(); RESULT.add(x); :}; +Namex ::= EXACTLY Name:x {: nod(x); RESULT=new ArrayList(); RESULT.add(null); RESULT.add(x); :}; +Namex ::= Namex:a COMMA Name:b {: nod(b); a.add(b); RESULT=a; :}; +Namex ::= Namex:a COMMA EXACTLY Name:b {: nod(b); a.add(null); a.add(b); RESULT=a; :}; + +// [electrum] additional parameter for variable declarations (for fields) +Decla ::= DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(null, k, null, null, a, mult(b)); :}; +Decla ::= PRIVATE:p DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(p, k, null, null, a, mult(b)); :}; +Decla ::= PRIVATE:p Names:a COLON Expr:b {: RESULT=new Decl(p, null, null, null, a, mult(b)); :}; +Decla ::= Names:a COLON Expr:b {: RESULT=new Decl(null, null, null, null, a, mult(b)); :}; + +Decla ::= VAR:v DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(null, k, null, v, a, mult(b)); :}; +Decla ::= VAR:v PRIVATE:p DISJ:k Names:a COLON Expr:b {: RESULT=new Decl(p, k, null, v, a, mult(b)); :}; +Decla ::= VAR:v PRIVATE:p Names:a COLON Expr:b {: RESULT=new Decl(p, null, null, v, a, mult(b)); :}; +Decla ::= VAR:v Names:a COLON Expr:b {: RESULT=new Decl(null, null, null, v, a, mult(b)); :}; + +Decla ::= DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(null, k, d, null, a, mult(b)); :}; +Decla ::= PRIVATE:p DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, k, d, null, a, mult(b)); :}; +Decla ::= PRIVATE:p Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, null, d, null, a, mult(b)); :}; +Decla ::= Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(null, null, d, null, a, mult(b)); :}; + +Decla ::= VAR:v DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(null, k, d, v, a, mult(b)); :}; +Decla ::= VAR:v PRIVATE:p DISJ:k Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, k, d, v, a, mult(b)); :}; +Decla ::= VAR:v PRIVATE:p Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(p, null, d, v, a, mult(b)); :}; +Decla ::= VAR:v Names:a COLON DISJ:d Expr:b {: RESULT=new Decl(null, null, d, v, a, mult(b)); :}; + +Declb ::= Decla:x {: RESULT=x; :}; + +Declb ::= DISJ:d Names EQUALS Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; +Declb ::= PRIVATE DISJ:d Names EQUALS Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; +Declb ::= PRIVATE:p Names:a EQUALS Expr:b {: RESULT=new Decl(p, null, null, null, a, ExprUnary.Op.EXACTLYOF.make(null, b)); :}; +Declb ::= Names:a EQUALS Expr:b {: RESULT=new Decl(null, null, null, null, a, ExprUnary.Op.EXACTLYOF.make(null, b)); :}; + +Declb ::= DISJ Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; +Declb ::= PRIVATE DISJ Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; +Declb ::= PRIVATE Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; +Declb ::= Names EQUALS DISJ:d Expr {: if (1==1) throw new ErrorSyntax(d, "Defined fields cannot be disjoint."); :}; + +Declz ::= Declz:x COMMA Decla:y {: RESULT=x; RESULT.add(y); :}; +Declz ::= Decla:y {: RESULT=new ArrayList(); RESULT.add(y); :}; + +Declp ::= Declp:x COMMA Declb:y {: RESULT=x; RESULT.add(y); :}; +Declp ::= Declb:y {: RESULT=new ArrayList(); RESULT.add(y); :}; + +Decls ::= {: RESULT=new ArrayList(); :}; +Decls ::= Declb:x {: RESULT=new ArrayList(); RESULT.add(x); :}; +Decls ::= Declb:x COMMA Decls:y {: RESULT=y; RESULT.add(0,x); :}; +Decls ::= COMMA Decls:y {: RESULT=y; :}; + +Let ::= Name:a EQUALS:o Expr:b SuperOrBar:x {: + nod(a); + if (a.label.indexOf('/')>=0) throw new ErrorSyntax(a.pos, "Let variable name cannot contain \'/\'"); + if (a.label.indexOf('@')>=0) throw new ErrorSyntax(a.pos, "Let variable name cannot contain \'@\'"); + RESULT = ExprLet.make(o, ExprVar.make(a.pos, a.label), b, x); +:}; + +Let ::= Name:a EQUALS:o Expr:b COMMA Let:x {: + nod(a); + if (a.label.indexOf('/')>=0) throw new ErrorSyntax(a.pos, "Let variable name cannot contain \'/\'"); + if (a.label.indexOf('@')>=0) throw new ErrorSyntax(a.pos, "Let variable name cannot contain \'@\'"); + RESULT = ExprLet.make(o, ExprVar.make(a.pos, a.label), b, x); +:}; + +// [electrum] temporal seq expressions have the lowest precedence +SuperOpt ::= {: RESULT=null; :}; +SuperOpt ::= Super:x {: RESULT=x; :}; +Super ::= LBRACE:a SuperP:x RBRACE:b {: RESULT=ExprUnary.Op.NOOP.make(a.merge(b), x); :}; +Super ::= LBRACE:a RBRACE:b {: RESULT=ExprConstant.Op.TRUE.make(a.merge(b), 0); :}; +SuperP ::= Expr:a {: RESULT=a; :}; +SuperP ::= SuperP:a Expr:b {: RESULT=ExprBinary.Op.AND.make(null, null, a, b); :}; +SuperP ::= Expr:a TRCSEQ:o SuperP:b {: RESULT=ExprBinary.Op.AND.make(o, null, a, ExprUnary.Op.AFTER.make(o, b)); :}; + +SuperOrBar ::= BAR ExprNoSeq:x {: RESULT=x; :}; +SuperOrBar ::= Super:x {: RESULT=x; :}; +SuperOrBar ::= BAR ExprNoSeq:x TRCSEQ:o Expr:y {: RESULT=ExprBinary.Op.AND.make(o, null, x, ExprUnary.Op.AFTER.make(o, y)); :}; + +Exprs ::= {: RESULT=new ArrayList(); :}; +Exprs ::= Exprp:x {: RESULT=x; :}; +Exprp ::= Expr:x {: RESULT=new ArrayList(); RESULT.add(x); :}; +Exprp ::= Exprp:a COMMA Expr:b {: a.add(b); RESULT=a; :}; + +//============================================================================= + +Expr ::= ExprNoSeq:a {: RESULT=a; :}; +Expr ::= ExprNoSeq:a TRCSEQ:o Expr:b {: RESULT=ExprBinary.Op.AND.make(o, null, a, ExprUnary.Op.AFTER.make(o, b)); :}; + +ExprNoSeq ::= OrExprA:x {: RESULT = x; :}; +ExprNoSeq ::= OrExprB:x {: RESULT = x; :}; +ExprNoSeq ::= Bind:x {: RESULT = x; :}; +Bind ::= LET Let:x {: RESULT = x; :}; +Bind ::= ALL2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.ALL .make(o, null, a, b); :}; +Bind ::= NO2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.NO .make(o, null, a, b); :}; +Bind ::= SOME2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.SOME.make(o, null, a, b); :}; +Bind ::= LONE2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.LONE.make(o, null, a, b); :}; +Bind ::= ONE2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.ONE .make(o, null, a, b); :}; +Bind ::= SUM2:o Declp:a SuperOrBar:b {: RESULT = ExprQt.Op.SUM .make(o, null, a, b); :}; + +OrExprA ::= EquivExprA:a {: RESULT=a; :}; +OrExprA ::= OrExprB:a OR:o Bind:b {: RESULT=ExprBinary.Op.OR.make(o, null, a, b); :}; +OrExprB ::= EquivExprB:b {: RESULT=b; :}; +OrExprB ::= OrExprB:a OR:o EquivExprB:b {: RESULT=ExprBinary.Op.OR.make(o, null, a, b); :}; + +EquivExprA ::= ImpliesExprA:b {: RESULT=b; :}; +EquivExprA ::= EquivExprB:a IFF:o Bind:b {: RESULT=ExprBinary.Op.IFF.make(o, null, a, b); :}; +EquivExprB ::= ImpliesExprB:b {: RESULT=b; :}; +EquivExprB ::= EquivExprB:a IFF:o ImpliesExprB:b {: RESULT=ExprBinary.Op.IFF.make(o, null, a, b); :}; + +ImpliesExprA ::= ImpliesExprCloseA:a {: RESULT=a; :}; +ImpliesExprA ::= ImpliesExprOpenA:a {: RESULT=a; :}; +ImpliesExprCloseA ::= AndExprA:a {: RESULT=a; :}; +ImpliesExprCloseA ::= AndExprB:a IMPLIES:o ImpliesExprCloseB:b ELSE ImpliesExprCloseA:c {: RESULT = ExprITE.make(o,a,b,c); :}; +ImpliesExprOpenA ::= AndExprB:a IMPLIES:o ImpliesExprCloseB:b ELSE ImpliesExprOpenA:c {: RESULT = ExprITE.make(o,a,b,c); :}; +ImpliesExprOpenA ::= AndExprB:a IMPLIES:o ImpliesExprA:b {: RESULT = ExprBinary.Op.IMPLIES.make(o, null, a, b); :}; + +ImpliesExprCloseA ::= AndExprB:a IMPLIES:o ImpliesExprCloseB:b ELSE Bind:c {: RESULT = ExprITE.make(o,a,b,c); :}; +ImpliesExprOpenA ::= AndExprB:a IMPLIES:o Bind:b {: RESULT = ExprBinary.Op.IMPLIES.make(o, null, a, b); :}; + +ImpliesExprB ::= ImpliesExprCloseB:a {: RESULT=a; :}; +ImpliesExprB ::= ImpliesExprOpenB:a {: RESULT=a; :}; +ImpliesExprCloseB ::= AndExprB:a {: RESULT=a; :}; +ImpliesExprCloseB ::= AndExprB:a IMPLIES:o ImpliesExprCloseB:b ELSE ImpliesExprCloseB:c {: RESULT = ExprITE.make(o,a,b,c); :}; +ImpliesExprOpenB ::= AndExprB:a IMPLIES:o ImpliesExprCloseB:b ELSE ImpliesExprOpenB:c {: RESULT = ExprITE.make(o,a,b,c); :}; +ImpliesExprOpenB ::= AndExprB:a IMPLIES:o ImpliesExprB:b {: RESULT = ExprBinary.Op.IMPLIES.make(o, null, a, b); :}; + +AndExprA ::= TempBinaryA:a {: RESULT=a; :}; +AndExprA ::= AndExprB:a AND:o Bind:b {: RESULT=ExprBinary.Op.AND.make(o, null, a, b); :}; +AndExprB ::= TempBinaryB:b {: RESULT=b; :}; +AndExprB ::= AndExprB:a AND:o TempBinaryB:b {: RESULT=ExprBinary.Op.AND.make(o, null, a, b); :}; + +// [electrum] binary temporal formulas, highest precedence among binary operators +TempBinaryA ::= UnaryExprA:a {: RESULT=a; :}; +TempBinaryA ::= TempBinaryB:a UNTIL:o Bind:b {: RESULT=ExprBinary.Op.UNTIL .make(o, null, a, b); :}; +TempBinaryA ::= TempBinaryB:a SINCE:o Bind:b {: RESULT=ExprBinary.Op.SINCE .make(o, null, a, b); :}; +TempBinaryA ::= TempBinaryB:a TRIGGERED:o Bind:b {: RESULT=ExprBinary.Op.TRIGGERED.make(o, null, a, b); :}; +TempBinaryA ::= TempBinaryB:a RELEASES:o Bind:b {: RESULT=ExprBinary.Op.RELEASES .make(o, null, a, b); :}; +TempBinaryB ::= UnaryExprB:b {: RESULT=b; :}; +TempBinaryB ::= TempBinaryB:a UNTIL:o UnaryExprB:b {: RESULT=ExprBinary.Op.UNTIL .make(o, null, a, b); :}; +TempBinaryB ::= TempBinaryB:a SINCE:o UnaryExprB:b {: RESULT=ExprBinary.Op.SINCE .make(o, null, a, b); :}; +TempBinaryB ::= TempBinaryB:a RELEASES:o UnaryExprB:b {: RESULT=ExprBinary.Op.RELEASES .make(o, null, a, b); :}; +TempBinaryB ::= TempBinaryB:a TRIGGERED:o UnaryExprB:b {: RESULT=ExprBinary.Op.TRIGGERED.make(o, null, a, b); :}; + +// [electrum] unary temporal formulas, same precedence as other unary operators +UnaryExprA ::= CompareExprA:b {: RESULT=b; :}; +UnaryExprA ::= NOT:o Bind:b {: RESULT=ExprUnary.Op.NOT.make(o, b); :}; +UnaryExprA ::= NOT:o UnaryExprA:b {: RESULT=ExprUnary.Op.NOT.make(o, b); :}; +UnaryExprA ::= ALWAYS:o Bind:b {: RESULT=ExprUnary.Op.ALWAYS.make(o, b); :}; +UnaryExprA ::= ALWAYS:o UnaryExprA:b {: RESULT=ExprUnary.Op.ALWAYS.make(o, b); :}; +UnaryExprA ::= EVENTUALLY:o Bind:b {: RESULT=ExprUnary.Op.EVENTUALLY.make(o, b); :}; +UnaryExprA ::= EVENTUALLY:o UnaryExprA:b {: RESULT=ExprUnary.Op.EVENTUALLY.make(o, b); :}; +UnaryExprA ::= AFTER:o Bind:b {: RESULT=ExprUnary.Op.AFTER.make(o, b); :}; +UnaryExprA ::= AFTER:o UnaryExprA:b {: RESULT=ExprUnary.Op.AFTER.make(o, b); :}; +UnaryExprA ::= HISTORICALLY:o Bind:b {: RESULT=ExprUnary.Op.HISTORICALLY.make(o, b); :}; +UnaryExprA ::= HISTORICALLY:o UnaryExprA:b {: RESULT=ExprUnary.Op.HISTORICALLY.make(o, b); :}; +UnaryExprA ::= ONCE:o Bind:b {: RESULT=ExprUnary.Op.ONCE.make(o, b); :}; +UnaryExprA ::= ONCE:o UnaryExprA:b {: RESULT=ExprUnary.Op.ONCE.make(o, b); :}; +UnaryExprA ::= BEFORE:o Bind:b {: RESULT=ExprUnary.Op.BEFORE.make(o, b); :}; +UnaryExprA ::= BEFORE:o UnaryExprA:b {: RESULT=ExprUnary.Op.BEFORE.make(o, b); :}; +UnaryExprB ::= CompareExprB:b {: RESULT=b; :}; +UnaryExprB ::= NOT:o UnaryExprB:b {: RESULT=ExprUnary.Op.NOT.make(o, b); :}; +UnaryExprB ::= ALWAYS:o UnaryExprB:b {: RESULT=ExprUnary.Op.ALWAYS.make(o, b); :}; +UnaryExprB ::= EVENTUALLY:o UnaryExprB:b {: RESULT=ExprUnary.Op.EVENTUALLY.make(o, b); :}; +UnaryExprB ::= AFTER:o UnaryExprB:b {: RESULT=ExprUnary.Op.AFTER.make(o, b); :}; +UnaryExprB ::= HISTORICALLY:o UnaryExprB:b {: RESULT=ExprUnary.Op.HISTORICALLY.make(o, b); :}; +UnaryExprB ::= ONCE:o UnaryExprB:b {: RESULT=ExprUnary.Op.ONCE.make(o, b); :}; +UnaryExprB ::= BEFORE:o UnaryExprB:b {: RESULT=ExprUnary.Op.BEFORE.make(o, b); :}; + +CompareExprA ::= CompareExprB:a IN:o ShiftExprA:b {: RESULT=ExprBinary.Op.IN .make(o, null, a, mult(b)); :}; +CompareExprA ::= CompareExprB:a EQUALS:o ShiftExprA:b {: RESULT=ExprBinary.Op.EQUALS .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a LT:o ShiftExprA:b {: RESULT=ExprBinary.Op.LT .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a GT:o ShiftExprA:b {: RESULT=ExprBinary.Op.GT .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a LTE:o ShiftExprA:b {: RESULT=ExprBinary.Op.LTE .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a GTE:o ShiftExprA:b {: RESULT=ExprBinary.Op.GTE .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a NOTIN:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_IN .make(o, null, a, mult(b)); :}; +CompareExprA ::= CompareExprB:a NOTEQUALS:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_EQUALS.make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a NOTLT:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_LT .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a NOTGT:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_GT .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a NOTLTE:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_LTE .make(o, null, a, b); :}; +CompareExprA ::= CompareExprB:a NOTGTE:o ShiftExprA:b {: RESULT=ExprBinary.Op.NOT_GTE .make(o, null, a, b); :}; +CompareExprA ::= ALL:o ShiftExprA {: if (1==1) throw new ErrorSyntax(o,"The \"all x\" construct is no longer supported. If you know the range of possible values of x, consider rewriting it as \"x == set_of_all_possible_values\"."); :}; +CompareExprA ::= NO:o ShiftExprA:b {: RESULT=ExprUnary.Op.NO .make(o, b); :}; +CompareExprA ::= SOME:o ShiftExprA:b {: RESULT=ExprUnary.Op.SOME .make(o, b); :}; +CompareExprA ::= LONE:o ShiftExprA:b {: RESULT=ExprUnary.Op.LONE .make(o, b); :}; +CompareExprA ::= ONE:o ShiftExprA:b {: RESULT=ExprUnary.Op.ONE .make(o, b); :}; +CompareExprA ::= SET:o ShiftExprA:b {: RESULT=ExprUnary.Op.SETOF.make(o, b); :}; +CompareExprA ::= SEQ:o ShiftExprA:b {: RESULT=ExprBinary.Op.ISSEQ_ARROW_LONE.make(o, null, ExprVar.make(o, "seq/Int"), b); parser.dashmodule.addSeq(o); :}; +CompareExprA ::= ShiftExprA:b {: RESULT=b; :}; + +CompareExprB ::= CompareExprB:a IN:o ShiftExprB:b {: RESULT=ExprBinary.Op.IN .make(o, null, a, mult(b)); :}; +CompareExprB ::= CompareExprB:a EQUALS:o ShiftExprB:b {: RESULT=ExprBinary.Op.EQUALS .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a LT:o ShiftExprB:b {: RESULT=ExprBinary.Op.LT .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a GT:o ShiftExprB:b {: RESULT=ExprBinary.Op.GT .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a LTE:o ShiftExprB:b {: RESULT=ExprBinary.Op.LTE .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a GTE:o ShiftExprB:b {: RESULT=ExprBinary.Op.GTE .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a NOTIN:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_IN .make(o, null, a, mult(b)); :}; +CompareExprB ::= CompareExprB:a NOTEQUALS:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_EQUALS.make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a NOTLT:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_LT .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a NOTGT:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_GT .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a NOTLTE:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_LTE .make(o, null, a, b); :}; +CompareExprB ::= CompareExprB:a NOTGTE:o ShiftExprB:b {: RESULT=ExprBinary.Op.NOT_GTE .make(o, null, a, b); :}; +CompareExprB ::= ALL:o ShiftExprB {: if (1==1) throw new ErrorSyntax(o,"The \"all x\" construct is no longer supported. If you know the range of possible values of x, consider rewriting it as \"x == set_of_all_possible_values\"."); :}; +CompareExprB ::= NO:o ShiftExprB:b {: RESULT=ExprUnary.Op.NO .make(o, b); :}; +CompareExprB ::= SOME:o ShiftExprB:b {: RESULT=ExprUnary.Op.SOME .make(o, b); :}; +CompareExprB ::= LONE:o ShiftExprB:b {: RESULT=ExprUnary.Op.LONE .make(o, b); :}; +CompareExprB ::= ONE:o ShiftExprB:b {: RESULT=ExprUnary.Op.ONE .make(o, b); :}; +CompareExprB ::= SET:o ShiftExprB:b {: RESULT=ExprUnary.Op.SETOF.make(o, b); :}; +CompareExprB ::= SEQ:o ShiftExprB:b {: RESULT=ExprBinary.Op.ISSEQ_ARROW_LONE.make(o, null, ExprVar.make(o,"seq/Int"), b); parser.dashmodule.addSeq(o); :}; +CompareExprB ::= ShiftExprB:b {: RESULT=b; :}; + +ShiftExprA ::= UnionDiffExprA:b {: RESULT=b; :}; +ShiftExprA ::= ShiftExprB:a SHL:o Bind:b {: RESULT=ExprBinary.Op.SHL.make(o, null, a, b); :}; +ShiftExprA ::= ShiftExprB:a SHR:o Bind:b {: RESULT=ExprBinary.Op.SHR.make(o, null, a, b); :}; +ShiftExprA ::= ShiftExprB:a SHA:o Bind:b {: RESULT=ExprBinary.Op.SHA.make(o, null, a, b); :}; +ShiftExprB ::= UnionDiffExprB:b {: RESULT=b; :}; +ShiftExprB ::= ShiftExprB:a SHL:o UnionDiffExprB:b {: RESULT=ExprBinary.Op.SHL.make(o, null, a, b); :}; +ShiftExprB ::= ShiftExprB:a SHR:o UnionDiffExprB:b {: RESULT=ExprBinary.Op.SHR.make(o, null, a, b); :}; +ShiftExprB ::= ShiftExprB:a SHA:o UnionDiffExprB:b {: RESULT=ExprBinary.Op.SHA.make(o, null, a, b); :}; + +UnionDiffExprA ::= MulExprA:b {: RESULT=b; :}; +UnionDiffExprA ::= UnionDiffExprB:a PLUS:o Bind:b {: RESULT=ExprBinary.Op.PLUS .make(o, null, a, b); :}; +UnionDiffExprA ::= UnionDiffExprB:a MINUS:o Bind:b {: RESULT=ExprBinary.Op.MINUS.make(o, null, a, b); :}; +UnionDiffExprA ::= UnionDiffExprB:a INTADD:o Bind:b {: RESULT=ExprBinary.Op.IPLUS.make(o, null, a, b); :}; +UnionDiffExprA ::= UnionDiffExprB:a INTSUB:o Bind:b {: RESULT=ExprBinary.Op.IMINUS.make(o, null, a, b); :}; +UnionDiffExprB ::= MulExprB:b {: RESULT=b; :}; +UnionDiffExprB ::= UnionDiffExprB:a PLUS:o MulExprB:b {: RESULT=ExprBinary.Op.PLUS .make(o, null, a, b); :}; +UnionDiffExprB ::= UnionDiffExprB:a MINUS:o MulExprB:b {: RESULT=ExprBinary.Op.MINUS.make(o, null, a, b); :}; +UnionDiffExprB ::= UnionDiffExprB:a INTADD:o MulExprB:b {: RESULT=ExprBinary.Op.IPLUS.make(o, null, a, b); :}; +UnionDiffExprB ::= UnionDiffExprB:a INTSUB:o MulExprB:b {: RESULT=ExprBinary.Op.IMINUS.make(o, null, a, b); :}; + +MulExprA ::= NumUnopExprA:b {: RESULT=b; :}; +MulExprA ::= MulExprB:a INTMUL:o Bind:b {: RESULT=ExprBinary.Op.MUL .make(o, null, a, b); :}; +MulExprA ::= MulExprB:a INTDIV:o Bind:b {: RESULT=ExprBinary.Op.DIV .make(o, null, a, b); :}; +MulExprA ::= MulExprB:a INTREM:o Bind:b {: RESULT=ExprBinary.Op.REM .make(o, null, a, b); :}; +MulExprB ::= NumUnopExprB:b {: RESULT=b; :}; +MulExprB ::= MulExprB:a INTMUL:o NumUnopExprB:b {: RESULT=ExprBinary.Op.MUL .make(o, null, a, b); :}; +MulExprB ::= MulExprB:a INTDIV:o NumUnopExprB:b {: RESULT=ExprBinary.Op.DIV .make(o, null, a, b); :}; +MulExprB ::= MulExprB:a INTREM:o NumUnopExprB:b {: RESULT=ExprBinary.Op.REM .make(o, null, a, b); :}; + +NumUnopExprA ::= OverrideExprA:b {: RESULT=b; :}; +NumUnopExprA ::= HASH:o Bind:b {: RESULT=ExprUnary.Op.CARDINALITY.make(o, b); :}; +NumUnopExprA ::= SUM:o Bind:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; +//[AM]: INT->SIGINT +NumUnopExprA ::= INT:o Bind:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; +NumUnopExprA ::= HASH:o NumUnopExprA:b {: RESULT=ExprUnary.Op.CARDINALITY.make(o, b); :}; +NumUnopExprA ::= SUM:o NumUnopExprA:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; +//[AM]: INT->SIGINT +NumUnopExprA ::= INT:o NumUnopExprA:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; +NumUnopExprB ::= OverrideExprB:b {: RESULT=b; :}; +NumUnopExprB ::= HASH:o NumUnopExprB:b {: RESULT=ExprUnary.Op.CARDINALITY.make(o, b); :}; +NumUnopExprB ::= SUM:o NumUnopExprB:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; +//[AM]: INT->SIGINT +NumUnopExprB ::= INT:o NumUnopExprB:b {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, b)); :}; + +OverrideExprA ::= IntersectExprA:b {: RESULT=b; :}; +OverrideExprA ::= OverrideExprB:a PLUSPLUS:o Bind:b {: RESULT=ExprBinary.Op.PLUSPLUS.make(o, null, a, b); :}; +OverrideExprB ::= IntersectExprB:b {: RESULT=b; :}; +OverrideExprB ::= OverrideExprB:a PLUSPLUS:o IntersectExprB:b {: RESULT=ExprBinary.Op.PLUSPLUS.make(o, null, a, b); :}; + +IntersectExprA ::= RelationExprA:b {: RESULT=b; :}; +IntersectExprA ::= IntersectExprB:a AMPERSAND:o Bind:b {: RESULT=ExprBinary.Op.INTERSECT.make(o, null, a, b); :}; +IntersectExprB ::= RelationExprB:b {: RESULT=b; :}; +IntersectExprB ::= IntersectExprB:a AMPERSAND:o RelationExprB:b {: RESULT=ExprBinary.Op.INTERSECT.make(o, null, a, b); :}; + +RelOp ::= ARROW:o {: RESULT=new Pair(o, ExprBinary.Op.ARROW ); :}; +RelOp ::= ANY_ARROW_SOME:o {: RESULT=new Pair(o, ExprBinary.Op.ANY_ARROW_SOME ); :}; +RelOp ::= ANY_ARROW_ONE:o {: RESULT=new Pair(o, ExprBinary.Op.ANY_ARROW_ONE ); :}; +RelOp ::= ANY_ARROW_LONE:o {: RESULT=new Pair(o, ExprBinary.Op.ANY_ARROW_LONE ); :}; +RelOp ::= SOME_ARROW_ANY:o {: RESULT=new Pair(o, ExprBinary.Op.SOME_ARROW_ANY ); :}; +RelOp ::= SOME_ARROW_SOME:o {: RESULT=new Pair(o, ExprBinary.Op.SOME_ARROW_SOME); :}; +RelOp ::= SOME_ARROW_ONE:o {: RESULT=new Pair(o, ExprBinary.Op.SOME_ARROW_ONE ); :}; +RelOp ::= SOME_ARROW_LONE:o {: RESULT=new Pair(o, ExprBinary.Op.SOME_ARROW_LONE); :}; +RelOp ::= ONE_ARROW_ANY:o {: RESULT=new Pair(o, ExprBinary.Op.ONE_ARROW_ANY ); :}; +RelOp ::= ONE_ARROW_SOME:o {: RESULT=new Pair(o, ExprBinary.Op.ONE_ARROW_SOME ); :}; +RelOp ::= ONE_ARROW_ONE:o {: RESULT=new Pair(o, ExprBinary.Op.ONE_ARROW_ONE ); :}; +RelOp ::= ONE_ARROW_LONE:o {: RESULT=new Pair(o, ExprBinary.Op.ONE_ARROW_LONE ); :}; +RelOp ::= LONE_ARROW_ANY:o {: RESULT=new Pair(o, ExprBinary.Op.LONE_ARROW_ANY ); :}; +RelOp ::= LONE_ARROW_SOME:o {: RESULT=new Pair(o, ExprBinary.Op.LONE_ARROW_SOME); :}; +RelOp ::= LONE_ARROW_ONE:o {: RESULT=new Pair(o, ExprBinary.Op.LONE_ARROW_ONE ); :}; +RelOp ::= LONE_ARROW_LONE:o {: RESULT=new Pair(o, ExprBinary.Op.LONE_ARROW_LONE); :}; + +RelationExprA ::= DomainExprA:a {: RESULT=a; :}; +RelationExprA ::= DomainExprB:a RelOp:o Bind:b {: RESULT=o.b.make(o.a, null, a, b); :}; +RelationExprB ::= DomainExprB:a {: RESULT=a; :}; +RelationExprB ::= DomainExprB:a RelOp:o RelationExprB:b {: RESULT=o.b.make(o.a, null, a, b); :}; + +DomainExprA ::= RangeExprA:b {: RESULT=b; :}; +DomainExprA ::= DomainExprB:a DOMAIN:o Bind:b {: RESULT=ExprBinary.Op.DOMAIN.make(o, null, a, b); :}; +DomainExprB ::= RangeExprB:b {: RESULT=b; :}; +DomainExprB ::= DomainExprB:a DOMAIN:o RangeExprB:b {: RESULT=ExprBinary.Op.DOMAIN.make(o, null, a, b); :}; + +RangeExprA ::= BracketExprA:b {: RESULT=b; :}; +RangeExprA ::= RangeExprB:a RANGE:o Bind:b {: RESULT=ExprBinary.Op.RANGE.make(o, null, a, b); :}; +RangeExprB ::= BracketExprB:b {: RESULT=b; :}; +RangeExprB ::= RangeExprB:a RANGE:o BracketExprB:b {: RESULT=ExprBinary.Op.RANGE.make(o, null, a, b); :}; + +BracketExprA ::= DotExprA:b {: RESULT=b; :}; +BracketExprB ::= DotExprB:b {: RESULT=b; :}; +BracketExprB ::= BracketExprB:a LBRACKET Exprs:b RBRACKET:c {: Expr aa=a; for(Expr bb:b) aa=t(aa.span().merge(bb.span()), c, bb, aa, c); RESULT=aa; :}; +BracketExprB ::= DISJ:a LBRACKET Exprs:b RBRACKET:c {: Expr aa=ExprVar.make(a, "disj"); for(Expr bb:b) aa=t(aa.span().merge(bb.span()), c, bb, aa, c); RESULT=aa; :}; +BracketExprB ::= TOTALORDER:a LBRACKET Exprs:b RBRACKET:c {: Expr aa=ExprVar.make(a, "pred/totalOrder"); for(Expr bb:b) aa=t(aa.span().merge(bb.span()), c, bb, aa, c); RESULT=aa; :}; +//[AM]: INT->SIGINT +BracketExprB ::= INT:a LBRACKET Exprs:b RBRACKET:c {: Expr aa=ExprVar.make(a, "int"); for(Expr bb:b) aa=t(aa.span().merge(bb.span()), c, bb, aa, c); RESULT=ExprUnary.Op.CAST2SIGINT.make(a, aa); :}; +BracketExprB ::= SUM:a LBRACKET Exprs:b RBRACKET:c {: Expr aa=ExprVar.make(a, "int"); for(Expr bb:b) aa=t(aa.span().merge(bb.span()), c, bb, aa, c); RESULT=ExprUnary.Op.CAST2SIGINT.make(a, aa); :}; + +DotExprA ::= UnopExprA:b {: RESULT=b; :}; +DotExprA ::= BracketExprB:a DOT:o Bind:b {: RESULT=t(o, null, a, b, null); :}; +DotExprB ::= UnopExprB:b {: RESULT=b; :}; +DotExprB ::= BracketExprB:a DOT:o UnopExprB:b {: RESULT=t(o, null, a, b, null); :}; +DotExprB ::= BracketExprB:a DOT:o DISJ:b {: RESULT=t(o, null, a, ExprVar.make(b, "disj"), null); :}; +DotExprB ::= BracketExprB:a DOT:o TOTALORDER:b {: RESULT=t(o, null, a, ExprVar.make(b, "pred/totalOrder"), null); :}; +//[AM]: INT->SIGINT +DotExprB ::= BracketExprB:a DOT:o INT {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, a)); :}; +DotExprB ::= BracketExprB:a DOT:o SUM {: RESULT=ExprUnary.Op.CAST2SIGINT.make(o, ExprUnary.Op.CAST2INT.make(o, a)); :}; + +// [electrum] unary temporal expressions, same precedence as other unary operators +UnopExprA ::= TILDE:o Bind:b {: RESULT=ExprUnary.Op.TRANSPOSE.make(o,b); :}; +UnopExprA ::= STAR:o Bind:b {: RESULT=ExprUnary.Op.RCLOSURE .make(o,b); :}; +UnopExprA ::= CARET:o Bind:b {: RESULT=ExprUnary.Op.CLOSURE .make(o,b); :}; +UnopExprA ::= TILDE:o UnopExprA:b {: RESULT=ExprUnary.Op.TRANSPOSE.make(o,b); :}; +UnopExprA ::= STAR:o UnopExprA:b {: RESULT=ExprUnary.Op.RCLOSURE .make(o,b); :}; +UnopExprA ::= CARET:o UnopExprA:b {: RESULT=ExprUnary.Op.CLOSURE .make(o,b); :}; +UnopExprB ::= BaseExpr:b {: RESULT=b; :}; +UnopExprB ::= TILDE:o UnopExprB:b {: RESULT=ExprUnary.Op.TRANSPOSE.make(o,b); :}; +UnopExprB ::= STAR:o UnopExprB:b {: RESULT=ExprUnary.Op.RCLOSURE .make(o,b); :}; +UnopExprB ::= CARET:o UnopExprB:b {: RESULT=ExprUnary.Op.CLOSURE .make(o,b); :}; +UnopExprA ::= Bind:b PRIME:o {: RESULT=ExprUnary.Op.PRIME .make(o,b); :}; +UnopExprA ::= UnopExprA:b PRIME:o {: RESULT=ExprUnary.Op.PRIME .make(o,b); :}; +UnopExprB ::= UnopExprB:b PRIME:o {: RESULT=ExprUnary.Op.PRIME .make(o,b); :}; + +BaseExpr ::= NUMBER:x {: RESULT = x; :}; +BaseExpr ::= STR:x {: RESULT = x; :}; +BaseExpr ::= IDEN:o {: RESULT = ExprVar.make(o, "iden"); :}; +BaseExpr ::= THIS:o {: RESULT = ExprVar.make(o, "this"); :}; +BaseExpr ::= INTMIN:o {: RESULT = ExprConstant.Op.MIN.make(o, 0); :}; +BaseExpr ::= INTMAX:o {: RESULT = ExprConstant.Op.MAX.make(o, 0); :}; +BaseExpr ::= INTNEXT:o {: RESULT = ExprConstant.Op.NEXT.make(o, 0); :}; +BaseExpr ::= LPAREN Expr:x RPAREN {: RESULT = x; :}; +BaseExpr ::= SigRef:x {: RESULT = x; :}; +BaseExpr ::= AT:o Name:x {: nod(x); RESULT = ExprVar.make(o.merge(x.pos), "@"+x.label); :}; +BaseExpr ::= Super:x {: RESULT = x; :}; +BaseExpr ::= LBRACE:o Declz:a SuperOrBar:b RBRACE:c {: RESULT = ExprQt.Op.COMPREHENSION.make(o, c, a, b); :}; +BaseExpr ::= LBRACE:o Declz:a RBRACE:c {: RESULT = ExprQt.Op.COMPREHENSION.make(o, c, a, ExprConstant.TRUE); :}; + +//============================================================================= + + +//DASH grammar ------------------------------------------------------------------------ + +// besides creating a DashState; the parsing also has count buffers and create indexes +// for those buffers in order to have the correct open statements + +// a few Dash errors here + +// adding a case for the Spec +Spec ::= Spec StateRoot:o ; + +// Root State Declaration +StateRoot ::= STATE:o Name:n LBRACE RBRACE:e // empty state + {: + // first line in file is line 1 + parser.dashmodule.rootStartLine = o.y; + parser.dashmodule.rootEndLine = e.y; + parser.dashmodule.addRoot( + new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates())); + :}; +StateRoot ::= STATE:o Name:n LBRACE StateItemList:c RBRACE:e + {: + parser.dashmodule.rootStartLine = o.y; + parser.dashmodule.rootEndLine = e.y; + parser.dashmodule.addRoot( + new DashState(o, + n.label, + null, + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + c)); + :}; + +StateItemList ::= StateItem:x + {: List xList = new ArrayList(); xList.add(x); RESULT= xList; :}; +StateItemList ::= StateItemList:c StateItem:s + {: c.add(s); RESULT = c; :}; + +// or-state, non-default, empty +StateItem ::= STATE:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates() ); + :}; + +// or-state, non-default, substates +StateItem ::= STATE:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// or-state, default, empty state +StateItem ::= DEF STATE:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates()); + :}; + +// or-state, default, substates +StateItem ::= DEF STATE:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.OR, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// conc state, non-default, empty +StateItem ::= CONC:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates()); + :}; + +// conc state, non-default, substates +StateItem ::= CONC:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// conc state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates() ); + :}; + +// conc state, default, substates +StateItem ::= DEF CONC:o Name:n LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + DashState.noParam(), + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// parametrized state, non-default, empty +StateItem ::= CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + DashState.noSubstates()); + :}; + +// parametrized state, non-default, substates +StateItem ::= CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.NOTDEFAULT, + c); + :}; + +// parametrized state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + DashState.noSubstates()); + :}; + +// parametrized state, default, empty +StateItem ::= DEF CONC:o Name:n LBRACKET Name:m RBRACKET LBRACE StateItemList:c RBRACE + {: RESULT = new DashState(o, + n.label, + m.label, + DashStrings.StateKind.AND, + DashStrings.DefKind.DEFAULT, + c); + :}; + +// event decls +StateItem ::= EVENT:o Names:n LBRACE RBRACE + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashEventDecls(o, ll, DashStrings.IntEnvKind.INT); :}; +StateItem ::= ENV EVENT:o Names:n LBRACE RBRACE + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashEventDecls(o, ll, DashStrings.IntEnvKind.ENV); :}; + +// var decls +StateItem ::= + // we don't support the full variations of declarations here + // don't know what the pos should be for this one + Names:n COLON:o Expr:b + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashVarDecls(o, ll ,b, DashStrings.IntEnvKind.INT); :}; +StateItem ::= ENV:o Names:n COLON Expr:b + {: ArrayList ll = new ArrayList(); + for (ExprVar x: n) ll.add(x.label); + RESULT = new DashVarDecls(o, ll, b, DashStrings.IntEnvKind.ENV); :}; + +//buffer decls +//we have to know the number of buffers for the open statements, +//which have to be loaded at the beginning of parsing +//Soln: parse twice +//first time stores buffer names, element types in DashSituation +//second time includes the appropriate opens (based on values in DashSituation) +//when do new DashModule() before start parsing +//collection here is the same regardless of parsing pass +StateItem ::= Names:n COLON:o BUF LBRACKET Name:m RBRACKET + {: + ArrayList ll = new ArrayList(); + Integer startIndex = DashSituation.bufferIndex; + for (ExprVar x: n) { + ll.add(x.label); + // it will do this the same way both passes through parsing + DashSituation.bufferElements.add(m.label); + DashSituation.bufferNames.add(x.label); + DashSituation.bufferIndex++; + } + // endIndex is inclusive + Integer endIndex = DashSituation.bufferIndex - 1; + RESULT = new DashBufferDecls(o, ll, m.label, DashStrings.IntEnvKind.INT, startIndex, endIndex); + :}; +StateItem ::= Names:n COLON:o BUF LBRACKET SIGINT RBRACKET + {: + ArrayList ll = new ArrayList(); + Integer startIndex = DashSituation.bufferIndex; + for (ExprVar x: n) { + ll.add(x.label); + // it will do this the same way both passes through parsing + DashSituation.bufferElements.add(DashStrings.intName); + DashSituation.bufferNames.add(x.label); + DashSituation.bufferIndex++; + } + // endIndex is inclusive + Integer endIndex = DashSituation.bufferIndex - 1; + RESULT = new DashBufferDecls(o, ll, DashStrings.intName, DashStrings.IntEnvKind.INT, startIndex, endIndex); + :}; + +// init +// Super is a list of expressions joined by conjunction +StateItem ::= INIT:o Super:v + {: RESULT = new DashInit(o, v); :}; + +// invariant +StateItem ::= INVARIANT:o Super:v + {: RESULT = new DashInv(o, v); :}; + +// invariant +StateItem ::= INVARIANT:o Name: n Super:v + {: RESULT = new DashInv(o, n.label, v); :}; + +// entered +StateItem ::= ENTER:o Super:v + {: RESULT = new DashEntered(o, v); :}; + +// exited +StateItem ::= EXIT:o Super:v + {: RESULT = new DashExited(o, v); :}; + +//StateItem ::= INVARIANT:o Name:n Super:v +// {: RESULT = new DashInv(o, n.label, v); :}; + +// action +//StateItem ::= ACTION:o Name:n LBRACKET Expr:e RBRACKET LBRACE RBRACE +// {: RESULT = new DashAction(o, n.label, e); :}; + +// condition +//StateItem ::= CONDITION:o Name:n LBRACKET Expr:e RBRACKET LBRACE RBRACE +// {: RESULT = new DashCondition(o, n.label, e); :}; + +// named expression +StateItem ::= PRED:o Name:n LBRACE Expr:e RBRACE + {: RESULT = new DashPred(o, n.label, e); :}; + +// transition +StateItem ::= TRANS:o Name:n LBRACE TransItemList:c RBRACE + {: RESULT = new DashTrans(o, n.label, c); :}; +// transition +StateItem ::= TRANS:o Name:n LBRACE RBRACE + {: RESULT = new DashTrans(o, n.label, new ArrayList()); :}; + +TransItemList ::= TransItem:x + {: RESULT = new ArrayList(); RESULT.add(x); :}; +TransItemList ::= TransItemList:c TransItem:x + {: c.add(x); RESULT = c; :}; + +//Exprp is non-empty list of comma-separated Expr +//Exprs could be empty ist of comma-separated Expr + +// src/dest --------------------- +TransItem ::= FROM:o Name:n + {: RESULT = new DashFrom(o, DashRef.createStateDashRef(o, n.label,DashRef.emptyParamValuesList())); :}; + +TransItem ::= FROM Name:n LBRACKET:o Exprp:e RBRACKET + {: RESULT = new DashFrom(o, DashRef.createStateDashRef(o,n.label,e)); :}; + +TransItem ::= GOTO:o Name:n + {: RESULT = new DashGoto(o, DashRef.createStateDashRef(o,n.label,DashRef.emptyParamValuesList())); :}; + +TransItem ::= GOTO Name:n LBRACKET:o Exprp:e RBRACKET + {: RESULT = new DashGoto(o, DashRef.createStateDashRef(o, n.label,e)); :}; + +// events A/B[a1]/ev1 --------------------------- + +TransItem ::= ON:o Name:n + {: RESULT = new DashOn(o, DashRef.createEventDashRef(o, n.label,DashRef.emptyParamValuesList()) ); :}; + +TransItem ::= ON Name:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: RESULT = new DashOn(o, DashRef.createEventDashRef(o, a.toString() + '/' + e.label, b)); :}; + +TransItem ::= SEND:o Name:n + {: RESULT = new DashSend(o, DashRef.createEventDashRef(o, n.label,DashRef.emptyParamValuesList()) ); :}; + +TransItem ::= SEND Name:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: RESULT = new DashSend(o, DashRef.createEventDashRef(o, a.toString() + '/' + e.label, DashRef.emptyParamValuesList()) ); :}; + + +// actions/guards +TransItem ::= WHEN:o Expr:v + {: RESULT = new DashWhen(o, v); :}; + +TransItem ::= DO:o Expr:v + {: RESULT = new DashDo(o, v); :}; + +// DASH PLUS REFERENCE +// in Alloy can't have a "/Variable" in the following as a regular +// expression so we need more syntax +// and this distinguishes it from other Alloy expressions +// A/B/C[ParamValue1, ParamValue2]/Variable +// note PRIME is a special token in grammar and we want to support v' + +BracketExprB ::= BracketExprB:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e + {: + // have to find the error here + // because if put Name:a in rule above, get shift/reduce conflict + // and DashRef expects a String + if (!ExprHelper.isExprVar(a)) DashErrors.notVarBeforeDashRef(o,a.toString()); + else { + String r = a.toString() + '/' + e.label; + RESULT = DashRef.createVarDashRef(o, r, b); + } + :}; +BracketExprB ::= BracketExprB:a LBRACKET:o Exprs:b RBRACKET SLASH Name:e PRIME + {: + if (!ExprHelper.isExprVar(a)) DashErrors.notVarBeforeDashRef(o,a.toString()); + else { + String r = a.toString() + '/' + e.label + "'"; + RESULT = DashRef.createVarDashRef(o,r, b); + } + :}; + +//DASH end grammar --------------------------------------------------------------------- + diff --git a/org.alloytools.alloy.dash/parser/Dash.lex b/org.alloytools.alloy.dash/parser/Dash.lex new file mode 100644 index 000000000..36be89477 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/Dash.lex @@ -0,0 +1,295 @@ +/* + * DO NOT EDIT THIS FILE + * DASH: file copied from Alloy src with replacements for Dash - see install-alloy-files.sh + */ + + +// Alloy Analyzer 4 -- Copyright (c) 2006-2008, Felix Chang +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package ca.uwaterloo.watform.parser; + +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Version; +import edu.mit.csail.sdg.ast.ExprConstant; +import edu.mit.csail.sdg.ast.ExprVar; +import java.util.List; +import java_cup.runtime.*; +import edu.mit.csail.sdg.parser.CompModule; + + +/** Autogenerated by JFlex 1.4.1 */ + +// @modified [electrum] added temporal keywords and operators (single quotes also +// interpreted as primes); forbade primes in identifiers + +%% + +// There are 3 sets of "special tokens" that the lexer will not output. +// But the Parser expects them. +// So a special Filter class is written that sits between Lexer and Parser. +// The Filter class observes the stream of tokens, and intelligently +// merges or changes some primitive tokens into special tokens. +// For more details, refer to the main documentation. +// +// But, very briefly, here are the 3 groups: +// +// (1) The lexer will generate only ALL, NO, LONE, ONE, SUM, SOME. +// It will not output ALL2, NO2, LONE2, ONE2, SUM2, SOME2. +// (The Filter class will change some ONE into ONE2, etc) +// +// (2) The lexer won't output NOTEQUALS, NOTIN, NOTLT, NOTLTE, NOTGT, NOTGTE. +// Instead it outputs them as separate tokens (eg. "NOT" "EQUALS"). +// (The Filter class is used to merge them into a single "NOTEQUALS" token) +// +// (3) The lexer willn't output the 15 special arrows (eg. ONE_ARROW_ONE) +// Instead it outputs them as separate tokens (eg. "ONE", "ARROW", "ONE") +// (The Filter class is used to merge them into a single "ONE_ARROW_ONE" token) + +%class DashLexer // The ordering of these directives is important +%cupsym DashSym +%cup +%eofval{ + return new Symbol(DashSym.EOF, alloy_here(" "), alloy_here(" ")); +%eofval} +%public +%final +%unicode +%line +%column +%pack + +%{ + public String alloy_filename=""; + public int alloy_lineoffset=0; // If not zero, it is added to the current LINE NUMBER + public List alloy_seenDollar; + public CompModule alloy_module; + private final Pos alloy_here(String txt) { + return new Pos(alloy_filename,yycolumn+1,yyline+1+alloy_lineoffset,yycolumn+txt.length(),yyline+1); + } + private final Symbol alloy_sym(String txt, int type) { + Pos p = alloy_here(txt); return new Symbol(type, p, p); + } + private final Symbol alloy_string(String txt) throws Err { + Pos p = alloy_here(txt); + if (!Version.experimental) throw new ErrorSyntax(p, "String literal is not currently supported."); + StringBuilder sb = new StringBuilder(txt.length()); + for(int i=0; i=txt.length()) throw new ErrorSyntax(p, "String literal cannot end with a single \\"); + c = txt.charAt(i); + if (c=='n') c='\n'; else if (c!='\"' && c!='\\') throw new ErrorSyntax(p, "String literal currently only supports\nthree escape sequences: \\\\, \\n, and \\\""); + } + sb.append(c); + } + txt = sb.toString(); + if (txt.length()==2) throw new ErrorSyntax(p, "Empty string is not allowed; try rewriting your model to use an empty set instead."); + return new Symbol(DashSym.STR, p, ExprConstant.Op.STRING.make(p, txt)); + } + private final Symbol alloy_id(String txt) throws Err { + Pos p=alloy_here(txt); + if (alloy_seenDollar.size()==0 && txt.indexOf('$')>=0) alloy_seenDollar.add(null); + return new Symbol(DashSym.ID, p, ExprVar.make(p,txt)); + } + private final Symbol alloy_num(String txt) throws Err { + Pos p=alloy_here(txt); + int n=0; + try { + txt = txt.replaceAll("_",""); + n=Integer.parseInt(txt); + } catch(NumberFormatException ex) { + throw new ErrorSyntax(p, "The number "+txt+" " + ex); + } + return new Symbol(DashSym.NUMBER, p, ExprConstant.Op.NUMBER.make(p, n)); + } + private final Symbol alloy_hexnum(String txt) throws Err { + Pos p=alloy_here(txt); + int n=0; + try { + txt = txt.substring(2).replaceAll("_",""); + n=Integer.parseInt(txt, 16); + } catch(NumberFormatException ex) { + throw new ErrorSyntax(p, "The hex number "+txt+" " + ex); + } + return new Symbol(DashSym.NUMBER, p, ExprConstant.Op.NUMBER.make(p, n)); + } + private final Symbol alloy_binarynum(String txt) throws Err { + Pos p=alloy_here(txt); + int n=0; + try { + txt = txt.substring(2).replaceAll("_",""); + n=Integer.parseInt(txt, 2); + } catch(NumberFormatException ex) { + throw new ErrorSyntax(p, "The binary number "+txt+" " + ex); + } + return new Symbol(DashSym.NUMBER, p, ExprConstant.Op.NUMBER.make(p, n)); + } +%} + +%% + +"!" { return alloy_sym(yytext(), DashSym.NOT );} +"#" { return alloy_sym(yytext(), DashSym.HASH );} +"&&" { return alloy_sym(yytext(), DashSym.AND );} +"&" { return alloy_sym(yytext(), DashSym.AMPERSAND );} +"(" { return alloy_sym(yytext(), DashSym.LPAREN );} +")" { return alloy_sym(yytext(), DashSym.RPAREN );} +"*" { return alloy_sym(yytext(), DashSym.STAR );} +"++" { return alloy_sym(yytext(), DashSym.PLUSPLUS );} +"+" { return alloy_sym(yytext(), DashSym.PLUS );} +"," { return alloy_sym(yytext(), DashSym.COMMA );} +"->" { return alloy_sym(yytext(), DashSym.ARROW );} +"-" { return alloy_sym(yytext(), DashSym.MINUS );} +"." { return alloy_sym(yytext(), DashSym.DOT );} +"/" { return alloy_sym(yytext(), DashSym.SLASH );} +"::" { return alloy_sym(yytext(), DashSym.DOT );} +":>" { return alloy_sym(yytext(), DashSym.RANGE );} +":" { return alloy_sym(yytext(), DashSym.COLON );} +"<=>" { return alloy_sym(yytext(), DashSym.IFF );} +"<=" { return alloy_sym(yytext(), DashSym.LTE );} +"<:" { return alloy_sym(yytext(), DashSym.DOMAIN );} +"<<" { return alloy_sym(yytext(), DashSym.SHL );} +"<" { return alloy_sym(yytext(), DashSym.LT );} +"=<" { return alloy_sym(yytext(), DashSym.LTE );} +"=>" { return alloy_sym(yytext(), DashSym.IMPLIES );} +"=" { return alloy_sym(yytext(), DashSym.EQUALS );} +">>>" { return alloy_sym(yytext(), DashSym.SHR );} +">>" { return alloy_sym(yytext(), DashSym.SHA );} +">=" { return alloy_sym(yytext(), DashSym.GTE );} +">" { return alloy_sym(yytext(), DashSym.GT );} +"@" { return alloy_sym(yytext(), DashSym.AT );} +"[" { return alloy_sym(yytext(), DashSym.LBRACKET );} +"]" { return alloy_sym(yytext(), DashSym.RBRACKET );} +"^" { return alloy_sym(yytext(), DashSym.CARET );} +"{" { return alloy_sym(yytext(), DashSym.LBRACE );} +"||" { return alloy_sym(yytext(), DashSym.OR );} +"|" { return alloy_sym(yytext(), DashSym.BAR );} +"}" { return alloy_sym(yytext(), DashSym.RBRACE );} +"~" { return alloy_sym(yytext(), DashSym.TILDE );} +"abstract" { return alloy_sym(yytext(), DashSym.ABSTRACT );} +"all" { return alloy_sym(yytext(), DashSym.ALL );} +"and" { return alloy_sym(yytext(), DashSym.AND );} +"assert" { return alloy_sym(yytext(), DashSym.ASSERT );} +"as" { return alloy_sym(yytext(), DashSym.AS );} +"but" { return alloy_sym(yytext(), DashSym.BUT );} +"check" { return alloy_sym(yytext(), DashSym.CHECK );} +"disjoint" { return alloy_sym(yytext(), DashSym.DISJ );} +"disj" { return alloy_sym(yytext(), DashSym.DISJ );} +"else" { return alloy_sym(yytext(), DashSym.ELSE );} +"enum" { return alloy_sym(yytext(), DashSym.ENUM );} +"exactly" { return alloy_sym(yytext(), DashSym.EXACTLY );} +"expect" { return alloy_sym(yytext(), DashSym.EXPECT );} +"extends" { return alloy_sym(yytext(), DashSym.EXTENDS );} +"fact" { return alloy_sym(yytext(), DashSym.FACT );} +"for" { return alloy_sym(yytext(), DashSym.FOR );} +"fun" { return alloy_sym(yytext(), DashSym.FUN );} +"iden" { return alloy_sym(yytext(), DashSym.IDEN );} +"iff" { return alloy_sym(yytext(), DashSym.IFF );} +"implies" { return alloy_sym(yytext(), DashSym.IMPLIES );} +"Int" { return alloy_sym(yytext(), DashSym.SIGINT );} +"int" { return alloy_sym(yytext(), DashSym.INT );} +"in" { return alloy_sym(yytext(), DashSym.IN );} +"let" { return alloy_sym(yytext(), DashSym.LET );} +"lone" { return alloy_sym(yytext(), DashSym.LONE );} +"module" { return alloy_sym(yytext(), DashSym.MODULE );} +"none" { return alloy_sym(yytext(), DashSym.NONE );} +"not" { return alloy_sym(yytext(), DashSym.NOT );} +"no" { return alloy_sym(yytext(), DashSym.NO );} +"one" { return alloy_sym(yytext(), DashSym.ONE );} +"open" { return alloy_sym(yytext(), DashSym.OPEN );} +"or" { return alloy_sym(yytext(), DashSym.OR );} +"pred" { return alloy_sym(yytext(), DashSym.PRED );} +"private" { return alloy_sym(yytext(), DashSym.PRIVATE );} +"run" { return alloy_sym(yytext(), DashSym.RUN );} +"seq" { return alloy_sym(yytext(), DashSym.SEQ );} +"set" { return alloy_sym(yytext(), DashSym.SET );} +"sig" { return alloy_sym(yytext(), DashSym.SIG );} +"some" { return alloy_sym(yytext(), DashSym.SOME );} +"String" { return alloy_sym(yytext(), DashSym.STRING );} +"sum" { return alloy_sym(yytext(), DashSym.SUM );} +"this" { return alloy_sym(yytext(), DashSym.THIS );} +"univ" { return alloy_sym(yytext(), DashSym.UNIV );} +"always" { return alloy_sym(yytext(), DashSym.ALWAYS );} +"after" { return alloy_sym(yytext(), DashSym.AFTER );} +"eventually" { return alloy_sym(yytext(), DashSym.EVENTUALLY );} +"historically" { return alloy_sym(yytext(), DashSym.HISTORICALLY);} +"before" { return alloy_sym(yytext(), DashSym.BEFORE );} +"once" { return alloy_sym(yytext(), DashSym.ONCE );} +"releases" { return alloy_sym(yytext(), DashSym.RELEASES );} +"until" { return alloy_sym(yytext(), DashSym.UNTIL );} +"since" { return alloy_sym(yytext(), DashSym.SINCE );} +"triggered" { return alloy_sym(yytext(), DashSym.TRIGGERED );} +";" { return alloy_sym(yytext(), DashSym.TRCSEQ );} +"var" { return alloy_sym(yytext(), DashSym.VAR );} +"steps" { return alloy_sym(yytext(), DashSym.TIME );} +"'" { return alloy_sym(yytext(), DashSym.PRIME );} +"‘" { return alloy_sym(yytext(), DashSym.PRIME );} +"’" { return alloy_sym(yytext(), DashSym.PRIME );} +//DASH SYNTAX ADDITIONS + +"state" { return alloy_sym(yytext(), DashSym.STATE );} +"conc" { return alloy_sym(yytext(), DashSym.CONC );} +"default" { return alloy_sym(yytext(), DashSym.DEF );} + +"event" { return alloy_sym(yytext(), DashSym.EVENT );} +"env" { return alloy_sym(yytext(), DashSym.ENV );} +"buf" { return alloy_sym(yytext(), DashSym.BUF );} + +"init" { return alloy_sym(yytext(), DashSym.INIT );} +"invariant" { return alloy_sym(yytext(), DashSym.INVARIANT );} +"enter" { return alloy_sym(yytext(), DashSym.ENTER );} +"exit" { return alloy_sym(yytext(), DashSym.EXIT );} +//"action" { return alloy_sym(yytext(), DashSym.ACTION );} +//"condition" { return alloy_sym(yytext(), DashSym.CONDITION );} + +"trans" { return alloy_sym(yytext(), DashSym.TRANS );} + +"from" { return alloy_sym(yytext(), DashSym.FROM );} +"on" { return alloy_sym(yytext(), DashSym.ON );} +"when" { return alloy_sym(yytext(), DashSym.WHEN );} +"do" { return alloy_sym(yytext(), DashSym.DO );} +"goto" { return alloy_sym(yytext(), DashSym.GOTO );} +"send" { return alloy_sym(yytext(), DashSym.SEND );} + + +//END DASH SYNTAX ADDITIONS + + +[\"] ([^\\\"] | ("\\" .))* [\"] [\$0-9a-zA-Z_\"] [\$0-9a-zA-Z_\"]* { throw new ErrorSyntax(alloy_here(yytext()),"String literal cannot be followed by a legal identifier character."); } +[\"] ([^\\\"] | ("\\" .))* [\"] { return alloy_string(yytext()); } +[\"] ([^\\\"] | ("\\" .))* { throw new ErrorSyntax(alloy_here(yytext()),"String literal is missing its closing \" character"); } +[0]"x"([_]|([0-9A-Fa-f][0-9A-Fa-f]))+ { return alloy_hexnum (yytext()); } +[0]"b"[01_]+ { return alloy_binarynum (yytext()); } +[0-9][0-9]*[\$a-zA-Z_\"][\$0-9a-zA-Z_\"]* { throw new ErrorSyntax(alloy_here(yytext()),"Name cannot start with a number."); } +[0-9][0-9_]* { return alloy_num (yytext()); } +[:jletter:][[:jletterdigit:]\"]* { return alloy_id (yytext()); } + + +"/**" ~"*/" { } + +"/*" ~"*/" { } + +("//"|"--") [^\r\n]* [\r\n] { } + +("//"|"--") [^\r\n]* { } // This rule is shorter than the previous rule, + // so it will only apply if the final line of a file is missing the \n or \r character. + +[ \t\f\r\n] { } + +. { throw new ErrorSyntax(alloy_here(" "), "Syntax error at the "+yytext()+" character. HEX: \\u"+Integer.toString(yytext().charAt(0),16)+")"); } diff --git a/org.alloytools.alloy.dash/parser/README.md b/org.alloytools.alloy.dash/parser/README.md new file mode 100644 index 000000000..fd054aed6 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/README.md @@ -0,0 +1,10 @@ +# README.md + +Dash.cup and Dash.lex were created by the script install-alloy.files.sh, +which does some renaming and integrates the various parts of the lexer/grammar needed for Dash. + +Do NOT edit Dash.lex or Dash.cup directly. + +If Alloy is updated, rerun this script. + +If any of Dash-cup-*.txt or Dash-lex-*.txt are edited, rerun this script. \ No newline at end of file diff --git a/org.alloytools.alloy.dash/parser/install-alloy-files.sh b/org.alloytools.alloy.dash/parser/install-alloy-files.sh new file mode 100755 index 000000000..ddd5ad894 --- /dev/null +++ b/org.alloytools.alloy.dash/parser/install-alloy-files.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# The purpose of this script is to copy the Alloy files that we use +# but have to do some slight renaming in them +# rerun this script whenever Alloy updates these files + +# /g means multiple places on line + +# it's tricky when to convert to turn CompModule into DCModule (the original CompModule with renaming) +# vs DashModule (our code, which is an extension of DCModule) + +# Maintenance +# When Alloy.lex, Alloy.cup change the line numbers below will have to change! + +p=../../org.alloytools.alloy.core/parser/ +msg=$'/*\n * DO NOT EDIT THIS FILE\n * DASH: file copied from Alloy src with replacements for Dash - see install-alloy-files.sh \n */\n\n' + + +cp $p/Alloy.lex . + +sed -i -e 's/package edu.mit.csail.sdg.parser/package ca.uwaterloo.watform.parser/' Alloy.lex + +sed -i -e 's/CompLexer/DashLexer/g' Alloy.lex +sed -i -e 's/CompSym/DashSym/g' Alloy.lex +#sed -i -e 's/CompModule/DashModule/g' Alloy.lex + +# FILE LINE NUMBER DEPENDENCE BELOW +sed -n -e '1,24p' Alloy.lex > part1.txt # to the end of imports +sed -n -e '25,235p' Alloy.lex > part2.txt # to the end of tokens +sed -n -e '236,$p' Alloy.lex > part3.txt +{ echo "$msg"; cat part1.txt Dash-lex-imports.txt part2.txt Dash-lex-addition.txt part3.txt ; } > Dash.lex +rm Alloy.lex part*.txt +rm *.lex-e + +# -------------- + +cp $p/Alloy.cup . + +sed -i -e 's/package edu.mit.csail.sdg.parser/package ca.uwaterloo.watform.parser/' Alloy.cup + +sed -i -e 's/CompLexer/DashLexer/g' Alloy.cup +sed -i -e 's/CompSym/DashSym/g' Alloy.cup +sed -i -e 's/CompParser/DashParser/g' Alloy.cup +sed -i -e 's/CompFilter/DashFilter/g' Alloy.cup + +sed -i -e 's/alloymodule/dashmodule/g' Alloy.cup +sed -i -e 's/public CompModule dashmodule=null;/public DashModule dashmodule=null;/g' Alloy.cup +sed -i -e 's/static CompModule alloy_parseStream/static DashModule alloy_parseStream/' Alloy.cup +sed -i -e 's/CompModule u = new CompModule(root, filename, prefix);/DashModule u = new DashModule(root, filename, prefix);/' Alloy.cup + +# split it up and put it back together +# FILE LINE NUMBER DEPENDENCE BELOW +sed -n -e '1,61p' Alloy.cup > part1.txt # to end of imports +sed -n -e '62,247p' Alloy.cup > part2.txt # to the end of symbols +sed -n -e '248,529p' Alloy.cup > part3.txt # to end of terminals +sed -n -e '530,617p' Alloy.cup > part4.txt # to end of nonterminals +sed -n -e '618,$p' Alloy.cup > part5.txt # to end of file +{ echo "$msg"; cat part1.txt Dash-cup-imports.txt part2.txt Dash-cup-symbols.txt part3.txt Dash-cup-terminals.txt part4.txt Dash-cup-nonterminals.txt part5.txt Dash-cup-grammar.txt; } > Dash.cup +rm Alloy.cup part*.txt +rm *.cup-e + + + + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/DeclExt.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/DeclExt.java new file mode 100644 index 000000000..233dc2746 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/DeclExt.java @@ -0,0 +1,82 @@ +package ca.uwaterloo.watform.alloyasthelper; + +import java.util.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.StringJoiner; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprVar; + +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashStrings; + +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +public class DeclExt extends Decl { + + public DeclExt(ExprVar v, Expr e, boolean isVar) { + super(null, null, null, + isVar ? Pos.UNKNOWN:null, + new ArrayList<>(Arrays.asList(v)) , + e); + } + public DeclExt(String v, Expr e) { + // not sure if mult is needed on last arg + super(null, null, null, null, new ArrayList<>(Arrays.asList(ExprHelper.createVar(v))) , e); + } + // default is "one" + public DeclExt(String v, String typ) { + super(null, null, null, null, new ArrayList<>(Arrays.asList(ExprHelper.createVar(v))), ExprHelper.createOne(ExprHelper.createVar(typ))); + } + public DeclExt(String v, Expr e, boolean isVar) { + // not sure if mult is needed on last arg + super(null, null, null, + isVar ? Pos.UNKNOWN:null, + new ArrayList<>(Arrays.asList(ExprHelper.createVar(v))), + e); + + } + public String toString() { + // Decl does not have a toString() + String x = new String(); + StringJoiner sj = new StringJoiner(", "); + // var keyword + //System.out.println("Decl" + names + (this.isVar==null)); + if (isVar != null) { + x += DashStrings.varName + " "; + } + names.forEach(n -> sj.add(n.toString())); + x += sj.toString(); + x += " : "; + //ExprToString eToString = new ExprToString(false); + x += ExprHelper.ppExpr(expr); + return x; + } + + + public static DeclExt newOneDeclExt(String v, String typ) { + return new DeclExt(v, ExprHelper.createOne(ExprHelper.createVar(typ))); + } + //public static DeclExt newOneDeclExt(String v, Expr typ) { + // return new DeclExt(v, typ); + //} + public static DeclExt newSetDeclExt(String v, String typ) { + return new DeclExt(v, ExprHelper.createSet(ExprHelper.createVar(typ))); + } + //public static DeclExt newSetDeclExt(String v, Expr typ) { + // return new DeclExt(v, typ); + //} + + // using Pos.UNKNOWN here as the 4th arg + // makes it seem like there is a pos for "var" + // making it a "var" decl + public static DeclExt newVarDeclExt(String v, Expr typ) { + + return new DeclExt(v , typ, true); + } + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprExt.old b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprExt.old new file mode 100644 index 000000000..1114403ef --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprExt.old @@ -0,0 +1,39 @@ +package ca.uwaterloo.watform.alloyasthelper; + +import java.util.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.StringJoiner; + + +import edu.mit.csail.sdg.ast.Expr; + + +import ca.uwaterloo.watform.core.DashErrors; + +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; + +// this is necessary to make a better toString method for +// Joins where brackets are printed +// we will have to use this within any expressions in actions or guards or event parameters +public class ExprExt extends Expr { + + public Expr exp; + + public ExprExt(Expr e) { + this.exp = e; + } + + public String toString() { + if (this.exp isinstance ExprJoin) { + s = new String(); + s += this.exp.left.toString(); + s += " . "; + if (this.exp.right isinstance ExprJoin) { + s += "( "; + s += this.exp.right.toString(); + s += " )"; + } + } else return e.toString(); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprHelper.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprHelper.java new file mode 100644 index 000000000..94e63ee3f --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprHelper.java @@ -0,0 +1,489 @@ +package ca.uwaterloo.watform.alloyasthelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; +import java.util.stream.Collectors; + +import edu.mit.csail.sdg.alloy4.Pos; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprBadJoin; +import edu.mit.csail.sdg.ast.ExprBinary; +import edu.mit.csail.sdg.ast.ExprITE; +import edu.mit.csail.sdg.ast.ExprList; +import edu.mit.csail.sdg.ast.ExprLet; +import edu.mit.csail.sdg.ast.ExprQt; +import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.ExprHasName; +import edu.mit.csail.sdg.ast.ExprBinary; +import edu.mit.csail.sdg.ast.ExprCall; +import edu.mit.csail.sdg.ast.ExprChoice; +import edu.mit.csail.sdg.ast.ExprConstant; + +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +// these are all static +// don't want to make them an extension +// because then would have to put them in all different classes + + +public class ExprHelper { + + // tests ------------------------------------ + public static boolean isExprBinary(Expr e) { + return (e instanceof ExprBinary); + } + public static boolean isExprUnary(Expr e) { + return (e instanceof ExprUnary); + } + public static boolean isExprSet(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.SETOF)); + } + public static boolean isExprOne(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.ONE)); + } + public static boolean isExprLone(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.LONE)); + } + public static boolean isExprCard(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.CARDINALITY)); + } + + public static boolean isExprRClosure(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.RCLOSURE)); + } + + public static boolean isExprClosure(Expr e) { + return ((e instanceof ExprUnary) && ((ExprUnary) e).op.equals(ExprUnary.Op.CLOSURE)); + } + + + public static boolean isExprJoin(Expr e) { + return ((e instanceof ExprBinary) && ((ExprBinary) e).op.equals(ExprBinary.Op.JOIN)); + } + public static boolean isExprArrow(Expr e) { + return ((e instanceof ExprBinary) && ((ExprBinary) e).op.equals(ExprBinary.Op.ARROW)); + } + public static boolean isExprBadJoin(Expr e) { + return (e instanceof ExprBadJoin); + } + public static boolean isExprVar(Expr e) { + return (e instanceof ExprVar); + } + + public static boolean isPrimedVar(Expr e) { + return (e instanceof ExprUnary && + ((ExprUnary) e).sub instanceof ExprVar && + ((ExprUnary) e).op == ExprUnary.Op.PRIME); + } + + // simple equality: two var names are equal ----------------------- + public static boolean sEquals(Expr e1, Expr e2) { + return ( (e1 == e2) || + (isExprVar(e1) && isExprVar(e2) && + getVarName((ExprVar) e1).equals(getVarName((ExprVar) e2)))) ; + } + + // destructors ------------------------------- + public static String getVarName(ExprVar e) { + return e.label; + } + + public static Expr getRight(Expr e) { + if (isExprBinary(e)) + return ((ExprBinary) e).right; + else if (isExprBadJoin(e) ) + return ((ExprBadJoin) e).right; + else if (e instanceof ExprITE) + return ((ExprITE) e).right; + else { DashErrors.getRightNotBinaryOrJoin(e.getClass().getName()); return null; } + } + public static Expr getLeft(Expr e) { + if (isExprBinary(e)) + return ((ExprBinary) e).left; + else if (isExprBadJoin(e)) + return ((ExprBadJoin) e).left; + else if (e instanceof ExprITE) + return ((ExprITE) e).left; + else { DashErrors.getLeftNotBinaryOrJoin(e.getClass().getName()); return null; } + } + + public static Expr getSub(Expr e) { + if (isExprUnary(e)) { + return ((ExprUnary) e).sub; + } else { + DashErrors.getSubNotUnary(e.getClass().getName()); return null; + } + } + public static ExprBinary.Op getBinaryOp(Expr e) { + assert(e instanceof ExprBinary); + return ((ExprBinary) e).op; + } + public static ExprUnary.Op getUnaryOp(Expr e) { + assert(e instanceof ExprUnary); + return ((ExprUnary) e).op; + } + public static Expr getCond(Expr e) { + assert(e instanceof ExprITE); + return ((ExprITE) e).cond; + } + + // constructors ----------------------------------- + + // useful in development + public static Expr createNullExpr() { + return createEquals(createTrue(),createTrue()); + } + public static ExprVar createTrue() { + return ExprVar.make(Pos.UNKNOWN, DashStrings.trueName); + } + public static Expr createIsTrue(Expr e) { + List elist = new ArrayList(); + elist.add(e); + return createPredCall(DashStrings.isTrue,elist); + } + public static Expr createIsFalse(Expr e) { + List elist = new ArrayList(); + elist.add(e); + return createPredCall(DashStrings.isFalse,elist); + } + public static ExprVar createFalse() { + return ExprVar.make(Pos.UNKNOWN, DashStrings.falseName); + } + public static ExprVar createNone() { + return ExprVar.make(Pos.UNKNOWN, DashStrings.noneName); + } + public static ExprVar createVar(String v) { + return ExprVar.make(Pos.UNKNOWN, v); + } + public static ExprVar createVar(Pos p, String v) { + return ExprVar.make(p, v); + } + public static List createVarList(List vList) { + List retList = new ArrayList(); + for (String v: vList) { + retList.add(createVar(v)); + } + return retList; + } + public static List createVarList(String prefix, List vList) { + List retList = new ArrayList(); + for (String v: vList) { + retList.add(createVar(prefix+v)); + } + return retList; + } + + + + // to avoid the need to cast every ExprVar to an Expr + public static List createExprVarList(List vList) { + List retList = new ArrayList(); + for (String v: vList) { + retList.add((ExprVar) createVar(v)); + } + return retList; + } + public static List createExprVarList(String prefix, List vList) { + List retList = new ArrayList(); + for (String v: vList) { + retList.add((ExprVar) createVar(prefix + v)); + } + return retList; + } + + /* generic ones */ + public static Expr createBinaryExpr(Expr left, ExprBinary.Op op, Expr right) { + return (ExprBinary) op.make(Pos.UNKNOWN, Pos.UNKNOWN,left,right); + } + public static Expr createUnaryExpr(ExprUnary.Op op, Expr sub) { + return (ExprUnary) op.make(Pos.UNKNOWN, sub); + } + public static Expr createPrime(Expr sub) { + return ExprUnary.Op.PRIME.make(Pos.UNKNOWN, sub); + } + + public static Expr createExprList(ExprList.Op op, List args) { + return (Expr) ExprList.make(Pos.UNKNOWN, Pos.UNKNOWN, op, args); + } + public static Expr createExprQt(ExprQt.Op op, List decls, Expr expr) { + return op.make(Pos.UNKNOWN, Pos.UNKNOWN, decls,expr); + } + + /* a few useful specific ones */ + public static Expr createNoop(Expr sub) { + return (ExprUnary) ExprUnary.Op.NOOP.make(Pos.UNKNOWN, sub); + } + public static Expr createNot(Expr sub) { + return (ExprUnary) ExprUnary.Op.NOT.make(Pos.UNKNOWN, sub); + } + public static Expr createOne(Expr sub) { + return (ExprUnary) ExprUnary.Op.ONE.make(Pos.UNKNOWN, sub); + } + public static Expr createLone(Expr sub) { + return (ExprUnary) ExprUnary.Op.LONE.make(Pos.UNKNOWN, sub); + } + public static Expr createSomeOf(Expr sub) { + return (ExprUnary) ExprUnary.Op.SOMEOF.make(Pos.UNKNOWN, sub); + } + public static Expr createNo(Expr sub) { + return (ExprUnary) ExprUnary.Op.NO.make(Pos.UNKNOWN, sub); + } + public static Expr createSet(Expr sub) { + return (ExprUnary) ExprUnary.Op.SETOF.make(Pos.UNKNOWN, sub); + } + public static ExprUnary createReflexiveTransitiveClosure(Expr sub) { + return (ExprUnary) ExprUnary.Op.RCLOSURE.make(Pos.UNKNOWN, sub); + } + public static ExprBinary createJoin(Expr left, Expr right) { + return (ExprBinary) ExprBinary.Op.JOIN.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static ExprBinary createJoin(Pos p, Expr left, Expr right) { + return (ExprBinary) ExprBinary.Op.JOIN.make(p, p, left, right); + } + public static Expr createJoinList(List elist) { + Expr ret = null; + assert(elist!=null); + Collections.reverse(elist); + ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createJoin(el,ret); + } + return ret; + } + public static Expr createJoinList(List elist, Expr e) { + assert(elist!=null); + Collections.reverse(elist); + Expr ret = e; + for (Expr el: elist) { + ret = createJoin(el,ret); + } + return ret; + } + public static ExprBinary createRangeRes(Expr left, Expr right) { + return (ExprBinary) ExprBinary.Op.RANGE.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static ExprBinary createDomainRes(Expr left, Expr right) { + return (ExprBinary) ExprBinary.Op.DOMAIN.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + + public static Expr createUnionList(List elist) { + Expr ret = null; + assert(elist!=null); + ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createUnion(ret,el); + } + return ret; + } + public static Expr createDiffList(List elist) { + Expr ret = null; + assert(elist!=null); + ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createDiff(ret,el); + } + return ret; + } + public static Expr createEquals(Expr left, Expr right) { + if (sEquals(left,right)) return (Expr) createTrue(); + else return (Expr) ExprBinary.Op.EQUALS.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static ExprBinary createNotEquals(Expr left, Expr right) { + return (ExprBinary) ExprBinary.Op.NOT_EQUALS.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + + public static Expr createAnd(Expr left, Expr right) { + if (sEquals(left, createFalse())) return createFalse(); + if (sEquals(right, createFalse())) return createFalse(); + if (sEquals(left, createTrue())) return right; + if (sEquals(right, createTrue())) return left; + return (Expr) ExprBinary.Op.AND.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static Expr createAndList(List args) { + //TODO put simplifications in here + return (Expr) ExprList.make(Pos.UNKNOWN, Pos.UNKNOWN, ExprList.Op.AND, args); + } + + public static Expr createAndFromList(List elist) { + // does simplifications + if (elist.isEmpty()) return createTrue(); + Expr ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createAnd(ret,el); + } + return ret; + } + public static Expr createOr(Expr left, Expr right) { + if (sEquals(left, createTrue())) return createTrue(); + if (sEquals(right, createTrue())) return createTrue(); + if (sEquals(left, createFalse())) return right; + if (sEquals(right, createFalse())) return left; + return (Expr) ExprBinary.Op.OR.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static Expr createOrFromList(List elist) { + if (elist.isEmpty()) return createTrue(); + Expr ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createOr(ret,el); + } + return ret; + } + public static ExprList createOrList(List args) { + // put simplifications in here so can replace createOrFromList + return (ExprList) ExprList.make(Pos.UNKNOWN, Pos.UNKNOWN, ExprList.Op.OR, args); + } + public static Expr createIff(Expr left, Expr right) { + return (Expr) ExprBinary.Op.IFF.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static Expr createImplies(Expr left, Expr right) { + return (Expr) ExprBinary.Op.IMPLIES.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static ExprBinary createArrow(Expr left,Expr right) { + return (ExprBinary) ExprBinary.Op.ARROW.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + // set union + public static ExprBinary createUnion(Expr left,Expr right) { + return (ExprBinary) ExprBinary.Op.PLUS.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static Expr createUnionFromList(List elist) { + //TODO make an ExprList + if (elist.isEmpty()) return createNone(); + Expr ret = elist.get(0); + for (Expr el: elist.subList(1,elist.size())) { + ret = createUnion(ret,el); + } + return ret; + } + public static ExprBinary createIntersect(Expr left,Expr right) { + return (ExprBinary) ExprBinary.Op.INTERSECT.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + // set diff + public static ExprBinary createDiff(Expr left,Expr right) { + return (ExprBinary) ExprBinary.Op.MINUS.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + public static ExprBinary createIn(Expr left,Expr right) { + return (ExprBinary) ExprBinary.Op.IN.make(Pos.UNKNOWN, Pos.UNKNOWN, left, right); + } + // {x,y,z} + // returns x -> (y -> z) + public static Expr createArrowStringList(List eList) { + assert(eList != null); + Collections.reverse(eList); + Expr o = createVar(eList.get(0)); + for (String e: eList.subList(1,eList.size())) { + o = createArrow(createVar(e), o); + } + return o; + } + public static Expr createArrowExprList(List eList) { + assert(!eList.isEmpty()); + //System.out.println("input " + eList); + List xList = DashUtilFcns.reverse(eList); + //assert(!xList.isEmpty()); + //System.out.println("reversed: " +xList); + Expr o = xList.get(0); + if (xList.size() == 1) return o; + else { + for (Expr x: xList.subList(1,xList.size())) { + o = createArrow(x, o); + } + } + return o; + } + + // Alloy won't use boolean/True or boolean/False as formulas + // but it can be convenient in our code to use them + // so let's just simplify them out in formulas + public static Expr createITE(Expr cond, Expr impliesExpr, Expr elseExpr) { + if (sEquals(cond, createTrue())) return (Expr) impliesExpr; + if (sEquals(cond,createFalse())) return (Expr) elseExpr; + if (sEquals(impliesExpr,createTrue())) return createOr(cond, createAnd(createNot(cond),elseExpr)); + if (sEquals(impliesExpr,createFalse())) return createAnd(createNot(cond),elseExpr); + if (sEquals(elseExpr,createTrue())) return createOr(createAnd(cond,impliesExpr), createNot(cond)); + if (sEquals(elseExpr,createFalse())) return createAnd(cond,impliesExpr); + else return (Expr) ExprITE.make(Pos.UNKNOWN, cond, impliesExpr, elseExpr); + } + + + public static ExprQt createAll(List decls, Expr expr) { + return (ExprQt) ExprQt.Op.ALL.make(Pos.UNKNOWN, Pos.UNKNOWN, decls, expr); + } + public static ExprQt createSome(List decls, Expr expr) { + return (ExprQt) ExprQt.Op.SOME.make(Pos.UNKNOWN, Pos.UNKNOWN, decls, expr); + } + + public static ExprUnary createAlways(Expr expr) { + return (ExprUnary) ExprUnary.Op.ALWAYS.make(Pos.UNKNOWN, expr); + } + + public static Expr createPredCall(String name, List elist) { + // using ExprCall.make is overkill + // b/c it required the entire function definition to be passed + // as an argument + // joins are equivalent but not as nice to look at :-) + // order of joins is tricky + Expr o = createVar(name); + for (Expr e:elist) { + o = createJoin(e,o); + } + return o; + } + + /* these wrap the object creation and call to the pretty printer */ + public static String ppExpr(Expr e) { + ExprToString eToString = new ExprToString(false); + return eToString.exprToString(e); + } + + public static String ppDecl(Decl d) { + ExprToString eToString = new ExprToString(false); + return eToString.declToString(d); + } + + public static boolean usedIn(Expr v, Expr exp) { + + assert(isExprVar(v)); + if (isExprVar(exp)) { + return (getVarName((ExprVar) exp).equals(getVarName((ExprVar) v))); + } + else if (isExprBinary(exp) || isExprBadJoin(exp)) { + return (usedIn(v,getLeft(exp)) || usedIn(v,getRight(exp))); + } else if (exp instanceof ExprCall) { + for (Expr e: ((ExprCall) exp).args) + if (usedIn(v,e)) return true; + return false; + } else if (exp instanceof ExprChoice){ + for (Expr e: ((ExprChoice) exp).choices) + if (usedIn(v,e)) return true; + return false; + } else if (exp instanceof ExprITE){ + return (usedIn(v,getCond(exp)) || usedIn(v,getLeft(exp)) || usedIn(v, getRight(exp))); + } else if (exp instanceof ExprList){ + for (Expr e: ((ExprList) exp).args) + if (usedIn(v,e)) return true; + return false; + } else if (exp instanceof ExprUnary){ + return usedIn(v,((ExprUnary) exp).sub); + } else if (exp instanceof ExprLet){ + return usedIn(v,(((ExprLet) exp).expr)) || usedIn(v,((ExprLet) exp).sub); + } else if (exp instanceof ExprQt){ + List ll = ((ExprQt) exp).decls.stream() + .map(i -> i.expr) + .collect(Collectors.toList()); + for (Expr e: ll) if (usedIn(v,e)) return true; + return false; + } else if (exp instanceof ExprConstant){ + return false; + } else { + DashErrors.UnsupportedExpr("usedIn", ""); + return false; + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprToString.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprToString.java new file mode 100644 index 000000000..7b002ff4f --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/alloyasthelper/ExprToString.java @@ -0,0 +1,471 @@ +package ca.uwaterloo.watform.alloyasthelper; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.List; +import java.util.Collections; +import java.util.stream.Collectors; + +import de.uka.ilkd.pp.DataLayouter; +import de.uka.ilkd.pp.NoExceptions; +import de.uka.ilkd.pp.StringBackend; + + +import edu.mit.csail.sdg.alloy4.ConstList; +import edu.mit.csail.sdg.alloy4.Pair; +import edu.mit.csail.sdg.ast.*; +import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.ast.Sig.PrimSig; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +import ca.uwaterloo.watform.core.DashFQN; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashStrings; + +/* + Notes on the pretty printer primitives + .begin(boolean consistent, int spaces) - start block + .beginC(x) = .begin(true,x) + .end() - end block + .print(string text) + .brk(int spacesifnotbroken, int spacestoaddorsubtractfromindentifbroken) + .brk(x) = .brk(x,0) + .brk() = .brk(1,0) + .close() - finish the string + + consistent block means if break required then all have breaks + inconsistent block means put as much as possible on a line +*/ +public class ExprToString { + + int indent = DashStrings.tab.length(); + int lineWidth = 60; + StringBackend back = new StringBackend(lineWidth); + DataLayouter out = new DataLayouter(back, indent);; + Boolean isAfterAlloyResolveAll; + + + public ExprToString(boolean isAfterAlloyResolveAll) { + this.isAfterAlloyResolveAll = isAfterAlloyResolveAll; + } + + public String exprToString(Expr e) { + out.beginC(0); + ExprToOut(e); + out.end(); + out.close(); + return back.getString(); + } + public String declToString(Decl d) { + out.beginC(0); + DeclToOut(d); + out.end(); + out.close(); + return back.getString(); + } + private void ExprToOut(Expr expr) { + + /* + if (expr instanceof ExprBad){ + ExprBadToOut((ExprBad)expr); + + } else if (expr instanceof ExprBadCall){ + ExprBadCallToOut((ExprBadCall)expr); + */ + if (expr instanceof ExprBadJoin){ + ExprBadJoinToOut((ExprBadJoin)expr); + } else if (expr instanceof ExprBinary) { + ExprBinaryToOut((ExprBinary)expr); + } else if (expr instanceof ExprCall){ + ExprCallToOut((ExprCall)expr); + } else if (expr instanceof ExprChoice){ + ExprChoiceToOut((ExprChoice)expr); + } else if (expr instanceof ExprConstant){ + ExprConstantToOut((ExprConstant)expr); + } else if (expr instanceof ExprITE){ + ExprITEToOut((ExprITE)expr); + } else if (expr instanceof ExprLet){ + ExprLetToOut((ExprLet)expr); + } else if (expr instanceof ExprList){ + ExprListToOut((ExprList)expr); + } else if (expr instanceof ExprQt){ + ExprQtToOut((ExprQt)expr); + } else if (expr instanceof ExprUnary){ + ExprUnaryToOut((ExprUnary)expr); + } else if (expr instanceof ExprVar){ + out.print(cleanLabel(((ExprVar) expr).label)); + } else if (expr instanceof Sig){ + out.print(cleanLabel(((Sig) expr).label)); + } else if (expr instanceof Field){ + out.print("(").print(cleanLabel(((Field) expr).label)).print(")"); + } else { + DashErrors.missingExpr("ExprToOut :" +expr.getClass().getName()); + } + } + /* + private void ExprBad(ExprBad expr) { + StringBuilder tempOut = new StringBuilder(); + expr.toString(tempOut, -1); + out.print(tempOut.toString()); + } + + private void ExprBadCall(ExprBadCall expr) { + out.print(cleanLabel(expr.fun.label)).print('[').beginCInd(); + for (int i = 0; i < expr.args.size(); i++) { + if (i > 0) + out.print(", "); + Expr(expr.args.get(i)); + } + out.end().print(']'); + } + */ + + /* + private Boolean isBinary(Expr e) { + return (e instanceof ExprBinary); + } + */ + private void ExprBinaryToOut(ExprBinary expr) { + if (DashRef.isDashRef(expr)) { + out.print(expr.toString()); + } else if (expr.op == ExprBinary.Op.ISSEQ_ARROW_LONE) { + out.print("seq "); + out.beginC(2); + ExprToOut(expr.right); + out.end(); + //out.print(")"); + } else if (expr.op == ExprBinary.Op.JOIN) { + // there are really long join expressions + //out.beginI(2); + addBracketsIfNeeded(getLeft(expr)); + //out.brk(1,0); + out.print(expr.op); + //out.brk(1,0); + addBracketsIfNeeded(getRight(expr)); + //out.end(); + } else { + out.beginI(2); + addBracketsIfNeeded(getLeft(expr)); + out.brk(1,0); + out.print(expr.op); + out.brk(1,0); + addBracketsIfNeeded(getRight(expr)); + out.end(); + } + } + +/* + private void addBracketsIfNeededNoBlocks(Expr expr) { + Boolean bracketNotNeeded = + isExprVar(expr) || + (isExprUnary(expr) && + !isExprCard(expr)&& + !isExprRClosure(expr) && + !isExprClosure(expr)); + if (!(isExprVar(expr) || (isExprUnary(expr) && !isExprCard(expr) ))) { + //out.beginC(2); + out.print("("); + } + ExprToOut(expr); + if (!(isExprVar(expr) || (isExprUnary(expr) && !isExprCard(expr) ) )) { + out.print(")"); + //out.end(); + } + } +*/ + + private void addBracketsIfNeeded(Expr expr) { + Boolean bracketsNotNeeded = + isExprVar(expr) || + (isExprUnary(expr) && + !isExprCard(expr)&& + !isExprRClosure(expr) && + !isExprClosure(expr)); + if (!bracketsNotNeeded) { + //out.beginC(2); + out.print("("); + } + //System.out.println("---- class: " + expr.getClass().toString()); + //if (isExprUnary(expr)) System.out.println(getUnaryOp(expr).toString()); + //System.out.println("bracketsNotNeeded: " + bracketsNotNeeded.toString()); + //System.out.println(expr.toString()); + ExprToOut(expr); + if (!bracketsNotNeeded) { + out.print(")"); + //out.end(); + } + } + + private void ExprBadJoinToOut(ExprBadJoin expr) { + addBracketsIfNeeded(expr.left); + out.print('.'); + addBracketsIfNeeded(expr.right); + } + + private void ExprCallToOut(ExprCall expr) { + out.print(cleanLabel(expr.fun.label)); + if (expr.args.size() == 0) + return; + out.print('['); + out.beginC(2); + for (int i = 0; i < expr.args.size(); i++) { + if (i > 0) out.print(", "); + ExprToOut(expr.args.get(i)); + } + out.end(); + out.print(']'); + + } + + private void ExprChoiceToOut(ExprChoice expr) { + out.print("<"); + for (Expr e : expr.choices) { + ExprToOut(e); + out.print(";"); + } + out.print(">"); + } + + private void ExprConstantToOut(ExprConstant expr) { + if (expr.op == ExprConstant.Op.NUMBER) + out.print(expr.num); + else if (expr.op == ExprConstant.Op.STRING) + out.print(expr.string); + else + out.print(expr.op); + } + + private void ExprITEToOut(ExprITE expr) { + out.beginC(2); + out.print("{"); + addBracketsIfNeeded(expr.cond); + out.print("=>"); + out.brk(1,indent); + addBracketsIfNeeded(expr.left); + out.brk(1,0); + out.print("else"); + //{") + out.brk(1,indent); + addBracketsIfNeeded(expr.right); + out.print("}"); + //out.print(" }"); + out.brk(1,-indent); + out.end(); + //out.print(')'); + } + + private void ExprLetToOut(ExprLet expr) { + out.print("(let"); + out.brk(1,0); + out.print(cleanLabel(expr.var.label)); + out.brk(1,0); + out.print("="); + out.brk(1,0); + ExprToOut(expr.expr); + out.brk(1,0); + out.print("|"); + out.brk(1,0); + out.beginC(2); + ExprToOut(expr.sub); + out.end(); + out.print(')'); + } + + private void ExprListToOut(ExprList expr) { + if (expr.op == ExprList.Op.AND ) { + String op = " &&"; + out.beginC(2); + for (int i = 0; i < expr.args.size(); i++) { + if (i > 0) + out.print(op).brk(1,0); + ExprToOut(expr.args.get(i)); + } + out.end(); + } + else if (expr.op == ExprList.Op.OR) { + String op = " ||"; + out.print("{ "); + out.beginC(2); + for (int i = 0; i < expr.args.size(); i++) { + if (i > 0) { + out.print(op); + out.brk(1,0); + } + ExprToOut(expr.args.get(i)); + } + out.end(); + out.print(" }"); + } + else { + out.print(expr.op); + out.print("["); + out.beginCInd(); + out.brk(1,0); + out.beginC(2); + for (int i = 0; i < expr.args.size(); i++) { + if (i > 0) + out.print(",").brk(1,0); + ExprToOut(expr.args.get(i)); + } + out.brk(1,-indent); + out.end(); + out.print(']'); + } + } + + private void ExprQtToOut(ExprQt expr) { + boolean first = true; + if (expr.op != ExprQt.Op.COMPREHENSION) + out.print('(').print(expr.op).print(' ').beginCInd(); + else + out.print('{').beginCInd(); + DeclsToOut(expr.decls); + if (expr.op != ExprQt.Op.COMPREHENSION || !(expr.sub instanceof ExprConstant) || ((ExprConstant) expr.sub).op != ExprConstant.Op.TRUE) { + out.print(" | "); + ExprToOut(expr.sub); + } + if (expr.op != ExprQt.Op.COMPREHENSION) + out.end().print(')'); + else + out.end().print('}'); + } + + private void ExprUnaryToOut(ExprUnary expr) { + + switch (expr.op) { + // special cases for the + // ones that the Alloy op.toString() + // does not seem to print in a way that matches + // how the symbol is input + // e.g. set X becomes set of X + case SOMEOF : + out.print("some"); + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + case LONEOF : + out.print("lone"); + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + case ONEOF : + out.print("one"); + + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + + case EXACTLYOF : + out.print("exactly"); + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + case SETOF : + out.print("set"); + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + case CAST2INT : + out.print("int["); + ExprToOut(expr.sub); + out.print(']'); + break; + case CAST2SIGINT : + out.print("Int["); + ExprToOut(expr.sub); + out.print(']'); + break; + case PRIME : + //TODO: perhaps this one should not exist? + //TODO: other temporal formulas that should not exist? + addBracketsIfNeeded(expr.sub); + out.print("'"); + break; + case RCLOSURE : + out.print("*"); + out.brk(1,0); + addBracketsIfNeeded(expr.sub); + break; + case TRANSPOSE : + out.print("~"); + out.brk(1,0); + addBracketsIfNeeded(expr.sub); + break; + case CLOSURE : + out.print("^"); + out.brk(1); + addBracketsIfNeeded(expr.sub); + break; + case NOT : + out.print("!"); + //out.brk(1,0); + addBracketsIfNeeded(expr.sub); + break; + case NOOP : + // { expr } is parsed as NOOP (expr) + addBracketsIfNeeded(expr.sub); + break; + default : + // many operators print okay + // e.g., one, + out.print(expr.op); + out.brk(1); + addBracketsIfNeeded(expr.sub); + } + + } + + + // Helper method to print a list of declarations + private void DeclsToOut(List decls) { + //TODO add appropriate breaks here + boolean first = true; + for (Decl decl : decls) { + StringJoiner namesJoiner = new StringJoiner(","); + if (decl.disjoint != null) { + out.print("disj").print(" "); + } + decl.names.forEach(name -> namesJoiner.add(cleanLabel(name.label))); + if (!first) { + out.print(","); + } + first = false; + out.print(namesJoiner.toString()); + out.print(": "); + ExprToOut(decl.expr); + } + } + + private void DeclToOut(Decl decl) { + if (decl.disjoint != null) { + out.print("disj").print(" "); + } + if (decl.isVar != null) { + out.print(DashStrings.varName + " "); + } + out.print(DashUtilFcns.strCommaList(decl.names)); + out.print(": "); + ExprToOut(decl.expr); + } + // Helper method to change "{path/label}" to "label" + private String cleanLabel(String label) { + if (!label.contains("this/")) { + return label; + } + if (label.endsWith("}") && label.startsWith("{")){ + label = label.substring(1,label.length()-1); + } + int index = label.lastIndexOf('/'); + if (index > -1) { + label = label.substring(index+1); + } + return label; + } + + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/Dash.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/Dash.java new file mode 100644 index 000000000..d2e7248e1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/Dash.java @@ -0,0 +1,19 @@ +package ca.uwaterloo.watform.ast; + + +import edu.mit.csail.sdg.alloy4.Pos; + +public class Dash { + // methods that all of Dash AST should have + + /** + * The filename, line, and column position in the original Alloy model file + * (cannot be null). + */ + public Pos pos; + + public final Pos getPos() { + return pos; + } + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashBufferDecls.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashBufferDecls.java new file mode 100644 index 000000000..7a2698631 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashBufferDecls.java @@ -0,0 +1,60 @@ +package ca.uwaterloo.watform.ast; + +import java.util.List; +import java.util.StringJoiner; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashBufferDecls extends Dash { + /** + * The filename, line, and column position in the original Alloy model file + * (cannot be null). + */ + + private List names; + private String element; + private DashStrings.IntEnvKind kind; + private Integer startIndex; + private Integer endIndex; + + public DashBufferDecls(Pos pos, List n, String element, DashStrings.IntEnvKind k, int startIndex, int endIndex) { + assert (n != null && element != null); + this.pos = pos; + this.names = n; + this.element = element; + this.kind = k; + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + + public String toString() { + // indices are hidden + String s = new String(""); + if (kind == DashStrings.IntEnvKind.ENV) { + s += DashStrings.envName + " "; + } + StringJoiner sj = new StringJoiner(",\n"); + names.forEach(n -> sj.add(n)); + s += sj.toString() + ":" + DashStrings.bufName + "[" + element + "]\n"; + return s; + } + public List getNames() { + return names; + } + public String getElement() { + return element; + } + public DashStrings.IntEnvKind getKind() { + return kind; + } + public int getStartIndex() { + return startIndex; + } + public int getEndIndex() { + return endIndex; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashDo.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashDo.java new file mode 100644 index 000000000..1c3acbe58 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashDo.java @@ -0,0 +1,30 @@ +package ca.uwaterloo.watform.ast; + + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashDo extends Dash { + public Expr action; + + public DashDo(Pos pos,Expr a) { + assert (a != null); + this.pos = pos; + this.action = a; + + } + public String toString() { + String s = new String(); + s += DashStrings.doName + " "; + s += "{\n"; + s += action.toString() + "\n"; + s += "}\n"; + return s; + } + public Expr getDo() { + return action; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEntered.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEntered.java new file mode 100644 index 000000000..2ac330068 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEntered.java @@ -0,0 +1,20 @@ +package ca.uwaterloo.watform.ast; + + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashEntered extends DashExpr { + + + public DashEntered(Pos p, Expr e) { + super(p,e); + } + + public String toString() { + return super.toString(DashStrings.enterName); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEventDecls.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEventDecls.java new file mode 100644 index 000000000..bfd8ac1b7 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashEventDecls.java @@ -0,0 +1,40 @@ +package ca.uwaterloo.watform.ast; + +import java.util.List; +import java.util.StringJoiner; + +import edu.mit.csail.sdg.alloy4.Pos; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashEventDecls extends Dash { + + + + private List names; + private DashStrings.IntEnvKind kind; + + public DashEventDecls(Pos pos, List n, DashStrings.IntEnvKind kind) { + assert(n != null); + this.pos = pos; + this.names = n; + this.kind = kind; + } + + public String toString() { + String s = new String(""); + if (kind == DashStrings.IntEnvKind.ENV) { + s += DashStrings.envName + " "; + } + StringJoiner sj = new StringJoiner(",\n"); + names.forEach(n -> sj.add(n)); + s += DashStrings.eventName + " " + sj.toString() +"{ }\n"; + return s; + } + public List getNames() { + return names; + } + public DashStrings.IntEnvKind getKind() { + return kind; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExited.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExited.java new file mode 100644 index 000000000..1f6ea5252 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExited.java @@ -0,0 +1,20 @@ +package ca.uwaterloo.watform.ast; + + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashExited extends DashExpr { + + + public DashExited(Pos p, Expr e) { + super(p,e); + } + + public String toString() { + return super.toString(DashStrings.exitName); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExpr.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExpr.java new file mode 100644 index 000000000..08f184aea --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashExpr.java @@ -0,0 +1,33 @@ +/* + These classes are used only during parsing because + we do not know what order items within a state will be parsed in. +*/ + +package ca.uwaterloo.watform.ast; + + + +import ca.uwaterloo.watform.core.DashStrings; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +public abstract class DashExpr extends Dash { + + public Expr exp; + + public DashExpr(Pos p, Expr e) { + assert(e != null); + this.pos = p; + this.exp = e; + } + public String toString(String name) { + String s = new String(); + s += name + " {\n"; + s += exp.toString() + "\n"; + return s + "}\n"; + } + public Expr getExp() { + return exp; + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashFrom.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashFrom.java new file mode 100644 index 000000000..59f8c3fd6 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashFrom.java @@ -0,0 +1,21 @@ +package ca.uwaterloo.watform.ast; + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashFrom extends Dash { + + public Expr src; + public DashFrom(Pos pos,Expr d) { + assert(d != null); + this.pos = pos; + this.src = d; + } + public String toString() { + return DashStrings.fromName + " " + src.toString() + "\n"; + } + +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashGoto.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashGoto.java new file mode 100644 index 000000000..c5288c3c6 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashGoto.java @@ -0,0 +1,22 @@ +package ca.uwaterloo.watform.ast; + +import java.util.List; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashUtilFcns.*; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashRef; + +public class DashGoto extends Dash { + public Expr dest; + public DashGoto(Pos pos,Expr d) { + assert(d!=null); + this.pos = pos; + this.dest = d; + } + public String toString() { + return DashStrings.gotoName + " " +dest.toString() + "\n"; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInit.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInit.java new file mode 100644 index 000000000..0007497f1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInit.java @@ -0,0 +1,23 @@ +/* + These classes are used only during parsing because + we do not know what order items within a state will be parsed in. +*/ + +package ca.uwaterloo.watform.ast; + + + +import ca.uwaterloo.watform.core.DashStrings; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +public class DashInit extends DashExpr { + + public DashInit(Pos p, Expr i) { + super(p,i); + } + public String toString() { + return super.toString(DashStrings.initName); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInv.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInv.java new file mode 100644 index 000000000..e4a2eb5fc --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashInv.java @@ -0,0 +1,27 @@ +package ca.uwaterloo.watform.ast; + + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashInv extends DashExpr { + + String name; // unused + + public DashInv(Pos p, Expr inv) { + super(p,inv); + + } + + public DashInv(Pos p, String n, Expr inv) { + super(p,inv); + this.name = n; + } + + public String toString() { + return super.toString(DashStrings.invName + " "+name); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashOn.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashOn.java new file mode 100644 index 000000000..3345361c5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashOn.java @@ -0,0 +1,35 @@ +package ca.uwaterloo.watform.ast; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashRef; + +public class DashOn extends Dash { + //public DashRef ref; + public Expr exp; + /* + public DashOn(Pos pos,DashRef r) { + assert(r != null); + this.pos = pos; + this.ref = r; + this.exp = null; + } + */ + public DashOn(Pos pos, Expr e) { + assert (e != null); + this.pos = pos; + this.exp = e; + //this.ref = null; + } + public String toString() { + //if (ref != null) + // return DashStrings.onName + " " + ref.toString() + "\n"; + //else + return DashStrings.onName + " " + exp.toString() + "\n"; + } + public Expr getExp() { + return exp; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashPred.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashPred.java new file mode 100644 index 000000000..4f6850a6b --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashPred.java @@ -0,0 +1,35 @@ +package ca.uwaterloo.watform.ast; + + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashPred extends Dash { + + public Expr exp; + public String name; // has no meaning + + public DashPred(Pos p, String n, Expr i) { + assert(n != null && i != null); + this.pos = pos; + this.name = n; + this.exp = i; + } + public String toString() { + String s = new String(); + s += DashStrings.predName +" "; + if (name != null) s += name; + s += " {\n"; + s += exp.toString() + "\n"; + return s + "}\n"; + } + public Expr getExp() { + return exp; + } + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashSend.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashSend.java new file mode 100644 index 000000000..b1ea33efd --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashSend.java @@ -0,0 +1,51 @@ +/* + This class is used only during parsing but is necessary because + we do not know what order items of a transitions will be parsed in. +*/ + +package ca.uwaterloo.watform.ast; + + +import java.util.ArrayList; +import java.util.StringJoiner; + +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashRef; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +// send P[x]/ev1 +// send ev1 +// send y.x.ev1 + +public class DashSend extends Dash { + + //public DashRef ref; + public Expr exp; + + /* + public DashSend(Pos pos,DashRef r) { + assert(r != null); + this.pos = pos; + this.ref = r; + this.exp = null; + } + */ + public DashSend(Pos pos,Expr e) { + assert(e != null); + this.pos = pos; + this.exp = e; + //this.ref = null; + } + public String toString() { + //if (ref != null) + // return DashStrings.sendName + " " + ref.toString() + "\n"; + //else + return DashStrings.sendName + " " + exp.toString() + "\n"; + } + public Expr getExp() { + return exp; + } +} + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashState.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashState.java new file mode 100644 index 000000000..a23ead5b8 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashState.java @@ -0,0 +1,404 @@ +package ca.uwaterloo.watform.ast; + +import java.util.*; + +import java.util.List; +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.Collections; +import java.util.stream.Collectors; + + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.*; + +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; +import ca.uwaterloo.watform.parser.StateTable; +import ca.uwaterloo.watform.parser.TransTable; +import ca.uwaterloo.watform.parser.EventTable; +import ca.uwaterloo.watform.parser.VarTable; +import ca.uwaterloo.watform.parser.PredTable; + +import static ca.uwaterloo.watform.parser.ResolveExpr.*; + +//import ca.uwaterloo.watform.parser.BufferTable; + +public class DashState extends Dash { + + // stuff from parsing + public String name; + //private String sfqn; // set during resolveAllState + private String param; + private DashStrings.StateKind kind; // basic state = OR with no subStates + private DashStrings.DefKind def; + private List items; + private int tabsize = 2; + + // fully general constructor + // 6 args + // probably not used? + public DashState(Pos p, String n, String prm, DashStrings.StateKind k, DashStrings.DefKind d, List i) { + assert(n != null && i != null); + this.pos = p; + this.name = n; + this.param = prm; + this.kind = k; + this.def = d; + this.items = i; + //System.out.println("here1 creating "+this.name); + //System.out.println("here1 " + (this.param == null)); + + } + /* + // basic state - default or non-default + // 3 args + public DashState(Pos p, String n, DashStrings.DefKind d) { + assert(n != null); + this.pos = p; + this.name = n; + this.param = null; + this.kind = DashStrings.StateKind.OR; + this.def = d; + this.items = null; // no substates here makes it a basic state + //System.out.println("here2 creating "+this.name+" "+ this.kind); + } + // non-parametrized and/or/basic state + // 5 args + public DashState(Pos p, String n, DashStrings.StateKind k, DashStrings.DefKind d, List i) { + assert(n != null && i != null); + this.pos = p; + this.name = n; + this.param = null; + this.kind = k; + this.def = d; + this.items = i; + //System.out.println("here3 creating "+this.name+" "+ this.kind); + } + // parametrized and state (cannot be default state) + // 4 args + public DashState(Pos p, String n, String prm, List i) { + assert(n != null && prm != null & i != null); + this.pos = p; + this.name = n; + this.param = prm; + this.kind = DashStrings.StateKind.AND; + this.def = DashStrings.DefKind.NOTDEFAULT; + this.items = i; + //System.out.println("here4 creating "+this.name+" "+ this.kind); + } + */ + public String toString() { + String s = new String(""); + //s += s.join("", Collections.nCopies(tab*tabsize, " ")); + if (def == DashStrings.DefKind.DEFAULT) { + s += DashStrings.defaultName + " "; + } + if (kind == DashStrings.StateKind.AND) { + s += DashStrings.concName +" "; + } + if (items == null) { + s += DashStrings.stateName + " " + name + " { }\n"; + } else { + s += DashStrings.stateName + " " + name; + if (param == null) s += " {\n"; + else s += " [" + param + "] {\n"; + StringJoiner j = new StringJoiner(""); + items.forEach(i -> j.add(i.toString())); + s += j.toString() + "}\n"; + + } + return s; + } + + public static String noParam() { + return null; + } + public static List noSubstates() { + return new ArrayList(); + } + + /* + * check for errors in the state hierarchy + * and put all states in the state table + */ + public void load(StateTable st, TransTable tt, EventTable et, VarTable vt, PredTable pt, List ances) { + // this state is not yet in the st + // but its parent is in the st + + if (DashFQN.isFQN(name)) DashErrors.stateNameCantBeFQN(pos, name); + String sfqn = DashFQN.fqn(ances,name); + String parentfqn = DashFQN.fqn(ances); + + //System.out.println("Resolving state "+sfqn); + + // make a copy of the items list so we can + // subtract from it for error checking + // but keep the original items for printing, etc. + List xItems = new ArrayList(items); + + + // invariants --------------------- + List invList = new ArrayList(); + if (items != null) + invList = + items.stream() + .filter(i -> i instanceof DashInv) + .map(p -> (DashInv) p) + .collect(Collectors.toList()); + xItems.removeAll(invList); + + // inits --------------------- + List initList = new ArrayList(); + if (items != null) + initList = + items.stream() + .filter(i -> i instanceof DashInit) + .map(p -> (DashInit) p) + .collect(Collectors.toList()); + xItems.removeAll(initList); + + // entered --------------------- + List enteredList = new ArrayList(); + if (items != null) + enteredList = + items.stream() + .filter(i -> i instanceof DashEntered) + .map(p -> ((DashEntered) p).getExp()) + .collect(Collectors.toList()); + // enteredList is a list of Exp + // to remove, we need a list of items + xItems.removeAll( + items.stream() + .filter(i -> i instanceof DashEntered) + .collect(Collectors.toList())); + + // exited --------------------- + List exitedList = new ArrayList(); + if (items != null) + exitedList = + items.stream() + .filter(i -> i instanceof DashExited) + .map(p -> ((DashExited) p).getExp()) + .collect(Collectors.toList()); + // exitedList is a list of Exp + // to remove, we need a list of items + xItems.removeAll( + items.stream() + .filter(i -> i instanceof DashExited) + .collect(Collectors.toList())); + + /* + // actions --------------------- + List actionList = new ArrayList(); + if (items != null) + actionList = + items.stream() + .filter(i -> i instanceof DashAction) + .map(p -> (DashAction) p) + .collect(Collectors.toList()); + xItems.removeAll(actionList); + + // conditions --------------------- + List conditionList = new ArrayList(); + if (items != null) + conditionList = + items.stream() + .filter(i -> i instanceof DashCondition) + .map(p -> (DashCondition) p) + .collect(Collectors.toList()); + xItems.removeAll(conditionList); + */ + + // --------------------- + // process the children + // have to make a copy so that recursion does not just + // continue to add to list everywhere + List newAnces = new ArrayList(ances); + newAnces.add(name); + List newParams = new ArrayList(); + List newParamsIdx = new ArrayList(); + if (parentfqn != null) { + newParams.addAll(st.getParams(parentfqn)); + newParamsIdx.addAll(st.getParamsIdx(parentfqn)); + } + if (param != null) { + newParams.add(param); + int idx = st.addToParamsList(param); + newParamsIdx.add(idx); + } + + List substatesList = new ArrayList(); + if (items != null) + substatesList = + xItems.stream() + .filter(i -> i instanceof DashState) + .map(p -> (DashState) p) + .collect(Collectors.toList()); + + + + if (substatesList.isEmpty() ) { + if (!st.add(sfqn, kind, param, newParams, newParamsIdx, def,parentfqn, new ArrayList(), + invList, initList, enteredList, exitedList)) DashErrors.addStateToStateTableDup(sfqn);; + + } else { + + // all sibling states must have different names + ArrayList childFQNs = new ArrayList(); + substatesList.forEach(i -> childFQNs.add(DashFQN.fqn(ances,name, i.name))); + // DashUtilFcns.myprint("childFQNS: "+childFQNs); + Set dups = DashUtilFcns.findDuplicates(childFQNs); + if (!dups.isEmpty()) + DashErrors.dupSiblingNames(DashUtilFcns.strCommaList(dups.stream().collect(Collectors.toList()))); + + // add this state to the table + if (!st.add(sfqn,kind, param, newParams,newParamsIdx, def, parentfqn, childFQNs, + invList, initList, enteredList, exitedList)) DashErrors.addStateToStateTableDup(sfqn);; + + // add all substates to the table + for (DashState s: substatesList) s.load(st, tt, et, vt, pt, newAnces); + + // make sure defaults are correct + // if there's only one child it is automatically the default + if (substatesList.size() == 1) { + // make sure it is set as default + // this child should already be in the state table + // might already be set as duplicate but that's okay + // have to use the substate's FQN here + st.setAsDefault(childFQNs.get(0)); + } else { + // default states + List defaultsList = + substatesList.stream() + .filter(i -> (i.def == DashStrings.DefKind.DEFAULT)) + .collect(Collectors.toList()); + List andList = + substatesList.stream() + .filter(i -> (i.kind == DashStrings.StateKind.AND)) + .collect(Collectors.toList()); + if (andList.equals(substatesList) && defaultsList.size() == 0) { + // all AND-states are not designated as defaults so all are defaults + for (String ch: childFQNs) st.setAsDefault(ch); + } else if (defaultsList.size() == 0) + DashErrors.noDefaultState(sfqn); + else { + // if defaults list contains an OR states, it should be size 1 + boolean flag = defaultsList.stream().anyMatch( (s) -> s.kind == DashStrings.StateKind.OR); + if (flag) { + if (defaultsList.size() != 1) DashErrors.tooManyDefaults(sfqn); + // o/w one OR state is default + } else { + // if defaults list is all c's, all c children should be included + //System.out.println("defaultsList: "+defaultsList); + //System.out.println("andList: "+andList); + if (!(defaultsList.equals(andList))) DashErrors.allAndDefaults(sfqn); + } + } + } + } + xItems.removeAll(substatesList); + + // add declared events --------------------- + List eventDeclsList = new ArrayList(); + if (items != null) + eventDeclsList = + xItems.stream() + .filter(i -> i instanceof DashEventDecls) + .map(p -> (DashEventDecls) p) + .collect(Collectors.toList()); + // put in event table with FQN + for (DashEventDecls e:eventDeclsList) { + DashStrings.IntEnvKind k = e.getKind(); + for (String x: e.getNames()) { + if (DashFQN.isFQN(x)) DashErrors.eventNameCantBeFQN(e.getPos(), x); + String xfqn = DashFQN.fqn(sfqn,x); + if (!et.add(xfqn,k, newParams, newParamsIdx)) DashErrors.duplicateEventName(e.getPos(),x); + } + } + xItems.removeAll(eventDeclsList); + + // add declared variables ------------------------ + List varDeclsList = new ArrayList(); + if (items != null) + varDeclsList = + items.stream() + .filter(i -> i instanceof DashVarDecls) + .map(p -> (DashVarDecls) p) + .collect(Collectors.toList()); + // put in var table with FQN + for (DashVarDecls v:varDeclsList) { + DashStrings.IntEnvKind k = v.getKind(); + Expr t = v.getTyp(); + for (String x: v.getNames()) { + if (DashFQN.isFQN(x)) DashErrors.varNameCantBeFQN(v.getPos(), x); + String xfqn = DashFQN.fqn(sfqn,x); + if (!vt.addVar(xfqn,k, newParams, newParamsIdx, t)) DashErrors.duplicateVarName(v.getPos(),x); + } + } + xItems.removeAll(varDeclsList); + + // add preds ------------------------ + List predsList = new ArrayList(); + if (items != null) + predsList = + items.stream() + .filter(i -> i instanceof DashPred) + .map(p -> (DashPred) p) + .collect(Collectors.toList()); + // put in var table with FQN + for (DashPred p:predsList) { + String name = p.getName(); + Expr e = p.getExp(); + if (DashFQN.isFQN(name)) DashErrors.nameCantBeFQN(p.getPos(), name); + String nfqn = DashFQN.fqn(sfqn,name); + if (!pt.addPred(nfqn,e)) DashErrors.duplicateName(p.getPos(),name); + } + xItems.removeAll(predsList); + + // add declared buffers --------------------------- + List bufferDeclsList = new ArrayList(); + if (items != null) + bufferDeclsList = + items.stream() + .filter(i -> i instanceof DashBufferDecls) + .map(p -> (DashBufferDecls) p) + .collect(Collectors.toList()); + // put in var table with FQN + for (DashBufferDecls b:bufferDeclsList) { + DashStrings.IntEnvKind k = b.getKind(); + String el = b.getElement(); + Integer idx = b.getStartIndex(); + for (String x: b.getNames()) { + if (DashFQN.isFQN(x)) DashErrors.bufferNameCantBeFQN(b.getPos(), x); + String xfqn = DashFQN.fqn(sfqn,x); + if (!vt.addBuffer(xfqn,k, newParams, newParamsIdx, el, idx)) DashErrors.duplicateBufferName(b.getPos(),x); + idx++; + } + if (idx != b.getEndIndex()+1) DashErrors.bufferIndexDoesNotMatchBufferNumber(); + } + xItems.removeAll(bufferDeclsList); + + // add transitions ---------------------- + List transList = new ArrayList(); + if (items != null) + transList = + items.stream() + .filter(i -> i instanceof DashTrans) + .map(p -> (DashTrans) p) + .collect(Collectors.toList()); + + for (DashTrans t:transList) { + //System.out.println("newAnces: " +newAnces); + t.load(tt, newParams, newParamsIdx, newAnces); + } + + xItems.removeAll(transList); + + + if (!xItems.isEmpty()) DashErrors.nonEmptyStateItems(xItems); + } + + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashTrans.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashTrans.java new file mode 100644 index 000000000..fa3c81d72 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashTrans.java @@ -0,0 +1,93 @@ +package ca.uwaterloo.watform.ast; + +import java.util.List; +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.Collections; +import java.util.stream.Collectors; + +import ca.uwaterloo.watform.core.*; + +import ca.uwaterloo.watform.parser.StateTable; +import ca.uwaterloo.watform.parser.TransTable; + +import edu.mit.csail.sdg.alloy4.Pos; + +public class DashTrans extends Dash { + String name; + List items; + + public DashTrans(Pos p,String n, List i) { + assert(n != null && i != null); + this.pos = p; + this.name = n; + this.items = i; + } + + public String toString() { + String s = new String(""); + if (items.isEmpty()) { + s += DashStrings.transName + " " + name + " { }\n"; + } else { + s += DashStrings.transName + " " + name + " {\n"; + StringJoiner j = new StringJoiner(""); + items.forEach(i -> j.add(i.toString())); + s += j.toString() + "}\n"; + } + return s; + } + public void load(TransTable tt, List params, List paramsIdx, List ances) { + + if (DashFQN.isFQN(name)) DashErrors.transNameCantBeFQN(pos, name); + String tfqn = DashFQN.fqn(ances,name); + //System.out.println("HERE3 "+items.toString()); + List xItems = new ArrayList(items); + //System.out.println("HERE3 "+xItems.toString()); + List fromList = + xItems.stream() + .filter(i -> i instanceof DashFrom) + .map(i -> (DashFrom) i) + .collect(Collectors.toList()); + xItems.removeAll(fromList); + + List onList = + xItems.stream() + .filter(i -> i instanceof DashOn) + .map(i -> (DashOn) i) + .collect(Collectors.toList()); + + xItems.removeAll(onList); + + List whenList = + xItems.stream() + .filter(i -> i instanceof DashWhen) + .map(i -> (DashWhen) i) + .collect(Collectors.toList()); + xItems.removeAll(whenList); + + List gotoList = + xItems.stream() + .filter(i -> i instanceof DashGoto) + .map(i -> (DashGoto) i) + .collect(Collectors.toList()); + xItems.removeAll(gotoList); + + List sendList = + xItems.stream() + .filter(i -> i instanceof DashSend) + .map(i -> (DashSend) i) + .collect(Collectors.toList()); + xItems.removeAll(sendList); + + List doList = + xItems.stream() + .filter(i -> i instanceof DashDo) + .map(i -> (DashDo) i) + .collect(Collectors.toList()); + xItems.removeAll(doList); + + if (!tt.add(tfqn,params, paramsIdx, fromList, onList, whenList, gotoList, sendList, doList)) DashErrors.dupTransNames(pos,name); + //System.out.println(xItems); + if (!xItems.isEmpty()) DashErrors.nonEmptyTransItems(); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashVarDecls.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashVarDecls.java new file mode 100644 index 000000000..9c960ee7b --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashVarDecls.java @@ -0,0 +1,45 @@ +package ca.uwaterloo.watform.ast; + +import java.util.List; +import java.util.StringJoiner; + +import ca.uwaterloo.watform.core.DashStrings; +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +public class DashVarDecls extends Dash { + + + private List names; + private Expr typ; + private DashStrings.IntEnvKind kind; + + + + public DashVarDecls (Pos pos, List n, Expr e, DashStrings.IntEnvKind k) { + assert(n != null && e != null); + this.pos = pos; + this.names = n; + this.typ = e; + this.kind = k; + } + + public String toString() { + String s = new String(""); + if (kind == DashStrings.IntEnvKind.ENV) { + s += DashStrings.envName + " "; + } + StringJoiner sj = new StringJoiner(",\n"); + names.forEach(n -> sj.add(n)); + return s + sj.toString() + ":" + typ.toString() + "\n"; + } + public List getNames() { + return names; + } + public Expr getTyp() { + return typ; + } + public DashStrings.IntEnvKind getKind() { + return kind; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashWhen.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashWhen.java new file mode 100644 index 000000000..5c11e6348 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/ast/DashWhen.java @@ -0,0 +1,21 @@ +package ca.uwaterloo.watform.ast; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashStrings; + +public class DashWhen extends Dash { + public Expr when; + public DashWhen(Pos pos,Expr w) { + assert(w != null); + this.pos = pos; + this.when = w; + } + public String toString() { + return DashStrings.whenName + " " + when.toString() + "\n"; + } + public Expr getWhen() { + return when; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashErrors.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashErrors.java new file mode 100644 index 000000000..ef310d646 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashErrors.java @@ -0,0 +1,307 @@ +/* + * All the errors that can be thrown in Dash code + */ + +package ca.uwaterloo.watform.core; + +import java.util.List; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.ast.Expr; + +public class DashErrors { + + // syntax errors -------------------------------------------- + + public static String onlyOneStateMsg = "Dash model can only have one 'state' section"; + public static void onlyOneState(Pos o) throws Err { + throw new ErrorSyntax(o,onlyOneStateMsg); + } + public static String noTransMsg = "Dash Model does not contain any transitions."; + public static void noTrans() throws Err { + throw new ErrorSyntax(noTransMsg); + } + public static String noStatesMsg = "Dash model must have at least one state."; + public static void noStates() throws Err { + throw new ErrorSyntax(noStatesMsg); + } + public static String tooManyDefaultStatesMsg = "Too many default states in state: "; + public static void tooManyDefaults(String fqn) throws Err { + throw new ErrorSyntax(tooManyDefaultStatesMsg+fqn); + } + public static String noDefaultStateMsg = "State does not have default state: "; + public static void noDefaultState(String fqn) throws Err { + throw new ErrorSyntax(noDefaultStateMsg+fqn); + } + public static String allConcDefaultStatesMsg = "All conc children of state must be defaults if one is for state: "; + public static void allAndDefaults(String sfqn) throws Err { + throw new ErrorSyntax(allConcDefaultStatesMsg+sfqn); + } + public static String stateNameCantBeFQNMsg = "When declared, state name cannot have slash: "; + public static void stateNameCantBeFQN(Pos o, String name) throws Err { + throw new ErrorSyntax(o,stateNameCantBeFQNMsg+name); + } + public static String nameCantBeFQNMsg = "When declared, name cannot have slash: "; + public static void nameCantBeFQN(Pos o, String name) throws Err { + throw new ErrorSyntax(o,nameCantBeFQNMsg+name); + } + public static String dupSiblingNamesMsg = "Duplicate sibling state names: "; + public static void dupSiblingNames(String dups) throws Err { + throw new ErrorSyntax(dupSiblingNamesMsg + dups); + } + public static String dupTransNameMsg = "Duplicate transition names: "; + public static void dupTransNames(Pos o, String dups) throws Err { + throw new ErrorSyntax(o, dupTransNameMsg + dups); + } + /* + public static String moreThanOneSrcDestMsg = "Transition has more than one src or dest: "; + public static void moreThanOneSrcDest(String x, String n) throws Err { + throw new ErrorSyntax(moreThanOneSrcDestMsg + x); + } + */ + public static String unknownSrcDestMsg = "Src/Dest of trans is unknown: "; + public static void unknownSrcDest(String x, String t, String tfqn) throws Err { + throw new ErrorSyntax(unknownSrcDestMsg + "trans "+tfqn+" "+t+" "+x); + } + public static String fqnSrcDestMustHaveRightNumberParamsMsg = "Incorrect number of parameters: "; + public static void fqnSrcDestMustHaveRightNumberParams(String xType, String tfqn) throws Err { + throw new ErrorSyntax(fqnSrcDestMustHaveRightNumberParamsMsg + xType + " of transition "+ tfqn ); + } + public static String srcDestCantHaveParamMsg = "Non-fully qualified src/dest cannot have parameters: "; + public static void srcDestCantHaveParam(String xType, String tfqn) throws Err { + throw new ErrorSyntax(srcDestCantHaveParamMsg + xType + " of transition "+ tfqn ); + } + public static String ambiguousRefMsg = "Name not unique: "; + public static void ambiguousRef(Pos pos, String expString) throws Err { + throw new ErrorSyntax(pos + " " + ambiguousRefMsg + expString); + } + + // below this have not been tested + public static String unknownStateMsg = "State does not exist: "; + public static void unknownState(Pos pos, String expString) { + throw new ErrorSyntax(pos + " " + unknownStateMsg + expString); + } + public static String unknownEventMsg = "Event does not exist: "; + public static void unknownEvent(Pos pos, String expString) { + throw new ErrorSyntax(pos + " " + unknownEventMsg + expString); + } + + public static String nameShouldNotBePrimedMsg = "Declared state/trans/event/var cannot have a primed name: "; + public static void nameShouldNotBePrimed(String n) { + throw new ErrorSyntax(nameShouldNotBePrimedMsg+n); + } + + public static String transNameCantBeFQNMsg = "Trans name cannot be fully qualified at declaration: "; + public static void transNameCantBeFQN(Pos o, String s) { + throw new ErrorSyntax(o, transNameCantBeFQNMsg + s); + } + + public static String eventNameCantBeFQNMsg = "Event name cannot be fully qualified at declaration: "; + public static void eventNameCantBeFQN(Pos o, String s) { + throw new ErrorSyntax(o, eventNameCantBeFQNMsg + s); + } + public static String duplicateEventNameMsg = "Event name already in use: "; + public static void duplicateEventName(Pos o, String s) { + throw new ErrorSyntax(o, duplicateEventNameMsg + s); + } + public static String varNameCantBeFQNMsg = "Var name cannot be fully qualified at declaration: "; + public static void varNameCantBeFQN(Pos o, String s) { + throw new ErrorSyntax(o, varNameCantBeFQNMsg + s); + } + public static String duplicateVarNameMsg = "Var name already in use: "; + public static void duplicateVarName(Pos o, String s) { + throw new ErrorSyntax(o, duplicateVarNameMsg + s); + } + public static String bufferNameCantBeFQNMsg = "Buffer name cannot be fully qualified at declaration: "; + public static void bufferNameCantBeFQN(Pos o, String s) { + throw new ErrorSyntax(o, bufferNameCantBeFQNMsg + s); + } + public static String duplicateBufferNameMsg = "Buffer name already in use: "; + public static void duplicateBufferName(Pos o, String s) { + throw new ErrorSyntax(o, duplicateBufferNameMsg + s); + } + public static String duplicateNameMsg = "Name already in use: "; + public static void duplicateName(Pos o, String s) { + throw new ErrorSyntax(o, duplicateNameMsg + s); + } + + // event errors + public static String tooManyMsg = "Multiple "; + public static void tooMany(String xType, String tfqn) { + throw new ErrorSyntax(tooManyMsg + xType + " in " + tfqn); + } + public static String cantSendAnEnvEventMsg = " can't send an environmental event: "; + public static void cantSendAnEnvEvent(Pos p, String expString) { + throw new ErrorSyntax(p + cantSendAnEnvEventMsg + expString); + } + /* + public static String ambiguousEventMsg = "Event name not unique within this conc/Root region: "; + public static void ambiguousEvent(String xType, String v, String tfqn) { + throw new ErrorSyntax(ambiguousEventMsg +v+" in "+ tfqn + " "+xType); + } + */ + public static String fqnEventMissingParametersMsg = "Fully qualified event name missing paramaters: "; + public static void fqnEventMissingParameters(String xType, String v, String tfqn) { + throw new ErrorSyntax(fqnEventMissingParametersMsg + v + " in "+tfqn + " " + xType); + } + public static String expNotEventMsg = "Not an event for: "; + public static void expNotEvent(String xType, String tfqn) { + throw new ErrorSyntax(expNotEventMsg + tfqn + " " + xType); + } + //public static void siblingsSameKind(String fqn) throws Err { + // throw new ErrorSyntax("Children of "+fqn+" must all be of concurrent or not concurrent"); + //} + //public static void crossRefMoreThanOneArg(Pos o, String n) throws Err { + // throw new ErrorSyntax(o,"Two many args to reference to "+n+" in sibling state"); + //} + public static String noPrimedVarsMsg = " Primed variables are not allowed in: "; + public static void noPrimedVars(Pos pos, String expString) { + throw new ErrorSyntax(pos + " " + noPrimedVarsMsg + expString); + } + public static String ambiguousVarMsg = "Var name not unique within this conc/Root region: "; + public static void ambiguousVar(String xType, String v, String tfqn) { + throw new ErrorSyntax(ambiguousVarMsg +v+" in "+ tfqn + " "+xType); + } + public static String fqnVarWrongNumberParametersMsg = "Wrong number of parameter values for: "; + public static String fqnVarWrongNumberParameters(String s1, String s2, String s3) { + throw new ErrorSyntax(fqnVarWrongNumberParametersMsg + s1 + " "+s2 +" "+s3); + } + + public static String cantPrimeAnExternalVarMsg = " Internal var/buffer cannot be primed: "; + public static String cantPrimeAnExternalVar(Pos pos, String expString) { + throw new ErrorSyntax(pos + " " + cantPrimeAnExternalVarMsg + expString); + } + public static String emptyModuleMsg = "Empty module"; + public static String emptyModule() { + throw new ErrorSyntax(emptyModuleMsg); + } + public static String emptyFileMsg = "Empty file: "; + public static String emptyFile(String fname) { + throw new ErrorSyntax(emptyFileMsg+fname); + } + public static String ambiguousUseOfThisMsg = " Ambiguous use of 'this' "; + public static String ambiguousUseOfThis(Pos pos, String expString) { + throw new ErrorSyntax(pos + ambiguousUseOfThisMsg + expString); + } + public static String nonParamUseOfThisMsg = " 'this' must refer to a parametrized state: "; + public static String nonParamUseOfThis(Pos pos, String expString) { + throw new ErrorSyntax(pos + nonParamUseOfThisMsg + expString); + } + public static String wrongNumberParamsMsg = " Incorrect number of parameters: "; + public static void wrongNumberParams(Pos pos, String expString) { + throw new ErrorSyntax(pos + " " + wrongNumberParamsMsg + expString); + } + public static String varPredOverlapMsg = "Same name used for dynamic variable and Dash predicate: "; + public static void varPredOverlap(List s) { + throw new ErrorSyntax(varPredOverlapMsg + s); + } + // parts of the code that should be unreachable ------------- + + public static String ancesNotPrefixMsg = " must be a prefix of "; + public static void ancesNotPrefix(String a, String d) throws Err { + throw new ErrorFatal(a + ancesNotPrefixMsg + d); + } + public static String notVarBeforeDashRefMsg = "must be var: "; + public static void notVarBeforeDashRef (Pos o, String expString) { + throw new ErrorFatal(o + notVarBeforeDashRefMsg + expString); + } + public static void toAlloyNoDash() throws Err { + throw new ErrorFatal("Translating to Alloy when no Dash part"); + } + public static void addStateToStateTableDup(String fqn) throws Err { + throw new ErrorFatal(fqn + "entered more than once in StateTable"); + } + public static void nonBasicEmptyChildren(String fqn) throws Err { + throw new ErrorFatal(fqn + " empty children for non-basic state"); + } + public static void isBasicNotExist(String q) throws Err { + throw new ErrorFatal(q + " isBasicState of state that does not exist"); + } + public static void transTableDup(String n) throws Err { + throw new ErrorFatal("tried to add trans "+n+" to trans table twice"); + } + public static void stateDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", state "+n+ " does not exist in state table"); + } + public static void transDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", trans "+n+ " does not exist in trans table"); + } + public static void varDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", var "+n+ " does not exist in var table"); + } + public static void predDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", var "+n+ " does not exist in pred table"); + } + public static void bufferDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", buffer "+n+ " does not exist in buffer table"); + } + public static void varBufferDoesNotExist(String s1, String n) throws Err { + throw new ErrorFatal("for function "+s1+", "+n+ " does not exist in buffer or var table"); + } + public static void missingExpr(String s) throws Err { + throw new ErrorFatal("Missing expr type in "+s); + } + public static void tooHighParamDepth() throws Err { + throw new ErrorFatal("paramsDepthInUse called with too high a number"); + } + public static String paramNumberProblemMsg = "wrong number of param values: "; + public static void paramNumberProblem(String s) throws Err { + throw new ErrorFatal(paramNumberProblemMsg + s); + } + public static String chopPrefixFromFQNwithNoPrefixMsg = "chopPrefixFromFQNwithNoPrefix: "; + public static void chopPrefixFromFQNwithNoPrefix(String s) throws Err { + throw new ErrorFatal(chopPrefixFromFQNwithNoPrefixMsg + s); + } + public static void nonEmptyStateItems(List x) throws Err { + throw new ErrorFatal("Non-empty state items at end of state resolve: " + x); + } + public static void nonEmptyTransItems() throws Err { + throw new ErrorFatal("Non-empty trans items at end of trans resolve"); + } + public static void getRightNotBinaryOrJoin(String s) throws Err { + throw new ErrorFatal("getRightNotBinaryOrJoin: "+s); + } + public static void getLeftNotBinaryOrJoin(String s) throws Err { + throw new ErrorFatal("getLeftNotBinaryOrJoin: "+s); + } + public static void getSubNotUnary(String s) throws Err { + throw new ErrorFatal("getSubNotUnary: "+s); + } + public static void replaceDashRefExprVarError() throws Err { + throw new ErrorFatal("replaceDashRefExprVarError"); + } + public static void nonDashRefExpr() throws Err { + throw new ErrorFatal("nonDashRefExpr"); + } + public static void eventTableEventNotFound(String m, String efqn) { + throw new ErrorFatal("eventTableEventNotFound: "+m+" "+efqn); + } + + public static void createTestIfNextStableCallMultipleScopesAtSameLevel() { + throw new ErrorFatal("createTestIfNextStableCallMultipleScopesAtSameLevel"); + } + public static String UnsupportedExpr(String s1, String s2) { + throw new ErrorFatal("unsupported expression type in: "+ s1 + " "+s2); + } + public static String UnsupportedExpr(String s1, Expr e) { + throw new ErrorFatal("unsupported expression type in: "+ s1+ " " + e.toString()); + } + public static void bufferIndexDoesNotMatchBufferNumber() { + throw new ErrorFatal("bufferIndexDoesNotMatchBufferNumber"); + } + public static void doesNotExist(String fcnName, String m) { + throw new ErrorFatal("fcn "+fcnName+" arg "+m+"not in table"); + } + public static void noInitialEntered(){ + throw new ErrorFatal("there are no default initial states"); + } + public static void sistersDontChangeDoesNotHaveParams(String s) { + throw new ErrorFatal("sistersDontChangeDoesNotHaveParams: "+s); + } + public static void hasSpecificParamValues() { + throw new ErrorFatal("hasSpecificParamValues"); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashFQN.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashFQN.java new file mode 100644 index 000000000..e8a0019fc --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashFQN.java @@ -0,0 +1,180 @@ +package ca.uwaterloo.watform.core; + +import java.util.StringJoiner; +import java.util.List; +import java.util.Collection; +import java.util.Set; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.stream.Collectors; + + + +public class DashFQN { + + // used for translation to Alloy + //NAD TODO this should match the qualChar used in parsing for vars and state names + private static String inputQualChar = "/"; + private static String internalQualChar = inputQualChar; + private static String outputQualChar = "_"; + + // to create Alloy output + public static String translateFQN(String n) { + return n.replace(internalQualChar, outputQualChar); + } + + // testing inputs from parsing + public static Boolean isFQN(String n) { + return n.contains(inputQualChar); + } + + // creating FQNs from inputs -------------------------- + + public static String fqn(String s1,String s2) { + String q = new String(s1); + q += internalQualChar; + q += s2; + return q; + } + // not really needed unless we change it so that + // inputQualChar != internal QualChar + public static String fqn(String n) { + return n.replace(inputQualChar, internalQualChar); + } + public static String fqn(List pth) { + if (pth.isEmpty()) return null; // for root + StringJoiner sj = new StringJoiner(internalQualChar); + pth.forEach(n -> sj.add(fqn(n))); + return sj.toString(); + } + + public static String fqn(List pth, String name) { + if (isFQN(name)) + return fqn(name); + else { + StringJoiner sj = new StringJoiner(internalQualChar); + pth.forEach(n -> sj.add(fqn(n))); + sj.add(fqn(name)); + return sj.toString(); + } + } + public static String fqn(List pth, String parent, String child) { + if (isFQN(child)) + //return child.replace(inputQualChar,outputQualChar); + return fqn(child); + else { + StringJoiner sj = new StringJoiner(internalQualChar); + pth.forEach(n -> sj.add(fqn(n))); + sj.add(fqn(parent)); + sj.add(fqn(child)); + return sj.toString(); + } + } + + // operations on FQNs + public static List splitFQN(String fqn) { + return Arrays.asList(fqn.split(internalQualChar)); + } + // A/B + B/C => A/B/C + // no longer used probably + public static String mergeFQN(String fqn1, String fqn2) { + List fqn1parts = splitFQN(fqn1); + List fqn2parts = splitFQN(fqn2); + int fqn1i = 0; + int fqn2i = 0; + List outparts = new ArrayList(); + while (fqn1i < fqn1parts.size() && !(fqn1parts.get(fqn1i).equals(fqn2parts.get(fqn2i))) ) { + outparts.add(fqn1parts.get(fqn1i)); + fqn1i++; + } + if (fqn1i == fqn1parts.size()) return ""; + while (fqn1i < fqn1parts.size() + && fqn2i < fqn2parts.size() + && fqn1parts.get(fqn1i).equals(fqn2parts.get(fqn2i)) + ) { + outparts.add(fqn1parts.get(fqn1i)); + fqn1i++; + fqn2i++; + } + if (fqn1i == fqn1parts.size() && fqn2i == fqn2parts.size()) return fqn(outparts); + if (fqn1i == fqn1parts.size() && fqn2i < fqn2parts.size()) { + while (fqn2i < fqn2parts.size()) { + outparts.add(fqn2parts.get(fqn2i)); + fqn2i++; + } + return fqn(outparts); + } + else return ""; + } + public static int commonPrefixLength(String s1, String s2) { + List parts1 = splitFQN(s1); + List parts2 = splitFQN(s2); + int i = 0; + while (i < parts1.size() && i < parts2.size() && parts1.get(i).equals(parts2.get(i))) i++; + return i; + } + public static String chopNameFromFQN(String fqn) { + // this is from an output FQN + return DashUtilFcns.lastElement(splitFQN(fqn)); + } + // useful for getting parent state of a trans/event decl, etc. + public static String chopPrefixFromFQN(String fqn) { + List s = splitFQN(fqn); + if (s.size() < 2) { DashErrors.chopPrefixFromFQNwithNoPrefix(fqn); return null; } + else return fqn(DashUtilFcns.allButLast(splitFQN(fqn))); + } + // can't just take longest prefix because states may have similar names + // such as Bit1 and Bit2 + public static String longestCommonFQN(String a, String b) { + List aSplit = splitFQN(a); + List bSplit = splitFQN(b); + String result = new String(); + int minLength = Math.min(aSplit.size(), bSplit.size()); + int i = 0; + while (i < minLength && aSplit.get(i).equals(bSplit.get(i))) i++; + return fqn(aSplit.subList(0,i)); + } + // include this fqn + public static List allPrefixes(String fqn) { + List prefixes = new ArrayList(); + List splitfqn = splitFQN(fqn); + for (int i=0;i < splitfqn.size(); i++) { + StringJoiner sj = new StringJoiner(internalQualChar); + for (int j=0;j<=i;j++) { + sj.add(splitfqn.get(j)); + } + prefixes.add(sj.toString()); + } + return prefixes; + } + /* + suffix("A/B/C/x", "C/x") is true + suffix("A/B/C/x", "x") is true + suffix("x","x") is true + suffix("A/B/xyz", "yz") is false + */ + public static boolean suffix(String a, String b) { + //System.out.println(a); + //System.out.println(b); + if (a.endsWith(b)) { + int x = a.lastIndexOf(b); + //System.out.println(x); + if (x != -1) { + if (x == 0) return true; + //System.out.println(a.charAt(x-1)); + if (a.charAt(x-1) == internalQualChar.charAt(0)) return true; + } + } + return false; + } + /* ances: A/B/C dest: A/B/C/D/E returns A/B/C/D */ + public static String getChildOfContextAncesOfDest(String ances, String dest) { + if (dest.equals(ances)) return dest; + else if (dest.startsWith(ances)) + // dest must be longer than ances + return fqn(splitFQN(dest).subList(0,splitFQN(ances).size()+1)); + else { DashErrors.ancesNotPrefix(ances,dest); return null; } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashOptions.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashOptions.java new file mode 100644 index 000000000..63b0bcdb7 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashOptions.java @@ -0,0 +1,22 @@ +package ca.uwaterloo.watform.core; + +// everything must be static +public class DashOptions { + + + public static String dashModelLocation = ""; + + public static boolean isElectrum = false; + public static boolean isTcmc = false; + public static boolean isTraces = true; + public static boolean singleEventInput = false; + public static boolean reachability = true; // predicate + public static boolean enoughOperations = true; // predicate + public static boolean includeTrans = true; // for debugging + //NAD other stuff that might be removed + //public static boolean variablesUnchanged = true; + + //public static boolean generateSigAxioms = false; + //public static boolean reachabilityCheck = false; + +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashRef.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashRef.java new file mode 100644 index 000000000..6b8e82cf4 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashRef.java @@ -0,0 +1,454 @@ +/* + These static methods let us treat an Expr as a reference to a Dash object + that has a name and a list of parameter values. + + From Root/A/B[exp1,exp2]/v1 in parsing + a DashRef is recorded in the AST as $$PROCESSREF$$ . exp2 . exp1 . Root/A/B/v1 + + After resolving, a DashRef with no params is $$PROCESSREF$$. var1 + + These references can be within Alloy Expr so we can't do a class extension. + + Even though we could do something different for states/events + (where they aren't referenced within Expr) + its best to use the same functions for all + + Note: we cannot allow any of + b1 -> a1 -> var1 + b1.a1.var1 + var1[a1,b1] + as a way to reference vars or events with parameter values b/c we cannot + tell the difference between the above and something like Chairs.occupied' + where "Chairs" is not a parameter value but a something to be joined with + occupied after it has all of its parameter values. +*/ + +package ca.uwaterloo.watform.core; + +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorWarning; +import edu.mit.csail.sdg.ast.Browsable; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.Type; +import edu.mit.csail.sdg.ast.VisitReturn; + + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import java.util.ArrayList; +//import java.util.JoinableList; + +import edu.mit.csail.sdg.alloy4.Pos; +//import edu.mit.csail.sdg.alloy4.ErrorWarning; +//import edu.mit.csail.sdg.alloy4.Err; +//import edu.mit.csail.sdg.ast.Type; +//import edu.mit.csail.sdg.ast.Browsable; +//import edu.mit.csail.sdg.ast.VisitReturn; +//import edu.mit.csail.sdg.ast.Expr; +//import edu.mit.csail.sdg.ast.ExprBinary; +//import edu.mit.csail.sdg.ast.ExprVar; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +//import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +public class DashRef extends Expr { + + //private Pos pos; + private DashRefKind kind; + private String name; + private List paramValues; + + // generally in the code we know the kind by context but + // for printing we need the kind here + // and this simplified some code for the DashRef to know its kind + private static enum DashRefKind { + STATE, + EVENT, + VAR, + TRANS + // BUFFER ???? + } + + // for internal uses + public DashRef(DashRefKind k, String n, List prmValues) { + super(Pos.UNKNOWN, Type.FORMULA); + this.kind = k; + this.name = n; + this.paramValues = prmValues; + //List ll = new ArrayList(eList); + //Collections.reverse(ll); + //ll.add(createVar(n)); + //return createJoin(processRef(), createJoinList(ll)); + } + + // for uses in parsing + public DashRef(Pos p, DashRefKind k, String n, List prmValues) { + super(p, Type.FORMULA); + this.kind = k; + this.name = n; + this.paramValues = prmValues; + //List ll = new ArrayList(eList); + //Collections.reverse(ll); + //ll.add(createVar(n)); + //return createJoin(processRef(), createJoinList(ll)); + } + + public static DashRef createStateDashRef(Pos p, String n, List prmValues) { + return new DashRef(p, DashRefKind.STATE,n, prmValues); + } + public static DashRef createEventDashRef(Pos p, String n, List prmValues) { + return new DashRef(p, DashRefKind.EVENT,n, prmValues); + + } + public static DashRef createVarDashRef(Pos p, String n, List prmValues) { + return new DashRef(p, DashRefKind.VAR,n, prmValues); + } + public static DashRef createStateDashRef(String n, List prmValues) { + return new DashRef(DashRefKind.STATE,n, prmValues); + } + public static DashRef createEventDashRef(String n, List prmValues) { + return new DashRef(DashRefKind.EVENT,n, prmValues); + + } + public static DashRef createVarDashRef(String n, List prmValues) { + return new DashRef(DashRefKind.VAR,n, prmValues); + } + public static DashRef createTransDashRef(String n, List prmValues) { + return new DashRef(DashRefKind.TRANS,n, prmValues); + + } + + /* + public static Expr createDashRef(Pos p, String n, List eList) { + List ll = new ArrayList(eList); + Collections.reverse(ll); + ll.add(createVar(p, n)); + return createJoin(p, processRef(), createJoinList(ll)); + } + */ + public static List emptyParamValuesList() { + return new ArrayList(); + } + + // we probably don't need this anymore + /* + private static Expr processRef() { + return createVar(DashStrings.processRef); + } + */ + + public static boolean isDashRef(Expr r) { + return (r instanceof DashRef); + /* + if (isExprJoin(e)) + if (isExprVar(getLeft(e))) + return sEquals(getLeft(e), processRef()); + return false; + */ + } + public String getName() { + return name; + } + public List getParamValues() { + return paramValues; + } + public boolean isState() { + return kind == DashRefKind.STATE; + } + public boolean isEvent() { + return kind == DashRefKind.EVENT; + } + public boolean isVar() { + return kind == DashRefKind.EVENT; + } + //public Pos getPos() { + // return pos; + //} + + public String toString() { + // STATE: Root/A/B[a1,b1] + // other: Root/A/B[a1,b1]/var1 + String s = ""; + if (kind == DashRefKind.STATE) { + s += getName(); + } else { + // might not yet have a prefix + if (DashFQN.isFQN(getName())) + s += DashFQN.chopPrefixFromFQN(getName()); + else + s += "NoPrefixYet"; + } + + if (!paramValues.isEmpty()) { + s += "["; + List paramValues = + getParamValues().stream() + .map(i -> i.toString()) + .collect(Collectors.toList()); + //Collections.reverse(paramValues); + s += DashUtilFcns.strCommaList(paramValues); + s += "]"; + } + if (kind != DashRefKind.STATE) { + s += "/"; + s += DashFQN.chopNameFromFQN(getName()); + } + return s; + } + + /** {@inheritDoc} */ + @Override + public void toString(StringBuilder out, int indent) { + // STATE: Root/A/B[a1,b1] + // other: Root/A/B[a1,b1]/var1 + // String s = ""; + if (kind == DashRefKind.STATE) { + out.append(getName()); + } else { + if (DashFQN.isFQN(getName())) + out.append(DashFQN.chopPrefixFromFQN(getName())); + else + out.append("NoPrefixYet"); + } + if (!paramValues.isEmpty()) { + out.append("["); + List paramValues = + getParamValues().stream() + .map(i -> i.toString()) + .collect(Collectors.toList()); + //Collections.reverse(paramValues); + out.append(DashUtilFcns.strCommaList(paramValues)); + out.append("]"); + } + if (kind != DashRefKind.STATE) { + out.append("/"); + out.append(DashFQN.chopNameFromFQN(getName())); + } + } + + //TODO: fix below this line as these are methods + // that must be present to inherit from Expr + // but not sure what they should do + // or if it is okay to have them do nothing + // because DashRefs disappear in conversion to Alloy + /** {@inheritDoc} */ + @Override + public int getDepth() { + int max = 1; + for (Expr x : paramValues) { + int tmp = x.getDepth(); + if (max < tmp) + max = tmp; + } + return 1 + max; + } +/** {@inheritDoc} */ + @Override + public Expr resolve(Type p, Collection warns) { + // this is not needed because DashRef disappear before + // Alloy resolve + return createNone(); + } + /** {@inheritDoc} */ + @Override + public final T accept(VisitReturn visitor) throws Err { + return null; + } + /** {@inheritDoc} */ + @Override + public List< ? extends Browsable> getSubnodes() { + //Browsable a = make(var.pos, var.pos, "var " + var.label + " = ...", expr); + //Browsable b = make(sub.span(), sub.span(), "where...", sub); + return null; + } + /** {@inheritDoc} */ + @Override + public String getHTML() { + return ""; + } + /* + public static String getName(Expr e) { + assert(isDashRef(e) || isExprVar(e)); + if (isDashRef(e)) { + // might be a $$PROCESSREF$$.a.b.PRIME(e) + while (isExprJoin(e)) e = getRight(e); + assert(isExprVar(e)); + } + return getVarName((ExprVar) e); + } + public static List getParamValues(Expr e) { + assert(isDashRef(e) || isExprVar(e)); + List plist = new ArrayList(); + // strip off $$PROCESSREF$$ + if (isDashRef(e)) { + Expr f = getRight(e); + while (isExprJoin(f)) { + //System.out.println(f.toString()); + plist.add(getLeft(f)); + f = getRight(f); + } + } + return plist; + } + */ + /* + public static Expr subForDashRefArrow(Expr e, Expr r) { + if (isExprVar(e)) return r; + else return createArrow(getLeft(e), subForDashRefArrow(getRight(e),r)); + } + // works for Join or BadJoin + public static Expr subForDashRefJoin(Expr e, Expr r) { + if (isExprVar(e)) return r; + else return createJoin(getLeft(e), subForDashRefJoin(getRight(e),r)); + } + */ + /* + public Expr convertToJoin() { + List ll = new ArrayList(getParamValues()); + //Collections.reverse(ll); + ll.add(createVar(name)); + return createJoinList(ll); + } + public Expr convertToArrow() { + List ll = new ArrayList(getParamValues()); + //Collections.reverse(ll); + ll.add(createVar(name)); + return createArrowExprList(ll); + } + */ + /* + private static Expr convertDashRefToArrowAux(Expr e) { + //if (isExprVar(e)) return createVar(DashFQN.fqn(getVarName((ExprVar) e))); + //else return createArrow(getLeft(e), convertDashRefToArrowAux(getRight(e))); + } + */ + /* + public static Expr convertDashRefToArrow(Expr e) { + // removes $$PROCESSREF$$ and replaces joins with arrows + Expr e1 = getRight(e); + return convertDashRefToArrowAux(e1); + } + */ + + + /* + private Pos pos; + private String name; + private List paramValues; + + public DashRef(Pos p, String n, List eList) { + this.pos = p; + this.name = n; + assert(n != null); + assert(!n.isEmpty()); + assert(eList != null); + this.paramValues = eList; + } + + public DashRef(String n, List eList) { + this.pos = Pos.UNKNOWN; + this.name = n; + this.paramValues = eList; + //System.out.println(n); + //System.out.println(eList); + } + */ + + /* + public String getName() { + return name; + } + public List getParamValues() { + return paramValues; + } + public String toString() { + String r = ""; + r += name + "[" + DashUtilFcns.strCommaList(paramValues) +"]"; + return r; + } + */ + + + + /* + can only be used in an action + exp2. exp1. Root/A/B/v1 or + exp2. exp1. Root/A/B/v1' + */ + /* + public static boolean isDashRefJoin(Expr e) { + if (isExprJoin(e)) { + Expr e2 = e; + while (isExprJoin(e2)) e2 = getRight(e2); + if (isExprVar(e2)) return true; + //String v = getVarName((ExprVar)e2); + //if (DashFQN.isFQN(v)) return true; + //} + } + return false; + } + */ + // results from pred calls Tk[xx] + /* + public static boolean isDashRefBadJoin(Expr e) { + //System.out.println(e); + //System.out.println(e.getClass().getName()); + if (isExprBadJoin(e)) { + Expr e2 = e; + while (isExprBadJoin(e2)) { + e2 = getRight(e2); + } + if (isExprVar(e2)) return true; //{ + //String v = getVarName((ExprVar)e2); + //if (DashFQN.isFQN(v)) return true; + //} + } + return false; + } + */ + /* + can only be used in an event + exp2 -> exp1 -> Root/A/B/ev1 + */ + /* + public static boolean isDashRefArrow(Expr e) { + if (isExprArrow(e)) { + Expr e2 = e; + while (isExprArrow(e2)) e2 = getRight(e2); + if (isExprVar(e2)) return true; //{ + //String v = getVarName((ExprVar)e2); + //if (DashFQN.isFQN(v)) return true; + //} + } + return false; + } + */ + /* + from exp2. exp2. Root/A/B/v1' return Root/A/B/v1' + */ + + /* + replaceDashRefExprVar(exp2. exp1. Root/A/B/v1', sNext.Root/A/B/v1 ) + returns exp2.exp1.sNext.Root/A/B/v1 + */ + + + + // referencing a for loop variable in a filter does not work + // so do this as a loop + public static List hasNumParams(List dr, int i) { + // filter to ones that have this number of params + //System.out.println(i); + //System.out.println(dr); + List o = dr.stream() + .filter(x -> x.getParamValues().size() == i) + .collect(Collectors.toList()); + //System.out.println(o); + return o; + } + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashSituation.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashSituation.java new file mode 100644 index 000000000..baa5f8a9b --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashSituation.java @@ -0,0 +1,30 @@ +package ca.uwaterloo.watform.core; + +import java.util.*; +import edu.mit.csail.sdg.alloy4.Pair; + +// everything must be static +public class DashSituation { + + // we need a little bit of knowledge of the state of the process because + // open statements have to be done before anything else in an + // Alloy file, but we don't know how many buffers we have + // so we have to run parsing once to count buffers + // and then a second time with the appropriate open statements + // we don't want to put this state within the DashModule because + // then we'd have to pass the dash module into the parser + // which isn't available at the parseFromFile in DashUtil (copied from CompUtil) + // so we set this after the first parse run + // and check it during the second parse run + public static boolean haveCountedBuffers = false; + // buffer elements in order of buffers + // its a pain to make a pair in Alloy (Pair class is difficult) + // or Java where javafx.util.Pair does not seem to be available + // for this version of Alloy + // so just keep two lists in sync + public static List bufferNames = new ArrayList(); + public static List bufferElements = new ArrayList(); + public static int bufferIndex = 0; + // we will need more here to know the names of the elements + // of the buffers for the open statements +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashStrings.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashStrings.java new file mode 100644 index 000000000..253fbddcf --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashStrings.java @@ -0,0 +1,171 @@ + /* string names used in Dash and conversion to Alloy */ + +package ca.uwaterloo.watform.core; + +public class DashStrings { + + // pretty printing anywhere + public static String tab = " "; + + /* alloy keywords */ + public static String moduleName = "module"; + public static String extendsName = "extends"; + public static String inName = "in"; + public static String abstractName = "abstract"; + public static String oneName = "one"; + public static String loneName = "lone"; + public static String varName = "var"; + public static String openName = "open"; + public static String asName = "as"; + + public static String noneName = "none"; + public static String intName = "int"; + public static String sigName = "sig"; + public static String predName = "pred"; + public static String factName = "fact"; + public static String thisName = "this"; + + + // standard modules + public static String utilBooleanName = "util/boolean"; + public static String boolName = "boolean/Bool"; + public static String trueName = "boolean/True"; + public static String falseName = "boolean/False"; + public static String isTrue = "boolean/isTrue"; + public static String isFalse = "boolean/isFalse"; + + //public static String utilOrderingName = "util/ordering"; + public static String utilTracesName = "util/traces"; + public static String tracesFirstName = "first"; + public static String tracesNextName = "next"; + public static String tracesLastName = "last"; + + public static String utilBufferName = "util/buffer"; + + public static String utilTcmcPathName = "util/tcmc"; + public static String tcmcInitialStateName = "tcmc/ks_s0"; + public static String tcmcSigmaName = "tcmc/ks_sigma"; + + + + // Dash input keywords + // used for printing: parts of Dash syntax + // must be in sync with Dash-cup-symbols.txt + public static String stateName = "state"; + public static String concName = "conc"; + public static String defaultName = "default"; + public static String eventName = "event"; + public static String envName = "env"; + public static String bufName = "buf"; + public static String transName = "trans"; + public static String fromName = "from"; + public static String onName = "on"; + public static String whenName = "when"; + public static String doName = "do"; + public static String gotoName = "goto"; + public static String sendName = "send"; + public static String invName = "inv"; + public static String enterName = "enter"; + public static String exitName = "exit"; + public static String initName = "init"; + + + // user must be aware of this name + public static String bufferIndexName = "bufIdx"; + + public static String dsh_prefix = "dsh_"; + // init is a reserved word in Dash + public static String initFactName = dsh_prefix + "initial"; + public static String electrumInitName = dsh_prefix + "init"; + // predicate names + + public static String smallStepName = dsh_prefix + "small_step"; + public static String stableName = dsh_prefix + "stable"; + public static String stutterName = dsh_prefix + "stutter"; + //public static String equalsName = "equals"; + public static String isEnabled = dsh_prefix + "isEnabled"; + public static String tracesFactName = dsh_prefix + "traces_fact"; + public static String electrumFactName = dsh_prefix + "electrum_fact"; + public static String tcmcFactName = dsh_prefix + "tcmc_fact"; + public static String singleEventName = dsh_prefix + "single_event"; + public static String reachabilityName = dsh_prefix + "reachability"; + public static String enoughOperationsName = dsh_prefix + "enough_operations"; + public static String completeBigStepsName = dsh_prefix + "complete_big_steps"; + /* names used in Dash translation */ + // sig names + public static String DshPrefix = "Dsh"; + public static String snapshotName = DshPrefix + "Snapshot"; + public static String allEventsName = DshPrefix + "Events"; + public static String allEnvironmentalEventsName = DshPrefix + "EnvEvents"; + public static String allInternalEventsName = DshPrefix + "IntEvents"; + public static String variablesName = DshPrefix + "Vars"; + public static String stateLabelName = DshPrefix + "States"; + public static String scopeLabelName = DshPrefix + "Scopes"; + //public static String systemStateName = "SystemState"; + public static String transitionLabelName = "Transitions"; + public static String noTransName = "NO_TRANS"; + public static String identifierName = DshPrefix + "Ids"; + public static String bufferName = DshPrefix + "Buffer"; + public static String scopeSuffix = "Scope"; + + // field names + public static String confName = dsh_prefix + "conf"; + public static String scopesUsedName = dsh_prefix + "sc_used"; + public static String eventsName = dsh_prefix + "events"; + public static String transTakenName = dsh_prefix + "taken"; + // predicate names + //public static String tName = "dsh_t"; + public static String preName = "_pre"; + public static String postName = "_post"; + //public static String semanticsName = "_semantics"; + public static String testIfNextStableName = "_nextIsStable"; + public static String enabledAfterStepName = "_enabledAfterStep"; + public static String allSnapshotsDifferentName = "allSnapshotsDifferent"; + // variable/parameter names + // how to name parameter variables + public static String curName = "s"; + public static String nextName = "sn"; + public static String pName = "p"; + public static String genEventName = "genEvs"; + public static String scopeName = "sc"; + public static String randomParamExt = "_aa"; + + // strings used internally + public static String processRef = "$$PROCESSREF$$"; + public static String SLASH = "/"; + public static String PRIME = "'"; + + public static String prime(String a) { + return a+"'"; + }; + + public static enum IntEnvKind { + INT, + ENV + } + + public static enum StateKind { + AND, + OR + // basic is determined if no children + } + + // this distinct is only used at parsing + // within StateTable the default of a state is String name + // or null + public static enum DefKind { + DEFAULT, + NOTDEFAULT + } + + + public static boolean hasPrime(String s) { + return (s.substring(s.length()-1, s.length()).equals(PRIME)); + } + public static String removePrime(String s) { + if (hasPrime(s)) return s.substring(0, s.length()-1); + else return s; + } + + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashUtilFcns.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashUtilFcns.java new file mode 100644 index 000000000..242e6ad94 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/core/DashUtilFcns.java @@ -0,0 +1,87 @@ +/* + * For the util functions used many places + */ + +package ca.uwaterloo.watform.core; + +import java.util.StringJoiner; +import java.util.List; +import java.util.Collection; +import java.util.Set; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.stream.Collectors; + +public class DashUtilFcns { + + /* copied from https://stackoverflow.com/questions/7414667/identify-duplicates-in-a-list */ + public static Set findDuplicates(Collection collection) { + + Set duplicates = new LinkedHashSet<>(); + Set uniques = new HashSet<>(); + + for(T t : collection) + if(!uniques.add(t)) + duplicates.add(t); + return duplicates; + } + + public static String strCommaList(List ll) { + StringJoiner sj = new StringJoiner(", "); + ll.forEach(n -> sj.add(n.toString())); + return sj.toString(); + } + public static Set listToSet(List ll) { + return ll.stream().collect(Collectors.toSet()); + } + + public static List setToList(Set ll) { + return new ArrayList(ll); + } + + public static void myprint(String s) { + // debugging output + System.out.println(s); + } + public static List newListWith(List ll, T s) { + List x = new ArrayList(ll); + x.add(s); + return x; + } + public static String NoneStringIfNeeded(T x) { + return ( (x == null) ? "none" : x.toString()) ; + } + + public static void handleException(Exception e) { + e.printStackTrace(System.err); + System.exit(1); + } + + public static T lastElement(List ll) { + return ll.get(ll.size() - 1 ); + } + + public static List allButLast(List ll) { + if (ll.isEmpty()) return ll; + else return ll.subList(0,ll.size()-1); + } + // java's Collection.reverse doesn't work sometimes + public static List reverse(List ll) { + assert(!ll.isEmpty()); + List x = new ArrayList(); + for (int i=ll.size()-1;i>=0;i--) { + x.add(ll.get(i)); + } + assert(x.size() == ll.size()); + return x; + } + + public static List listOfInt(int start, int stop) { + assert(start <= stop); + List x = new ArrayList(); + for (int i=start; i <= stop; i++) x.add(i); + return x; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddAllSnapshotsDifferentFact.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddAllSnapshotsDifferentFact.java new file mode 100644 index 000000000..09ccc9dfe --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddAllSnapshotsDifferentFact.java @@ -0,0 +1,69 @@ +package ca.uwaterloo.watform.dashtoalloy; + +//import java.util.Collections; +//import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +//import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +//import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddAllSnapshotsDifferentFact { + /* + fact allSnapshotsDifferent { + all s:DshSnapshot, sn:DshSnapshot | + s.dsh_sc_used0 = sn.dsh_sc_used0 and + s.dsh_conf0 = sn.dsh_conf0 and + s.dsh_taken0 = sn.dsh_taken0 and + s.dsh_events0 = sn.dsh_events0 and + s.dsh_stable = sn.dsh_stable => + s = sn + } + */ + public static void addAllSnapshotsDifferentFact(DashModule d) { + List body = new ArrayList(); + Expr e; + for (int i = 0; i <= d.getMaxDepthParams(); i++) { + if (!d.hasOnlyOneState()) + body.add(createEquals(curConf(i),nextConf(i))); + // s.scopesUsedi = sn.scopesUsedi + if (d.hasConcurrency()) + body.add(createEquals(curScopesUsed(i),nextScopesUsed(i))); + body.add(createEquals(curTransTaken(i),nextTransTaken(i))); + if (d.hasInternalEventsAti(i)) + body.add(createEquals(curEvents(i),nextEvents(i))); + } + if (d.hasConcurrency()) + body.add(createEquals(curStable(),nextStable())); + List allVarsAndBuffers = d.getAllVarNames(); + allVarsAndBuffers.addAll(d.getAllBufferNames()); + for (String v: allVarsAndBuffers) { + body.add(createEquals(curJoinExpr(createVar(translateFQN(v))), nextJoinExpr(createVar(translateFQN(v))))); + } + + //TODO: have to add something for all dynamic variables !!!! + e = createAll(curNextDecls(), createImplies(createAndList(body), createEquals(curVar(), nextVar()))); + body = new ArrayList(); + body.add(e); + d.alloyString += d.addFactSimple(DashStrings.allSnapshotsDifferentName, body); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddCompleteBigSteps.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddCompleteBigSteps.java new file mode 100644 index 000000000..b02cb06b3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddCompleteBigSteps.java @@ -0,0 +1,59 @@ +/* + * completeBigStepsFact + * + * Every non-stable snapshot included in the next snapshot relation + * has a next snapshot, which means every big step must be complete. + * fact completeBigSteps { + * all s : Snapshot | s.stable == False => some s': Snapshot. small_step[s,s'] + * } + * + * The above works for all methods. + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.IntStream; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddCompleteBigSteps { + + public static void addCompleteBigSteps(DashModule d) { + if (d.hasConcurrency()) { + Expr b = createAll(curDecls(), + createImplies( + curStableFalse(), + createSome(nextDecls(), + createPredCall(DashStrings.smallStepName, curNextVars())))); + + List body = new ArrayList(); + body.add(b); + d.alloyString += d.addFactSimple(DashStrings.completeBigStepsName, body); + } + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddElectrumFact.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddElectrumFact.java new file mode 100644 index 000000000..66cbd28b3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddElectrumFact.java @@ -0,0 +1,56 @@ +/* + Add fact for Electrum +*/ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import static ca.uwaterloo.watform.core.DashStrings.*; +//import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +//import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +import ca.uwaterloo.watform.alloyasthelper.DeclExt; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddElectrumFact { + + public static void addElectrumFact(DashModule d) { + + /* + fact electrum { + init and always small_step + } + */ + + assert(DashOptions.isElectrum); + List body = new ArrayList(); + + body.add(createVar(initFactName)); + body.add(createAlways(createVar(smallStepName))); + d.alloyString += d.addFactSimple(initFactName, body); + + } +} + + + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddEnoughOperationsPred.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddEnoughOperationsPred.java new file mode 100644 index 000000000..07b08bca9 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddEnoughOperationsPred.java @@ -0,0 +1,57 @@ +/* + * There exists at least one representative of every transition + * + * pred operationsSignificance { + * some s, s’: Snapshot | some p0, p1 | T1[s, s’] + * some s, s’: Snapshot | T2[s, s’] + * some s, s’: Snapshot | T3[s, s’] + * ... + * } + */ + + +package ca.uwaterloo.watform.dashtoalloy; + +//import java.util.Collections; +//import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +//import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddEnoughOperationsPred { + + public static void addEnoughOperationsPred(DashModule d) { + + ArrayList body = new ArrayList(); + + for (String tfqn: d.getAllTransNames()) { + String tout = translateFQN(tfqn); + body.add(createSome( + curNextParamsDecls(d.getTransParamsIdx(tfqn),d.getTransParams(tfqn)), + createPredCall(tout,curNextParamVars(d.getTransParamsIdx(tfqn),d.getTransParams(tfqn))))); + } + ArrayList nodecls = new ArrayList(); + d.alloyString += d.addPredSimple(DashStrings.enoughOperationsName,nodecls, body); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInit.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInit.java new file mode 100644 index 000000000..c42b69bdb --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInit.java @@ -0,0 +1,120 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.IntStream; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddInit { + + // -------------------------------------------------------------------------------------- + /* + TODO add here + TODO add Electrum + */ + public static void addInit(DashModule d) { + + List prs = d.getAllParamsInOrder(); + List body = new ArrayList(); + + if (!d.hasOnlyOneState()) { + // forall i. confi = default entries + List entered = d.initialEntered(); + if (entered.isEmpty()) DashErrors.noInitialEntered(); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + List ent = DashRef.hasNumParams(entered,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + if (!ent.isEmpty()) body.add(createEquals(curConf(i),createUnionList(ent))); + else body.add(createEquals(curConf(i), createNone())); + } + } + for (int i = 0; i <= d.getMaxDepthParams(); i++) { + // scopesUsedi = none + if (d.hasConcurrency()) + body.add(createEquals( + curScopesUsed(i), + createNoneArrow(i))); + if (i == 0 ) + body.add(createEquals( + curTransTaken(i), + createVar(DashStrings.noTransName))); + else + body.add(createEquals( + curTransTaken(i), + createNoneArrow(i))); + // no limits on initial set of events except that they must be environmental + //s.events1 :> internalEvents = none -> none + if (d.hasInternalEventsAti(i)) + body.add(createEquals( + createRangeRes(curEvents(i), allInternalEventsVar()), + createNoneArrow(i))); + } + + + + + // even if these are empty we need this predicate to exist + for (Expr i: d.getInits()) + // these may have the use of parameters in them + body.add(translateExpr(i,d)); + + // it was really tricky to get these types/lists right + // so don't try to combine these steps + + Expr e; + List decls; + if (!body.isEmpty()) { + if (!prs.isEmpty()) { + // all parameters are not used in init + decls = new ArrayList(); + e = createAndFromList(body); + for (int i=0; i < prs.size();i++) { + if (usedIn(paramVar(i,prs.get(i)),e )) { + decls.add(paramDecl(i,prs.get(i))); + } + } + if (!decls.isEmpty()) e = createAll(decls,e); + } + else e = createAndFromList(body); + body = new ArrayList(); + body.add(e); + } + if (d.hasConcurrency()) body.add(curStableTrue()); + // init is a reserved word in Electrum + if (DashOptions.isElectrum) { + d.alloyString += d.addPredSimple(DashStrings.initFactName, new ArrayList(), body); + } else { + // snapshot will always be needed as a parameter + // because it is used in conf (every model has at least one state) + d.alloyString += d.addPredSimple( + DashStrings.initFactName, + curDecls(), + body); + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInv.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInv.java new file mode 100644 index 000000000..d805abb3c --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddInv.java @@ -0,0 +1,79 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; + + + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +//import static ca.uwaterloo.watform.core.DashFQN.*; + + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddInv { + + // -------------------------------------------------------------------------------------- + /* + TODO add here + */ + public static void addInv(DashModule d) { + + List prs = d.getAllParamsInOrder(); + List body = new ArrayList(); + + // since this is a fact, we don't need it if there are no invariants + if (!d.getInvs().isEmpty()) { + for (Expr i: d.getInvs()) + // these may have the use of parameters in them + body.add(translateExpr(i,d)); + + // it was really tricky to get these types/lists right + // so don't try to combine these steps + + Expr e; + List decls = new ArrayList(); + if (!body.isEmpty()) { + if (!prs.isEmpty()) { + // all parameters are not used in inv + e = createAndFromList(body); + for (int i=0; i < prs.size();i++) { + if (usedIn(paramVar(i,prs.get(i)),e )) { + decls.add(paramDecl(i,prs.get(i))); + } + } + if (!decls.isEmpty()) e = createAll(decls,e); + } + else e = createAndFromList(body); + body = new ArrayList(); + body.add(e); + } else e = createAndFromList(body); + if (usedIn(curVar(),e)) decls.add(curDecl()); + if (!DashOptions.isElectrum) { + body = new ArrayList(); + if (!decls.isEmpty()) body.add(createAll(decls,e)); + else body.add(e); + } + d.alloyString += d.addFactSimple(DashStrings.invName, body); + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddReachabilityPred.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddReachabilityPred.java new file mode 100644 index 000000000..de997cf84 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddReachabilityPred.java @@ -0,0 +1,55 @@ +/* + * + * Every snapshot is reachable from an initial snapshot + * fact reachabilityAxiom { + * all s : Snapshot | s in Snapshot .(( initial) <: * (sigma)) + * } + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.IntStream; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddReachabilityPred { + + public static void addReachabilityPred(DashModule d) { + assert(!DashOptions.isElectrum && !DashOptions.isTraces); + Expr b = createAll(curDecls(), + createIn(curVar(), + createJoin(createVar(DashStrings.snapshotName), + createDomainRes(createVar(DashStrings.tcmcInitialStateName), + createReflexiveTransitiveClosure(createVar(DashStrings.tcmcSigmaName)))))); + List body = new ArrayList(); + body.add(b); + List emptyDecls = new ArrayList(); + // d.alloyString += d.addPredSimple(DashStrings.reachabilityName, emptyDecls, body); + d.alloyString += d.addPredSimple(DashStrings.reachabilityName, emptyDecls, body); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSingleEventInputFact.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSingleEventInputFact.java new file mode 100644 index 000000000..387a641fc --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSingleEventInputFact.java @@ -0,0 +1,73 @@ +/* + * Optional fact for single "input" assumption + * For Dash+, this means only one env event per big step + * + * + * + * fact single_input { + * all s: Snapshot | + * lone s.events0 :> ExternalEvents and no s.events1:> ExternalEvents and no.events2:> ExternalEvents or ... + * no s.events0:> ExternalEvents and lone s.events1:> ExternalEvents and no s.events2 :> ExternalEventsor ... + * no s.events0 :> ExternalEvents and no s.events1:> ExternalEvents and lone s.events2:> ExternalEvents or ... + * } + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.IntStream; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddSingleEventInputFact { + + public static void addSingleEventInputFact(DashModule d) { + if (d.hasEnvironmentalEvents()) { + Expr e; + Expr b = createFalse(); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (d.hasEventsAti(i)) { + e = createTrue(); + for (int j=0;j <= d.getMaxDepthParams(); j++) { + if (d.hasEventsAti(j)) { + if (i==j) { + e = createAnd(e,createLone(createRangeRes(curEvents(i), allEnvironmentalEventsVar()))); + } else { + e = createAnd(e,createNo(createRangeRes(curEvents(i), allEnvironmentalEventsVar()))); + } + } + } + b = createOr(b,e); + } + } + List body = new ArrayList(); + if (DashOptions.isElectrum) body.add(b); + else body.add(createAll(curDecls(),b)); + d.alloyString += d.addFactSimple(DashStrings.singleEventName, body); + } + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSmallStep.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSmallStep.java new file mode 100644 index 000000000..abf51cda1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSmallStep.java @@ -0,0 +1,79 @@ +package ca.uwaterloo.watform.dashtoalloy; + +//import java.util.Collections; +//import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +//import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +//import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddSmallStep { + /* + pred small_step [s:Snapshot, s': Snapshot] { + (some pparam0 : Param0 , pparam1 : Param1 ... | + { // for all t’s at level i with params Param5, Param6, ... + (or t[s, s_next, pparam5, pparam6 ]) + }) + or + (!(some pparam0 : Param0 , pparam1 : Param1 ... | + { // for all t’s at level i with params Param5, Param6, ... + (or t_pre[s, s_next, pparam5, pparam6 ]) ) + and s = s') + + */ + public static void addSmallStep(DashModule d) { + + ArrayList e = new ArrayList(); + List prs = d.getAllParamsInOrder(); + + // trans is taken + for (String tfqn: d.getAllTransNames()) { + String tout = translateFQN(tfqn); + // p3.p2.p1.t for parameters of this transition + if (DashOptions.isElectrum) e.add(createPredCall(tout,paramVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p3.p2.p1.s'.s.t for parameters of this transition + else e.add(createPredCall(tout,curNextParamVars(d.getTransParamsIdx(tfqn),d.getTransParams(tfqn)))); + } + Expr transIsTaken; + if (d.getAllParamsInOrder().isEmpty()) transIsTaken = createOrFromList(e); + else transIsTaken = createSome(paramDecls(DashUtilFcns.listOfInt(0,prs.size()-1),prs),createOrFromList(e)); + + // no trans is enabled + e = new ArrayList(); + for (String tfqn: d.getAllTransNames()) { + String tout = translateFQN(tfqn); + // p3.p2.p1.t for parameters of this transition + if (DashOptions.isElectrum) e.add(createPredCall(tout,paramVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p3.p2.p1.s'.s.t for parameters of this transition + else e.add(createPredCall(tout+DashStrings.preName,curParamVars(d.getTransParamsIdx(tfqn),d.getTransParams(tfqn)))); + } + Expr transIsNotEnabled; + if (d.getAllParamsInOrder().isEmpty()) transIsNotEnabled = createOrFromList(e); + else transIsNotEnabled = createSome(paramDecls(DashUtilFcns.listOfInt(0,prs.size()-1),prs),createOrFromList(e)); + transIsNotEnabled = createAnd(createNot(transIsNotEnabled), createPredCall(DashStrings.stutterName, curNextVars())); + + e = new ArrayList(); + e.add(createOr(transIsTaken, transIsNotEnabled)); + d.alloyString += d.addPredSimple(DashStrings.smallStepName,curNextDecls(),e); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSnapshotSignature.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSnapshotSignature.java new file mode 100644 index 000000000..f2f283ba9 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSnapshotSignature.java @@ -0,0 +1,287 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.core.DashStrings; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddSnapshotSignature { + + public static void addSnapshotSignature(DashModule d){ + if (DashOptions.isElectrum) { + // if Electrum add var sigs + // scopesUsed0, conf0, event0 + List decls; + + if (d.hasConcurrency()) + d.alloyString += d.addVarSigSimple(scopesUsedName+"0", createVar(stateLabelName)); + if (!d.hasOnlyOneState()) + d.alloyString += d.addVarSigSimple(confName+"0", createVar(stateLabelName)); + d.alloyString += d.addVarSigSimple(transTakenName+"0", createVar(transitionLabelName)); + if (d.hasEvents()) + d.alloyString += d.addVarSigSimple(eventsName+"0", createVar(allEventsName)); + + // sig Identifiers { + // conf1: StateLabel, + // scopesUsed1: StateLabel, + // events1: AllEvent, + // conf2: Identifiers -> StateLabel, + // scopesUsed2: Identifers -> StateLabel, + // etc + // } + if (d.getMaxDepthParams() != 0) { + List cop; + decls = new ArrayList(); + for (int i = 1; i <= d.getMaxDepthParams(); i++) { + cop = new ArrayList (Collections.nCopies(i-1,createVar(identifierName))); + // conf 1, etc. + if (!d.hasOnlyOneState()) + decls.add( + DeclExt.newVarDeclExt( + confName+Integer.toString(i), + createArrowExprList(DashUtilFcns.newListWith(cop, createSet(createVar(stateLabelName)))))); + + decls.add( + DeclExt.newVarDeclExt( + transTakenName+Integer.toString(i), + createArrowExprList(DashUtilFcns.newListWith(cop, createSet(createVar(transitionLabelName)))))); + if (d.hasConcurrency()) + // scopesUsed 1, etc. + decls.add( + DeclExt.newVarDeclExt( + scopesUsedName+Integer.toString(i), + createArrowExprList(DashUtilFcns.newListWith(cop, createSet(createVar(stateLabelName)))))); + if (d.hasEvents() & d.hasEventsAti(i)) + // events 1, etc. + decls.add( + DeclExt.newVarDeclExt( + eventsName+Integer.toString(i), + createArrowExprList(DashUtilFcns.newListWith(cop, createSet(createVar(allEventsName)))))); + } + d.alloyString += d.addSigWithDeclsSimple(identifierName, decls); + } + + // stable: one boolean; + if (d.hasConcurrency()) { + d.alloyString += d.addVarSigSimple(stableName, createVar(boolName)); + } + // add vars and parameter sets -------------------------------------- + + + List allvfqns = d.getAllVarNames(); + List allbfqns = d.getAllBufferNames(); + + // vfqns with no params and simple type + // becomes var sig vfqn in var {} + // no buffers in this case + // this is tricky if one/lone/set modifiers on type *** + List allvfqnsNoParamsSimpleTyp = allvfqns.stream() + .filter(i -> d.getVarBufferParams(i).size() == 0 && !isWeirdOne(i,d)) + .collect(Collectors.toList()); + for (String v: allvfqnsNoParamsSimpleTyp) { + + Expr typ = d.getVarType(v); + //System.out.println(typ.getClass()); + //System.out.println(((ExprUnary) typ).op); + if (isExprVar(typ)) { + d.alloyString += d.addVarSigSimple(translateFQN(v), ((ExprVar) translateExpr(typ,d,true)) ); + } else if (isExprSet(typ) && isExprVar(getSub(typ))) { + d.alloyString += d.addVarSigSimple(translateFQN(v), ((ExprVar)translateExpr(getSub(typ),d,true)) ); + } else if (isExprLone(typ) && isExprVar(getSub(typ))) { + d.alloyString += d.addVarLoneSigSimple(translateFQN(v), ((ExprVar)translateExpr(getSub(typ),d,true)) ); + } else if (isExprOne(typ) && isExprVar(getSub(typ))) { + d.alloyString += d.addVarOneSigSimple(translateFQN(v), ((ExprVar) translateExpr(getSub(typ),d,true)) ); + } else { + TranslationToAlloyErrors.Unsupported(typ); + } + } + + // vfqns with no params and non-simple var types (weird ones) + // becomes sig A { var vfqn: B } + // but A has already been declared somewhere by the user + // and we can't easily add a field to an existing signature in + // Alloy module, so instead add one atom to model + // one sig Variables { + // v1: typ1 + // } + // and have to deal with this case in translation to Alloy + // no buffers in this case because they can be grouped with index + List allvfqnsNoParamsArrowTyp = allvfqns.stream() + .filter(i -> Common.isWeirdOne(i,d)) + .collect(Collectors.toList()); + if (!allvfqnsNoParamsArrowTyp.isEmpty()) { + decls = new ArrayList(); + for (String v: allvfqnsNoParamsArrowTyp) + decls.add(DeclExt.newVarDeclExt(translateFQN(v), translateExpr(d.getVarType(v),d, true))); + d.alloyString += d.addOneSigWithDeclsSimple(DashStrings.variablesName, decls); + } + + // vfqns with parameters P1, P2, P3 + // sig P1 { + // var v1: P2 -> P3 -> typ1 + // var buf: P2 -> P3 -> bufindex -> eltype + // } + // it is enough to look at state parameters to get all parameters + List allvfqnsWithThisFirstParam; + List allbfqnsWithThisFirstParam; + List plist; + + for (String prm: DashUtilFcns.listToSet(d.getAllParamsInOrder())) { + + // variables with parameters grouped with parameter + allvfqnsWithThisFirstParam = allvfqns.stream() + // must be at least one parameter + .filter(i -> d.getVarBufferParams(i).size() != 0 && d.getVarBufferParams(i).get(0).equals(prm)) + .collect(Collectors.toList()); + // construct decls -- might be none but still have to + // create sig for this parameter + decls = new ArrayList(); + for (String v: allvfqnsWithThisFirstParam) { + if (d.getVarBufferParams(v).size() == 1) { + decls.add(DeclExt.newVarDeclExt(translateFQN(v), translateExpr(d.getVarType(v),d, true))); + } else { + plist = createVarList(d.getVarBufferParams(v).subList(1, d.getVarBufferParams(v).size()-1)); + plist.add(translateExpr(d.getVarType(v),d, true)); + decls.add(DeclExt.newVarDeclExt(translateFQN(v),createArrowExprList(plist))); + } + } + // buffers with parameters grouped with parameter + allbfqnsWithThisFirstParam = allbfqns.stream() + // must be at least one parameter + .filter(i -> d.getVarBufferParams(i).size() != 0 && d.getVarBufferParams(i).get(0).equals(prm)) + .collect(Collectors.toList()); + // construct decls -- might be none but still have to + // create sig for this parameter + for (String b: allbfqnsWithThisFirstParam) { + if (d.getVarBufferParams(b).size() != 1) + plist = createVarList(d.getVarBufferParams(b).subList(1, d.getVarBufferParams(b).size()-1)); + else + plist = new ArrayList(); + plist.add(bufferIndexVar(d.getBufferIndex(b))); + plist.add(createVar(d.getBufferElement(b))); + decls.add(DeclExt.newVarDeclExt(translateFQN(b),createArrowExprList(plist))); + } + d.alloyString += d.addSigExtendsWithDeclsSimple(prm, identifierName, decls); + + } + + // buffers with no parameters + // grouped in buffer index introduction + // every buffer has a different index + // so just one decl per sig + List allbfqnsWithNoParams = allbfqns.stream() + // must be at least one parameter + .filter(i -> d.getVarBufferParams(i).size() == 0 ) + .collect(Collectors.toList()); + for (String b: allbfqnsWithNoParams) { + decls = new ArrayList(); + decls.add(DeclExt.newVarDeclExt( + translateFQN(b), + createVar(d.getBufferElement(b)))); + d.alloyString += d.addSigWithDeclsSimple( + bufferIndexName + d.getBufferIndex(b), + decls); + } + + } else { + // if traces/tcmc sig Snapshot {} with fields + List decls = new ArrayList(); + + // scopesUsed0, conf0, event0 + + if (d.hasConcurrency()) + decls.add(DeclExt.newSetDeclExt(scopesUsedName+"0", scopeLabelName)); + if (!d.hasOnlyOneState()) decls.add(DeclExt.newSetDeclExt(confName+"0", stateLabelName)); + decls.add(DeclExt.newSetDeclExt(transTakenName+"0", transitionLabelName)); + if (d.hasEvents()) + decls.add(DeclExt.newSetDeclExt(eventsName+"0", allEventsName)); + List cop; + for (int i = 1; i <= d.getMaxDepthParams(); i++) { + cop = Collections.nCopies(i,identifierName); + // scopesUsed 1, etc. + //if (d.transAtThisParamDepth(i)) + if (d.hasConcurrency()) + decls.add((Decl) new DeclExt( + scopesUsedName+Integer.toString(i), + createArrowStringList(DashUtilFcns.newListWith(cop, scopeLabelName)))); + // conf 1, etc. + if (!d.hasOnlyOneState()) + decls.add((Decl) new DeclExt( + confName+Integer.toString(i), + createArrowStringList(DashUtilFcns.newListWith(cop, stateLabelName)))); + decls.add((Decl) new DeclExt( + transTakenName+Integer.toString(i), + createArrowStringList(DashUtilFcns.newListWith(cop, transitionLabelName)))); + // event 1, etc. + if (d.hasEvents() && d.hasEventsAti(i)) + decls.add((Decl) new DeclExt( + eventsName+Integer.toString(i), + createArrowStringList(DashUtilFcns.newListWith(cop, allEventsName)))); + } + // stable: one boolean; + if (d.hasConcurrency()) { + decls.add(new DeclExt(stableName, createOne(createVar(boolName)))); + } + // add vars + List typlist; + for (String vfqn: d.getAllVarNames()) { + typlist = createVarList(d.getVarBufferParams(vfqn)); // could be empty + typlist.add(translateExpr(d.getVarType(vfqn),d, true)); + //System.out.println(d.getVarType(vfqn)); + //System.out.println(translateExpr(d.getVarType(vfqn),d, true)); + if (typlist.size() > 1 ) { + decls.add((Decl) new DeclExt( + translateFQN(vfqn), + createArrowExprList(typlist))); + //System.out.println(decls); + } + else { + decls.add((Decl) new DeclExt( + translateFQN(vfqn), + typlist.get(0))); + //System.out.println(decls); + } + } + // add buffers + for (String bfqn: d.getAllBufferNames()) { + typlist = createVarList(d.getVarBufferParams(bfqn)); // could be empty + typlist.add(bufferIndexVar(d.getBufferIndex(bfqn))); + typlist.add(createVar(d.getBufferElement(bfqn))); + if (typlist.size() > 1 ) + decls.add((Decl) new DeclExt( + translateFQN(bfqn), + createArrowExprList(typlist))); + else + decls.add((Decl) new DeclExt( + translateFQN(bfqn), + typlist.get(0))); + } + d.alloyString += d.addSigWithDeclsSimple( snapshotName, decls); + } + d.alloyString += "\n"; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSpaceSignatures.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSpaceSignatures.java new file mode 100644 index 000000000..aed82a4f9 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddSpaceSignatures.java @@ -0,0 +1,131 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddSpaceSignatures { + + + // same for Electrum and other + + public static void addSpaceSignatures(DashModule d) { + // abstract sig Statelabel {} + if (!d.hasOnlyOneState()) { + d.alloyString += d.addAbstractSigSimple(DashStrings.stateLabelName); + d.alloyString += d.addAbstractExtendsSigSimple(d.getRootName(),DashStrings.stateLabelName); + } + if (d.hasConcurrency()) { + d.alloyString += d.addAbstractSigSimple(DashStrings.scopeLabelName); + d.alloyString += d.addOneExtendsSigSimple(d.getRootName()+DashStrings.scopeSuffix,DashStrings.scopeLabelName); + } + recurseCreateStateSpaceSigs(d, d.getRootName()); + d.alloyString += "\n"; + + + // abstract sig TransLabel {} + d.alloyString += d.addAbstractSigSimple(DashStrings.transitionLabelName); + d.alloyString += d.addOneExtendsSigSimple(DashStrings.noTransName, DashStrings.transitionLabelName); + // add all transitions as one sig extensions of TransLabel + for (String t : d.getAllTransNames()) { + d.alloyString += d.addOneExtendsSigSimple(translateFQN(t), DashStrings.transitionLabelName); + } + d.alloyString += "\n"; + + // abstract sig Identifiers {} if this model has parametrized components + // if not Electrum + // o/w conf1, etc have to be fields in sig Identifiers + // and this functionality is within AddSnapshotSignatures + if (!DashOptions.isElectrum) + if (d.getMaxDepthParams() != 0) { + d.alloyString += d.addAbstractSigSimple(DashStrings.identifierName); + for (String s: DashUtilFcns.listToSet(d.getAllParamsInOrder())) + d.alloyString += d.addExtendsSigSimple(s, DashStrings.identifierName); + d.alloyString += "\n"; + } + + // events ---------------------- + if (d.hasEvents()) { + d.alloyString += d.addAbstractSigSimple(DashStrings.allEventsName); + if (d.hasInternalEvents()) { + d.alloyString += d.addAbstractExtendsSigSimple(DashStrings.allInternalEventsName, DashStrings.allEventsName); + for (String e: d.getAllInternalEventNames()) { + d.alloyString += d.addOneExtendsSigSimple(translateFQN(e),DashStrings.allInternalEventsName); + } + } + if (d.hasEnvironmentalEvents()){ + d.alloyString += d.addAbstractExtendsSigSimple( DashStrings.allEnvironmentalEventsName, DashStrings.allEventsName); + for (String e: d.getAllEnvironmentalEventNames()) { + d.alloyString += d.addOneExtendsSigSimple(translateFQN(e),DashStrings.allEnvironmentalEventsName); + } + } + d.alloyString += "\n"; + } + + // abstract sig BufIdx {} if this model has buffers + // if not Electrum or if this buffer would be grouped under a parameter in Electrum declaration + // o/w buffers have to be fields in sig BufIdx + // and this functionality is within AddSnapshotSignatures + + if (d.hasBuffers()) { + // buffers with parameters + // every buffer has a different index + // so just one decl per sig + List allbfqns = d.getAllBufferNames(); + for (String b:allbfqns) { + if (DashOptions.isElectrum) { + if (d.getVarBufferParams(b).size() != 0) + // because buffer is declared under param + // o/w declared with buffer index in Snapshot stuff + d.alloyString += d.addSigSimple(DashStrings.bufferIndexName + d.getBufferIndex(b)); + } else + d.alloyString += d.addSigSimple(DashStrings.bufferIndexName + d.getBufferIndex(b)); + } + } + + } + private static void recurseCreateStateSpaceSigs(DashModule d, String parent) { + for (String child: d.getImmChildren(parent)) { + //System.out.println(translateFQN(child)+" "+translateFQN(parent)); + // for scopes Used + if (d.hasConcurrency()) + d.alloyString += d.addOneExtendsSigSimple(translateFQN(child)+DashStrings.scopeSuffix,DashStrings.scopeLabelName); + // for conf + if (!d.hasOnlyOneState()) { + if (d.isLeaf(child)) d.alloyString += d.addOneExtendsSigSimple(translateFQN(child),translateFQN(parent)); + else { + //if (d.isAnd(parent)) + //d.alloyString += d.addExtendsSigSimple(translateFQN(child), translateFQN(parent)); + //else + String x = d.addAbstractExtendsSigSimple(translateFQN(child), translateFQN(parent)); + d.alloyString += x; + //System.out.println("HERE" + x); + } + } + if (!d.isLeaf(child)) recurseCreateStateSpaceSigs(d,child); + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddStutter.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddStutter.java new file mode 100644 index 000000000..66a2a2953 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddStutter.java @@ -0,0 +1,78 @@ +/* + * + * In a weird case where a transition is triggered on an internal event + * but its guard depends on an external var value + * it won't be triggered after a stutter + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.IntStream; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddStutter { + + // low priority no environmental stutter predicate + + public static void addStutter(DashModule d) { + + + List body = new ArrayList(); + + // all the dsh defined parts of the snapshot stay the same + if (d.hasConcurrency()) body.add(noChange(DashStrings.stableName)); + for (int i = 0; i <= d.getMaxDepthParams(); i++) { + if (!d.hasOnlyOneState()) + body.add(noChange(DashStrings.confName+Integer.toString(i))); + if (d.hasConcurrency()) + body.add(noChange(DashStrings.scopesUsedName+Integer.toString(i))); + if (i == 0) + body.add(createEquals(nextTransTaken(i), createVar(DashStrings.noTransName))); + else + body.add(createEquals(nextTransTaken(i), createNoneArrow(i))); + if (d.hasEvents() && d.hasInternalEventsAti(i)) + // internal events go away + // external events can be added + body.add(createEquals( + createRangeRes(nextEvents(i),allInternalEventsVar()), + createNoneArrow(i))); + } + + // internal vars + // stays the same for all parameter values + // so can just say that the whole relation is the same and no parameter values needed !! + for (String vfqn: d.getAllInternalVarNames()) body.add(noChange(vfqn)); + // buffers are all internal + for (String bfqn: d.getAllBufferNames()) body.add(noChange(bfqn)); + d.alloyString += d.addPredSimple(DashStrings.stutterName, curNextDecls(), body); + + } + + private static Expr noChange(String n) { + return createEquals(nextJoinExpr(createVar(translateFQN(n))), curJoinExpr(createVar(translateFQN(n)))); + } +} + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTcmcFact.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTcmcFact.java new file mode 100644 index 000000000..22167dfb8 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTcmcFact.java @@ -0,0 +1,78 @@ +/* + Add fact for tcmc +*/ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import static ca.uwaterloo.watform.core.DashStrings.*; +//import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +//import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +import ca.uwaterloo.watform.alloyasthelper.DeclExt; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTcmcFact { + + public static void addTcmcFact(DashModule d) { + + /* + open util/tcmc[Snapshot] as snapshot + + fact tcmc { + // ksS0 satisfies init (initial) constraints + (all s: one Snapshot | { s in tcmc/ks_s0 } <=> init[s]) + // ksSigma satisfies small_step predicate + (all s,s_next: one Snapshot | ({ s -> s_next } in tcmc/ks_sigma) <=> small_step[s, s_next ]) + } + + */ + + assert(DashOptions.isTcmc); + List body = new ArrayList(); + + List decls = new ArrayList(); + decls.add(curDecl()); + + List args = new ArrayList(); + args.add(curVar()); + body.add( + createAll( + decls, + createIff( + createIn(curVar(), createVar(tcmcInitialStateName)), + createPredCall(initFactName,args)))); + + body.add( + createAll( + curNextDecls(), + createIff( + createIn( + createArrow(curVar(), nextVar()), + createVar(tcmcSigmaName)), + createPredCall(smallStepName, curNextVars())))); + + d.alloyString += d.addFactSimple(tcmcFactName, body); + + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTestIfNextStable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTestIfNextStable.java new file mode 100644 index 000000000..956059e5e --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTestIfNextStable.java @@ -0,0 +1,69 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTestIfNextStable { + + // only one per module + public static void addTestIfNextStable(DashModule d) { + List body = new ArrayList(); + List decls = new ArrayList(); + List allParams = d.getAllParamsInOrder(); + if (!DashOptions.isElectrum) { + decls.addAll(curNextDecls()); + } + for (int i=0; i < allParams.size(); i++) { + decls.add(paramDecl(i,allParams.get(i))); + } + for (int i=0; i<= d.getMaxDepthParams(); i++) { + decls.add(scopeDecl(i)); + if (d.hasEventsAti(i)) { + decls.add(genEventDecl(i)); + } + } + List args; + // this will include transition tfqn itself + for (String tfqn: d.getAllTransNames()) { + args = new ArrayList(); + if (!DashOptions.isElectrum) args.addAll(curNextVars()); + for (int i=0; i body = new ArrayList(); + + Expr snapShotFirst = createVar(snapshotName + "/" + tracesFirstName); + Expr snapShotLast = createVar(snapshotName + "/" + tracesLastName); + Expr snapShotNext = createVar(snapshotName + "/" + tracesNextName); + + List args = new ArrayList(); + args.add(snapShotFirst); + body.add(createPredCall(initFactName,args)); + + args = new ArrayList(); + args.add(curVar()); + args.add(curJoinExpr(snapShotNext)); + List decls = new ArrayList(); + decls.add((Decl) new DeclExt(curName, createOne(createDiff(createVar(snapshotName), snapShotLast)))); + body.add(createAll(decls,createPredCall(smallStepName,args))); + + d.alloyString += d.addFactSimple(tracesFactName, body); + + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTrans.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTrans.java new file mode 100644 index 000000000..1725def44 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTrans.java @@ -0,0 +1,63 @@ + package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +//import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import static ca.uwaterloo.watform.core.DashStrings.*; +//import ca.uwaterloo.watform.core.DashUtilFcns; +//import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.alloyasthelper.DeclExt; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTrans { + + // -------------------------------------------------------------------------------------- + /* + pred t1[s:Snapshot,s':Snapshot,pparam0:param0,pparam1:param1,pparam2:param2,...] = + pparam2.pparam1.pparam0.s.pre_1 and + pparam2.pparam1.pparam0.s'.s.post_1 and + pparam2.pparam1.pparam0.s'.s'.semantics_t1 + */ + public static void addTrans(DashModule d, String tfqn) { + + // e.g. [ClientId,ServerId.,,,] + List prs = d.getTransParams(tfqn); + List body = new ArrayList(); + String tout = translateFQN(tfqn); // output FQN + + if (DashOptions.isElectrum) { + // pre_transName[ p0, p1, p2] -> p2.p1.p0.pre_transName + body.add(createPredCall(tout+ preName, paramVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p2.p1.p0.post_transName + body.add(createPredCall(tout + postName, paramVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p2.p1.p0.semantics_transName + //body.add(createPredCall(tout + semanticsName, paramVars(prs))); + } else { + // pre_transName[s, p0, p1, p2] -> p2.p1.p0.s.pre_transName + body.add(createPredCall(tout + preName, curParamVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p2.p1.p0.s'.s.post_transName + body.add(createPredCall(tout + postName, curNextParamVars(d.getTransParamsIdx(tfqn), d.getTransParams(tfqn)))); + // p2.p1.p0.s'.s.semantics_transName + //body.add(createPredCall(tout + semanticsName, curNextParamVars(prs))); + } + d.alloyString += d.addPredSimple(tout, curNextParamsDecls(d.getTransParamsIdx(tfqn),d.getTransParams(tfqn)), body); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransIsEnabledAfterStep.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransIsEnabledAfterStep.java new file mode 100644 index 000000000..c7824df9c --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransIsEnabledAfterStep.java @@ -0,0 +1,161 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTransIsEnabledAfterStep { + // --------------------------------------------------- + /* + // this is considering all instances of t1s (thus, the existential quantification) + pred t1_enabledAfterStep[ + s:Snapshot,s':Snapshot, + pParam0: Param0, + ... + scopes0: StateLabel, + scopes1: Identifiers -> StateLabel, + ... + genEvents0:EventLabel, + genEvents1: Identifiers -> EventLabel, + ... ] + { + // many of these may depend on param values + some (src_state_t1 & s'.confi) // where i is depth of src_state, + guard_cond_t1[s'] + (s.stable = True) => + o1: forall i. not(t1_nonOrthScopei in scopesi) + ev1: t1_on in (s.eventsi :> EnvEvents) + genEventsi // if t1_on is internal this is false + else { + o2: forall i. not(t1_nonOrthScopei in scopesi + s'.scopesUsedi) + ev2: t1_on in s.eventsi + genEventsi + } + } + */ + public static void addTransIsEnabledAfterStep(DashModule d, String tfqn) { + + String tout = translateFQN(tfqn); + List prsIdx = d.getTransParamsIdx(tfqn); + List prs = d.getTransParams(tfqn); + List decls = new ArrayList(); + List body = new ArrayList(); + + if (DashOptions.isElectrum) { + decls.addAll(paramDecls(prsIdx,prs)); + } else { + decls.addAll(curNextParamsDecls(prsIdx,prs)); + } + for (int i=0; i<= d.getMaxDepthParams(); i++) { + decls.add(scopeDecl(i)); + if (d.hasEventsAti(i)) { + decls.add(genEventDecl(i)); + } + } + + if (!d.hasOnlyOneState()) + // some (p3 -> p2 -> p1 -> src & s'.confi) + // src does not have to be a basic state + body.add( + createSomeOf( + createIntersect( + translateDashRefToArrow(d.getTransSrc(tfqn)), + nextConf(prsIdx.size())))); + + // primed guard condition is true + // TODO + + // orthogonality ------------------ + + // if first step of the big step + // tfqn's non-orthogonal scope are not in any scopes used in the parameters + List orth1 = new ArrayList(); + List nonO = d.nonOrthogonalScopesOf(tfqn); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + List u = DashRef.hasNumParams(nonO,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + // o1: forall i. not(t1_nonOrthScopei in scopesi) + for (Expr x: u) orth1.add(createNot(createIn(x,scopeVar(i)))); + } + Expr o1 = createAndFromList(orth1); + + + // if not the first of the big step + // tfqn's non-orthogonal scope are not in any scopes used in the parameters + the cur scopes used + List orth2 = new ArrayList(); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + List u = DashRef.hasNumParams(nonO,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + // o2: forall i. not(t1_nonOrthScopei in scopesi + s'.scopesUsedi) + for (Expr x: u) orth1.add(createNot(createIn(x,createUnion(curScopesUsed(i), scopeVar(i))))); + } + Expr o2 = createAndFromList(orth2); + + // events ---------------------------- + + DashRef ev = d.getTransOn(tfqn); + Expr ev1, ev2; + if (ev != null) { + //ev1: t1_on in (s.eventsi :> EnvEvents) + genEventsi // if t1_on is internal this is false + if (d.isInternalEvent(ev.getName())) { + ev1 = createFalse(); + } else { + ev1 = createIn( + translateDashRefToArrow(ev), + createUnion( + createRangeRes( + curEvents(ev.getParamValues().size()), + allEnvironmentalEventsVar()), + genEventVar(ev.getParamValues().size()))); + } + // ev2: t1_on in s.eventsi + genEventsi + ev2 = createIn( + translateDashRefToArrow(ev), + createUnion( + curEvents(ev.getParamValues().size()), + genEventVar(ev.getParamValues().size()))); + } else { + ev1 = createTrue(); + ev2 = createTrue(); + } + + if (d.hasConcurrency()) + body.add( + createITE(curStableTrue(), + createAnd( + o1, + ev1), + createAnd( + o2, + ev2))); + else + body.add(createAnd(o1,ev1)); + + d.alloyString += d.addPredSimple(tout+DashStrings.enabledAfterStepName,decls,body); + } + + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPost.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPost.java new file mode 100644 index 000000000..6664723ba --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPost.java @@ -0,0 +1,406 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.core.DashErrors; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTransPost { + + /* + pred post_t1[s,s':Snapshot] { + forall i: confi' = confi - exitedi + enteredi + forall i : scopesUsedi' = scopesUsedi + scopesUsed + action_t1[s,s'] + testIfNextStable[s,s',t1,t1_send_ev] => { + s'.stable = True + // empty scopesUsed + forall i : scopesUsedi' = none + s.stable = True => { + // case 1 + // big step = one small step + // only internal events are those generated by t1 + // allow env events to change + forall i: eventsi' :> InternalEvents = t1_send_ev (if i) + } else { + // case 2 + // last small step of the big step + // add t1's gen events to the internal events + // allow env events to change + forall i: eventsi' :> InternalEvent = + t1_send_ev (if i) + (eventsi :> InternalEvent ) + } + } else { + stable' = False + env_vars_unchanged[s,s'] + s.stable = True => { + // case 3 + // first small step of the big step + // only internal events are those generated by t1 + forall i: eventsi' :> InternalEvent = t1_send_ev (if i) + // env events stay the same + forall i: eventsi' :> EnvironmentalEvent = eventsi :> EnvironmentalEvent + // empty previous scopes used and just add this one + forall i : scopesUsedi' = scopesUsed + } else { + // case 4 + // intermediate small step + // add t1's gen event to the events + // env events don't change + forall i: eventsi' = eventsi + t1_send_ev (if i) + // just add to scopesUsed + forall i : scopesUsedi' = scopesUsedi + scopesUsed + } + } + } + */ + + + public static void addTransPost(DashModule d, String tfqn) { + String tout = translateFQN(tfqn); + List prsIdx = d.getTransParamsIdx(tfqn); + List prs = d.getTransParams(tfqn); + List body = new ArrayList(); + + if (!d.hasOnlyOneState()) { + // confi' = confi - exitedi + enteredi + List entered = d.entered(tfqn); + List exited = d.exited(tfqn); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + List ent = DashRef.hasNumParams(entered,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + List exi = DashRef.hasNumParams(exited,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + // both ent and exi could be empty at this level + Expr e; + if (!exi.isEmpty()) + e = createDiff(curConf(i),createUnionList(exi)); + else + e = curConf(i); + if (!ent.isEmpty()) e = createUnion(e,createUnionList(ent)); + body.add(createEquals(nextConf(i),e)); + } + } + + // action_t1[s,s'] + if (d.getTransDo(tfqn) != null) + body.add(translateExpr(d.getTransDo(tfqn),d)); + + Expr ex; + DashRef dr; + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (prsIdx.size() == i) { + // for convenience of methods, make it a DashRef first + dr = DashRef.createTransDashRef(tout, paramVars(prsIdx,prs)); + ex = translateDashRefToArrow(dr); + } else ex = createNoneArrow(i); + body.add(createEquals(nextTransTaken(i), ex)); + } + // vars not mentioned in action do not change + // includes entered/exited + Set intVarsBuffersThatDontChange = DashUtilFcns.listToSet(d.getAllInternalVarNames()); + intVarsBuffersThatDontChange.addAll(d.getAllBufferNames()); + // we treat buffers the same as variables because their index is the closest arg and + // either the entire buffer within a sister component stays the same or it doesn't -- there is no need + // to reference the buffer index argument. + + //System.out.println(intVarsBuffersThatDontChange); + // remove variables mentioned in invariants + // whether they are primed or not + for (Expr i:d.getInvs()) { + List primedDashRefs = d.primedDashRefs(i); + for (DashRef r:primedDashRefs) { + intVarsBuffersThatDontChange.remove(r.getName()); + } + } + + // separate primed variables in transitions into those + // that we can't put any constraints on (remove these from intVarsThatDontChange) + // and those that we constrain the sister value os (sistersDontChange) + Set sistersDontChange = new HashSet(); + if (d.getTransDo(tfqn) != null) { + for (DashRef r: d.primedDashRefs(d.getTransDo(tfqn))) { + //System.out.println(r); + if (r.getParamValues().isEmpty()) intVarsBuffersThatDontChange.remove(r.getName()); + else if (hasSpecificParamValues(d, r)) { + //System.out.println("has specific param values"); + intVarsBuffersThatDontChange.remove(r.getName()); + // might not be in sistersDontChange + sistersDontChange.remove(r.getName()); + } else { + //System.out.println("has generic param values"); + // has generic param values + sistersDontChange.add(r.getName()); + intVarsBuffersThatDontChange.remove(r.getName()); + } + } + } + //System.out.println(tfqn); + //System.out.println(sistersDontChange); + //System.out.println("----"); + List decls; + List args; + + // constraints on sister elements + for (String x: sistersDontChange) { + decls = new ArrayList(); + args = new ArrayList(); + List paramsIdx = d.getVarBufferParamsIdx(x); + List params = d.getVarBufferParams(x); + for (int i=0; i < params.size();i++) { + String p = params.get(i); + decls.add(new DeclExt(p + randomParamExt, + createDiff(createVar(p), paramVar(paramsIdx.get(i), p)))); + args.add(createVar(p + randomParamExt)); + } + if (decls.isEmpty()) DashErrors.sistersDontChangeDoesNotHaveParams(x); + else body.add(createAll(decls, + createEquals( + createJoinList(args, curJoinExpr(createVar(translateFQN(x)))), + createJoinList(args, nextJoinExpr(createVar(translateFQN(x))))))); + } + + + // constraint on untouched vars + for (String x:intVarsBuffersThatDontChange) { + decls = new ArrayList(); + args = new ArrayList(); + for (String p: d.getVarBufferParams(x)) { + decls.add(new DeclExt(p + randomParamExt, p)); + args.add(createVar(p + randomParamExt)); + } + if (decls.isEmpty()) body.add(createEquals( + curJoinExpr(createVar(translateFQN(x))), + nextJoinExpr(createVar(translateFQN(x))))); + else body.add(createAll(decls, createEquals( + createJoinList(args, curJoinExpr(createVar(translateFQN(x)))), + createJoinList(args, nextJoinExpr(createVar(translateFQN(x))))))); + } + + + DashRef ev = d.getTransSend(tfqn); + Expr rhs, rhs1, q; + + // case 1 + // forall i. eventsi' :> InternalEvents = t1_send (if i) + // eventsi' :> InternalEvents = none (if not i) + List case1 = new ArrayList(); + Expr c1; + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (d.hasInternalEventsAti(i)) { + if (ev != null && ev.getParamValues().size() == i) rhs = translateDashRefToArrow(ev); + else rhs = createNoneArrow(i); + case1.add(createEquals( + createRangeRes(nextEvents(i),allInternalEventsVar()), + rhs)); + } + } + //if (case1.isEmpty()) c1 = createTrue(); + c1 = createAndFromList(case1); + + // case 2 + // forall i. eventsi' :> InternalEvents = t1_send_ev (if i) + eventsi + // eventsi' :> InternalEvents = eventsi (if not i) + List case2 = new ArrayList(); + Expr c2; + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (d.hasInternalEventsAti(i)) { + q = createRangeRes(curEvents(i), allInternalEventsVar()); + if (ev != null && ev.getParamValues().size() == i) rhs = createUnion(translateDashRefToArrow(ev), q); + else rhs = q; + case2.add(createEquals( + createRangeRes(nextEvents(i),allInternalEventsVar()), + rhs)); + } + } + //if (case2.isEmpty()) c2 = createTrue(); + c2 = createAndFromList(case2); + + Expr stableTrueAndScopesUsedEmpty; + if (d.hasConcurrency()) { + List scopesUsedEmpty = new ArrayList(); + + for (int i=0;i <= d.getMaxDepthParams(); i++) { + scopesUsedEmpty.add(createEquals(nextScopesUsed(i),createNoneArrow(i))); + } + stableTrueAndScopesUsedEmpty = + createAnd(nextStableTrue(), createAndFromList(scopesUsedEmpty)); + } else { + stableTrueAndScopesUsedEmpty = nextStableTrue(); + } + + // case 3 + // forall i: (eventsi' :> InternalEvent = t1_send_ev (if i)) + // (eventsi' :> InternalEvent = none) (if not i) + // and (eventsi' :> EnvironmentalEvent = eventsi :> EnvironmentalEvent) + List case3 = new ArrayList(); + Expr c3; + // have to be initialized to something + Expr intEvExpr = createNone(); + Expr envEvExpr = createNone(); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (d.hasInternalEventsAti(i)) { + if (ev != null && ev.getParamValues().size() == i) rhs1 = translateDashRefToArrow(ev); + else rhs1 = createNoneArrow(i); + intEvExpr = createEquals( + createRangeRes(nextEvents(i),allInternalEventsVar()), + rhs1); + } + if (d.hasEnvironmentalEventsAti(i)) { + envEvExpr = createEquals( + createRangeRes(nextEvents(i),allEnvironmentalEventsVar()), + createRangeRes(curEvents(i),allEnvironmentalEventsVar()) ); + } + if (d.hasInternalEventsAti(i)) { + if (d.hasEnvironmentalEventsAti(i)) case3.add(createAnd(intEvExpr, envEvExpr)); + else case3.add(intEvExpr); + } else { + if (d.hasEnvironmentalEventsAti(i)) case3.add(envEvExpr); + } + case3.add(createEquals(nextScopesUsed(i),createNoneArrow(i))); + } + //if (case3.isEmpty()) c3 = createTrue(); + c3 = createAndFromList(case3); + + // case 4 + // forall i. eventsi' = eventsi + t1_send (if i) + // eventsi' = eventsi (if not i) + List case4 = new ArrayList(); + List sU = d.scopesUsed(tfqn); + List u; + Expr e; + for (int i=0;i <= d.getMaxDepthParams(); i++) { + if (d.hasEventsAti(i)) { + if (ev != null && ev.getParamValues().size() == i) + case4.add(createEquals(nextEvents(i),createUnion(curEvents(i), translateDashRefToArrow(ev)))); + } + if (d.hasConcurrency()) { + // scopesUsedi' = scopesUsedi + scopesUsed + u = DashRef.hasNumParams(sU,i).stream() + .map(x -> translateDashRefToArrow(replaceScope(x))) + .collect(Collectors.toList()); + e = curScopesUsed(i); + if (!u.isEmpty()) e = createUnion(e,createUnionFromList(u)); + case4.add(createEquals(nextScopesUsed(i),e)); + } + } + + //if (case4.isEmpty()) c4 = createTrue(); + Expr c4 = createAndFromList(case4); + + // env_vars_unchanged[s,s'] + + List allVarBuffers = d.getAllVarNames(); + allVarBuffers.addAll(d.getAllBufferNames()); + // might just return true if allVarBuffers is empty + Expr envNoChange = createAndFromList(allVarBuffers.stream() + .filter(i -> !d.isInternal(i)) + .map(i -> createVarDoesNotChange(d, i)) + .collect(Collectors.toList())); + Expr stableFalseAndEnvNoChange = createAnd(nextStableFalse(), envNoChange); + + // big ITE is simplified for boolean/True, boolean/False + // b/c Alloy does not allow those as "formulas" + if (d.hasConcurrency()) + body.add( + createITE(createTestIfNextStableCall(d, tfqn), + createAnd( + stableTrueAndScopesUsedEmpty, + createITE (curStableTrue(), + c1, + c2)), + createAnd( + stableFalseAndEnvNoChange, + createITE(curStableTrue(), + c3, + c4)))); + + + d.alloyString += d.addPredSimple(tout+postName,curNextParamsDecls(prsIdx,prs),body); + } + + public static Expr createVarDoesNotChange(DashModule d, String x) { + Expr e = createEquals( + createJoinList(DashUtilFcns.newListWith(curParamVars(d.getVarBufferParamsIdx(x), d.getVarBufferParams(x)),createVar(translateFQN(x)))), + createJoinList(DashUtilFcns.newListWith(nextParamVars(d.getVarBufferParamsIdx(x), d.getVarBufferParams(x)),createVar(translateFQN(x))))); + if (d.getVarBufferParamsIdx(x).isEmpty()) return e; + else return createAll(paramDecls(d.getVarBufferParamsIdx(x),d.getAllParamsInOrder()),e); + } + + // pred call: testIfNextStable[s,s',scope1, scope2, ... , send1, send2, ...] + // where scopei, evi is "none" if this transition's scope and send event + private static Expr createTestIfNextStableCall(DashModule d, String tfqn) { + List args = new ArrayList(); + if (!DashOptions.isElectrum) { + args.add(curVar()); + args.add(nextVar()); + } + // add args for parameters; has to be something or none for every possible parameter in the system + List paramsIdxUsed = d.getTransParamsIdx(tfqn); + for (int i=0;i sU = d.scopesUsed(tfqn); + DashRef ev = d.getTransSend(tfqn); + for (int i=0; i <= d.getMaxDepthParams(); i++) { + //TODO could only have scopesUsedi for i that has scopesUsed + List u = DashRef.hasNumParams(sU,i).stream() + .map(x -> translateDashRefToArrow(x)) + .collect(Collectors.toList()); + if (u.size() == 1) args.add(u.get(0)); + else if (u.size() ==0 ) args.add(createNoneArrow(i)); + else { DashErrors.createTestIfNextStableCallMultipleScopesAtSameLevel(); return null; } + if (d.hasEventsAti(i)) { + if (ev != null && ev.getParamValues().size() == i) args.add(translateDashRefToArrow(ev)); + else args.add(createNoneArrow(i)); + } + } + return createPredCall(testIfNextStableName,args); + } + + private static boolean hasSpecificParamValues(DashModule d, DashRef r) { + // only for variables + //TODO buffers?? + List genericPValues = paramVars(d.getVarBufferParamsIdx(r.getName()), d.getVarBufferParams(r.getName())); + List actualPValues = r.getParamValues(); + Boolean ret = false; + if (genericPValues.size() == actualPValues.size()) { + for (int i=0; i < genericPValues.size(); i++) { + //System.out.println("generic: " + genericPValues.get(i)); + //System.out.println("actual: " + actualPValues.get(i)); + if (!sEquals(genericPValues.get(i), actualPValues.get(i))) ret = ret || true; + } + } else DashErrors.hasSpecificParamValues(); + return ret; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPre.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPre.java new file mode 100644 index 000000000..3f1c092a5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/AddTransPre.java @@ -0,0 +1,124 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +import static ca.uwaterloo.watform.dashtoalloy.Common.*; + +public class AddTransPre { + // -------------------------------------------------------------------------------------- + /* + pred pre_t1[s:Snapshot,pparam0:Param0, ...] { + + some (src_state_t1 & .s.conf) + orthogonal to any scopes uses + + guard_cond_t1 [s] + + s.stable = True => + { // beginning of a big step + // transition can be triggered only by environmental events + .trig_events_t1 in (s.events & ExternalEvent ) + } else { + // intermediate snapshot + // transition can be triggered by any type of event + .trig_events_t1 in s.events + } + pre of a higher priority transition is not enabled + } + Assumption: prs for src state and trig events are a subset of prs for trans + */ + public static void addTransPre(DashModule d, String tfqn) { + List prsIdx = d.getTransParamsIdx(tfqn); + List params = d.getTransParams(tfqn); + List body = new ArrayList(); + String tout = translateFQN(tfqn); + + if (!d.hasOnlyOneState()) + // p3 -> p2 -> p1 -> src & s.confVar(i) != none + // src does not have to be a basic state + body.add( + createSomeOf( + createIntersect( + translateDashRefToArrow(d.getTransSrc(tfqn)), + curConf(prsIdx.size())))); + + if (d.getTransWhen(tfqn) != null) + body.add(translateExpr(d.getTransWhen(tfqn),d)); + + if (d.hasConcurrency()) { + // has a scope that is orthogonal to any scopes used + List nonO = d.nonOrthogonalScopesOf(tfqn); + for (int i=0;i <= d.getMaxDepthParams(); i++) { + List u = DashRef.hasNumParams(nonO,i).stream() + .map(x -> translateDashRefToArrow(replaceScope(x))) + .collect(Collectors.toList()); + for (Expr x: u) body.add(createNot(createIn(x,curScopesUsed(i)))); + } + } + + // event trigger + // only one triggering event + if (d.hasConcurrency() && d.getTransOn(tfqn) != null && d.hasEnvironmentalEvents()) { + // trig_events_t1 + DashRef ev = d.getTransOn(tfqn); + int sz = ev.getParamValues().size(); + Expr ifBranch; + if (d.isInternalEvent(ev.getName())) { + ifBranch = createFalse(); + } else { + ifBranch = createIn(translateDashRefToArrow(ev), + createRangeRes( + curEvents(sz), + allEnvironmentalEventsVar())); + } + Expr elseBranch = createIn(translateDashRefToArrow(ev), curEvents(sz)); + body.add(createITE( + curStableTrue(), + ifBranch, + elseBranch + )); + } else if (d.getTransOn(tfqn) != null) { + DashRef ev = d.getTransOn(tfqn); + int sz = ev.getParamValues().size(); + body.add(createIn(translateDashRefToArrow(ev),curEvents(sz))); + } + + // not a higher priority transition enabled + List priTrans = d.getHigherPriTrans(tfqn); + List args = new ArrayList(); + for (String t:priTrans) { + // src must directly above this trans in the hierarchy + // so its parameters must be a subset of the current parameters + // and we don't need to quantify over them + args = curParamVars(d.getTransParamsIdx(t), d.getTransParams(t)); + body.add(createNot(createPredCall(translateFQN(t)+DashStrings.preName, args))); + } + //System.out.println(body); + //body.add(createNullExpr()); + d.alloyString += d.addPredSimple(tout+DashStrings.preName, curParamsDecls(prsIdx,params), body); + d.alloyString += "\n"; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/Common.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/Common.java new file mode 100644 index 000000000..e53ec1ea3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/Common.java @@ -0,0 +1,527 @@ +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.Collections; +import java.util.stream.Collectors; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +//import edu.mit.csail.sdg.ast.Decl; +//import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.*; +import edu.mit.csail.sdg.alloy4.ConstList; + +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashStrings; +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.core.DashErrors; + + +// shortens the code to import these statically +import static ca.uwaterloo.watform.core.DashFQN.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.alloyasthelper.DeclExt; +import ca.uwaterloo.watform.alloyasthelper.ExprToString; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.CompModuleHelper; + +public class Common { + + // s:Snapshot + public static Decl curDecl() { + return (Decl) new DeclExt(DashStrings.curName, DashStrings.snapshotName); + } + + + // s':Snapshot + public static Decl nextDecl() { + return (Decl) new DeclExt(DashStrings.nextName, DashStrings.snapshotName); + } + + + // p0:P0 + public static Decl paramDecl(Integer n, String name) { + return (Decl) new DeclExt(DashStrings.pName+n+"_"+name, name); + } + + //pi: Identfiers + //public static Decl posParamDecl(Integer i) { + // return (Decl) new DeclExt(DashStrings.pName+Integer.toString(i), DashStrings.identifierName); + //} + + // [s:Snapshot, s':Snapshot] + public static List curDecls() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) + o.add(curDecl()); + return o; + } + public static List nextDecls() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) + o.add(nextDecl()); + return o; + } + + // [s:Snapshot, s':Snapshot] + public static List curNextDecls() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) { + o.add(curDecl()); + o.add(nextDecl()); + } + return o; + } + + // [p0:P0, p1:P1, ...] + public static List paramDecls(List prsIdx , List prs) { + List o = new ArrayList(); + for (int i=0;i curParamsDecls(List prsIdx, List prs) { + List o = new ArrayList(); + o.addAll(curDecls()); + o.addAll(paramDecls(prsIdx, prs)); + return o; + } + // s:Snapshot, s':Snapshot, p0:P0, p1:P1, ...] + public static List curNextParamsDecls(List prsIdx, List prs) { + List o = new ArrayList(); + o.addAll(curNextDecls()); + o.addAll(paramDecls(prsIdx, prs)); + return o; + } + + public static Decl genEventDecl(int i) { + if (i==0) return (Decl) new DeclExt( + DashStrings.genEventName + i, + createVar(DashStrings.allEventsName)); + else { + Listcop = Collections.nCopies(i,DashStrings.identifierName); + return (Decl) new DeclExt( + DashStrings.genEventName + i, + createArrowStringList(DashUtilFcns.newListWith(cop, DashStrings.allEventsName))); + } + } + + public static Decl scopeDecl(int i) { + Listcop = Collections.nCopies(i,DashStrings.identifierName); + return (Decl) new DeclExt( + DashStrings.scopeName + i, + createArrowStringList(DashUtilFcns.newListWith(cop, DashStrings.stateLabelName))); + } + + // common vars + // s + public static ExprVar curVar() { + return createVar(DashStrings.curName); + } + // s' + public static ExprVar nextVar() { + return createVar(DashStrings.nextName); + } + public static List curVars() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) { + o.add(curVar()); + } + return o; + } + public static List nextVars() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) { + o.add(nextVar()); + } + return o; + } + //[s,s'] + public static List curNextVars() { + List o = new ArrayList(); + if (!DashOptions.isElectrum) { + o.add(curVar()); + o.add(nextVar()); + } + return o; + } + //pi: Identfiers + //public static Expr posParamVar(Integer i) { + // return createVar(DashStrings.pName+Integer.toString(i)); + //} + // p0_AID + public static Expr paramVar(Integer i, String n) { + return createVar(DashStrings.pName+Integer.toString(i)+"_"+n); + } + // [p0_AID,p1_AID,...] + public static List paramVars(List prsIdx, List prs) { + assert(prsIdx.size() == prs.size()); + List o = new ArrayList(); + for (int i=0;i curParamVars(List prsIdx, List prs) { + List o = new ArrayList(); + o.addAll(curVars()); + o.addAll(paramVars(prsIdx,prs)); + return o; + } + // [s', p1,p2,...] + public static List nextParamVars(List prsIdx, List prs) { + List o = new ArrayList(); + + o.addAll(nextVars()); + o.addAll(paramVars(prsIdx, prs)); + return o; + } + // [s,s', p1,p2,...] + public static List curNextParamVars(List prsIdx, List prs) { + List o = new ArrayList(curNextVars()); + o.addAll(paramVars(prsIdx,prs)); + return o; + } + + // stable + public static Expr stable() { + return createVar(DashStrings.stableName); + } + + public static Expr allInternalEventsVar() { + return createVar(DashStrings.allInternalEventsName); + } + public static Expr allEnvironmentalEventsVar() { + return createVar(DashStrings.allEnvironmentalEventsName); + } + + public static Expr scopesUsedVar(int size) { + return createVar(DashStrings.scopesUsedName + size); + } + public static Expr scopeVar(int size) { + return createVar(DashStrings.scopeName + size); + } + public static Expr genEventVar(int size) { + return createVar(DashStrings.genEventName + size); + } + public static Expr confVar(int size) { + return createVar(DashStrings.confName + size); + } + public static Expr eventsVar(int size) { + return createVar(DashStrings.eventsName + size); + } + public static Expr transTakenVar(int size) { + return createVar(DashStrings.transTakenName + size); + } + + public static Expr curScopesUsed(int size) { + return curJoinExpr(scopesUsedVar(size)); + } + // s'.scopesUsed5 + public static Expr nextScopesUsed(int size) { + return nextJoinExpr(scopesUsedVar(size)); + } + // s.conf4 + public static Expr curConf(int size) { + return curJoinExpr(confVar(size)); + } + // s'.conf3 + public static Expr nextConf(int size) { + return nextJoinExpr(confVar(size)); + } + // s.event4 + public static Expr curEvents(int size) { + return curJoinExpr(eventsVar(size)); + } + // s'.event3 + public static Expr nextEvents(int size) { + return nextJoinExpr(eventsVar(size)); + } + public static Expr curTransTaken(int size) { + return curJoinExpr(transTakenVar(size)); + } + public static Expr nextTransTaken(int size) { + return nextJoinExpr(transTakenVar(size)); + } + public static Expr curStable() { + return curJoinExpr(stable()); + } + public static Expr nextStable() { + return nextJoinExpr(stable()); + } + // s.stable == boolean/True + public static Expr curStableTrue() { + return createIsTrue(curJoinExpr(stable())); + //return createEquals(curJoinExpr(stable()),createTrue()); + } + // s.stable == boolean/False + public static Expr curStableFalse() { + return createIsFalse(curJoinExpr(stable())); + //return createEquals(curJoinExpr(stable()),createFalse()); + } + // s'.stable == boolean/True + public static Expr nextStableTrue() { + return createIsTrue(nextJoinExpr(stable())); + //return createEquals(nextJoinExpr(stable()),createTrue()); + } + // s'.stable == boolean/False + public static Expr nextStableFalse() { + return createIsFalse(nextJoinExpr(stable())); + //return createEquals(nextJoinExpr(stable()),createFalse()); + } + + // s.name + public static Expr curJoinExpr(Expr e) { + if (DashOptions.isElectrum) return e; + else return createJoin(curVar(), e); + } + //s'.name + public static Expr nextJoinExpr(Expr e) { + if (DashOptions.isElectrum) { + assert(isExprVar(e)); + return primedVarExpr(e); + } else { + return createJoin(nextVar(), e); + } + } + public static Expr primedVarExpr(Expr e) { + return createPrime(e); + } + /* + // p3 -> p2 -> p1 -> x + public static Expr paramsToXArrow(List prsIdx, List prs, String x) { + Collections.reverse(prsIdx); + Expr e = createVar(x); + for (int i=0;i ll = new ArrayList(e.getParamValues()); + Collections.reverse(ll); + ll.add(createVar(translateFQN(e.getName()))); + return createArrowExprList(ll); + } + + public static Expr translateDashRefToJoin(DashRef e) { + List ll = new ArrayList(e.getParamValues()); + Collections.reverse(ll); + ll.add(createVar(translateFQN(e.getName()))); + return createJoinList(ll); + } + + //in Electrum - if we have a dynamic var (not buffer) with a non-var, non-one var, non-lone var, non-set var + // type, we have to handle is specially + public static boolean isWeirdOne(String vfqn, DashModule d) { + //System.out.println("Vqn: " + vfqn); + if (d.hasVar(vfqn)) { + Expr typ = d.getVarType(vfqn); + return (d.getVarBufferParams(vfqn).size() == 0 && + !((isExprOne(typ) && isExprVar(getSub(typ))) || + (isExprLone(typ) && isExprVar(getSub(typ))) || + (isExprSet(typ) && isExprVar(getSub(typ))))); + } else { + // it is a buffer and getVarType does not work on buffers + return false; + } + } + + // common case + public static Expr translateExpr(Expr exp, DashModule d) { + return translateExpr(exp,d,false); + } + + // onlyGetName = true is ONLY used for the case when + // translating type expressions of signatures + // there we only require the full name with underscores + public static Expr translateExpr(Expr exp, DashModule d, boolean onlyGetName ) { + // special case for Variables.v1 if v1 has no params and has an + // arrow type and isElectrum + //System.out.println(exp); + if (DashRef.isDashRef(exp)) { + //System.out.println(exp); + String vName = ((DashRef) exp).getName(); + + // used for types in snapshot signature + if (onlyGetName) { + //System.out.println("here: " + createVar(vName)); + return createVar(translateFQN(vName)); + } + // have to translate paramvalues + // may be empty + List paramValuesList = + ((DashRef) exp).getParamValues().stream() + .map(i -> translateExpr(i,d, onlyGetName)) + .collect(Collectors.toList()); + + //common subexpressions + Boolean hasPrime = DashStrings.hasPrime(vName); + Boolean isWeirdOne = isWeirdOne(DashStrings.removePrime(vName),d); + Expr voutNotPrime = createVar(translateFQN(DashStrings.removePrime(vName))); + Expr voutMayHavePrime; + if (!hasPrime) voutMayHavePrime = voutNotPrime; + else voutMayHavePrime = + createVar(translateFQN(DashStrings.removePrime(vName))+DashStrings.PRIME); + + //System.out.println(paramValuesList); + if (DashOptions.isElectrum) { + // already has prime or not + if (isWeirdOne) + return createJoin(createVar(DashStrings.variablesName), voutMayHavePrime); + else { + paramValuesList.add(voutMayHavePrime); + return createJoinList(paramValuesList); + } + } else { + if (hasPrime) paramValuesList.add(nextJoinExpr(voutNotPrime)); + else paramValuesList.add(curJoinExpr(voutNotPrime)); + return createJoinList(paramValuesList); + } + + } else if (isExprVar(exp)) { + return exp; + + } else if (isExprBinary(exp)) { + return ((ExprBinary) exp).op.make( + exp.pos, + exp.closingBracket, + translateExpr(getLeft(exp),d, onlyGetName), + translateExpr(getRight(exp),d, onlyGetName)); + + } else if (isExprBadJoin(exp)) { + return ExprBadJoin.make( + exp.pos, + exp.closingBracket, + translateExpr(getLeft(exp),d, onlyGetName), + translateExpr(getRight(exp),d, onlyGetName)); + + } else if (exp instanceof ExprCall) { + return ExprCall.make( + exp.pos, + exp.closingBracket, + ((ExprCall) exp).fun, + ((ExprCall) exp).args.stream() + .map(i -> translateExpr(i,d, onlyGetName)) + .collect(Collectors.toList()), + ((ExprCall) exp).extraWeight); + + } else if (exp instanceof ExprChoice){ + //TODO: check into this cast + // not sure why is it necessary + ConstList x = (ConstList) ((ExprChoice) exp).choices.stream() + .map(i -> translateExpr(i,d, onlyGetName)) + .collect(Collectors.toList()); + return ExprChoice.make( + false, + exp.pos, + x, + ((ExprChoice) exp).reasons); + + } else if (exp instanceof ExprITE){ + return ExprITE.make( + exp.pos, + translateExpr(getCond(exp),d, onlyGetName), + translateExpr(getLeft(exp),d, onlyGetName), + translateExpr(getRight(exp),d, onlyGetName)); + + } else if (exp instanceof ExprList){ + return ExprList.make( + exp.pos, + exp.closingBracket, + ((ExprList) exp).op, + ((ExprList) exp).args.stream() + .map(i -> translateExpr(i,d, onlyGetName)) + .collect(Collectors.toList())); + + } else if (exp instanceof ExprUnary){ + return ((ExprUnary) exp).op.make( + exp.pos, + translateExpr(((ExprUnary) exp).sub,d, onlyGetName)); + + } else if (exp instanceof ExprLet){ + //TODO rule out var name + return ExprLet.make( + exp.pos, + ((ExprLet) exp).var, + translateExpr(((ExprLet) exp).expr,d, onlyGetName), + translateExpr(((ExprLet) exp).sub,d, onlyGetName)); + + } else if (exp instanceof ExprQt){ + + // have to translate the expressions in the decls too + List decls = ((ExprQt) exp).decls.stream() + .map(i -> new Decl( + i.isPrivate, + i.disjoint, + i.disjoint2, + i.isVar, + i.names, + translateExpr(i.expr, d, onlyGetName))) + .collect(Collectors.toList()); + return ((ExprQt) exp).op.make( + exp.pos, + exp.closingBracket, + decls, + translateExpr(((ExprQt) exp).sub,d, onlyGetName)); + + } else if (exp instanceof ExprConstant){ + return exp; + + } else { + DashErrors.UnsupportedExpr("translateExpr", exp); + return null; + } + } + + public static Expr bufferIndexVar(int i) { + return createVar(DashStrings.bufferIndexName + i); + } + // none -> none -> none + public static Expr createNoneArrow(int i) { + if (i==0) return createNone(); + else { + //System.out.println(i); + //System.out.println(Collections.nCopies(i+1,createNone())); + return createArrowExprList(Collections.nCopies(i+1,createNone())); + } + } + + + /* + public static Expr predJoinCurParams(String name, List prs) { + //p2.p1.p0.s.name + Expr e = createVar(name); + List prsVarList = convertParamsToVars(prs); + if (!DashOptions.isElectrum) e = createJoin(curVar(),e); + if (prs!= null) { + Collections.reverse(prsVarList); + prsVarList.add(e); + System.out.println("predJoinCurParams: " +prsVarList); + Expr x = createJoinList(prsVarList); + System.out.println("Join of prsVarList: " + x); + return createJoinList(prsVarList) ; + } else return e; + } + public static Expr predJoinCurNextParams(String name, List prs) { + //p2.p1.p0.s'.s.pre_transName + Expr e = createVar(name); + List prsVarList = convertParamsToVars(prs); + if (!DashOptions.isElectrum) e = createJoin(nextVar(),createJoin(curVar(),e)); + if (prs!=null) { + Collections.reverse(prsVarList); + prsVarList.add(e); + return createJoinList(prsVarList) ; + } else return e; + } + */ +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/DashToAlloy.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/DashToAlloy.java new file mode 100644 index 000000000..1f7f24dc8 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/DashToAlloy.java @@ -0,0 +1,46 @@ +/* + * The translation is done in place on the Dash module. + * This is the same for Electrum and other. + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.core.DashOptions; + +public class DashToAlloy { + + public static void translate(DashModule d) { + assert(d.hasRoot()); // there is a Dash component in this module + AddSpaceSignatures.addSpaceSignatures(d); // state, parameter, buffer space + AddSnapshotSignature.addSnapshotSignature(d); + AddInit.addInit(d); + AddInv.addInv(d); + for (String tfqn: d.getAllTransNames()) { + AddTransPre.addTransPre(d,tfqn); + AddTransPost.addTransPost(d,tfqn); + //createTransSemantics(t); + if (d.hasConcurrency()) AddTransIsEnabledAfterStep.addTransIsEnabledAfterStep(d,tfqn); + AddTrans.addTrans(d,tfqn); + } + if (d.hasConcurrency()) + AddTestIfNextStable.addTestIfNextStable(d); + AddStutter.addStutter(d); + AddSmallStep.addSmallStep(d); + if (DashOptions.isTcmc) AddCompleteBigSteps.addCompleteBigSteps(d); + if (DashOptions.isTcmc) AddAllSnapshotsDifferentFact.addAllSnapshotsDifferentFact(d); + if (DashOptions.enoughOperations) + AddEnoughOperationsPred.addEnoughOperationsPred(d); + if (DashOptions.singleEventInput) + AddSingleEventInputFact.addSingleEventInputFact(d); + if (DashOptions.isTcmc && DashOptions.reachability) + AddReachabilityPred.addReachabilityPred(d); + if (DashOptions.isTraces) + AddTracesFact.addTracesFact(d); + else if (DashOptions.isTcmc) + AddTcmcFact.addTcmcFact(d); + else if (DashOptions.isElectrum) + AddElectrumFact.addElectrumFact(d); + } +} + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/TranslationToAlloyErrors.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/TranslationToAlloyErrors.java new file mode 100644 index 000000000..6d6f742b5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtoalloy/TranslationToAlloyErrors.java @@ -0,0 +1,20 @@ +/* + * All the errors that can be thrown in Dash code + */ + +package ca.uwaterloo.watform.dashtoalloy; + +import java.util.List; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.ast.Expr; + +public class TranslationToAlloyErrors { + + public static void Unsupported(Expr e) throws Err { + throw new ErrorSyntax("Unsupported: " + e.toString()); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/AST.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/AST.java new file mode 100644 index 000000000..0d134dd5f --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/AST.java @@ -0,0 +1,21 @@ +package ca.uwaterloo.watform.dashtotla; + +import de.uka.ilkd.pp.DataLayouter; +import de.uka.ilkd.pp.NoExceptions; +import de.uka.ilkd.pp.StringBackend; + +public class AST +{ + public String node; + public AST left; + public AST right; + public static String singleton(String set) // the constraint that sets the cardinality of this set to 1 + { + return TLA.parenthesis(TLA.FOR_ALL+" x,y "+TLA.IN+" "+set+" "+TLA.PREDICATE_SCOPE+" x=y "); + } + public String print() + { + StringBuilder code = new StringBuilder(""); + return code.toString(); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Atom.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Atom.java new file mode 100644 index 000000000..3939a10c5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Atom.java @@ -0,0 +1,48 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.List; + +import ca.uwaterloo.watform.parser.DashModule; + + +public class Atom +{ + public static String leafStates(DashModule d) // atoms for each leaf state + { + List states = d.getAllStateNames(); + StringBuilder leafStates = new StringBuilder("\n\n"+TLA.comment("basic states")); + + for(String s : states) + if(d.isLeaf(s)) + leafStates.append("\n"+Util.resolveName(s)+" "+TLA.DEFINE+" "+TLA.string(Util.resolveName(s))); + + return leafStates.toString(); + } + public static String nonLeafStates(DashModule d) // atoms for each leaf state + { + List states = d.getAllStateNames(); + StringBuilder leafStates = new StringBuilder("\n\n"+TLA.comment(" non-basic states")); + + for(String s : states) + if(!d.isLeaf(s)) + leafStates.append("\n"+Util.resolveName(s)+" "+TLA.DEFINE+" "+TLA.string(Util.resolveName(s))); + + return leafStates.toString(); + } + public static String internalEvents(DashModule d) // atoms for each internal event in TLA+ + { + StringBuilder code = new StringBuilder("\n\n"+TLA.comment(" internal events")); + List events = d.getAllInternalEventNames(); + for(String ev : events) + code.append("\n"+Util.resolveName(ev)+" "+TLA.DEFINE+" "+TLA.string(Util.resolveName(ev))); + return code.toString(); + } + public static String environmentalEvents(DashModule d) // atoms for each internal event in TLA+ + { + StringBuilder code = new StringBuilder("\n\n"+TLA.comment(" environmental events")); + List events = d.getAllEnvironmentalEventNames(); + for(String ev : events) + code.append("\n"+Util.resolveName(ev)+" "+TLA.DEFINE+" "+TLA.string(Util.resolveName(ev))); + return code.toString(); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DashToTLA.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DashToTLA.java new file mode 100644 index 000000000..3c02767f8 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DashToTLA.java @@ -0,0 +1,41 @@ +package ca.uwaterloo.watform.dashtotla; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.core.DashOptions; + +public class DashToTLA +{ + + public static String translate(Object[] args) throws Exception + { + if(args.length!=2)throw new Exception("Invalid arguments to translate to TLA"); + + DashModule d = (DashModule)args[0]; + String moduleName = (String)args[1]; + boolean singleEnvInput = DashOptions.singleEventInput; + + if(!d.hasRoot())throw new Exception("Error - no root state, nothing to translate"); + + StringBuilder code = new StringBuilder(""); + code.append(TLA.header(moduleName)); + code.append("\n"+TLA.extend(TLA.MODULES)); + code.append(Variable.declareVariables(d)); + code.append(Atom.leafStates(d)); + code.append(Atom.nonLeafStates(d)); + code.append(Atom.internalEvents(d)); + code.append(Atom.environmentalEvents(d)); + code.append(Variable.supersets(d)); + code.append(Variable.initialValues(d)); + code.append(StandardFormulae.TypeOK(d)); + code.append(State.createInStates(d)); + code.append(Transition.transitions(d)); + code.append(StandardFormulae.Init(d,singleEnvInput)); + code.append(StandardFormulae.Stutter(d,singleEnvInput)); + code.append(StandardFormulae.Next(d)); + code.append("\n"+TLA.FOOTER); + code.append("\n"+TLA.comment("Modification History")+ + "\n"+TLA.comment("Translated from Dash at "+System.currentTimeMillis()+" EPOCH")); + + return code.toString(); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DesignDoc.md b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DesignDoc.md new file mode 100644 index 000000000..51f5b2e26 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/DesignDoc.md @@ -0,0 +1,76 @@ +# Translating Dash to TLA+ + +## Preface + +This document specifies the design details of a program to convert `.dsh` files to [TLA+](https://lamport.azurewebsites.net/tla/tla.html). + +## Running the Translator + +### Prerequisites + +- A runnable `.jar` file built from [https://github.com/WatForm/org.alloytools.alloy](https://github.com/WatForm/org.alloytools.alloy) + +- The target files are in a destination which can be read and written into by the `.jar` file + +The general format to run the translator: + +``` +java -cp ca.uwaterloo.watform.dash4whole.Dash -tla +``` + +The `` consists of a list of complete paths to the `.dsh` files, separated by spaces. + +By default, the translated files are stored in the same location as the source files with the same name and a `.tla` extension. In case one wishes to give a custom path as the target file, one can insert the full path to the target file immediately after the corresponding source file path. + +For instance, the following command translates `file1.dsh` and writes the TLA+ code into `target.tla` +``` +java -cp ./org.alloytools.alloy.dist.jar ca.uwaterloo.watform.dash4whole.Dash -tla ./file1.dsh ../new_folder/target.tla +``` + +The same format is followed when multiple `.dsh` files are translated at a time. For each `.dsh` file, a default target is created if the target file is left unspecified. + +## Guide to the Source Code + +- The argument `-tla` is defined in [Dash.java](), which calls `MainFunctions.translateTLA() ` in [MainFunctions.java](), which in turn calls `DashtoTLA.translate()`. + +- The functions and global constants used in the translation are stored in different classes, purely to enhance readability. The classes have no non-static elements and are not intended to be used as object templates + +- [Util.java] stores useful functions that perform operations independent of the context of the transation. + +- [Transition.java]() contains code responsible for providing the formulae for all the transitions. Each transition is broken into a precondition and a postcondition for output readability. + +- [Atom.java]() contains a class concerned with defining the literals to which symbols point to. The literals defined here are not meant to be referred to in any other part of the translatin; they exist only because `TLA+` does not alloy one to use variables without initialization to some primitive type (or a composition thereof) + +- [StandardFormulae.java]() holds functions which generate formulae that occur in every translation, like `stutter`, `Init`, `Next` and `TypeOK`. + +- [Variable.java]() holds functions and constants which deal with `TLA+` variables (both standard ones like `conf`, `internal_events`, `environmental_events`, `scope_used` etc and those defined in the input) + +- [State.java]() contains formulae dealing with the control states in the input. (Note that the term "control state" does not refer to the term "state" as commonly understood) + +-[TLA.java]() contains everything to do with the syntax of TLA+. All syntax is encoded here, nothing is hardcoded in other classes. This class serves as a layer of abstraction over the final TLA+ output + +## Design Decisions + +- No variable in the original file can contain underscore since that character is used to denote internal variables within the translation. + +- The entire translation is restricted to a single module since one `.tla` file is expected to contain exactly one module definition. + +- The module name in a `.tla` file must be the same as the name of the file, which is in turn the same as the name of the source `.dsh` file. Thus the name of the source file is passed to the translator which names the module. + +- The translator adds a comment stating the modification history at the end of the module, in a manner similar to the comment autogenerated by toolbox, the official TLA+ IDE. + +- Timestamp is given in terms of Unix epoch to avoid problems with international timezones and daylight savings. + +- TLA+ does not support non-primitive unspecified atoms, so each leaf state is defined using a string holding their fully qualified name. + +- Transitions are formulae and remain so. there is no treatment of them as objects or use of a `TransTaken` set + +- Formulae are global variables to enable quick edits + +- Internal and Environmental events are segregated + +- isInState will not guarantee that current value of conf is legal, but /\ is used to check for conc states since /\ is faster to compute + +- Cardinality is expensive to compute so Cardinality(S)=1 is the same as \all x,y \in S : x=y + + diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/StandardFormulae.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/StandardFormulae.java new file mode 100644 index 000000000..2c90f9a79 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/StandardFormulae.java @@ -0,0 +1,73 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.ArrayList; +import java.util.List; + +import ca.uwaterloo.watform.parser.DashModule; + +public class StandardFormulae +{ + // boilerplate formulae, shared by all functions + public static final String INIT = "Init"; + public static final String NEXT = "Next"; + public static final String TYPE_OK = "TypeOK"; + + public static final String STUTTER = "_stutter"; + + public static String Next(DashModule d) // Next formula in TLA+ + { + List tranList = d.getAllTransNames(); + StringBuilder next = new StringBuilder("\n\n"+NEXT+" "+TLA.DEFINE+" "+STUTTER); + for(String s : tranList) + { + next.append("\n\t"+TLA.OR+" "+Util.resolveName(s)); + } + return next.toString(); + } + public static String TypeOK(DashModule d) // TLA+'s technique to ensure that types are appropriate + { + String variables[] = new String[]{Variable.CONF, Variable.INTERNAL_EVENTS, Variable.ENVIRONMENTAL_EVENTS, Variable.SCOPES_USED}; + + StringBuilder code = new StringBuilder("\n\n"+TLA.comment("type-checking")+"\n"+TYPE_OK+" "+TLA.DEFINE+" "); + for(String s : variables) + code.append("\n\t"+TLA.AND+" "+s+" "+TLA.SUBSET+" "+Variable.superset(s)); + + return code.toString(); + } + public static String Init(DashModule d, boolean singleEnvInput) // Init formula in TLA+ + { + StringBuilder init = new StringBuilder("\n\n"+INIT+" "+TLA.DEFINE+" "); + + List variables = new ArrayList<>(); // both boilerplate and actual variables + variables.add(Variable.CONF); + variables.add(Variable.INTERNAL_EVENTS); + variables.add(Variable.SCOPES_USED); + variables.add(Variable.STABLE); + + for(String v : variables) + init.append("\n\t"+TLA.AND+" "+v+TLA.EQUAL+Variable.initial(v)); + + init.append("\n\t"+TLA.AND+" "+Variable.ENVIRONMENTAL_EVENTS+" "+TLA.SUBSET+" "+Variable.superset(Variable.ENVIRONMENTAL_EVENTS)); + if(singleEnvInput) + init.append(" "+TLA.AND+AST.singleton(Variable.ENVIRONMENTAL_EVENTS)); + + return init.toString(); + } + + // when no tranitions are enabled, the system stays in current state while waiting for an environmental event to be sent + public static String Stutter(DashModule d, boolean singleEnvInput) + { + return "\n\n"+STUTTER+" "+TLA.DEFINE+" "+TLA.NOT+Transition.EXISTS_ENABLED_TRANSITION+ + "\n\t"+TLA.AND+" "+Variable.prime(Variable.CONF)+TLA.EQUAL+Variable.CONF+ + "\n\t"+TLA.AND+" "+Variable.prime(Variable.INTERNAL_EVENTS)+TLA.EQUAL+Variable.INTERNAL_EVENTS+ + "\n\t"+TLA.AND+"\t"+TLA.OR+" "+Variable.prime(Variable.ENVIRONMENTAL_EVENTS)+TLA.EQUAL+Variable.ENVIRONMENTAL_EVENTS+ + "\n\t\t"+TLA.OR+" "+TLA.parenthesis(Variable.prime(Variable.ENVIRONMENTAL_EVENTS)+" "+TLA.SUBSET+" "+Variable.superset(Variable.ENVIRONMENTAL_EVENTS)+" "+ + (singleEnvInput?TLA.AND+" "+AST.singleton(Variable.ENVIRONMENTAL_EVENTS):""))+ + "\n\t"+TLA.AND+" "+Variable.prime(Variable.SCOPES_USED)+TLA.EQUAL+TLA.NULL_SET+ + "\n\t"+TLA.AND+" "+Variable.prime(Variable.STABLE)+TLA.EQUAL+TLA.TRUE; + + + + + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/State.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/State.java new file mode 100644 index 000000000..e3ef1f755 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/State.java @@ -0,0 +1,49 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.List; +import java.util.ArrayList; + +import ca.uwaterloo.watform.parser.DashModule; + +public class State +{ + public static String isInState(String state) // used to check if one is in a non-leaf state + { + return Util.resolveName("in__"+state); + } + public static String createInStates(DashModule d) // formulae to determine if one is present in a state + { + List states = Util.topoSortStates(d); + + StringBuilder code = new StringBuilder("\n\n"+TLA.comment(" in states")); + for(String s : states) + { + code.append("\n"+isInState(s)+" "+TLA.DEFINE+" "); + if(d.isLeaf(s)) + { + String resolved = Util.resolveName(s); + code.append(resolved+" \\in "+Variable.CONF); + continue; + } + + // dealing with non-leaf states + List children = d.getImmChildren(s); + List andChildren = new ArrayList<>(); //concurrency + + for(String ch : children) + if(d.isAnd(ch)) + andChildren.add(ch); + else + code.append("\n\t"+TLA.OR+" "+isInState(ch)); // can be in any "or" child + + // if is in one "and" child, must be in all "and" children + if(andChildren.size()==0) + continue; + code.append("\n\t"+TLA.OR); + for(String ch : andChildren) + code.append("\n\t\t"+TLA.AND+" "+isInState(ch)); + + } + return code.toString(); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/TLA.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/TLA.java new file mode 100644 index 000000000..801dd0518 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/TLA.java @@ -0,0 +1,73 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.List; + +public class TLA +{ + public static final String EQUAL = "="; + public static final String DEFINE = "=="; + + public static final String AND = "/\\"; + public static final String OR = "\\/"; + public static final String NOT = "~"; + + public static final String FOR_ALL = "\\A"; + public static final String EXISTS = "\\E"; + public static final String IN = "\\in"; + public static final String PREDICATE_SCOPE = "\\:"; + + public static final String TRUE = "TRUE"; + public static final String FALSE = "FALSE"; + + public static final String[] MODULES = new String[]{"Integers","FiniteSets"}; + + public static final String UNION = "\\union"; + public static final String INTERSECTION = "\\intersect"; + public static final String NULL_SET = set(""); + public static final String SUBSET = "\\subseteq"; + public static final String PROPER_SUBSET = "\\subset"; + public static final String SUPERSET = "\\superseteq"; + public static final String PROPER_SUPERSET = "\\superset"; + public static final String SET_DIFFERENCE = "\\"; + + public static String parenthesis(String exp){return "("+exp+")";} + public static String comment(String comment){return "\\* "+comment;} + public static String commentMultiLine(String comment){return "\n(*"+comment+"\n*)";} + public static String set(String exp){return "{"+exp+"}";} + public static String string(String exp){return "\""+exp+"\"";} + public static String cardinality(String exp){return "Cardinality("+exp+")";} + public static String set(List elements) // set in TLA+ notation + { + StringBuilder sb = new StringBuilder("{"); + for(int i=0;i variables) + { + if(variables.size()==0)return ""; + StringBuilder code = new StringBuilder("VARIABLES "); + for(int i=0;i entered = Util.toStringList(d.entered(trans)); + List exited = Util.toStringList(d.exited(trans)); + String confPrimed = "\n\t"+TLA.AND+" "+Variable.prime(Variable.CONF)+TLA.EQUAL + +TLA.parenthesis(Variable.CONF+" "+TLA.SET_DIFFERENCE+" "+TLA.set(Util.resolveList(exited)))+" "+TLA.UNION+" " + +TLA.set(Util.resolveList(entered)); + + // scopes_used' + List scopesUsed = Util.toStringList(d.scopesUsed(trans)); + String scopes = "\n\t"+TLA.AND+" "+Variable.prime(Variable.SCOPES_USED)+TLA.EQUAL+Variable.SCOPES_USED+" "+TLA.UNION+" "+TLA.set(Util.resolveList(scopesUsed)); + + code.append(confPrimed); + code.append(scopes); + code.append("\n\t"+TLA.AND+" "+Variable.prime(Variable.ENVIRONMENTAL_EVENTS)+TLA.EQUAL+Variable.ENVIRONMENTAL_EVENTS); + return code.toString(); + } + public static String preCondition(DashModule d, String trans) + { + StringBuilder code = new StringBuilder(""); + + // conf + String srcState = d.getTransSrc(trans).toString(); + String conf = "\n\t"+TLA.AND+" "+State.isInState(srcState); + + // formula for events + DashRef on = d.getTransOn(trans); + String events = ""; + if(on!=null)events = "\n\t"+TLA.AND+" "+TLA.set(Util.resolveName(on.getName()))+" "+TLA.SUBSET+" "+Variable.INTERNAL_EVENTS; + + // scopes_used + List nonOrthogonalScopes = Util.toStringList(d.nonOrthogonalScopesOf(trans)); + String scopes = "\n\t"+TLA.AND+" "+Variable.SCOPES_USED+" "+TLA.INTERSECTION+" "+TLA.set(Util.resolveList(nonOrthogonalScopes))+TLA.EQUAL+TLA.NULL_SET; + + code.append(conf); + code.append(events); + code.append(scopes); + return code.toString(); + } + public static String transitions(DashModule d) + { + // assumption - guard is tautology + StringBuilder ts = new StringBuilder("\n\n"+TLA.comment("transitions")); + List tranList = d.getAllTransNames(); + List preCondList = new ArrayList<>(); + for(String s : tranList) + { + String preConditionName = "_pre__"+Util.resolveName(s); + String postConditionName = "_post__"+Util.resolveName(s); + ts.append("\n\n"+preConditionName+" "+TLA.DEFINE+" "+preCondition(d, s)); + ts.append("\n"+postConditionName+" "+TLA.DEFINE+" "+postCondition(d, s)); + ts.append("\n"+Util.resolveName(s)+" "+TLA.DEFINE+" "+preConditionName+" "+TLA.AND+" "+postConditionName); + preCondList.add(preConditionName); + } + + StringBuilder somePrecond = new StringBuilder("\n\n"+EXISTS_ENABLED_TRANSITION+" "+TLA.DEFINE+" "); + for(String s : preCondList) + somePrecond.append("\n\t"+TLA.AND+" "+s); + + return ts.append(somePrecond).toString(); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Util.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Util.java new file mode 100644 index 000000000..1fe0cce29 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Util.java @@ -0,0 +1,54 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.parser.DashModule; + +public class Util +{ + public static String resolveName(String s) // get rid of unsupported characters in full names + { + char SP = '_'; // SP is a specual character that cannot appear in any variablename in dash, but can in TLA+ + return SP+s.replace('/', SP); + } + public static List topoSortStates(DashModule d) // each state occurs only after all its children occur + { + List states = new ArrayList<>(); + states.add(d.getRootName()); + int i = 0; + while(i < states.size()) + { + List children = d.getImmChildren(states.get(i)); + i++; + for(String ch : children)states.add(ch); + } + Collections.reverse(states); + return states; + } + public static List toStringList(List dfs) + { + List ls = new ArrayList<>(); + for(DashRef df : dfs)ls.add(df.getName()); + return ls; + } + + public static List resolveList(List elements) // set of strings in TLA+ notation + { + List resolvedNames = new ArrayList<>(); + elements.forEach(element -> {resolvedNames.add(resolveName(element));}); + return resolvedNames; + } + /* + public static List toDashRefList(List ls, Function createDashRef) + { + List dfs = new ArrayList<>(); + for (String s : ls) { + dfs.add(createDashRef.apply(s)); + } + return dfs; + } + */ +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Variable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Variable.java new file mode 100644 index 000000000..cebb047f9 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/dashtotla/Variable.java @@ -0,0 +1,78 @@ +package ca.uwaterloo.watform.dashtotla; + +import java.util.ArrayList; +import java.util.List; + +import ca.uwaterloo.watform.parser.DashModule; + +public class Variable +{ + + + // boilerplate variables + public static final String CONF = "_conf"; + public static final String INTERNAL_EVENTS = "_internal_events"; + public static final String ENVIRONMENTAL_EVENTS = "_environmental_events"; + public static final String SCOPES_USED = "_scopes_used"; + public static final String STABLE = "_stable"; + + // variable in next step + public static String prime(String variable){return variable+"'";} + + // set holding every value which a variable can hold + public static String superset(String variable){return variable+"__superset";} + + // initial value of a variable + public static String initial(String variable){return variable+"__initial";} + + public static String initialValues(DashModule d) + { + StringBuilder code = new StringBuilder("\n\n"+TLA.comment(" initial values")); + + code.append("\n"+initial(Variable.CONF)+" "+TLA.DEFINE+" "+TLA.set(Util.resolveList(Util.toStringList(d.initialEntered())))); + code.append("\n"+initial(Variable.ENVIRONMENTAL_EVENTS)+" "+TLA.DEFINE+" "+TLA.NULL_SET); + code.append("\n"+initial(Variable.SCOPES_USED)+" "+TLA.DEFINE+" "+TLA.NULL_SET); + code.append("\n"+initial(Variable.STABLE)+" "+TLA.DEFINE+" "+TLA.TRUE); + + return code.toString(); + } + public static String declareVariables(DashModule d) + { + List variables = new ArrayList<>(); + variables.add(SCOPES_USED); + variables.add(CONF); + variables.add(INTERNAL_EVENTS); + variables.add(ENVIRONMENTAL_EVENTS); + variables.add(STABLE); + return "\n"+TLA.variables(variables); + } + public static String supersets(DashModule d) // define the set of all possible values for a variable's elements + { + StringBuilder code = new StringBuilder("\n\n"+TLA.comment(" supersets")); + + // conf, scopes used + List resolvedStateNames = new ArrayList<>(); + List resolvedBasicStateNames = new ArrayList<>(); + for(String s : d.getAllStateNames()) + { + resolvedStateNames.add(Util.resolveName(s)); + if(d.isLeaf(s)) + resolvedBasicStateNames.add(Util.resolveName(s)); + } + code.append("\n"+superset(Variable.CONF)+" "+TLA.DEFINE+" "+TLA.set(resolvedBasicStateNames)); + code.append("\n"+superset(Variable.SCOPES_USED)+" "+TLA.DEFINE+" "+TLA.set(resolvedStateNames)); + + // internal events + List resolvedInternalEventNames = new ArrayList<>(); + for(String s : d.getAllInternalEventNames())resolvedInternalEventNames.add(Util.resolveName(s)); + code.append("\n"+superset(Variable.INTERNAL_EVENTS)+" "+TLA.DEFINE+" "+TLA.set(resolvedInternalEventNames)); + + // environmental events + List resolvedEnvironmentalEventNames = new ArrayList<>(); + for(String s : d.getAllEnvironmentalEventNames())resolvedEnvironmentalEventNames.add(Util.resolveName(s)); + code.append("\n"+superset(Variable.ENVIRONMENTAL_EVENTS)+" "+TLA.DEFINE+" "+TLA.set(resolvedEnvironmentalEventNames)); + + + return code.toString(); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/mainfunctions/MainFunctions.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/mainfunctions/MainFunctions.java new file mode 100644 index 000000000..04743ab31 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/mainfunctions/MainFunctions.java @@ -0,0 +1,161 @@ +package ca.uwaterloo.watform.mainfunctions; + +// drop this when removed print stmts here +import java.util.*; + +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.ast.Command; +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.parser.CompUtil; + +import edu.mit.csail.sdg.translator.A4Options; +import edu.mit.csail.sdg.translator.A4Options.SatSolver; +import edu.mit.csail.sdg.translator.A4Solution; +import edu.mit.csail.sdg.translator.TranslateAlloyToKodkod; + +import ca.uwaterloo.watform.core.DashSituation; +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.dashtotla.DashToTLA; + + +// no io in these! +// A4 reporter is not used in Dash stuff + +public class MainFunctions { + + // all these function expect DashOptions to be set + + public static DashModule parseDashFile(String filename, A4Reporter rep) { + //DashOptions.isTraces = true; + + // some necessary initialization for two passes of parsing + DashSituation.haveCountedBuffers = false; + DashSituation.bufferElements = new ArrayList(); + DashSituation.bufferNames = new ArrayList(); + // first pass to collect buffers for open statements + DashModule d = DashUtil.parseEverything_fromFileDash(rep, null, filename); + if (d == null) { + DashErrors.emptyFile(filename); + } else { + DashSituation.haveCountedBuffers = true; + // second pass, which will put in appropriate open statements for buffers + d = DashUtil.parseEverything_fromFileDash(rep, null, filename); + } + return d; + } + public static DashModule resolveDash(DashModule d, A4Reporter rep) { + if (d == null) { + DashErrors.emptyModule(); + } else { + // done in place + d.resolveAllDash(rep); + } + //d.debug(); + return d; + } + public static DashModule translate(DashModule d, A4Reporter rep) { + if (d == null) { + DashErrors.emptyModule(); + } else { + // done in place + d.translate(); + } + return d; + } + public static String translateTLA(DashModule d, String moduleName) + { + try + { + return DashToTLA.translate(new Object[]{d, moduleName}); + } + catch(Exception e) + { + + } + return null; + } + + public static CompModule resolveAlloy(CompModule c, A4Reporter rep) { + CompModule o = null; + if (c == null) { + DashErrors.emptyModule(); + } else { + System.out.println("here1"); + o = CompModule.resolveAll(rep,c); + System.out.println("here2"); + } + return o; + } + + // make our CLI also work for .als files + public static CompModule parseAlloyFileAndResolveAll(String filename, A4Reporter rep) { + CompModule c = CompUtil.parseEverything_fromFile(rep, null, filename); + if (c == null) { + DashErrors.emptyFile(filename); + } + return c; + } + + // for testing + public static DashModule parseAndResolveDashFile(String filename, A4Reporter rep) { + DashModule d = parseDashFile(filename,rep); + return resolveDash(d,rep); + } + + /* + // only needed for testing + public static void parseAndResolveAlloyFile(String filename, A4Reporter rep) { + DashModule dash = null; + + DashOptions.isTraces = true; + DashSituation.haveCountedBuffers = false; + DashSituation.bufferElements = new ArrayList(); + DashSituation.bufferNames = new ArrayList(); + dash = DashUtil.parseEverything_fromFileDash(rep, null, filename); + if (dash == null) { + System.err.println("Error in parsing"); + System.exit(1); + } else { + if (dash.hasRoot()) { + System.err.println("Not a pure Alloy file"); + System.exit(1); + } else { + dash.resolveAllAlloy(rep); + } + } + } + + public static String alloyString(DashModule dash) { + String s = null; + if (dash != null) { + s = dash.toString(); + } + return s; + } + */ + /* + public static DashModule translate(DashModule dash, A4Reporter rep) { + + DashOptions.isTraces = true; + if (dash != null) { + // translates in place + dash.translate(); + } + // Alloy wff check + dash.resolveAllAlloy(rep == null ? A4Reporter.NOP : rep); + //System.out.println(dash.toString()); + + return dash; + } + + */ + public static A4Solution executeCommand(Command cmd, CompModule alloy, A4Reporter rep, A4Options options) { + //TODO this should be an option also + options.solver = A4Options.SatSolver.SAT4J; + A4Solution ans = TranslateAlloyToKodkod.execute_command(rep, alloy.getAllReachableSigs(), cmd, options); + return ans; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/CompModuleHelper.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/CompModuleHelper.java new file mode 100644 index 000000000..6f2d26a30 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/CompModuleHelper.java @@ -0,0 +1,497 @@ +// No state here +// just helper functions for adding elements to the module +// return a string that is what the Alloy text would be; avoids us having to print all of Alloy constructs + +package ca.uwaterloo.watform.parser; + +// tmp +import java.util.*; + +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; +import java.lang.StringBuilder; +import java.util.StringJoiner; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.ast.Attr.AttrType; +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprVar; + +import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.ast.Sig.PrimSig; +import edu.mit.csail.sdg.ast.Sig; +import edu.mit.csail.sdg.parser.CompModule; + +import ca.uwaterloo.watform.core.DashStrings; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +//import static ca.uwaterloo.watform.alloyasthelper.ExprToString.*; + +public class CompModuleHelper extends CompModule { + + private String space = " "; + private String tab = DashStrings.tab; + + // this class is never instantiated + public CompModuleHelper(CompModule world, String filename, String path) { + super(world,filename,path); + } + + public String addOpenSimple(String name, List args, String aliasName) { + //System.out.println("adding open: "+name); + ExprVar alias = (aliasName == null) ? null : createVar(aliasName); + List argsExprList = new ArrayList(); + if (args != null) + for (String a: args) argsExprList.add(createVar(a)); + addOpen(null, null, createVar(name), argsExprList, alias); + // build the string that is this open + String s = DashStrings.openName + " "+name; + if (args != null) { + s += "["; + StringJoiner j = new StringJoiner(", "); + args.forEach(a -> j.add(a)); + s += j.toString(); + s += "]"; + } + if (aliasName != null) s += " " + DashStrings.asName + " " + aliasName; + return s+"\n"; + } + + /** + * adding signatures + * in CompModule, a signature has multiple related parts so can't just return a signature + * and let calling function add it to the module + * Alloy public Sig addSig(Pos namePos, String name, ExprVar par, + * List parents, List fields, Expr fact, Attr... attributes) throws Err { + */ + + public String addSigSimple(String name) { + // sig name {} + addSig( + Pos.UNKNOWN, + name, + null, + null, + new ArrayList(), + null, + null, + null, + null, + null, + null, + null); + String s = new String(); + s += DashStrings.sigName + space + name + " {}\n"; + //System.out.println(s); + return s; + } + + public String addAbstractSigSimple(String name) { + // abstract sig name {} + addSig( + Pos.UNKNOWN, + name, + null, + null, + new ArrayList(), + null, + AttrType.ABSTRACT.makenull(Pos.UNKNOWN), + null, + null, + null, + null, + null); + String s = new String(); + s += DashStrings.abstractName + space + DashStrings.sigName + space; + s += name + " {}\n"; + //System.out.println(s); + return s; + } + + public String addAbstractExtendsSigSimple(String extension, String extended) { + // abstract sig extension extends extended {} + addSig( + Pos.UNKNOWN, + extension, + createVar(DashStrings.extendsName), + createExprVarList(new ArrayList(Arrays.asList(extended))), + new ArrayList(), + null, + AttrType.ABSTRACT.makenull(Pos.UNKNOWN), + null, + null, + null, + null, + null); + String s = DashStrings.abstractName + space + DashStrings.sigName + space; + s += extension + space + DashStrings.extendsName + space; + s += extended; + s += " {} \n"; + //System.out.println(s); + return s; + } + + public String addExtendsSigSimple(String extension, String extended) { + // one sig extension extends extended {} + addSig( + Pos.UNKNOWN, + extension, + createVar(DashStrings.extendsName), + createExprVarList(new ArrayList(Arrays.asList(extended))), + new ArrayList(), + null, + null, + null, + null, + null, + null, + null); + String s = DashStrings.sigName + space; + s += extension + space + DashStrings.extendsName + space; + s += extended; + s += " {} \n"; + //System.out.println(s); + return s; + } + + public String addOneExtendsSigSimple(String extension, String extended) { + // one sig extension extends extended {} + addSig( + Pos.UNKNOWN, + extension, + createVar(DashStrings.extendsName), + createExprVarList(new ArrayList(Arrays.asList(extended))), + new ArrayList(), + null, + null, + null, + AttrType.ONE.makenull(Pos.UNKNOWN), + null, + null, + null); + String s = DashStrings.oneName + space + DashStrings.sigName + space; + s += extension + space + DashStrings.extendsName + space; + s += extended; + s += " {} \n"; + //System.out.println(s); + return s; + } + public String addSigWithDeclsSimple(String name, List decls) { + // sig name { decls } + addSig( + Pos.UNKNOWN, + name, + null, + null, + decls, + null, + null, + null, + null, + null, + null, + null); + String s = DashStrings.sigName + space + name; + s += " {\n"+tab; + if (!decls.isEmpty()) { + StringJoiner j = new StringJoiner(",\n"+tab); + decls.forEach(i -> j.add(ppDecl(i))); + s += j.toString() + "\n}\n"; + } else s += "}\n"; + //System.out.println(s); + return s; + } + public String addSigExtendsWithDeclsSimple(String extension, String extended, List decls) { + // sig name { decls } + addSig( + Pos.UNKNOWN, + extension, + createVar(DashStrings.extendsName), + createExprVarList(new ArrayList(Arrays.asList(extended))), + decls, + null, + null, + null, + null, + null, + null, + null); + String s = DashStrings.sigName + space; + s += extension + space + DashStrings.extendsName + space; + s += extended; + s += " {\n"; + //s += ppDecls(decls); + StringJoiner j = new StringJoiner(",\n"+tab); + decls.forEach(i -> j.add(ppDecl(i))); + s += j.toString() + "\n}\n"; + //System.out.println(s); + return s; + } + public String addOneSigWithDeclsSimple(String name, List decls) { + // sig name { decls } + addSig( + Pos.UNKNOWN, + name, + null, + null, + decls, + null, + null, + null, + AttrType.ONE.makenull(Pos.UNKNOWN), + null, + null, + null); + String s = DashStrings.oneName + space +DashStrings.sigName + space + name + space + "{\n"; + //s += ppDecls(decls); + StringJoiner j = new StringJoiner(",\n"); + decls.forEach(i -> j.add(ppDecl(i))); + s += j.toString() + "\n}\n"; + //System.out.println(s); + return s; + } + // var sig name in typ {} + public String addVarSigSimple(String name, ExprVar typ) { + // var sig s in typ {}; + addSig( + Pos.UNKNOWN, + name, + createVar(DashStrings.inName), + Arrays.asList(typ), + new ArrayList(), + null, + null, + null, + null, + null, + null, + AttrType.VARIABLE.makenull(Pos.UNKNOWN) + ); + String s = DashStrings.varName + space + DashStrings.sigName + space; + s += name + space + DashStrings.inName + space; + s += ppExpr(typ); + s += " { }\n"; + //System.out.println(s); + return s; + } + public String addVarSigSimple(String name, List typ) { + // var sig s in typ {}; + addSig( + Pos.UNKNOWN, + name, + createVar(DashStrings.inName), + typ, + new ArrayList(), + null, + null, + null, + null, + null, + null, + AttrType.VARIABLE.makenull(Pos.UNKNOWN) + ); + String s = DashStrings.varName + space + DashStrings.sigName + space; + s += name + space + DashStrings.inName + space; + s += ppExpr(((Expr) typ)); + s += " { }\n"; + //System.out.println(s); + return s; + } + + // var one sig name in typ {} + public String addVarOneSigSimple(String name, ExprVar typ) { + // var one sig s in typ {}; + addSig( + Pos.UNKNOWN, + name, + createVar(DashStrings.inName), + Arrays.asList(typ), + new ArrayList(), + null, + null, + null, + AttrType.ONE.makenull(Pos.UNKNOWN), + null, + null, + AttrType.VARIABLE.makenull(Pos.UNKNOWN) + ); + String s = DashStrings.varName + space + DashStrings.oneName + space + DashStrings.sigName + space; + s += name + space + DashStrings.inName + space; + s += ppExpr(typ); + s += " { }\n"; + //System.out.println(s); + return s; + } + + // var lone sig name in typ {} + public String addVarLoneSigSimple(String name, ExprVar typ) { + // var lone sig s in typ {}; + addSig( + Pos.UNKNOWN, + name, + createVar(DashStrings.inName), + Arrays.asList(typ), + new ArrayList(), + null, + null, + null, + AttrType.LONE.makenull(Pos.UNKNOWN), + null, + null, + AttrType.VARIABLE.makenull(Pos.UNKNOWN) + ); + String s = DashStrings.varName + space + DashStrings.loneName + space + DashStrings.sigName + space; + s += name + space + DashStrings.inName + space; + s += ppExpr(typ); + s += " { }\n"; + //System.out.println(s); + return s; + } + + + + /** + * adding functions/predicates + * + * Alloy: void addFunc(Pos p, Pos isPrivate, ExprVar n, Expr f, List decls, Expr t, Expr v) + * f is a label + * t is return type; null if predicate + */ + public String addPredSimple(String name, List decls, List eList) { + Expr body; + //NAD: no idea why a one line eList causes a problem + // but it does cause a problem in addFunc about multiplicity not allowed here + // at least if one formula starts with 'some ...' + if (eList.size() != 1) body = createAndFromList(eList); + else body = createNoop(eList.get(0)); + + + //System.out.println(createVar(name)); + //System.out.println(decls); + //System.out.println(body); + + addFunc(Pos.UNKNOWN, Pos.UNKNOWN, createVar(name), null, decls, null, body); + String s = new String(); + s += DashStrings.predName + " " + name; + if (!decls.isEmpty()) { + s += " [\n\t"; + //s += ppDecls(decls); + StringJoiner j = new StringJoiner(",\n\t"); + decls.forEach(i -> j.add(ppDecl(i))); + s += j.toString() + "]"; + } + // we have to use our own printer + // rather than expr.toString() + // because that fcn does not include brackets + // appropriately to get the correct associativity for joins + // + // later we could do something nicer for pred calls + // but remember the predicate call to testIfNextStable is nested + // inside an ITE + + s += " {\n"+tab; + StringJoiner sj = new StringJoiner("\n" + tab); + for (Expr e: eList) { + //ExprToString eToString = new ExprToString(false); + //System.out.println(ppExpr(e)); + sj.add(ppExpr(e)); + } + s += sj.toString(); + s += "\n}\n\n"; + return s; + } + + /** + * adding facts + * + * Alloy: void addFact(Pos pos, String name, Expr value) + */ + + public String addFactSimple(String name, List eList) { + Expr body = createAndFromList(eList); + addFact(Pos.UNKNOWN,name,body); + String s = new String(); + s += DashStrings.factName + " " + name + " {\n" + tab; + StringJoiner sj = new StringJoiner("\n" + tab); + for (Expr e: eList) { + //ExprToString eToString = new ExprToString(false); + sj.add(ppExpr(e)); + } + s += sj.toString() + "\n"; + s+= "}\n\n"; + return s; + } + + + // Helper method to change "{path/label}" to "label" + private String cleanLabel(String label) { + if (!label.contains("this/")) { + return label; + } + if (label.endsWith("}") && label.startsWith("{")){ + label = label.substring(1,label.length()-1); + } + int index = label.lastIndexOf('/'); + if (index > -1) { + label = label.substring(index+1); + } + return label; + } + + public String getFilePath() { + // complete path + filename of input file is + // Pos of the "module" statement in CompModule + return modulePos.filename; + } + // this seems incomplete -> DROP IT EVENTUALLY + // also need to print facts + /* + public String sigsToString() { + StringBuilder sb = new StringBuilder(""); + for(Sig sig: sigs.values()) { + if(sig.isVariable != null) + sb.append("var "); + if (sig.builtin) + sb.append("builtin "); + if (sig.isPrivate != null) + sb.append("private "); + if (sig.isAbstract != null) + sb.append("abstract "); + + if (sig.isLone != null) + sb.append("lone "); + + if (sig.isOne != null) + sb.append("one "); + + if (sig.isOne != null) + sb.append("some "); + + if (sig.isEnum != null) + sb.append("enum "); + sb.append("sig "); + sb.append(cleanLabel(sig.label)).append(" "); + if (sig.isSubsig != null && ((PrimSig) sig).parent.equals("univ")) { + sb.append("extends "); + sb.append(((PrimSig) sig).parent); + } else if (sig.isSubset != null) { + sb.append("in "); + sb.append(((PrimSig) sig).parent); + } + + sb.append(" {"); + for (Field f : sig.getFields()) { + StringJoiner namesJoiner = new StringJoiner(",\n"); + f.decl().names.forEach(name -> namesJoiner.add(cleanLabel(name.label))); + sb.append(namesJoiner.toString()); + } + sb.append(cleanLabel(sig.label)).append("}\n"); + + } + return sb.toString(); + } + */ + + +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashFilter.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashFilter.java new file mode 100644 index 000000000..0f026a8d1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashFilter.java @@ -0,0 +1,471 @@ +/* + * DO NOT EDIT THIS FILE + * DASH: file copied from Alloy src with replacements for DashModule - see install-alloy-files.sh + */ + + +/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package ca.uwaterloo.watform.parser; + +import static edu.mit.csail.sdg.parser.CompSym.ALL; +import static edu.mit.csail.sdg.parser.CompSym.ALL2; +import static edu.mit.csail.sdg.parser.CompSym.ANY_ARROW_LONE; +import static edu.mit.csail.sdg.parser.CompSym.ANY_ARROW_ONE; +import static edu.mit.csail.sdg.parser.CompSym.ANY_ARROW_SOME; +import static edu.mit.csail.sdg.parser.CompSym.ARROW; +import static edu.mit.csail.sdg.parser.CompSym.CHECK; +import static edu.mit.csail.sdg.parser.CompSym.COLON; +import static edu.mit.csail.sdg.parser.CompSym.COMMA; +import static edu.mit.csail.sdg.parser.CompSym.DISJ; +import static edu.mit.csail.sdg.parser.CompSym.EOF; +import static edu.mit.csail.sdg.parser.CompSym.EQUALS; +import static edu.mit.csail.sdg.parser.CompSym.FUN; +import static edu.mit.csail.sdg.parser.CompSym.GT; +import static edu.mit.csail.sdg.parser.CompSym.GTE; +import static edu.mit.csail.sdg.parser.CompSym.ID; +import static edu.mit.csail.sdg.parser.CompSym.IDEN; +import static edu.mit.csail.sdg.parser.CompSym.IN; +import static edu.mit.csail.sdg.parser.CompSym.INT; +import static edu.mit.csail.sdg.parser.CompSym.INTADD; +import static edu.mit.csail.sdg.parser.CompSym.INTDIV; +import static edu.mit.csail.sdg.parser.CompSym.INTMAX; +import static edu.mit.csail.sdg.parser.CompSym.INTMIN; +import static edu.mit.csail.sdg.parser.CompSym.INTMUL; +import static edu.mit.csail.sdg.parser.CompSym.INTNEXT; +import static edu.mit.csail.sdg.parser.CompSym.INTREM; +import static edu.mit.csail.sdg.parser.CompSym.INTSUB; +import static edu.mit.csail.sdg.parser.CompSym.LBRACE; +import static edu.mit.csail.sdg.parser.CompSym.LONE; +import static edu.mit.csail.sdg.parser.CompSym.LONE2; +import static edu.mit.csail.sdg.parser.CompSym.LONE_ARROW_ANY; +import static edu.mit.csail.sdg.parser.CompSym.LONE_ARROW_LONE; +import static edu.mit.csail.sdg.parser.CompSym.LONE_ARROW_ONE; +import static edu.mit.csail.sdg.parser.CompSym.LONE_ARROW_SOME; +import static edu.mit.csail.sdg.parser.CompSym.LT; +import static edu.mit.csail.sdg.parser.CompSym.LTE; +import static edu.mit.csail.sdg.parser.CompSym.MINUS; +import static edu.mit.csail.sdg.parser.CompSym.NO; +import static edu.mit.csail.sdg.parser.CompSym.NO2; +import static edu.mit.csail.sdg.parser.CompSym.NONE; +import static edu.mit.csail.sdg.parser.CompSym.NOT; +import static edu.mit.csail.sdg.parser.CompSym.NOTEQUALS; +import static edu.mit.csail.sdg.parser.CompSym.NOTGT; +import static edu.mit.csail.sdg.parser.CompSym.NOTGTE; +import static edu.mit.csail.sdg.parser.CompSym.NOTIN; +import static edu.mit.csail.sdg.parser.CompSym.NOTLT; +import static edu.mit.csail.sdg.parser.CompSym.NOTLTE; +import static edu.mit.csail.sdg.parser.CompSym.NUMBER; +import static edu.mit.csail.sdg.parser.CompSym.ONE; +import static edu.mit.csail.sdg.parser.CompSym.ONE2; +import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_ANY; +import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_LONE; +import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_ONE; +import static edu.mit.csail.sdg.parser.CompSym.ONE_ARROW_SOME; +import static edu.mit.csail.sdg.parser.CompSym.PRED; +import static edu.mit.csail.sdg.parser.CompSym.PRIVATE; +import static edu.mit.csail.sdg.parser.CompSym.RBRACE; +import static edu.mit.csail.sdg.parser.CompSym.RBRACKET; +import static edu.mit.csail.sdg.parser.CompSym.RPAREN; +import static edu.mit.csail.sdg.parser.CompSym.RUN; +import static edu.mit.csail.sdg.parser.CompSym.SET; +import static edu.mit.csail.sdg.parser.CompSym.SIGINT; +import static edu.mit.csail.sdg.parser.CompSym.SLASH; +import static edu.mit.csail.sdg.parser.CompSym.SOME; +import static edu.mit.csail.sdg.parser.CompSym.SOME2; +import static edu.mit.csail.sdg.parser.CompSym.SOME_ARROW_ANY; +import static edu.mit.csail.sdg.parser.CompSym.SOME_ARROW_LONE; +import static edu.mit.csail.sdg.parser.CompSym.SOME_ARROW_ONE; +import static edu.mit.csail.sdg.parser.CompSym.SOME_ARROW_SOME; +import static edu.mit.csail.sdg.parser.CompSym.STR; +import static edu.mit.csail.sdg.parser.CompSym.SUM; +import static edu.mit.csail.sdg.parser.CompSym.SUM2; +import static edu.mit.csail.sdg.parser.CompSym.THIS; +import static edu.mit.csail.sdg.parser.CompSym.TOTALORDER; +import static edu.mit.csail.sdg.parser.CompSym.UNIV; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.ast.ExprConstant; +import edu.mit.csail.sdg.ast.ExprVar; +import java_cup.runtime.Scanner; +import java_cup.runtime.Symbol; + +/** + * This class sits between the lexer and the parser. + *

+ * Reason: there are 3 sets of "special tokens" that the lexer will not output. + * But the Parser expects them. So this filter class observes the stream of + * tokens, and intelligently merges or changes some primitive tokens into + * special tokens. + *

+ * For more details, refer to the main documentation. But, very briefly, here + * are the 3 groups: + *

+ * (1) The lexer will generate only ALL, NO, LONE, ONE, SUM, SOME. It will not + * output ALL2, NO2, LONE2, ONE2, SUM2, SOME2. (The Filter class will change ONE + * into ONE2 when appropriate) + *

+ * (2) The lexer won't output NOTEQUALS, NOTIN, NOTLT, NOTLTE, NOTGT, NOTGTE. + * Instead it outputs them as separate tokens (eg. "NOT" "EQUALS"). (The Filter + * class is used to merge them into a single "NOTEQUALS" token) + *

+ * (3) The lexer won't output the 15 special arrows (eg. ONE_ARROW_ONE) Instead + * it outputs them as separate tokens (eg. "ONE", "ARROW", "ONE") (The Filter + * class is used to merge them into a single "ONE_ARROW_ONE" token) + */ + +final class DashFilter implements Scanner { + + // ===================== PHASE 1 + // ================================================================================== + + /** The underlying lexer. */ + private final Scanner r; + + /** + * A list of tokens that we prefetched from the underlying lexer. + */ + private final LinkedList undo = new LinkedList(); + + /** + * Stores the latest token passed from phase 1 to phase 2. + */ + private Symbol last = null; + + /** + * Reads a token from the underlying lexer; if the undo list is not empty, we + * take it from there instead. + */ + private Symbol myread() throws Err { + if (!undo.isEmpty()) + return undo.removeFirst(); + try { + return r.next_token(); + } catch (Exception ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("IO error: " + ex.getMessage(), ex); + } + } + + /** + * Reads one or more tokens from the underlying lexer, transform them if + * necessarly. + */ + @Override + public Symbol next_token() throws Err { + Symbol a = myread(), b; + int c; + if (last == null || (last.sym != COLON && last.sym != DISJ)) { + if (a.sym == NO) + c = NO2; + else if (a.sym == ALL) + c = ALL2; + else if (a.sym == SUM) + c = SUM2; + else if (a.sym == LONE) + c = LONE2; + else if (a.sym == ONE) + c = ONE2; + else if (a.sym == SOME) + c = SOME2; + else + return last = a; + final ArrayList temp = new ArrayList(); + temp.add(b = myread()); + if (b.sym == PRIVATE) + temp.add(b = myread()); + if (b.sym == DISJ) + temp.add(b = myread()); + while (b.sym == ID) { + temp.add(b = myread()); + if (b.sym == COMMA) + temp.add(b = myread()); + else if (b.sym == COLON) { + a.sym = c; + break; + } else { + break; + } + } + for (int i = temp.size() - 1; i >= 0; i--) + undo.add(0, temp.get(i)); + } + return last = a; + } + + /** + * Change a.pos to be the merger of a.pos and b.pos, then change a.sym to be + * sym, then return a. + */ + private static Symbol merge(Symbol a, Symbol b, int sym) { + a.pos = a.pos.merge(b.pos); + a.sym = sym; + return a; + } + + /** + * Construct a filter for the tokens from the given file. + */ + public DashFilter(DashModule module, List seenDollar, String filename, int lineOffset, Reader i) throws Err { + final DashLexer L = new DashLexer(i); + L.alloy_module = module; + L.alloy_filename = filename; + L.alloy_lineoffset = lineOffset; + L.alloy_seenDollar = seenDollar; + // Replace "ID : RUN/CHECK ID" with "RUN/CHECK ID ID" + // Replace "ID : RUN/CHECK {" WITH "RUN/CHECK ID {" + final Scanner A = new Scanner() { + + private Symbol a, b, c, d; + + @Override + public final Symbol next_token() throws Exception { + if (a == null) + a = L.next_token(); + if (a.sym == EOF) { + b = a; + c = a; + d = a; + } + if (b == null) + b = L.next_token(); + if (b.sym == EOF) { + c = b; + d = b; + } + if (c == null) + c = L.next_token(); + if (c.sym == EOF) { + d = c; + } + if (d == null) + d = L.next_token(); + if (a.sym == ID && b.sym == COLON && (c.sym == RUN || c.sym == CHECK) && (d.sym == ID || d.sym == LBRACE)) { + Symbol x = c; + b = d; + c = null; + d = null; + return x; + } + Symbol x = a; + a = b; + b = c; + c = d; + d = null; + return x; + } + }; + // Merges "pred" "/" "xxx" into the actual symbol + // Merges "fun" "/" "xxx" into the actual symbol + // Merges ! { in = < <= > >= } into a single symbol + // Merges {..}=>{..} into a single symbol + final Scanner B = new Scanner() { + + private Symbol undo; + + @Override + public final Symbol next_token() throws Exception { + Symbol x = undo; + undo = null; + if (x == null) + x = A.next_token(); + if (x.sym == NOT) { + Symbol y = A.next_token(); + if (y.sym == IN) + return merge(x, y, NOTIN); + if (y.sym == EQUALS) + return merge(x, y, NOTEQUALS); + if (y.sym == LT) + return merge(x, y, NOTLT); + if (y.sym == LTE) + return merge(x, y, NOTLTE); + if (y.sym == GT) + return merge(x, y, NOTGT); + if (y.sym == GTE) + return merge(x, y, NOTGTE); + undo = y; + } else if (x.sym == PRED) { + Symbol y = A.next_token(); + if (y.sym != SLASH) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("totalOrder")) + return merge(x, z, TOTALORDER); + undo = z; + } else if (x.sym == FUN) { + Symbol y = A.next_token(); + if (y.sym != SLASH) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("add")) + return merge(x, z, INTADD); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("sub")) + return merge(x, z, INTSUB); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("mul")) + return merge(x, z, INTMUL); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("div")) + return merge(x, z, INTDIV); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("rem")) + return merge(x, z, INTREM); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("min")) + return merge(x, z, INTMIN); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("max")) + return merge(x, z, INTMAX); + if (z.sym == ID && ((ExprVar) (z.value)).label.equals("next")) + return merge(x, z, INTNEXT); + } else if (x.sym == ONE) { + Symbol y = A.next_token(); + if (y.sym != ARROW) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ONE) + return merge(x, z, ONE_ARROW_ONE); + if (z.sym == LONE) + return merge(x, z, ONE_ARROW_LONE); + if (z.sym == SOME) + return merge(x, z, ONE_ARROW_SOME); + if (z.sym == SET) + return merge(x, z, ONE_ARROW_ANY); + else { + undo = z; + return merge(x, y, ONE_ARROW_ANY); + } + } else if (x.sym == LONE) { + Symbol y = A.next_token(); + if (y.sym != ARROW) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ONE) + return merge(x, z, LONE_ARROW_ONE); + if (z.sym == LONE) + return merge(x, z, LONE_ARROW_LONE); + if (z.sym == SOME) + return merge(x, z, LONE_ARROW_SOME); + if (z.sym == SET) + return merge(x, z, LONE_ARROW_ANY); + else { + undo = z; + return merge(x, y, LONE_ARROW_ANY); + } + } else if (x.sym == SOME) { + Symbol y = A.next_token(); + if (y.sym != ARROW) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ONE) + return merge(x, z, SOME_ARROW_ONE); + if (z.sym == LONE) + return merge(x, z, SOME_ARROW_LONE); + if (z.sym == SOME) + return merge(x, z, SOME_ARROW_SOME); + if (z.sym == SET) + return merge(x, z, SOME_ARROW_ANY); + else { + undo = z; + return merge(x, y, SOME_ARROW_ANY); + } + } else if (x.sym == SET) { + Symbol y = A.next_token(); + if (y.sym != ARROW) { + undo = y; + return x; + } + Symbol z = A.next_token(); + if (z.sym == ONE) + return merge(x, z, ANY_ARROW_ONE); + if (z.sym == LONE) + return merge(x, z, ANY_ARROW_LONE); + if (z.sym == SOME) + return merge(x, z, ANY_ARROW_SOME); + if (z.sym == SET) + return merge(x, z, ARROW); + else { + undo = z; + return merge(x, y, ARROW); + } + } else if (x.sym == ARROW) { + Symbol z = A.next_token(); + if (z.sym == ONE) + return merge(x, z, ANY_ARROW_ONE); + if (z.sym == LONE) + return merge(x, z, ANY_ARROW_LONE); + if (z.sym == SOME) + return merge(x, z, ANY_ARROW_SOME); + if (z.sym == SET) + return merge(x, z, ARROW); + else { + undo = z; + } + } + return x; + } + }; + // Merge "- number" into "-number" whenever it is not immediately + // following ")" "]" "}" DISJ TOTALORDER INT SUM ID NUMBER STR IDEN THIS + // INTMIN INTMAX INTNEXT UNIV SIGINT NONE + final Scanner C = new Scanner() { + + private Symbol last, undo; + + @Override + public final Symbol next_token() throws Exception { + Symbol x = undo; + undo = null; + if (x == null) + x = B.next_token(); + if (last != null) { + if (last.sym == RPAREN || last.sym == RBRACKET || last.sym == RBRACE || last.sym == DISJ || last.sym == TOTALORDER || last.sym == INT) + return last = x; + if (last.sym == SUM || last.sym == ID || last.sym == NUMBER || last.sym == STR || last.sym == IDEN || last.sym == THIS) + return last = x; + if (last.sym == INTMIN || last.sym == INTMAX || last.sym == INTNEXT || last.sym == UNIV || last.sym == SIGINT || last.sym == NONE) + return last = x; + } + if (x.sym == MINUS) { + Symbol y = B.next_token(); + if (y.sym == NUMBER) { + ExprConstant num = (ExprConstant) (y.value); + y.pos = x.pos.merge(y.pos); + y.value = ExprConstant.Op.NUMBER.make(y.pos, 0 - num.num); + return last = y; + } + undo = y; + return last = x; + } + return last = x; + } + }; + this.r = C; + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashModule.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashModule.java new file mode 100644 index 000000000..9cc037e78 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashModule.java @@ -0,0 +1,648 @@ +package ca.uwaterloo.watform.parser; + + +import java.io.FileReader; +import java.io.BufferedReader; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Collectors; +import java.time.format.DateTimeFormatter; +import java.time.LocalDateTime; + + + + + +//import edu.mit.csail.sdg.alloy4.Pair; +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.*; +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import ca.uwaterloo.watform.ast.*; +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +//import ca.uwaterloo.watform.parser.CompModuleHelper; +import ca.uwaterloo.watform.dashtoalloy.DashToAlloy; +//import ca.uwaterloo.watform.dashtoalloy.Common; + +public class DashModule extends CompModuleHelper { + + // let it be a list so we can have a good error message in wff checks (resolveAllDash) + private List roots = new ArrayList(); + private DashState root = null; // normally first element of roots + + // after parsing, these allow us to echo the Alloy-only parts + // of the file when printing + public String filename = null; + public Integer rootStartLine = null; + public Integer rootEndLine = null; + + // derived during resolveAllDash phase + private int maxDepthParams = 0; + private boolean[] transAtThisParamDepth; + //private SymbolTable symbolTable; + private StateTable stateTable = new StateTable(); + private TransTable transTable = new TransTable(); + private EventTable eventTable = new EventTable(); + private VarTable varTable = new VarTable(); + private PredTable predTable = new PredTable(); + + + // once created and parsed, the following are + // the phases of a DashModule + // all operations happen in place + // to the final DashModule also contains the original + // parsed Dash + public static enum Status { + CREATED, + PARSED, + RESOLVED_DASH, + TRANSLATED_TO_ALLOY, + RESOLVED_ALLOY, + ERROR + } + private Status status = Status.CREATED; + + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime now = LocalDateTime.now(); + + // strings for statements resulting from the translation + public String alloyString = new String(); + public String commentString = new String( + "/*\n" + + " Automatically created via translation of a Dash model to Alloy\n" + + " on "+dtf.format(now) + "\n" + + "*/\n\n" + ); + // the open statements added for Dash translation to Alloy + // go at the beginning of the model so these are separate from the others + private String opens = new String(); + // the statement for opening util/boolean is separate + // b/c we don't want to repeat it if the user has + // included it in the model + private String booleanOpen = new String(); + + // can't ever be initialized with another world + public DashModule(String filename) { + super(null,filename,null); + initializeDashModule(); + } + public DashModule(CompModule world, String filename, String path) { + // this function is just for compatibility with copied CompUtil -> DashUtil + // super must be first statement in constructor + super(world,filename,path); + // this is violated so something in Alloy parsing must call this within a world + // assert(world == null && path == null); + // as long as super is doing copying from incoming world to current world + // this should be fine + initializeDashModule(); + } + private void initializeDashModule() { + //assert (!DashOptions.isElectrum && (DashOptions.isTcmc || DashOptions.isTraces)); + // do the open stmts for Dash after we know how many buffers + // b/c the opens are parsed during parsing + if (DashSituation.haveCountedBuffers) { + importModules(DashSituation.bufferElements, DashSituation.bufferNames); + // because a DashModule is created for every parse of a file + // including recursively for open stmts + // make sure we only do import on second parsing pass + DashSituation.haveCountedBuffers = false; + DashSituation.bufferIndex = 0; + } + } + + // printing ----------------------------------------------------- + public String toString() { + if (status == Status.RESOLVED_ALLOY) return toStringAlloy(); + else return toStringRegular(); + } + public String toStringRegular() { + String s = ""; + try { + if (root != null) { + BufferedReader br = new BufferedReader(new FileReader(getFilePath())); + String r; + for (int j= 0; j < rootStartLine-1; j++) { + r = br.readLine(); + s += r +"\n"; + } + if (root != null) s += root.toString(); + // skip Dash stuff + for (int i = 0; i <= rootEndLine - rootStartLine+1; i++) br.readLine(); + // add the rest of the lines + String rr; + while ((rr = br.readLine()) != null) s += rr + "\n"; + } else { + // just put all the lines in the string because there is no Dash part + BufferedReader br = new BufferedReader(new FileReader(getFilePath())); + String k; + while ((k = br.readLine()) != null) s += k + "\n"; + } + } catch (Exception FileNotFoundException) { + // we know the file exists so this exception should never be thrown + System.err.println("File Not Found"); + } + return s; + } + public String toStringAlloy() { + String s = new String(commentString); + /* + if (rootStartLine != null) { + s += "Path " + getFilePath() +"\n"; + s += "Dash file start line " + rootStartLine + "\n"; + s += "Dash end line " + rootEndLine +"\n"; + } + */ + + try { + if (root != null) { + BufferedReader br = new BufferedReader(new FileReader(getFilePath())); + // put the extra open statements at the beginning or right after 'module' + String r; + Integer k = 0; + Boolean writeBooleanOpen = true; + Boolean wroteOpens = false; + //System.out.println(opens); + //if (rootStartLine == 1) { + // assume there were no opens in the file + // s += booleanOpen; + // s += opens; + //} else { + + //System.out.println(rootStartLine); + + // lines in file start counting at 1 + k = 0; + for (int j= 0; j < rootStartLine-1; j++) { + k = j; + //System.out.println(j); + r = br.readLine(); + // empty line + if (!(r.replaceAll("\\s+","").equals(""))) { + if (r.contains(DashStrings.moduleName) || r.contains(DashStrings.openName)) { + //make sure we don't open boolean twice + if (r.contains(DashStrings.openName) && r.contains(DashStrings.utilBooleanName)) writeBooleanOpen = false; + s += r +"\n"; + } else { + // we've reached the end of the opens in the file + // now add our own opens and quit this loop + if (writeBooleanOpen) s += booleanOpen; + s += opens + "\n"; + // have to write the line after module/opens + // that we just read + s += r +"\n"; + wroteOpens = true; + break; + } + } else s += "\n"; + } + if (!wroteOpens) { s += booleanOpen; s += opens; } + // add all the lines after the opens and before 'state' + if (k+1 < rootStartLine-1) { + for (int i = k+1; i < rootStartLine -1 ; i++) s += br.readLine() + "\n"; + } + //} + + // skip Dash stuff + for (int i = 0; i <= rootEndLine - rootStartLine+1; i++) br.readLine(); + // print the translated Dash + s += alloyString; + // add the rest of the lines + String rr; + while ((rr = br.readLine()) != null) s += rr + "\n"; + + } else { + // just put all the lines in the string because there is no Dash part + BufferedReader br = new BufferedReader(new FileReader(getFilePath())); + String k; + while ((k = br.readLine()) != null) s += k + "\n"; + } + } catch (Exception FileNotFoundException) { + // we know the file exists so this exception should never be thrown + System.err.println("File Not Found"); + } + return s; + } + + // needed during parsing ------------------------- + + public void importModules(List bufElements, List bufNames) { + //System.out.println("Adding open stmts"); + String noAlias = null; + // module might already include it + // safe to reopen it internally? + // but don't want it printed twice? + booleanOpen = this.addOpenSimple(DashStrings.utilBooleanName, null, noAlias); + if (DashOptions.isTcmc) + opens += this.addOpenSimple(DashStrings.utilTcmcPathName, Arrays.asList(DashStrings.snapshotName), noAlias); + else if (DashOptions.isTraces) + opens += this.addOpenSimple(DashStrings.utilTracesName, Arrays.asList(DashStrings.snapshotName),DashStrings.snapshotName); + // add the open statements for the buffers + if (bufElements != null ) + for (int i = 0; i < bufElements.size(); i++) + opens += this.addOpenSimple(DashStrings.utilBufferName, Arrays.asList(DashStrings.bufferIndexName+i, bufElements.get(i)), bufNames.get(i)); + } + + // constructors + + public void addRoot(DashState r) { + roots.add(r); + } + public void setParsed() { + assert(status == Status.CREATED); + status = Status.PARSED; + } + + // general query + public boolean hasRoot() { + return (root != null); + } + public boolean hasOnlyOneState() { + return stateTable.hasOnlyOneState(); + } + public String getRootName() { + if (root != null) return root.name; + else { DashErrors.toAlloyNoDash(); return null; } + } + public List getBufferIndices() { + return varTable.getBufferIndices(); + } + public boolean hasBuffers() { + return (!getBufferIndices().isEmpty()); + } + public boolean hasInternalEvents() { + return eventTable.hasInternalEvents(); + } + public boolean hasEnvironmentalEvents() { + return eventTable.hasEnvironmentalEvents(); + } + public boolean hasEvents() { + return eventTable.hasEvents(); + } + public boolean hasEventsAti(int i) { + return eventTable.hasEventsAti(i); + } + public boolean hasInternalEventsAti(int i) { + return eventTable.hasInternalEventsAti(i); + } + public boolean hasEnvironmentalEventsAti(int i) { + return eventTable.hasEnvironmentalEventsAti(i); + } + public boolean hasConcurrency() { + return stateTable.hasConcurrency(root.name); + } + public int getMaxDepthParams() { + // could precalculate this + return maxDepthParams; + } + public List getAllParamsInOrder() { + return stateTable.getAllParamsInOrder(); + } + + public List getAllStateNames() { + return stateTable.getAllStateNames(); + } + + //stuff about states (some of these are to expose the stateTable for testing) + public boolean isLeaf(String s) { + return (stateTable.isLeaf(s)); + } + public boolean isAnd(String s) { + return stateTable.isAnd(s); + } + public boolean isRoot(String s) { + return stateTable.isRoot(s); + } + public List getImmChildren(String parent) { + return stateTable.getImmChildren(parent); + } + public List getLeafStatesExited(DashRef s) { + return stateTable.getLeafStatesExited(s); + } + public List getLeafStatesEntered(DashRef s) { + return stateTable.getLeafStatesEntered(s); + } + public List getLeafStatesEnteredWithScope(DashRef context, DashRef s) { + return null; //stateTable.getLeafStatesEnteredWithScope(context, s); + } + public List getAllAnces(String sfqn) { + return stateTable.getAllAnces(sfqn); + } + public String getClosestParamAnces(String sfqn) { + return stateTable.getClosestParamAnces(sfqn); + } + public List getAllNonParamDesc(String sfqn) { + return stateTable.getAllNonParamDesc(sfqn); + } + public List getRegion(String sfqn) { + return stateTable.getRegion(sfqn); + } + public List getTransParamsIdx(String tfqn) { + return transTable.getParamsIdx(tfqn); + } + // stuff about transitions + public List getAllTransNames() { + return transTable.getAllTransNames(); + } + + public DashRef getTransSrc(String tfqn) { + return transTable.getSrc(tfqn); + } + public DashRef getTransDest(String tfqn) { + return transTable.getDest(tfqn); + } + public DashRef getTransOn(String tfqn) { + return transTable.getOn(tfqn); + } + public Expr getTransDo(String tfqn) { + return transTable.getDo(tfqn); + } + public Expr getTransWhen(String tfqn) { + return transTable.getWhen(tfqn); + } + public DashRef getTransSend(String tfqn) { + return transTable.getSend(tfqn); + } + public List getHigherPriTrans(String tfqn) { + return transTable.getHigherPriTrans(tfqn); + } + + public boolean isEnvironmentalEvent(String efqn) { + return eventTable.isEnvironmentalEvent(efqn); + } + public boolean isInternalEvent(String efqn) { + return eventTable.isInternalEvent(efqn); + } + public boolean hasVar(String name) { + return varTable.hasVar(name); + } + public List getAllVarNames() { + return varTable.getAllVarNames(); + } + public List getAllInternalVarNames() { + return varTable.getAllVarNames().stream() + .filter(i -> varTable.isInternal(i)) + .collect(Collectors.toList()); + } + public List getVarBufferParams(String vfqn) { + return varTable.getParams(vfqn); + } + public List getVarBufferParamsIdx(String vfqn) { + return varTable.getParamsIdx(vfqn); + } + public Expr getVarType(String vfqn) { + return varTable.getVarType(vfqn); + } + public Boolean transAtThisParamDepth(int i) { + if (i > maxDepthParams) { DashErrors.tooHighParamDepth(); return null; } + else + return transAtThisParamDepth[i]; + } + public List getTransParams(String t) { + return transTable.getParams(t); + } + + public List getInits() { + return stateTable.getInits(); + } + public List getInvs() { + return stateTable.getInvs(); + } + public List getAllBufferNames() { + return varTable.getAllBufferNames(); + } + public int getBufferIndex(String bfqn) { + return varTable.getBufferIndex(bfqn); + } + public String getBufferElement(String bfqn) { + return varTable.getBufferElement(bfqn); + } + public boolean isInternal(String vfqn) { + // works for buffers also + return varTable.isInternal(vfqn); + } + // stuff about both states and trans + public DashRef getScope(String tfqn) { + DashRef src = getTransSrc(tfqn); + DashRef dest = getTransDest(tfqn); + String sc = DashFQN.longestCommonFQN(src.getName(),dest.getName()); + // maxCommonParams is max number of params that could have in common + // but they don't necessarily have the same values + Integer maxCommonParams = stateTable.getParamsIdx(sc).size(); + List scopeParams = new ArrayList(); + Expr equals = null; + Expr s = null; + Expr d = null; + for (int i=0;i exited(String tfqn) { + DashRef scope = getScope(tfqn); + return stateTable.getLeafStatesExited(scope); + } + + // for debugging + public List allPrefixDashRefs(DashRef x) { + return stateTable.allPrefixDashRefs(x); + } + public List entered(String tfqn) { + return stateTable.getLeafStatesEnteredInScope( + getScope(tfqn), + getTransDest(tfqn)); + } + public List initialEntered() { + return stateTable.getRootLeafStatesEntered(); + } + public List onlyConc(List dr) { + return dr.stream() + .filter(x -> isAnd(x.getName())) + .collect(Collectors.toList()); + } + public List scopesUsed(String tfqn) { + DashRef scope = getScope(tfqn); + List aP = allPrefixDashRefs(scope); + List aPc = onlyConc(aP); + List r = new ArrayList(); + List prms; + Expr e; + Expr p; + if (aPc.isEmpty()) { + // no concurrent states in scope prefix + // so just add root + r.add(aP.get(0)); + } else { + for (DashRef s: allButLast(aPc)) { + // if a prefix scope includes all param values, it really + // is the scope + if (isAnd(s.getName()) && stateTable.hasParam(s.getName())) { + prms = new ArrayList(allButLast(s.getParamValues())); + e = lastElement(s.getParamValues()); + p = createITE(createEquals(e,createVar(stateTable.getParam(s.getName()))), + createVar(stateTable.getParam(s.getName())), + createNone()); + prms.add(p); + r.add(DashRef.createStateDashRef(s.getName(), prms)); + } + } + // if it has a parameter it will be included + r.add(lastElement(aPc)); + } + return r; + } + public List nonOrthogonalScopesOf(String tfqn) { + DashRef scope = getScope(tfqn); + //System.out.println(allPrefixDashRefs(scope)); + List aP = allPrefixDashRefs(scope); + // always needs to include Root + List r = new ArrayList(); + r.add(aP.get(0)); + r.addAll(onlyConc(aP)); + return r; + } + // processes --------------------------------------- + + public void debug() { + System.out.println(stateTable.toString()); + System.out.println(transTable.toString()); + System.out.println(eventTable.toString()); + System.out.println(varTable.toString()); + } + public void debug(String tfqn) { + System.out.println(stateTable.toString()); + System.out.println(transTable.toString()); + System.out.println(eventTable.toString()); + System.out.println(varTable.toString()); + for (String x: getAllTransNames()) { + // System.out.println(tfqn +" scope :" + getScope(x)); + } + if (tfqn != null) { + System.out.println("src " + getTransSrc(tfqn)); + System.out.println("dest " + getTransDest(tfqn)); + System.out.println("pre " + getTransWhen(tfqn)); + System.out.println("post " + getTransDo(tfqn)); + System.out.println("getScope " + getScope(tfqn)); + System.out.println("getClosestParamAnces: "+getClosestParamAnces(getTransSrc(tfqn).getName())); + //System.out.println("getAllNonParamDesc: " +getAllNonParamDesc(getClosestConcAnces(getTransSrc(tfqn).getName()))); + System.out.println("getRegion:"+"Root/S1/S2: "+getRegion(getTransSrc(tfqn).getName())); + System.out.println("exited: " + exited(tfqn)); + System.out.println("entered" + getLeafStatesEntered(getTransDest(tfqn))); + System.out.println("enteredInScope" + entered(tfqn)); + System.out.println("allPrefixDashRefs of scope: "+ allPrefixDashRefs(getScope(tfqn))); + System.out.println("scopesUsed: "+ scopesUsed(tfqn)); + System.out.println("nonOrthogonalScopes: " + nonOrthogonalScopesOf(tfqn)); + } + } + // should we use the rep arg here? + public void resolveAllDash(A4Reporter rep) { + + //System.out.println("Resolving Dash"); + if (roots.isEmpty()) { + DashErrors.noStates(); + } else if (roots.size() > 1) { + DashErrors.onlyOneState(roots.get(1).getPos()); + } else { + root = roots.get(0); + // passed with empty set of params, empty set of ancestors + stateTable.setRoot(root.name); + root.load(stateTable,transTable, eventTable, varTable, predTable, new ArrayList()); + // have to do states first so siblings of trans parent state + // are in place to search for src/dest + // root.resolveTransTable(stateTable,transTable); + // if root has no substates? + // if no transitions? + + // resolves inits, invariants + stateTable.resolve(getRootName(), eventTable, varTable, predTable); + + transTable.resolve(stateTable, eventTable, varTable, predTable); + varTable.resolve(stateTable, eventTable, predTable); + + // varTable and predTable names cannot overlap + + if (!Collections.disjoint(varTable.getAllVarNames() , predTable.getAllNames())) { + List x = varTable.getAllVarNames(); + x.retainAll(predTable.getAllNames()); + DashErrors.varPredOverlap(x); + } + // TODO check for other overlaps?? + + maxDepthParams = stateTable.getMaxDepthParams(); + + transAtThisParamDepth = transTable.transAtThisParamDepth(maxDepthParams); + // + //debug("Root/S1/t1"); + } + status = Status.RESOLVED_DASH; + } + + public List primedDashRefs(Expr exp) { + return varTable.primedDashRefs(exp); + } + + public void translate() { + assert(status == Status.RESOLVED_DASH); + //System.out.println("Translating to Alloy"); + // this is so we can partition the translation + // code into a different file + // translation is done in place + DashToAlloy.translate(this); + // if no errors + status = Status.TRANSLATED_TO_ALLOY; + } + + // for testing + public List getDefaults(String s) { + return stateTable.getDefaults(s); + } + + + + public List getAllInternalEventNames() { + //assert(hasInternalEvents()); + return eventTable.getAllInternalEvents(); + } + public List getAllEnvironmentalEventNames() { + //assert(hasExternalEvents()); + return eventTable.getAllEnvironmentalEvents(); + } + + + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashUtil.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashUtil.java new file mode 100644 index 000000000..a82764965 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/DashUtil.java @@ -0,0 +1,513 @@ +/* + * DO NOT EDIT THIS FILE + * DASH: file copied from Alloy src with replacements for DashModule - see install-alloy-files.sh + */ + + +/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package ca.uwaterloo.watform.parser; + +import static edu.mit.csail.sdg.ast.Sig.SEQIDX; +import static edu.mit.csail.sdg.ast.Sig.SIGINT; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.alloy4.ConstList; +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.ast.Command; +import edu.mit.csail.sdg.ast.Decl; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprBinary; +import edu.mit.csail.sdg.ast.ExprCall; +import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.ExprUnary.Op; +import edu.mit.csail.sdg.ast.Module; +import edu.mit.csail.sdg.ast.Sig; +import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.ast.Type.ProductType; +import edu.mit.csail.sdg.ast.VisitQueryOnce; +import edu.mit.csail.sdg.parser.CompModule.Open; + +/** + * This class provides convenience methods for calling the parser and the + * compiler. + * + * @modified [electrum] helper method to determine whether a model is fully + * static (classic Alloy); + */ + +public final class DashUtil { + + /** + * Constructor is private, since this class never needs to be instantiated. + */ + private DashUtil() { + } + + // =============================================================================================================// + + /** + * Go up the directory hierarchy 0 or more times.
+ * For example, on a UNIX machine, goUp("/home/abc/def",1) will return + * "/home/abc"
+ * For example, on a UNIX machine, goUp("/home/abc/def",2) will return "/home" + * + * @param filepath - this must be an absolute path + * @param numberOfSteps - the number of steps to go up + */ + private static String up(String filepath, int numberOfSteps) { + while (numberOfSteps > 0) { + numberOfSteps--; + int i = filepath.lastIndexOf(File.separatorChar); + if (i <= 0) + return ""; + filepath = filepath.substring(0, i); + } + return filepath; + } + + // =============================================================================================================// + + /** + * Given the name of a module, and the filename for that module, compute the + * filename for another module + * + * @param moduleA - must be a legal Alloy modulepath (eg. name) (eg. + * name/name/name) (must not start or end in '/') + * @param fileA - the filename corresponding to moduleA + * @param moduleB - must be a legal Alloy modulepath (eg. name) (eg. + * name/name/name) (must not start or end in '/') + * @return the filename corresponding to moduleB + */ + private static String computeModulePath(String moduleA, String fileA, String moduleB) { + fileA = Util.canon(fileA); // Make sure it's a canonical absolute path + if (moduleA.length() == 0) + moduleA = "anything"; // Harmonizes the boundary case + while (moduleA.length() > 0 && moduleB.length() > 0) { + int a = moduleA.indexOf('/'), b = moduleB.indexOf('/'); + String headOfA = (a >= 0) ? moduleA.substring(0, a) : moduleA; + String headOfB = (b >= 0) ? moduleB.substring(0, b) : moduleB; + if (!headOfA.equals(headOfB) || a < 0 || b < 0) { + // eg. util/boolean==/home/models/util/boolean.als, then + // test=>/home/models/test.als" + // eg. util/boolean==/home/models/util/boolean.als, then + // sub/test=>/home/models/sub/test.als + // eg. main==/home/models/main.als, then + // test=>/home/models/test.als + // eg. main==/home/models/main.als, then + // sub/test=>/home/models/sub/test.als" + int numberOfSlash = 0; + for (int i = 0; i < moduleA.length(); i++) + if (moduleA.charAt(i) == '/') + numberOfSlash++; + return up(fileA, numberOfSlash + 1) + File.separatorChar + moduleB.replace('/', File.separatorChar) + ".als"; + } + moduleA = moduleA.substring(a + 1); + moduleB = moduleB.substring(b + 1); + } + return ""; // This shouldn't happen, since there should always be some + // character after '/' in the module name + } + + // =============================================================================================================// + + /** + * Whether or not Int appears in the relation types found in these sigs + */ + public static boolean areIntsUsed(Iterable sigs, Command cmd) { + /* check for Int-typed relations */ + for (Sig s : sigs) { + for (Field f : s.getFields()) { + for (ProductType pt : f.type()) { + for (int k = 0; k < pt.arity(); k++) { + if (pt.get(k) == SIGINT || pt.get(k) == SEQIDX) + return true; + } + } + } + } + + if (cmd == null) + return false; + + /* check expressions; look for CAST2SIGING (Int[]) */ + try { + Object intTriggerNode; + intTriggerNode = cmd.formula.accept(new VisitQueryOnce() { + + @Override + public Object visit(ExprCall x) throws Err { + // skip integer arithmetic functions, because their + // arguments are always explicitly cast to SIGINT using + // Int[] + if (x.fun.label.startsWith("integer/")) + return null; + return super.visit(x); + } + + @Override + public Object visit(ExprUnary x) throws Err { + if (x.op == Op.CAST2SIGINT) + return x; + return super.visit(x); + } + }); + if (intTriggerNode != null) + return true; + } catch (Err e) { + } + + return false; + } + + /** + * Whether the given command is a temporal model (either there are variable + * sigs/fields or temporal operators in the formula). + */ + public static boolean isTemporalModel(Iterable sigs, Command cmd) { + for (Sig sig : sigs) { + if (sig.isVariable != null && !sig.builtin) + return true; + else { + for (Decl dec : sig.getFieldDecls()) { + if (dec.isVar != null) + return true; + } + } + } + Object varTriggerNode; + varTriggerNode = cmd.formula.accept(new VisitQueryOnce() { + + @Override + public Object visit(ExprUnary x) throws Err { + if (x.op == Op.AFTER || x.op == Op.BEFORE || x.op == Op.PRIME || x.op == Op.HISTORICALLY || x.op == Op.ALWAYS || x.op == Op.ONCE || x.op == Op.EVENTUALLY) + return x; + return super.visit(x); + } + + @Override + public Object visit(ExprBinary x) throws Err { + if (x.op == ExprBinary.Op.UNTIL || x.op == ExprBinary.Op.SINCE || x.op == ExprBinary.Op.TRIGGERED || x.op == ExprBinary.Op.RELEASES) + return x; + return super.visit(x); + } + }); + if (varTriggerNode != null) + return true; + + return false; + } + + // =============================================================================================================// + + /** + * Helper method that recursively parse a file and all its included subfiles + * + * @param loaded - this stores the text files we've loaded while parsing; cannot + * be null + * @param fc - if a file cannot be found, we consult this cache first before + * attempting to load it from disk/jar; cannot be null + * @param pos - the position of the "open" statement + * @param filename - the filename to open + * @param root - the root module (this field is ignored if prefix=="") + * @param prefix - the prefix for the file we are about to parse + * @param thispath - the set of filenames involved in the current + * chain_of_file_opening + */ + private static DashModule parseRecursivelyDash(List seenDollar, Map loaded, Map fc, Pos pos, String filename, DashModule root, String prefix, Set thispath, int initialResolution) throws Err, FileNotFoundException, IOException { + // Add the filename into a ArrayList, so that we can detect cycles in + // the module import graph + // How? I'll argue that (filename appears > 1 time along a chain) <=> + // (infinite loop in the import graph) + // => As you descend down the chain via OPEN, if you see the same FILE + // twice, then + // you will go into an infinite loop (since, regardless of the + // instantiating parameter, + // that file will attempt to OPEN the exact same set of files. leading + // back to itself, etc. etc.) + // <= If there is an infinite loop, that means there is at least 1 + // infinite chain of OPEN (from root). + // Since the number of files is finite, at least 1 filename will be + // repeated. + if (thispath.contains(filename)) + throw new ErrorSyntax(pos, "Circular dependency in module import. The file \"" + (new File(filename)).getName() + "\" is imported infinitely often."); + thispath.add(filename); + // No cycle detected so far. So now we parse the file. + DashModule u = DashUtil.parse(seenDollar, loaded, fc, root, 0, filename, prefix, initialResolution); + if (prefix.length() == 0) + root = u; + + // Here, we recursively open the included files + for (Open x : u.getOpens()) { + String cp = Util.canon(computeModulePath(u.getModelName(), filename, x.filename)), content = fc.get(cp); + try { + if (content == null) { + content = loaded.get(cp); + } + if (content == null) { + content = fc.get(x.filename); + if (content != null) + cp = x.filename; + } + if (content == null) { + content = loaded.get(x.filename); + if (content != null) + cp = x.filename; + } + if (content == null) { + content = Util.readAll(cp); + } + } catch (IOException ex1) { + try { + String newCp = cp.replaceAll("\\.als$", ".md"); + content = Util.readAll(newCp); + } catch (IOException exx) { + + try { + String newCp = (Util.jarPrefix() + "models/" + x.filename + ".als").replace('/', File.separatorChar); + content = Util.readAll(newCp); + cp = newCp; + } catch (IOException ex) { + } + } + } + loaded.put(cp, content); + x.setResolvedFilePath(cp); + DashModule y = parseRecursivelyDash(seenDollar, loaded, fc, x.pos, cp, root, (prefix.length() == 0 ? x.alias : prefix + "/" + x.alias), thispath, initialResolution); + x.connect(y); + } + thispath.remove(filename); // Remove this file from the CYCLE DETECTION + // LIST. + return u; + } + + // =============================================================================================================// + + /** + * Parses 1 module from the input string (without loading any subfiles) + * + * @return an array of 0 or more Command if no error occurred + */ + public static ConstList parseOneModule_fromString(String content) throws Err { + DashModule u = parseOneModule(content); + return ConstList.make(u.getAllCommands()); + } + + public static DashModule parseOneModule(String content) throws Err { + try { + Map fc = new LinkedHashMap(); + fc.put("", content); + return DashUtil.parse(new ArrayList(), null, fc, null, 0, "", "", 1); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } catch (Throwable ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("Unknown exception occurred: " + ex, ex); + } + } + + // =============================================================================================================// + + /** + * Parses 1 module from the file (without loading any subfiles) + * + * @return an array of 0 or more Command if no error occurred + */ + public static ConstList parseOneModule_fromFile(String filename) throws Err { + try { + DashModule u = DashUtil.parse(new ArrayList(), null, null, null, 0, filename, "", 1); + return ConstList.make(u.getAllCommands()); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } catch (Throwable ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("Unknown exception occurred: " + ex, ex); + } + } + + // =============================================================================================================// + + /** + * Parses then typecheck the given input String as an Alloy expression from that + * world + * + * @return the fully-typechecked expression if no error occurred + * @throws Err if world==null or if any other error occurred + */ + public static Expr parseOneExpression_fromString(Module world, String input) throws Err { + try { + if (world == null) + throw new ErrorFatal("Cannot parse an expression with null world."); + return world.parseOneExpressionFromString(input); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } catch (Throwable ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("Unknown exception occurred: " + ex, ex); + } + } + + // =============================================================================================================// + + /** + * Read everything from "file" and parse it; if it mentions submodules, open + * them and parse them too. + * + * @param rep - if nonnull, we will report compilation progress messages to it + * @param loaded - a cache of files that have been pre-fetched (can be null if + * there were no prefetching) + * @param filename - the main module we are parsing + * @return the root Module which contains pointers to all submodules + * @throws Err if an error occurred + *

+ * And if loaded!=null, it will contain all the files needed for + * this parse, and furthermore, other entries will be deleted. + */ + public static DashModule parseEverything_fromFileDash(A4Reporter rep, Map loaded, String filename) throws Err { + try { + filename = Util.canon(filename); + Set thispath = new LinkedHashSet(); + if (loaded == null) + loaded = new LinkedHashMap(); + Map fc = new LinkedHashMap(loaded); + loaded.clear(); + List seenDollar = new ArrayList(); + DashModule root = parseRecursivelyDash(seenDollar, loaded, fc, new Pos(filename, 1, 1), filename, null, "", thispath, 1); + root.seenDollar = seenDollar.size() > 0; + //return CompModule.resolveAll(rep == null ? A4Reporter.NOP : rep, root); + return root; //DASH: resolveAll is done later + } catch (FileNotFoundException ex) { + throw new ErrorSyntax("File cannot be found.\n" + ex.getMessage(), ex); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } catch (Throwable ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("Unknown exception occurred: " + ex, ex); + } + } + + /** + * Read everything from "file" and parse it; if it mentions submodules, open + * them and parse them too. + * + * @param rep - if nonnull, we will report compilation progress messages to it + * @param loaded - a cache of files that have been pre-fetched (can be null if + * there were no prefetching) + * @param filename - the main module we are parsing + * @param initialResolutionMode - use 1 for the historical behavior, and 2 for + * Alloy 4.2's new "universal implicit this" name resolution behavior + * @return the root DashModule which contains pointers to all submodules + * @throws Err if an error occurred + *

+ * And if loaded!=null, it will contain all the files needed for + * this parse, and furthermore, other entries will be deleted. + */ + public static DashModule parseEverything_fromFileDash(A4Reporter rep, Map loaded, String filename, int initialResolutionMode) throws Err { + try { + filename = Util.canon(filename); + Set thispath = new LinkedHashSet(); + if (loaded == null) + loaded = new LinkedHashMap(); + Map fc = new LinkedHashMap(loaded); + loaded.clear(); + List seenDollar = new ArrayList(); + DashModule root = parseRecursivelyDash(seenDollar, loaded, fc, new Pos(filename, 1, 1), filename, null, "", thispath, initialResolutionMode); + // if no sigs are defined by the user, add one + if (root.getAllReachableUserDefinedSigs().isEmpty()) { + root.addGhostSig(); + } + root.seenDollar = seenDollar.size() > 0; + //return CompModule.resolveAll(rep == null ? A4Reporter.NOP : rep, root); + return root; //DASH: resolveAll is done later + } catch (FileNotFoundException ex) { + throw new ErrorSyntax("File cannot be found.\n" + ex.getMessage(), ex); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } catch (Throwable ex) { + if (ex instanceof Err) + throw (Err) ex; + else + throw new ErrorFatal("Unknown exception occurred: " + ex, ex); + } + } + + /** + * @param rep - may be null + * @param content - alloy model + */ + public static DashModule parseEverything_fromStringDash(A4Reporter rep, String content) throws Err { + if (rep == null) + rep = new A4Reporter(); + try { + File tmpAls = flushModelToFile(content, null); + return DashUtil.parseEverything_fromFileDash(rep, null, tmpAls.getAbsolutePath()); + } catch (IOException ex) { + throw new ErrorFatal("IOException occurred: " + ex.getMessage(), ex); + } + } + + /** + * Saves the given alloy model to a file. + * + * @param model - alloy model + * @param tmpAls - if null, a temporary file will be created and returned + */ + public static File flushModelToFile(String model, File tmpAls) throws IOException { + if (tmpAls == null) { + tmpAls = File.createTempFile("alloy_heredoc", ".als"); + tmpAls.deleteOnExit(); + } + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpAls))) { + bos.write(model.getBytes()); + bos.flush(); + return tmpAls; + } + } + + static DashModule parse(List seenDollar, Map loaded, Map fc, DashModule root, int lineOffset, String filename, String prefix, int initialResolutionMode) throws Err, FileNotFoundException, IOException { + DashModule module = DashParser.alloy_parseStream(seenDollar, loaded, fc, root, lineOffset, filename, prefix, initialResolutionMode); + module.addDefaultCommand(); + return module; + } + + public static DashModule nullModule() { + return new DashModule(null, "", ""); + } +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/EventTable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/EventTable.java new file mode 100644 index 000000000..b4afb6a5b --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/EventTable.java @@ -0,0 +1,147 @@ +package ca.uwaterloo.watform.parser; + +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Collections; +import java.util.stream.Collectors; + +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprVar; + +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashFQN; +import ca.uwaterloo.watform.core.DashRef; + +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; +import ca.uwaterloo.watform.dashtoalloy.Common; + +public class EventTable { + + // stores Event Decls in a HashMap based on the event FQN + + private LinkedHashMap table; + + + public class EventElement { + private IntEnvKind kind; + private List params; + private List paramsIdx; + + public EventElement( + IntEnvKind k, + List prms, + List prmsIdx) { + assert(prms != null); + this.kind = k; + this.params = prms; + this.paramsIdx = prmsIdx; + } + public String toString() { + String s = new String(); + s += "kind: "+kind+"\n"; + s += "params: "+ NoneStringIfNeeded(params) +"\n"; + s += "paramsIdx: "+ NoneStringIfNeeded(paramsIdx) +"\n"; + return s; + } + } + + public EventTable() { + this.table = new LinkedHashMap(); + + } + public String toString() { + String s = new String("EVENT TABLE\n"); + for (String k:table.keySet()) { + s += " ----- \n"; + s += k + "\n"; + s += table.get(k).toString(); + } + return s; + } + public Boolean add(String efqn, IntEnvKind k, List prms, List prmsIdx) { + assert(prms!=null); + if (table.containsKey(efqn)) return false; + else if (hasPrime(efqn)) { DashErrors.nameShouldNotBePrimed(efqn); return false; } + else { table.put(efqn, new EventElement(k,prms,prmsIdx)); return true; } + } + public void resolveAllEventTable() { + // TODO + } + public boolean hasEvents() { + return (!table.keySet().isEmpty() ); + } + public boolean hasEvent(String e) { + return table.containsKey(e); + } + public boolean hasEventsAti(int i) { + for (String e: table.keySet()) { + if (table.get(e).params.size() == i) return true; + } + return false; + } + public boolean hasInternalEventsAti(int i) { + for (String e: table.keySet()) { + if (table.get(e).params.size() == i && table.get(e).kind == IntEnvKind.INT) return true; + } + return false; + } + public boolean hasEnvironmentalEventsAti(int i) { + for (String e: table.keySet()) { + if (table.get(e).params.size() == i && table.get(e).kind == IntEnvKind.ENV) return true; + } + return false; + } + public boolean hasInternalEvents() { + for (String e: table.keySet()) { + if (table.get(e).kind == IntEnvKind.INT) return true; + } + return false; + } + public boolean hasEnvironmentalEvents() { + for (String e: table.keySet()) { + if (table.get(e).kind == IntEnvKind.ENV) return true; + } + return false; + } + public List getAllInternalEvents() { + return table.keySet().stream() + .filter(i -> table.get(i).kind == IntEnvKind.INT) + .collect(Collectors.toList()); + } + public List getAllEnvironmentalEvents() { + return table.keySet().stream() + .filter(i -> table.get(i).kind == IntEnvKind.ENV) + .collect(Collectors.toList()); + } + public List getAllEventNames() { + return new ArrayList(table.keySet()); + } + public List getParams(String efqn) { + if (table.containsKey(efqn)) return table.get(efqn).params; + else { DashErrors.eventTableEventNotFound("getParams", efqn); return null; } + } + public List getParamsIdx(String efqn) { + if (table.containsKey(efqn)) return table.get(efqn).paramsIdx; + else { DashErrors.eventTableEventNotFound("getParamsIdx", efqn); return null; } + } + public boolean isEnvironmentalEvent(String efqn) { + if (table.containsKey(efqn)) return (table.get(efqn).kind == IntEnvKind.ENV); + else { DashErrors.eventTableEventNotFound("isEnvironmentalEvent", efqn); return false; } + } + public boolean isInternalEvent(String efqn) { + if (table.containsKey(efqn)) return (table.get(efqn).kind == IntEnvKind.INT); + else { DashErrors.eventTableEventNotFound("isInternalEvent", efqn); return false; } + } + public List getEventsOfState(String sfqn) { + // return all events declared in this state + // will have the sfqn as a prefix + return table.keySet().stream() + .filter(i -> DashFQN.chopPrefixFromFQN(i).equals(sfqn)) + .collect(Collectors.toList()); + } + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/PredTable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/PredTable.java new file mode 100644 index 000000000..9c3dd828a --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/PredTable.java @@ -0,0 +1,76 @@ +package ca.uwaterloo.watform.parser; + +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Collections; +import java.util.stream.Collectors; + + +import edu.mit.csail.sdg.ast.*; +import edu.mit.csail.sdg.alloy4.ConstList; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.core.*; +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.dashtoalloy.Common; + +import ca.uwaterloo.watform.parser.StateTable; +import ca.uwaterloo.watform.parser.VarTable; + +public class PredTable { + + private HashMap predTable; + + public PredTable() { + this.predTable = new LinkedHashMap(); + } + + public class PredElement { + + // this expression must be resolved in the context of the guard/action + // it is used in + // because otherwise we might have orphan parameter values + // from the context where it is declared + private Expr exp; + + public PredElement( + Expr e) { + this.exp = e; + } + public String toString() { + String s = new String(); + s += "exp: "+exp.toString() + "\n"; + return s; + } + } + + public String toString() { + String s = new String("PRED TABLE\n"); + for (String k:predTable.keySet()) { + s += " ----- \n"; + s += k + "\n"; + s += predTable.get(k).toString(); + } + return s; + } + public Boolean addPred(String n, Expr e) { + if (predTable.containsKey(n)) return false; + else { predTable.put(n, new PredElement(e)); return true; } + } + public Expr getExp(String pfqn) { + if (predTable.containsKey(pfqn)) return predTable.get(pfqn).exp; + else { DashErrors.predDoesNotExist("getExp", pfqn); return null; } + } + public boolean contains(String pfqn) { + return predTable.containsKey(pfqn); + } + public List getAllNames() { + return new ArrayList(predTable.keySet()); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/ResolveExpr.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/ResolveExpr.java new file mode 100644 index 000000000..8438a1fb2 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/ResolveExpr.java @@ -0,0 +1,436 @@ +/* + This function takes an Expr and sorts out any Dash names used in it to: + 1) make the names fully qualified + 2) figure out all the parameter values + 3) figures out what "thisState" means + 4) turns PRIME(v) into v' + + It is called from stateTable resolving for inits and invariants and that + It is called from varTable for resolving type of dynamic variables (where it resolves + only the name, not the parameters) + It is called from transTable to resolve all parts of transitions. + + Variation points for these uses is in where to search for + a name (stateTable, EventTable, varTable) + + Incoming Expr may also be a DashRef (from parsing for src/dest/on/send). + + Errors are given using "pos". +*/ +package ca.uwaterloo.watform.parser; + +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Collections; +import java.util.stream.Collectors; + +import edu.mit.csail.sdg.alloy4.Pos; + +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.ExprBinary; +import edu.mit.csail.sdg.ast.ExprUnary; +import edu.mit.csail.sdg.ast.ExprLet; +import edu.mit.csail.sdg.ast.ExprBadJoin; +import edu.mit.csail.sdg.ast.ExprCall; +import edu.mit.csail.sdg.ast.ExprChoice; +import edu.mit.csail.sdg.alloy4.ConstList; +import edu.mit.csail.sdg.ast.ExprITE; +import edu.mit.csail.sdg.ast.ExprList; +import edu.mit.csail.sdg.ast.ExprQt; +import edu.mit.csail.sdg.ast.ExprConstant; +import edu.mit.csail.sdg.ast.Decl; + +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashFQN; +import ca.uwaterloo.watform.core.DashRef; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; +import ca.uwaterloo.watform.dashtoalloy.Common; + + +public class ResolveExpr{ + + // returns an Expr (could be a DashRef) or raises an exception + // can be used for expr, event uses, state uses + // returned DashRef might have to be converted to a tuple for a state or an event in translation + + //TODO should probably be a visitor using accept methods of Expr + // have to recurse through exp types, replace dynamic vars with DashRef and rebuild exp + // don't use ExprHelper much here because we want to + // as much about the expression as possible + public static Expr resolveExpr( StateTable st, + EventTable et, + VarTable vt, + PredTable pt, + String kind, + boolean primeOk, + boolean primeOkInPrmValues, + boolean thisOk, + String sfqn, // could be parent of event or trans + Expr exp) { + //System.out.println("resolve: " + exp); + if (isExprVar(exp) || + isPrimedVar(exp) || + DashRef.isDashRef(exp)) + { + return resolveDashRef(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, exp); + + } else if (isExprBinary(exp)) { + return ((ExprBinary) exp).op.make( + exp.pos, + exp.closingBracket, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getLeft(exp)), + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getRight(exp))); + + } else if (isExprBadJoin(exp)) { + return ExprBadJoin.make( + exp.pos, + exp.closingBracket, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getLeft(exp)), + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getRight(exp))); + + } else if (exp instanceof ExprCall) { + return ExprCall.make( + exp.pos, + exp.closingBracket, + ((ExprCall) exp).fun, + ((ExprCall) exp).args.stream() + .map(i -> resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, i)) + .collect(Collectors.toList()), + ((ExprCall) exp).extraWeight); + + } else if (exp instanceof ExprChoice){ + //TODO: check into this cast + // not sure why is it necessary + ConstList x = (ConstList) ((ExprChoice) exp).choices.stream() + .map(i -> resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, i)) + .collect(Collectors.toList()); + return ExprChoice.make( + false, + exp.pos, + x, + ((ExprChoice) exp).reasons); + + } else if (exp instanceof ExprITE){ + return ExprITE.make( + exp.pos, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getCond(exp)), + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getLeft(exp)), + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, getRight(exp))); + + } else if (exp instanceof ExprList){ + return ExprList.make( + exp.pos, + exp.closingBracket, + ((ExprList) exp).op, + ((ExprList) exp).args.stream() + .map(i -> resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, i)) + .collect(Collectors.toList()) + ); + + } else if (exp instanceof ExprUnary){ + return ((ExprUnary) exp).op.make( + exp.pos, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, ((ExprUnary) exp).sub)); + + } else if (exp instanceof ExprLet){ + //TODO rule out var name + return ExprLet.make( + exp.pos, + ((ExprLet) exp).var, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, ((ExprLet) exp).expr), + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, ((ExprLet) exp).sub) ); + + } else if (exp instanceof ExprQt){ + //TODO rule out var names in delcs as dynamic vars later + + // have to convert the expressions in the decls too + List decls = ((ExprQt) exp).decls.stream() + .map(i -> new Decl( + i.isPrivate, + i.disjoint, + i.disjoint2, + i.isVar, + i.names, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn, i.expr))) + .collect(Collectors.toList()); + + return ((ExprQt) exp).op.make( + exp.pos, + exp.closingBracket, + decls, + resolveExpr(st, et, vt, pt,kind, primeOk, primeOkInPrmValues, thisOk, sfqn,((ExprQt) exp).sub)); + + } else if (exp instanceof ExprConstant){ + return exp; + + } else { + DashErrors.UnsupportedExpr(exp.toString(), sfqn); + return null; + } + } + + static Expr resolveDashRef( StateTable st, + EventTable et, + VarTable vt, + PredTable pt, + String kind, + boolean primeOk, + boolean primeOkInPrmValues, + boolean thisOk, + String sfqn, // could be parent of event or trans + Expr exp) { + + + assert(isExprVar(exp) || isPrimedVar(exp) || DashRef.isDashRef(exp)); + assert(kind.equals("state") || kind.equals("event") || kind.equals("var")); + + //System.out.println("in: " + exp); + + String v; + List paramsIdx = st.getParamsIdx(sfqn); + List params = st.getParams(sfqn); + + List paramValues = new ArrayList(); + + Boolean isPrimed = false; + Pos pos = exp.pos(); + if (isExprVar(exp)) { + // no param values + v = getVarName((ExprVar) exp); + + if (thisOk && v.startsWith(thisName)) { + // thisSname gets replaced with p0_AID as a normal variable + // not a dashsref + String suffix = v.substring(thisName.length(),v.length()); + List matches = findMatchesInRegion(st,et,vt,pt,"state",sfqn,suffix); + if (matches.size() == 1 && st.hasParam(matches.get(0))) + return Common.paramVar(st.getParamIdx(matches.get(0)), st.getParam(matches.get(0))); + else if (matches.size() == 1 && !st.hasParam(matches.get(0))) + DashErrors.nonParamUseOfThis(pos,exp.toString()); + else if (matches.size() > 1) { + DashErrors.ambiguousUseOfThis(pos,exp.toString()); + } + /* else we carry on with it as a regular var name with no params */ + } + } else if (isPrimedVar(exp)) { + // AlloyExpr is PrimeOp(name) + //System.out.println("isPrimedVar"); + isPrimed = true; + v = getVarName((ExprVar) getSub(exp)); + if (!primeOk) { DashErrors.noPrimedVars(pos, exp.toString()); return null; } + } else { + // name might not be fully resolved + // might have a prime on name + // due to the way DashRefs are parsed, + // they are not turned into PrimeOp(name) + v = ((DashRef) exp).getName(); + if (hasPrime(v)) { + isPrimed = true; + v = removePrime(v); + if (!primeOk) { DashErrors.noPrimedVars(pos, exp.toString()); return null; } + } + // have to recurse through param values as VARs + paramValues = ((DashRef) exp).getParamValues().stream() + .map(i -> resolveExpr(st, et, vt, pt,"var", primeOkInPrmValues, primeOkInPrmValues, thisOk, sfqn, i)) + .collect(Collectors.toList()); + } + + // now we have v as the name, paramValues as the possible empty set of resolved param values + // and isPrimed is set correctly + + + List matches; + if (paramValues.isEmpty()) { + // if no param values must be within region + // that has same param values + matches = findMatchesInRegion(st,et,vt,pt,kind,sfqn,v); + } else { + // if it has params values, could be suffix of any var + // and later we check it has the right number of params + matches = findMatches(st, et, vt, pt,kind, v); + } + + String m = ""; + if (matches.isEmpty()) { + if (kind.equals("state")) {DashErrors.unknownState(pos, exp.toString()); return null; } + else if (kind.equals("event")) { DashErrors.unknownEvent(pos, exp.toString()); return null; } + else { + // it's some var other than a dynamic variable or a predicate name + return exp; + } + } else { + m = chooseMatch(sfqn, matches); + if (m == null) { + DashErrors.ambiguousRef(pos, exp.toString()); + return null; + } + if (pt.contains(m)) + // best match is a predicate name + // has to be treated a little differently + // because does not have params and have to put its exp + // directly in place unlike a DashRef + // resolve the predicate value in place and add it in place + return resolveExpr(st,et,vt,pt,"var",primeOkInPrmValues, primeOkInPrmValues, thisOk, sfqn, pt.getExp(m)); + } + + // m is one match from var/state or event table + List mParams; + if (kind.equals("state")) mParams = st.getParams(m); + else if (kind.equals("event")) mParams = et.getParams(m); + else mParams = vt.getParams(m); + + if (paramValues.isEmpty()) { + // must have same param values as sfqn b/c in same region + if (mParams.size() > paramsIdx.size()) { + // getRegion did not return things that all + // have the same parameter values + + DashErrors.wrongNumberParams(pos, exp.toString()); + return null; + } else { + // could be a subset of param values + paramValues = + Common.paramVars( + paramsIdx.subList(0, mParams.size()), + params.subList(0,mParams.size())); + } + } else if (mParams.size() != paramValues.size()) { + // came with parameters so must be right number + //TODO could paramValues b less than mParams???? + // and paramValues be a suffix of mParams??? + // since the name can be a suffix + DashErrors.wrongNumberParams(pos, exp.toString()); + return null; + } else + + if (isPrimed && kind.equals("var")) + if (!vt.isInternal(m)) { + DashErrors.cantPrimeAnExternalVar(pos, v); + return null; + } + if (isPrimed) m = m+PRIME; + if (kind.equals("state")) { return DashRef.createStateDashRef(pos, m, paramValues); } + else if (kind.equals("event")) { return DashRef.createEventDashRef(pos, m, paramValues); } + else { + //System.out.println(DashRef.createVarDashRef(pos, m, paramValues)); + Expr out = DashRef.createVarDashRef(pos, m, paramValues); + //System.out.println("out: " + out); + return out; + } + } + + private static List findMatchesInRegion(StateTable st, EventTable et, VarTable vt, PredTable pt, String kind, String sfqn, String suffix) { + + List region = new ArrayList(); + if (kind.equals("state")) region = st.getRegion(sfqn); + else if (kind.equals("event")) { + for (String x: st.getRegion(sfqn)) region.addAll(et.getEventsOfState(x)); + } else if (kind.equals("var")) { + for (String x: st.getRegion(sfqn)) { + region.addAll(vt.getVarsOfState(x)); + region.addAll(vt.getBuffersOfState(x)); + // does not have to have to be within state + // because does not take parameter values + } + region.addAll(pt.getAllNames()); + } + return compareMatches(suffix,region); + } + private static List compareMatches(String suffix, List region) { + List matches = new ArrayList(); + for (String x:region) + // can't just end with the suffix b/c that might not be a complete name! + // e.g., Chairs can match xChairs and yChairs but those are actually different identifiers! + if (x.endsWith(suffix)) { + // matches to the very beginning + if (x.lastIndexOf(suffix) == 0) matches.add(x); + // matches starts with a "/" + else if (x.substring(x.lastIndexOf(suffix)-1,x.lastIndexOf(suffix)).equals("/")) matches.add(x); + } + return matches; + } + + private static List findMatches(StateTable st, EventTable et, VarTable vt, PredTable pt, String kind, String suffix) { + List region = new ArrayList(); + if (kind.equals("state")) region.addAll(st.getAllStateNames()); + else if (kind.equals("event")) region.addAll(et.getAllEventNames()); + else if (kind.equals("var")) { + region.addAll(vt.getAllVarNames()); + region.addAll(vt.getAllBufferNames()); + region.addAll(pt.getAllNames()); + } + return compareMatches(suffix,region); + } + + + private static String chooseMatch(String sfqn, List matches) { + // get highest rank match based on sfqn + // if two have same rank, then ambiguous + int longestCommonPrefix = 0; + String bestmatch = ""; + Boolean multipleBestMatches = false; + for (String s: matches) { + if (DashFQN.commonPrefixLength(sfqn,s) > longestCommonPrefix) { + longestCommonPrefix = DashFQN.commonPrefixLength(sfqn,s); + bestmatch = s; + multipleBestMatches = false; + } else if (DashFQN.commonPrefixLength(sfqn,s) == longestCommonPrefix) { + multipleBestMatches = true; + } + } + if (!multipleBestMatches && longestCommonPrefix > 0) { + return bestmatch; + } else { + return null; + } + } + +} + + /* + // there is one or more match + // sfqn is the context + // might be a suffix of the name, not just v + String m = ""; + if (matches.size() >= 1) { + if (matches.contains(DashFQN.mergeFQN(sfqn,v)) || matches.contains(sfqn)) { + // first choice: if a match is sfqn+/+v or sfqn itself + // that's the best match (if both are in matches then ambiguous) + if (matches.contains(DashFQN.fqn(sfqn,v))) { + if (matches.contains(sfqn)) { + DashErrors.ambiguousRef(pos, exp.toString()); + return null; + } else { + m = sfqn; + } + } else { + m = DashFQN.mergeFQN(sfqn,v); + } + } else { + List matchesWithinSfqn = matches.stream() + .filter(i -> i.startsWith(sfqn)) + .collect(Collectors.toList()); + if (matchesWithinSfqn.size() > 0) { + // next best is something internal to sfqn so match is sfqn / .... / v (must only one) + if (matchesWithinSfqn.size() == 1) m = matchesWithinSfqn.get(0); + else { + DashErrors.ambiguousRef(pos, exp.toString()); + return null; + } + } else { + // Final choice is something external to sfqn (must be only one) + if (matches.size() > 1) { + DashErrors.ambiguousRef(pos, exp.toString()); + return null; + } else { + m = matches.get(0); + } + } + } + } + */ \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/StateTable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/StateTable.java new file mode 100644 index 000000000..6ae8ef361 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/StateTable.java @@ -0,0 +1,554 @@ +/* The StateTable maps: + FullyQualStateName -> info about state + + It is created during the resolveAll phase. +*/ + +package ca.uwaterloo.watform.parser; + +//import java.io.*; + +//import java.util.Set; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +//import java.util.HashSet; +import java.util.Collections; +import java.util.stream.Collectors; + +import edu.mit.csail.sdg.ast.Expr; + +import ca.uwaterloo.watform.core.*; +import ca.uwaterloo.watform.core.DashRef; +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import static ca.uwaterloo.watform.core.DashStrings.*; +//import static ca.uwaterloo.watform.core.DashFQN.*; +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; + +import ca.uwaterloo.watform.ast.*; + +//import ca.uwaterloo.watform.parser.VarTable; +//import ca.uwaterloo.watform.dashtoalloy.Common; + +public class StateTable { + private HashMap table; + private boolean isResolved; + private String root; + private List inits = new ArrayList(); + private List invs = new ArrayList(); + private List allParamsInOrder = new ArrayList(); + + public Integer addToParamsList(String p) { + allParamsInOrder.add(p); + return allParamsInOrder.size()-1; + } + private String space = " "; + + /* nested class for elementes in the state table */ + public class StateElement { + // better than a tuple + private DashStrings.StateKind kind; // must exist AND/OR + private String param; // may be empty + private List params; // null if none; param is last of params if it exists + private List paramsIdx; // their pos in the list of params (will be a sequence) + private DashStrings.DefKind def; + // these all use fullQual names to point to trans in TransTable + // or states in this StateTable + private String parent; // null if none + // this could be a set b/c there are no dups and order + // doesn't matter, but lists are easier to work with + private List immChildren; // empty if none + private List origInvariants; + private List origInits; + // this aren't resolved here + // so no need to keep original separate from resolved + private List entered; + private List exited; + //private List actions; + //private List conditions; + // after resolve + private List invs; + private List inits; + + + public StateElement( + DashStrings.StateKind k, + String prm, + List prms, + List prmsIdx, + DashStrings.DefKind d, + String p, + List iChildren, + List invL, + List initL, + List entered, + List exited + //List actL, + //List condL + ) { + + assert(k != null); + assert(prm == null || !prm.isEmpty()); + assert(prms != null); + assert(p == null || !p.isEmpty()); + assert(iChildren != null); // could be empty + assert(invL != null); + assert(initL != null); + //assert(actL != null); + //assert(condL != null); + this.kind = k; + this.param = prm; + this.params = prms; + this.paramsIdx = prmsIdx; + this.def = d; + this.parent = p; + this.immChildren = iChildren; + this.origInvariants = invL; + this.origInits = initL; + this.entered = entered; + this.exited = exited; + //this.actions = actL; + //this.conditions = condL; + + } + public String toString() { + String s = new String(); + s += "kind: "+kind +"\n"; + s += "param:"+ NoneStringIfNeeded(param)+"\n"; + s += "params: "+ NoneStringIfNeeded(params) +"\n"; + s += "default: "+def+"\n"; + s += "parent: "+ NoneStringIfNeeded(parent) +"\n"; + s += "immChildren: "+NoneStringIfNeeded(immChildren) +"\n"; + // add more + return s; + } + + + } + + + public StateTable() { + this.table = new HashMap(); + this.isResolved = false; + } + public void setRoot(String s) { + root = s; + } + public String getRoot() { + return root; + } + public boolean isRoot(String s) { + return (s.equals(getRoot())); + } + public String toString() { + String s = new String("STATE TABLE\n"); + for (String k:table.keySet()) { + s += " ----- \n"; + //System.out.println(s); + s += k + "\n"; + //System.out.println(s); + s += table.get(k).toString(); + //System.out.println(s); + } + return s; + } + public void add(String fqn) { + assert(!fqn.isEmpty()); + if (!table.containsKey(fqn)) + table.put(fqn,null); + //System.out.println("adding State table: "+fqn); + } + public boolean add( + String fqn, + DashStrings.StateKind k, + String prm, + List prms, + List prmsIdx, + DashStrings.DefKind d, + String p, + List iChildren, + List invL, + List initL, + List enteredL, + List exitedL) { + // if its null, make it empty to not throw exceptions + //if (iChildren == null) iChildren = new ArrayList(); + //if (table.containsKey(fqn)) { + // StateElement se = table.get(fqn); + // if (se == null) + // table.replace(fqn, new StateElement(k,prm, prms,d, p,iChildren, invL, initL, actL, condL)); + // else if (!se.attributesSame(k,prm,prms,d,p,iChildren)) + // hopefully not possible + //DashErrors.addStateToStateTableDup(fqn); + //} + //else + if (table.containsKey(fqn)) return false; + else if (DashStrings.hasPrime(fqn)) { DashErrors.nameShouldNotBePrimed(fqn); return false; } + else { table.put(fqn, new StateElement(k,prm, prms,prmsIdx, d,p,iChildren, invL, initL, enteredL, exitedL)); return true; } + //System.out.println("adding to State table: "+fqn+space+prm + space + prms+space+d+space+p+iChildren); + } + public void addInit(Expr exp) { + inits.add(exp); + } + public void addInv(Expr exp) { + invs.add(exp); + } + public boolean containsKey(String s) { + return table.containsKey(s); + } + public boolean setAsDefault(String s) { + if (table.containsKey(s)) { + table.get(s).def = DashStrings.DefKind.DEFAULT; + return true; + } + else { DashErrors.stateDoesNotExist("setDefault", s); return false; } + } + public boolean isLeaf(String s) { + if (table.containsKey(s)) + return (table.get(s).immChildren.isEmpty()); + else { DashErrors.stateDoesNotExist("isLeaf", s); return false; } + } + public boolean isOr(String s) { + if (table.containsKey(s)) + return (table.get(s).kind == StateKind.OR); + else { DashErrors.stateDoesNotExist("isOr", s); return false; } + } + public boolean isAnd(String s) { + if (table.containsKey(s)) + return (table.get(s).kind == StateKind.AND); + else { DashErrors.stateDoesNotExist("isAnd",s); return false; } + } + public boolean isDefault(String s) { + if (table.containsKey(s)) + return (table.get(s).def == DefKind.DEFAULT); + else { DashErrors.stateDoesNotExist("isDefault",s); return false; } + } + public List getAllStateNames() { + return new ArrayList(table.keySet()); + } + public String getParam(String s) { + if (table.containsKey(s)) + return table.get(s).param; + else { DashErrors.stateDoesNotExist("getParam", s); return null; } + } + public Integer getParamIdx(String s) { + if (table.containsKey(s) && hasParam(s)) + return lastElement(table.get(s).paramsIdx); + else { DashErrors.stateDoesNotExist("getParam", s); return null; } + } + public boolean hasParam(String s) { + if (table.containsKey(s)) + return table.get(s).param != null; + else { DashErrors.stateDoesNotExist("hasParam", s); return false; } + } + public List getParams(String s) { + if (table.containsKey(s)) + return table.get(s).params; + else { DashErrors.stateDoesNotExist("getParams", s); return null; } + } + public List getParamsIdx(String s) { + if (table.containsKey(s)) + return table.get(s).paramsIdx; + else { DashErrors.stateDoesNotExist("getParamsIdx", s); return null; } + } + public Boolean hasConcurrency(String s) { + if (table.containsKey(s)) { + if (table.get(s).kind == DashStrings.StateKind.AND) return true; + else + for (String k: table.get(s).immChildren) { + if (hasConcurrency(k)) return true; + } + return false; + } else { DashErrors.stateDoesNotExist("hasConcurrency", s); return null; } + } + public Boolean hasOnlyOneState() { + return (table.keySet().size() == 1 ); + } + public String getParent(String child) { + if (table.containsKey(child)) + return table.get(child).parent; // could be null if root + else { DashErrors.stateDoesNotExist("getParent", child); return null; } + } + public List getImmChildren(String parent) { + if (table.containsKey(parent)) + return table.get(parent).immChildren; + else { DashErrors.stateDoesNotExist("getImmChildren", parent); return null; } + } + public List getAllAnces(String fqn) { + // do not need to walk over tree for this operation; can just use FQNs + List fqnSplit = DashFQN.splitFQN(fqn); + List x = new ArrayList(); + // include the state itself (could be Root) + if (fqnSplit.size() > 0) for (int i=0; i < fqnSplit.size(); i++) x.add(DashFQN.fqn(fqnSplit.subList(0,i+1))); + // list is in order from root, ...., fqn-1 on path + //System.out.println("getAllAnces of "+fqn+" is "+x); + // contains at least Root state + return x; + } + + public List getAllPrefixParamAnces(String sfqn) { + return getAllAnces(sfqn).stream() + .filter(i -> (isAnd(i) && hasParam(i)) || isRoot(i)) + .collect(Collectors.toList()); + } + // might not be used anymore + public String getClosestParamAnces(String s) { + // getAllAnces returns list from Root, ..., parentFQN on path + // could also just walk back through parents + List allAnces = getAllAnces(s); + //allAnces.add(s); + Collections.reverse(allAnces); + + String concAnces = null; + // allAnces cannot be empty b/c must have Root in it + for (String a:allAnces) { + if (hasParam(a) || isRoot(a)) { + concAnces = a; + break; + } + } + //System.out.println("getClosestConcAnces: "+concAnces); + return concAnces; // might be null + } + + + public List getAllNonParamDesc(String s) { + // get all the descendants not WITHIN parameterized states + // s is included + // have to be careful to avoid duplicates + List desc = new ArrayList(); + desc.add(s); // could be Root or a conc state + + if (table.containsKey(s)) { + for (String c: table.get(s).immChildren) { + //System.out.println("in getAllNonParamDesc: "+c); + if (isOr(c) || !hasParam(c)) desc.addAll(getAllNonParamDesc(c)); + } + return desc; + } else { DashErrors.stateDoesNotExist("getAllNonParamDesc", s); return null; } + } + // region is the area within which the src name does not need to be FQN + public List getRegion(String sfqn) { + List r = new ArrayList(); + for (String s: getAllPrefixParamAnces(sfqn)) { + r.addAll(getAllNonParamDesc(s)); + } + return r; + } + public int getMaxDepthParams() { + return getMaxDepthParams(root); + } + public int getMaxDepthParams(String s) { + // TODO: check this - seems to be not getting to full depth + int max = 0; + for (String c: getImmChildren(s)) { + if (getParams(c) != null) + if (max < getParams(c).size()) max = getParams(c).size(); + if (max < getMaxDepthParams(c)) max = getMaxDepthParams(c); + } + return max; + } + public List getAllParamsInOrder() { + // variety of ways of doing this operation + return allParamsInOrder; + //Set allParams = new HashSet(); + //for (String k: table.keySet()) { + // if (table.get(k).params != null) allParams.addAll(table.get(k).params); + //} + //return DashUtilFcns.setToList(allParams); + } + public void resolve(String root, EventTable et, VarTable vt, PredTable pt) { + // resolve inits and invariants + for (String sfqn: table.keySet()) { + inits.addAll( + table.get(sfqn).origInits.stream() + .map(i -> ResolveExpr.resolveExpr(this, et, vt, pt, "var", false, false, true, sfqn, i.getExp())) + .collect(Collectors.toList())); + invs.addAll( + table.get(sfqn).origInvariants.stream() + .map(i -> ResolveExpr.resolveExpr(this, et, vt, pt, "var", false, false, true, sfqn, i.getExp())) + .collect(Collectors.toList())); + // nothing to do for entered and exited + // because they are resolved in context + } + isResolved = true; + } + + + public List getInits() { + return inits; + } + public List getInvs() { + return invs; + } + public List getEnteredAction(String sfqn) { + if (table.containsKey(sfqn)) + return table.get(sfqn).entered; // could be null + else { DashErrors.stateDoesNotExist("getEntered", sfqn); return null; } + } + public List getExitedAction(String sfqn) { + if (table.containsKey(sfqn)) + return table.get(sfqn).exited; // could be null + else { DashErrors.stateDoesNotExist("getExited", sfqn); return null; } + } + public boolean hasEnteredAction(String sfqn) { + return (getEnteredAction(sfqn) == null); + } + public boolean hasExitedAction(String sfqn) { + return (getExitedAction(sfqn) == null); + } + public List getLeafStatesExited(DashRef s) { + List r = new ArrayList(); + //System.out.println("exiting" + s.toString()); + if (isLeaf(s.getName())) { + r.add(s); + return r; + } else { + // exit everything below even if not currently in it + for (String ch:getImmChildren(s.getName())) { + // exit all copies of the params + List newParamValues = new ArrayList(s.getParamValues()); + if (hasParam(ch)) newParamValues.add(ExprHelper.createVar(getParam(ch))); + r.addAll(getLeafStatesExited(DashRef.createStateDashRef(ch, newParamValues))); + } + return r; + } + } + public List getDefaults(String s) { + if (!table.containsKey(s)) + { DashErrors.stateDoesNotExist("getDefaults",s); return null; } + // else if (isLeaf(s)) return null; + else { + assert(!isLeaf(s) || getImmChildren(s).isEmpty()); + return getImmChildren(s).stream() + .filter(c -> isDefault(c)) + .collect(Collectors.toList()); + } + } + public List getLeafStatesEntered(DashRef s) { + List r = new ArrayList(); + if (isLeaf(s.getName())) + r.add(s); + else { + // enter every default below + // if enter one c/p state enter all + // might be one (if o) or many (if c/p) + List defaults = getDefaults(s.getName()); + assert(defaults != null); + for (String ch:defaults) { + //System.out.println(ch); + // enter all copies of the param if a parameterized state + List newParamValues = new ArrayList(s.getParamValues()); + if (hasParam(ch)) + newParamValues.add(ExprHelper.createVar(getParam(ch))); + r.addAll(getLeafStatesEntered(DashRef.createStateDashRef(ch, newParamValues))); + } + } + return r; + } + public List getRootLeafStatesEntered() { + List x = new ArrayList(); + //System.out.println(getLeafStatesEntered(new DashRef(root,x))); + return getLeafStatesEntered(DashRef.createStateDashRef(root,x)); + } + public List allPrefixDashRefs(DashRef s) { + List allPrefixFQNs = DashFQN.allPrefixes(s.getName()); + List r = new ArrayList(); + int i = 0; + for (String x:allPrefixFQNs) { + if (isAnd(x) && hasParam(x)) { + r.add(DashRef.createStateDashRef(x,s.getParamValues().subList(0,i+1))); + i++; + } else + r.add(DashRef.createStateDashRef(x,s.getParamValues().subList(0,i))); + } + assert(i == s.getParamValues().size()); + return r; + } + /* + Assumption: context is an ancestor of dest + + The param values of context do not have to match dest (but they will be subsets of the same set). + + The param values of context (from the scope) could be a set of param values or they could match dest + (and therefore src of the trans as well). But they could be an ITE expression because of expressions + used in src/dest. + + The dest param values must be singleton sets. + Does not seem to be any room for syntactic simplifications in these expressions. + */ + + public List getLeafStatesEnteredInScope(DashRef context, DashRef dest) { + List cR = allPrefixDashRefs(context); + List dR = allPrefixDashRefs(dest); + //System.out.println("cR: "+cR); + //System.out.println("dR: "+dR); + // cR is a prefix of dR but possibly with different param values + // enter all the possible side concurrent regions of the scope(context) + List r = new ArrayList(); // result + int p = 0; // parameter value position + List xP = new ArrayList(); // parameters carrying forward + List nP; // parameters for each addition + Expr e1; + Expr e2; + for (int i=0; i< cR.size(); i++) { + DashRef c = cR.get(i); + if (isAnd(c.getName()) && hasParam(c.getName())) { + nP = new ArrayList(xP); + e1 = DashUtilFcns.lastElement(c.getParamValues()); + e2 = dest.getParamValues().get(p); + if (!ExprHelper.sEquals(e1, e2)) { + nP.add(ExprHelper.createDiff(e1,e2)); + r.addAll(getLeafStatesEntered(DashRef.createStateDashRef(c.getName(), nP))); + } // if equal this is empty so don't include it + xP.add(e2); // just e2 for next one + p++; + } + } + //System.out.println("r: "+r); + // we've dealt with all the side paths in cR of dR (including the last one in CR) + // now deal with the rest of dR by looking at the side paths of the children + // might be nothing in this loop if cR and dR are the same length + for (int i=cR.size()-1;i< dR.size()-1;i++) { + DashRef d = dR.get(i); // first one will be match the last of cR + DashRef chOfDest = dR.get(i+1); + //System.out.println("d: "+d); + if (isAnd(chOfDest.getName())) { + // has sisters + if (hasParam(chOfDest.getName())) { + // ones not on path to dest + nP = new ArrayList + (DashUtilFcns.allButLast(chOfDest.getParamValues())); + // all param values + e1 = ExprHelper.createVar(getParam(chOfDest.getName())); + e2 = DashUtilFcns.lastElement(chOfDest.getParamValues()); + if (!ExprHelper.sEquals(e1, e2)) { + nP.add(ExprHelper.createDiff(e1, e2)); + r.addAll(getLeafStatesEntered( + DashRef.createStateDashRef(chOfDest.getName(),nP))); + } // if equal this is empty so don't include it + } + //siblings + List children = getImmChildren(d.getName()); + List andChildren = children.stream() + .filter(c -> isAnd(c)) + .collect(Collectors.toList()); + andChildren.remove(chOfDest.getName()); + // siblings + for (String ch:andChildren) { + nP = new ArrayList(d.getParamValues()); + if (hasParam(ch)) + // add the entire param set + nP.add(ExprHelper.createVar(getParam(ch))); + r.addAll(getLeafStatesEntered(DashRef.createStateDashRef(ch,nP))); + } + } + // if its an OR state, just go on to the next one + } + //System.out.println("r "+r); + r.addAll(getLeafStatesEntered(dest)); + return r; + } + + +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/TransTable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/TransTable.java new file mode 100644 index 000000000..b2e7c8a36 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/TransTable.java @@ -0,0 +1,328 @@ +/* The StateTable maps: + FullyQualStateName -> info about state + + It is created during the resolveAll phase. +*/ + +package ca.uwaterloo.watform.parser; + +import java.io.*; + + +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.stream.Collectors; + +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprVar; + +import ca.uwaterloo.watform.core.*; +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import ca.uwaterloo.watform.alloyasthelper.ExprHelper; +//import ca.uwaterloo.watform.alloyasthelper.ExprToString; +import ca.uwaterloo.watform.ast.*; +import ca.uwaterloo.watform.dashtoalloy.Common; +import static ca.uwaterloo.watform.parser.ResolveExpr.*; + + + +public class TransTable { + + private HashMap table; + private boolean isResolved; + + public class TransElement { + public List params; // null if no params + public List paramsIdx; + public List fromList; + public List onList; + public List whenList; + public List gotoList; + public List sendList; + public List doList; + + + + // calculated when resolved + public DashRef src; + public DashRef dest; + public Expr when; // expr + public DashRef on; // event + public Expr act; + public DashRef send; + + /* + public List changedDynSymbols; // includes buffers + */ + public TransElement( + List prms, + List prmsIdx, + List fl, + List ol, + List wl, + List gl, + List sl, + List dl + ) + { + this.params = prms; + this.paramsIdx = prmsIdx; + this.fromList = fl; + this.onList = ol; + this.whenList = wl; + this.gotoList = gl; + this.sendList = sl; + this.doList = dl; + } + public String toString() { + String s = new String(); + s += "params: " + NoneStringIfNeeded(params) +"\n"; + s += "paramsIdx: " + NoneStringIfNeeded(paramsIdx) +"\n"; + s += "src: " + NoneStringIfNeeded(src) + "\n"; + s += "dest: " + NoneStringIfNeeded(dest) + "\n"; + s += "on: " + NoneStringIfNeeded(on) + "\n"; + s += "send: " + NoneStringIfNeeded(send) + "\n"; + s += "when: " + NoneStringIfNeeded(when) + "\n"; + s += "do: " + NoneStringIfNeeded(act) + "\n"; + // add more + return s; + } + public void setSrc(DashRef s) { + src = s; + } + public void setDest(DashRef d) { + dest = d; + } + public void setOn(DashRef e) { + on = e; + } + public void setSend(DashRef e) { + send = e; + } + public void setWhen(Expr e) { + when = e; + } + public void setDo(Expr e) { + act = e; + } + } + + public TransTable() { + table = new HashMap(); + isResolved = false; + } + public boolean add( + String tfqn, + List params, + List paramsIdx, + List fromList, + List onList, + List whenList, + List gotoList, + List sendList, + List doList + ) + { + //System.out.println("Adding "+tfqn); + //System.out.println("onList: " + NoneStringIfNeeded(onList)); + assert(!tfqn.isEmpty()); + assert(params != null ); + assert(paramsIdx != null); + assert(fromList != null); + assert(onList != null); + assert(whenList != null); + assert(gotoList != null); + assert(sendList != null); + assert(doList != null); + if (table.containsKey(tfqn)) return false; + else if (DashStrings.hasPrime(tfqn)) { DashErrors.nameShouldNotBePrimed(tfqn); return false; } + else { table.put(tfqn, new TransElement(params,paramsIdx, fromList,onList,whenList,gotoList,sendList,doList)); return true; } + } + public String toString() { + String s = new String(); + s += "TRANS TABLE\n"; + for (String k:table.keySet()) { + s += " ----- \n"; + s += k + "\n"; + s += table.get(k).toString(); + } + return s; + } + + public List getAllTransNames() { + return new ArrayList(table.keySet()); + } + public List getParams(String t) { + if (table.containsKey(t)) return table.get(t).params; + else { DashErrors.transDoesNotExist("getParams", t); return null; } + } + public List getParamsIdx(String t) { + if (table.containsKey(t)) return table.get(t).paramsIdx; + else { DashErrors.transDoesNotExist("getParamsIdx", t); return null; } + } + public DashRef getSrc(String t) { + if (table.containsKey(t)) return table.get(t).src; + else { DashErrors.transDoesNotExist("getSrc", t); return null; } + } + public DashRef getDest(String t) { + if (table.containsKey(t)) return table.get(t).dest; + else { DashErrors.transDoesNotExist("getDest", t); return null; } + } + public DashRef getOn(String t) { + if (table.containsKey(t)) return table.get(t).on; + else { DashErrors.transDoesNotExist("getOn", t); return null; } + } + public DashRef getSend(String t) { + if (table.containsKey(t)) return table.get(t).send; + else { DashErrors.transDoesNotExist("getSend", t); return null; } + } + public Expr getDo(String t) { + if (table.containsKey(t)) return table.get(t).act; + else { DashErrors.transDoesNotExist("getDo", t); return null; } + } + public Expr getWhen(String t) { + if (table.containsKey(t)) return table.get(t).when; + else { DashErrors.transDoesNotExist("getWhen", t); return null; } + } + + // might be better to make this getTransWithThisSrc + // but this is more efficient if it is only used for higherPriTrans + public List getTransWithTheseSrcs(List slist) { + List tlist = new ArrayList(); + for (String k:table.keySet()) { + if (slist.contains(table.get(k).src.getName())) tlist.add(k); + } + return tlist; + } + public List getHigherPriTrans(String t) { + // list returned could be empty + String src = table.get(t).src.getName(); + List tlist = new ArrayList(); + // have to look for transitions from sources earlier on the path of this transitions src + // allPrefixes includes t so it contains at least one item + List allPrefixes = DashFQN.allPrefixes(src); + // remove the src state itself + allPrefixes.remove(src); + if (table.containsKey(t)) tlist.addAll(getTransWithTheseSrcs(allPrefixes)); + else DashErrors.transDoesNotExist("getParams", t); + return tlist; + } + + /* + * check for errors and put all the trans that are at this level + * in the trans table + * must be done after resolveAllState + * this fcn does not modify anything in this object + */ + public void resolve(StateTable st, EventTable et, VarTable vt, PredTable pt) { + + //System.out.println(st); + //System.out.println(toString()); + //System.out.println("Resolving trans table"); + if (getAllTransNames().isEmpty()) DashErrors.noTrans(); + for (String tfqn: table.keySet()) { + //String tfqn = DashFQN.fqn(sfqn,t.name); + String sfqn = DashFQN.chopPrefixFromFQN(tfqn); + // determining the src state + List fList = + table.get(tfqn).fromList.stream() + .map(p -> (p.src)) + .collect(Collectors.toList()); + + if (fList.size() > 1) DashErrors.tooMany("from", tfqn); + else if (fList.isEmpty()) + // can be a loop on root + table.get(tfqn) + .setSrc(DashRef.createStateDashRef(sfqn, + Common.paramVars(getParamsIdx(tfqn), getParams(tfqn)))); + else + table.get(tfqn) + .setSrc((DashRef) resolveExpr(st, et, vt, pt, "state", false, false, true, sfqn, fList.get(0))); + + // determining the dest state + List gList = + table.get(tfqn).gotoList.stream() + .map(p -> (p.dest)) + .collect(Collectors.toList()); + + if (gList.size() > 1) DashErrors.tooMany("goto", tfqn); + else if (gList.isEmpty()) + // can be a loop on root + table.get(tfqn) + .setDest(DashRef.createStateDashRef(sfqn, + Common.paramVars(getParamsIdx(tfqn),getParams(tfqn)))); + else + table.get(tfqn) + .setDest((DashRef) resolveExpr(st, et, vt, pt, "state", false, true, true, sfqn, gList.get(0))); + + // determining the on (event) + List onExpList = + table.get(tfqn).onList.stream() + .map(p -> (p.getExp())) + .collect(Collectors.toList()); + if (onExpList.size() > 1) DashErrors.tooMany("on", tfqn); + else if (!onExpList.isEmpty()) { + table.get(tfqn) + .setOn((DashRef) resolveExpr(st, et, vt, pt, "event", false, false, true, sfqn, onExpList.get(0))); + } + + // determining the send + List sendExpList = + table.get(tfqn).sendList.stream() + .map(p -> (p.getExp())) + .collect(Collectors.toList()); + if (sendExpList.size() > 1) DashErrors.tooMany("send", tfqn); + else if (!sendExpList.isEmpty()) { + DashRef x = (DashRef) resolveExpr(st, et, vt, pt, "event", false, true, true, sfqn, sendExpList.get(0)); + if (et.isEnvironmentalEvent(x.getName())) + DashErrors.cantSendAnEnvEvent(sendExpList.get(0).pos(),sendExpList.get(0).toString()); + else + table.get(tfqn) + . setSend((DashRef) resolveExpr(st, et, vt, pt, "event", false, true, true, sfqn, sendExpList.get(0))); + } + + // determining the when (expr) + List whenExpList = + table.get(tfqn).whenList.stream() + .map(p -> (p.getWhen())) + .collect(Collectors.toList()); + if (whenExpList.size() > 1) DashErrors.tooMany("when", tfqn); + else if (!whenExpList.isEmpty()) { + table.get(tfqn) + .setWhen(resolveExpr(st, et, vt, pt, "var", false, false, true, sfqn, whenExpList.get(0))); + } + + // determining the do + List doExpList = + table.get(tfqn).doList.stream() + .map(p -> (p.getDo())) + .collect(Collectors.toList()); + if (doExpList.size() > 1) DashErrors.tooMany("on", tfqn); + else if (!doExpList.isEmpty()) { + // already resolved src/dest + Expr action = doExpList.get(0); + if (st.hasEnteredAction(getDest(tfqn).getName())) + action = ExprHelper.createAnd(action,ExprHelper.createAndList(st.getEnteredAction(getDest(tfqn).getName()))); + if (st.hasExitedAction(getSrc(tfqn).getName())) + action = ExprHelper.createAnd(action,ExprHelper.createAndList(st.getExitedAction(getSrc(tfqn).getName()))); + table.get(tfqn) + .setDo(resolveExpr(st, et, vt, pt, "var", true, true, true, sfqn, action)); + } + + } + isResolved = true; + } + + public boolean[] transAtThisParamDepth(int max) { + boolean[] depthsInUse = new boolean[max+1]; // 0..max + for (int i=0; i <= max; i++) depthsInUse[i] = false; + for (String k:table.keySet()) + if (table.get(k).params == null) depthsInUse[0] = true; + else depthsInUse[table.get(k).params.size()] = true; + return depthsInUse; + } + + +} diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/VarTable.java b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/VarTable.java new file mode 100644 index 000000000..b9735d0e8 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/VarTable.java @@ -0,0 +1,292 @@ +package ca.uwaterloo.watform.parser; + +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Collections; +import java.util.stream.Collectors; + + +import edu.mit.csail.sdg.ast.*; +import edu.mit.csail.sdg.alloy4.ConstList; + +import static ca.uwaterloo.watform.alloyasthelper.ExprHelper.*; + +import ca.uwaterloo.watform.core.*; +import static ca.uwaterloo.watform.core.DashUtilFcns.*; +import static ca.uwaterloo.watform.core.DashStrings.*; +import ca.uwaterloo.watform.core.DashRef; +import ca.uwaterloo.watform.dashtoalloy.Common; + +import ca.uwaterloo.watform.parser.StateTable; +import ca.uwaterloo.watform.parser.EventTable; +import ca.uwaterloo.watform.parser.PredTable; + +public class VarTable { + + // stores Var, Buffer Decls in a HashMap based on the event FQN + + // LinkedHashMap so order of keySet is consistent + // Alloy requires declaration before use for variables + private LinkedHashMap varTable; + private LinkedHashMap bufferTable; + + public VarTable() { + this.varTable = new LinkedHashMap(); + this.bufferTable = new LinkedHashMap(); + } + + public class VarElement { + private IntEnvKind kind; + private List params; + private List paramsIdx; + private Expr typ; + + public VarElement( + IntEnvKind k, + List prms, + List prmsIdx, + Expr t) { + assert(prms != null); + this.kind = k; + this.params = prms; + this.paramsIdx = prmsIdx; + this.typ = t; + } + public String toString() { + String s = new String(); + s += "kind: "+kind+"\n"; + s += "params: "+ NoneStringIfNeeded(params) +"\n"; + s += "paramsIdx: "+ NoneStringIfNeeded(paramsIdx) +"\n"; + s += "typ: "+typ.toString() + "\n"; + return s; + } + public void setType(Expr typ) { + this.typ = typ; + } + } + + public void setVarType(String vfqn, Expr typ) { + if (varTable.containsKey(vfqn)) varTable.get(vfqn).setType(typ); + else { DashErrors.doesNotExist("setVarType", vfqn); } + } + public String toString() { + String s = new String("VAR TABLE\n"); + for (String k:varTable.keySet()) { + s += " ----- \n"; + s += k + "\n"; + s += varTable.get(k).toString(); + } + s += "\nBUFFER TABLE\n"; + for (String k:bufferTable.keySet()) { + s += " ----- \n"; + s += k + "\n"; + s += bufferTable.get(k).toString(); + } + return s; + } + public Boolean addVar(String vfqn, IntEnvKind k, List prms, List prmsIdx, Expr t) { + assert(prms!=null); + if (varTable.containsKey(vfqn)) return false; + if (hasPrime(vfqn)) { DashErrors.nameShouldNotBePrimed(vfqn); return false; } + else { varTable.put(vfqn, new VarElement(k,prms, prmsIdx, t)); return true; } + } + + public void resolve(StateTable st, EventTable et, PredTable pt) { + + for (String vfqn: varTable.keySet()) { + String sfqn = DashFQN.chopPrefixFromFQN(vfqn); + setVarType(vfqn,ResolveExpr.resolveExpr(st, et, this, pt, "var", false, false, true, sfqn,getVarType(vfqn) )); + } + /* buffer types don't need resolving because just buf[element] */ + + + } + public boolean hasVar(String name) { + return (varTable.containsKey(name)); + } + public List getAllVarNames() { + return new ArrayList(varTable.keySet()); + } + public List getAllNames() { + // vars plus buffers + List x = getAllVarNames(); + x.addAll(getAllBufferNames()); + return x; + } + public List getVarsOfState(String sfqn) { + // return all events declared in this state + // will have the sfqn as a prefix + return varTable.keySet().stream() + // prefix of vfqn are state names + .filter(i -> DashFQN.chopPrefixFromFQN(i).equals(sfqn)) + .collect(Collectors.toList()); + } + public List getBuffersOfState(String sfqn) { + // return all events declared in this state + // will have the sfqn as a prefix + return bufferTable.keySet().stream() + // prefix of vfqn are state names + .filter(i -> DashFQN.chopPrefixFromFQN(i).equals(sfqn)) + .collect(Collectors.toList()); + } + public List getNamesOfState(String sfqn) { + List x = getVarsOfState(sfqn); + x.addAll(getBuffersOfState(sfqn)); + return x; + } + // same function for buffers and variables + //TODO: what if var and buffer have the same name!!! + public List getParams(String fqn) { + //System.out.println("getParams: " + fqn); + if (bufferTable.containsKey(fqn)) return bufferTable.get(fqn).params; + if (varTable.containsKey(fqn)) return varTable.get(fqn).params; + else { DashErrors.varBufferDoesNotExist("getParams", fqn); return null; } + } + public List getParamsIdx(String fqn) { + if (bufferTable.containsKey(fqn)) return bufferTable.get(fqn).paramsIdx; + if (varTable.containsKey(fqn)) return varTable.get(fqn).paramsIdx; + else { DashErrors.varBufferDoesNotExist("getParams", fqn); return null; } + } + public Expr getVarType(String vfqn) { + if (varTable.containsKey(vfqn)) return varTable.get(vfqn).typ; + else { DashErrors.varDoesNotExist("getType", vfqn); return null; } + } + // same function for buffers and variables + public boolean isInternal(String fqn) { + if (bufferTable.containsKey(fqn)) return (bufferTable.get(fqn).kind == IntEnvKind.INT); + if (varTable.containsKey(fqn)) return (varTable.get(fqn).kind == IntEnvKind.INT); + else { DashErrors.varBufferDoesNotExist("isInternal", fqn); return false; } + } + + public class BufferElement { + private IntEnvKind kind; + private List params; + private List paramsIdx; + private String element; + private Integer index; + + public BufferElement( + IntEnvKind k, + List prms, + List prmsIdx, + String e, + Integer idx) { + assert(prms != null); + this.kind = k; + this.params = prms; + this.paramsIdx = prmsIdx; + this.element = e; + this.index = idx; + } + public String toString() { + String s = new String(); + s += "kind: "+kind+"\n"; + s += "params: "+ NoneStringIfNeeded(params) +"\n"; + s += "paramsIdx: "+ NoneStringIfNeeded(paramsIdx) +"\n"; + s += "element: "+element.toString() + "\n"; + s += "index:" + index; + return s; + } + } + + public List getAllBufferNames() { + return new ArrayList(bufferTable.keySet()); + } + public List getBufferIndices() { + List k = new ArrayList(); + for (int i=0; i< getAllBufferNames().size();i++) k.add(i); + return k; + } + + public int getBufferIndex(String bfqn) { + if (bufferTable.containsKey(bfqn)) return bufferTable.get(bfqn).index; + else { DashErrors.bufferDoesNotExist("getIndex", bfqn); return -1; } + } + public String getBufferElement(String bfqn) { + if (bufferTable.containsKey(bfqn)) return bufferTable.get(bfqn).element; + else { DashErrors.bufferDoesNotExist("getElement", bfqn); return null; } + } + + public Boolean addBuffer(String vfqn, IntEnvKind k, List prms, List prmsIdx, String el, Integer idx) { + assert(prms!=null); + if (bufferTable.containsKey(vfqn)) return false; + else { bufferTable.put(vfqn, new BufferElement(k,prms, prmsIdx, el, idx)); return true; } + } + + + + + + + // must be done after resolve + // might be primed or unprimed + public List collectDashRefs(Expr exp) { + assert(exp != null); + List x = new ArrayList(); + if (DashRef.isDashRef(exp)) { + x.add((DashRef) exp); + return x; + } else if (isExprVar(exp)) { + return x; + } else if (isExprBinary(exp)) { + x.addAll(collectDashRefs(getLeft(exp))); + x.addAll(collectDashRefs(getRight(exp))); + return x; + } else if (isExprBadJoin(exp)) { + x.addAll(collectDashRefs(getLeft(exp))); + x.addAll(collectDashRefs(getRight(exp))); + return x; + } else if (exp instanceof ExprCall) { + for (Expr e: ((ExprCall) exp).args) x.addAll(collectDashRefs(e)); + return x; + } else if (exp instanceof ExprChoice){ + for (Expr e: ((ExprChoice) exp).choices) x.addAll(collectDashRefs(e)); + return x; + } else if (exp instanceof ExprITE){ + x.addAll(collectDashRefs(getCond(exp))); + x.addAll(collectDashRefs(getLeft(exp))); + x.addAll(collectDashRefs(getRight(exp))); + return x; + } else if (exp instanceof ExprList){ + for (Expr e: ((ExprList) exp).args) x.addAll(collectDashRefs(e)); + return x; + } else if (exp instanceof ExprUnary){ + return collectDashRefs(((ExprUnary) exp).sub); + } else if (exp instanceof ExprLet){ + x.addAll(collectDashRefs(((ExprLet) exp).expr)); + x.addAll(collectDashRefs(((ExprLet) exp).sub)); + return x; + } else if (exp instanceof ExprQt){ + List ll = ((ExprQt) exp).decls.stream() + .map(i -> i.expr) + .collect(Collectors.toList()); + for (Expr e: ll) x.addAll(collectDashRefs(e)); + x.addAll(collectDashRefs(((ExprQt) exp).sub)); + return x; + } else if (exp instanceof ExprConstant){ + return new ArrayList(); + } else { + DashErrors.UnsupportedExpr("collectDashRefs", exp.toString()); + return null; + } + } + + // returns the primed variables in an exp (but w/o the primes) + public List primedDashRefs(Expr exp) { + List drs = collectDashRefs(exp); + List o = new ArrayList(); + String v; + List paramValues; + for (DashRef e: drs) { + v = e.getName(); + paramValues = e.getParamValues(); + if (hasPrime(v)) { + o.add(DashRef.createVarDashRef(removePrime(v), paramValues)); + } + } + return o; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/install-alloy-files.sh b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/install-alloy-files.sh new file mode 100755 index 000000000..903238718 --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser/install-alloy-files.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# The purpose of this script is to copy the Alloy files that we use +# but have to do some slight renaming in them +# rerun this script whenever Alloy updates these files + +# /g means multiple places on line + +# it's tricky when to convert to turn CompModule into DCModule (the original CompModule with renaming) +# vs DashModule (our code, which is an extension of DCModule) + +p=../../../../../../../../org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/parser/ +msg=$'/*\n * DO NOT EDIT THIS FILE\n * DASH: file copied from Alloy src with replacements for DashModule - see install-alloy-files.sh \n */\n\n' + +# -------------- +# the filter sits between the Lexer and the Parser - to get it to call our DashLexer, we have to make a copy of the file +cp $p/CompFilter.java . + +sed -i -e 's/package edu.mit.csail.sdg.parser/package ca.uwaterloo.watform.parser/' CompFilter.java + +sed -i -e 's/CompLexer/DashLexer/g' CompFilter.java +sed -i -e 's/CompModule/DashModule/g' CompFilter.java +sed -i -e 's/CompFilter/DashFilter/g' CompFilter.java +# just adding a comment to the line -- could delete this if comment not relevant anymore +# sed -i -e 's/L.alloy_module = module;/L.alloy_module = module; \/\/NAD: Tamjid had this line commented out/' CompFilter.java +{ echo "$msg"; cat CompFilter.java; } > DashFilter.java +rm CompFilter.java + +# -------------- +cp $p/CompUtil.java . +# order matters here +sed -i -e 's/package edu.mit.csail.sdg.parser/package ca.uwaterloo.watform.parser/' CompUtil.java +#sed -i -e 's/import edu.mit.csail.sdg.parser.CompModule.Context;/import ca.uwaterloo.watform.parser.DCModule.Context;/' CompUtil.java +#sed -i -e 's/edu.mit.csail.sdg.parser.CompModule.Open/ca.uwaterloo.watform.parser.DCModule.Open/' CompUtil.java + +# because resolveAll is done later for Dash processing +sed -i -e 's/return CompModule.resolveAll(rep == null ? A4Reporter.NOP : rep, root);/\/\/return CompModule.resolveAll(rep == null ? A4Reporter.NOP : rep, root);\n return root; \/\/DASH: resolveAll is done later/' CompUtil.java + +# careful to have space after this so we don't catch import edu.mit.csail.sdg.parser.Compodule.Open; +sed -i -e 's/CompModule /DashModule /g' CompUtil.java + +# one place CompModule is used other than in types +sed -it -e 's/return new CompModule(null, "", "");/return new DashModule(null, "", "");/' CompUtil.java + + +sed -i -e 's/CompUtil/DashUtil/g' CompUtil.java + +sed -i -e 's/CompParser/DashParser/g' CompUtil.java + +sed -i -e 's/parseRecursively/parseRecursivelyDash/' CompUtil.java + +sed -i -e 's/parseEverything_fromFile/parseEverything_fromFileDash/' CompUtil.java + +sed -i -e 's/parseEverything_fromString/parseEverything_fromStringDash/' CompUtil.java + +{ echo "$msg"; cat CompUtil.java; } > DashUtil.java + +rm CompUtil.java + + + +rm *.java-e *.javat + +# make DashModule an extension of DashCompModule + + diff --git a/org.alloytools.alloy.dash/src/main/resources/nothing.txt b/org.alloytools.alloy.dash/src/main/resources/nothing.txt new file mode 100644 index 000000000..230ef40ea --- /dev/null +++ b/org.alloytools.alloy.dash/src/main/resources/nothing.txt @@ -0,0 +1 @@ +Something here so org.alloytools.alloy.dash/src/main/resources is not empty. \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashCoreFQNTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashCoreFQNTests.java new file mode 100644 index 000000000..de0737fde --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashCoreFQNTests.java @@ -0,0 +1,144 @@ +package org.alloytools.alloy.dash; + +import java.util.*; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import edu.mit.csail.sdg.alloy4.ErrorFatal; + +import ca.uwaterloo.watform.core.*; + +public class DashCoreFQNTests { + + public List ll(String[] k) { + return Arrays.asList(k); + } + + @Test + public void test1() { + String k = DashFQN.fqn("Root"); + assertEquals(k, "Root"); + } + + @Test + public void test2() { + String k = DashFQN.fqn("Root/A/B"); + assertEquals(k, "Root/A/B"); + } + + @Test + public void test3() { + String k = DashFQN.fqn("Root/A/B"); + assertEquals(k, "Root/A/B"); + } + + @Test + public void testFQN1() { + String k = DashFQN.longestCommonFQN("Root/A","Root/B"); + assertEquals(k,"Root"); + } + + @Test + public void testFQN2() { + String k = DashFQN.longestCommonFQN("Root/A/Bit","Root/B/Bit"); + assertEquals(k,"Root"); + } + + @Test + public void testFQN3() { + String k = DashFQN.longestCommonFQN("Root/B/Bit","Root/B/Bit"); + assertEquals(k,"Root/B/Bit"); + } + + @Test + public void getChildOfContextAncesOfDest1() { + assertEquals( + DashFQN.getChildOfContextAncesOfDest ("A/B/C", "A/B/C/D/E"), + "A/B/C/D"); + } + @Test + public void getChildOfContextAncesOfDest2() { + assertEquals( + DashFQN.getChildOfContextAncesOfDest ("A/B/C", "A/B/C"), + "A/B/C"); + } + @Test + public void getChildOfContextAncesOfDest3() { + Exception exception = assertThrows(ErrorFatal.class, () -> { + DashFQN.getChildOfContextAncesOfDest ("A/D/C", "A/B/C"); + }); + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(DashErrors.ancesNotPrefixMsg)); + } + @Test + public void getChildOfContextAncesOfDest4() { + Exception exception = assertThrows(ErrorFatal.class, () -> { + DashFQN.getChildOfContextAncesOfDest ("A/B/C", "A/B"); + }); + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(DashErrors.ancesNotPrefixMsg)); + } + + @Test + public void allPrefixes1() { + assertTrue(DashFQN.allPrefixes("A").equals( + ll(new String[]{ + "A" + }))); + } + @Test + public void allPrefixes2() { + assertEquals(DashFQN.allPrefixes("A/B"), + ll(new String[]{ + "A", + "A/B" + })); + } + @Test + public void allPrefixes3() { + assertEquals(DashFQN.allPrefixes("A/B/C"), + ll(new String[]{ + "A", + "A/B", + "A/B/C" + })); + } + + @Test + public void suffix() { + assert(DashFQN.suffix("A/B/C/x", "C/x")); + assert(DashFQN.suffix("A/B/C/x", "x")); + assert(DashFQN.suffix("x","x")); + assert(!DashFQN.suffix("A/B/xyz", "yz")); + } + + @Test + public void mergeFQN() { + assertTrue(DashFQN.mergeFQN("A/B", "B/C").equals("A/B/C")); + assertTrue(DashFQN.mergeFQN("A/B/C", "B/C/D").equals("A/B/C/D")); + assertTrue(DashFQN.mergeFQN("A/B/C", "B/C/D/E").equals("A/B/C/D/E")); + assertTrue(DashFQN.mergeFQN("A", "A/C").equals("A/C")); + assertTrue(DashFQN.mergeFQN("A/C", "A/C").equals("A/C")); + + // non-merges + assertTrue(DashFQN.mergeFQN("", "B/C").equals("")); + assertTrue(DashFQN.mergeFQN("A/B", "").equals("")); + assertTrue(DashFQN.mergeFQN("A/B", "D/C").equals("")); + assertTrue(DashFQN.mergeFQN("A", "D/C").equals("")); + assertTrue(DashFQN.mergeFQN("A", "C").equals("")); + } + + @Test + public void commonPrefixLength() { + assertTrue(DashFQN.commonPrefixLength("A/B","A") == 1); + assertTrue(DashFQN.commonPrefixLength("","A") == 0); + assertTrue(DashFQN.commonPrefixLength("A/B","") == 0); + assertTrue(DashFQN.commonPrefixLength("C/B","A") == 0); + assertTrue(DashFQN.commonPrefixLength("A/B/C/D","A/B") == 2); + assertTrue(DashFQN.commonPrefixLength("A/B/C","A/B/C/D/E") == 3); + assertTrue(DashFQN.commonPrefixLength("C/B","A/D") == 0); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashEventTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashEventTests.java new file mode 100644 index 000000000..8d1c9d5e3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashEventTests.java @@ -0,0 +1,74 @@ +package org.alloytools.alloy.dash; + +import java.util.*; +import java.io.File; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import edu.mit.csail.sdg.alloy4.A4Reporter; + +import ca.uwaterloo.watform.core.DashUtilFcns; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.mainfunctions.MainFunctions; + +public class DashEventTests { + + private static String resourcePath = "src/test/resources/pass"; + + public static DashModule test(String fileName) { + File dir = new File(resourcePath); + String absolutePath = new File(resourcePath).getAbsolutePath(); + A4Reporter rep = new A4Reporter(); + return MainFunctions.parseAndResolveDashFile(absolutePath+"/"+fileName+".dsh", rep); + } + public List ll(String[] k) { + return Arrays.asList(k); + } + + public static String on(DashModule d, String s) { + return DashUtilFcns.NoneStringIfNeeded(d.getTransOn(s)); + } + + public static String send(DashModule d, String s) { + return DashUtilFcns.NoneStringIfNeeded(d.getTransSend(s)); + } + + @Test + public void event1() { + DashModule d = test("event1"); + String tfqn = "Root/t1"; + assertTrue( + on(d, tfqn).equals("Root/ev1")); + assertTrue( + send(d, tfqn).equals("Root/ev1")); + } + + @Test + public void event2() { + DashModule d = test("event2"); + String tfqn = "Root/t1"; + assertTrue( + on(d, tfqn).equals("none")); + assertTrue( + send(d, tfqn).equals("none")); + } + + @Test + public void event3() { + DashModule d = test("event3"); + String tfqn = "Root/t1"; + assertTrue( + on(d, tfqn).equals("Root/ev1")); + assertTrue( + send(d, tfqn).equals("none")); + } + + //TODO add many more tests + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashModuleTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashModuleTests.java new file mode 100644 index 000000000..70f8eb35c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashModuleTests.java @@ -0,0 +1,1089 @@ +/* + let's check that the tests in the pass directory + pass the parse and wff checks first +*/ + +package org.alloytools.alloy.dash; + +import java.util.*; +import java.io.File; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import edu.mit.csail.sdg.alloy4.A4Reporter; + +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.mainfunctions.MainFunctions; + +public class DashModuleTests { + + private static String resourcePath = "src/test/resources/pass"; + + public static DashModule test(String fileName) { + File dir = new File(resourcePath); + String absolutePath = new File(resourcePath).getAbsolutePath(); + A4Reporter rep = new A4Reporter(); + return MainFunctions.parseAndResolveDashFile(absolutePath+"/"+fileName+".dsh", rep); + } + public List ll(String[] k) { + return Arrays.asList(k); + } + + // helper functions ------------------ + + public static String src(DashModule d, String s) { + return d.getTransSrc(s).toString(); + } + public static String dest(DashModule d, String s) { + return d.getTransDest(s).toString(); + } + + public List allPrefixDashRefs(DashModule d, String tfqn) { + return d.allPrefixDashRefs(d.getScope(tfqn)) + .stream() + .map (i -> i.toString()) + .collect(Collectors.toList()); + } + + // src/dest ---------------- + @Test + public void noDefaultNeededTest1() { + DashModule d = test("noDefaultNeeded1"); + List result = Arrays.asList(new String[]{"Root/S"}); + assertTrue(d.getDefaults("Root").equals(result)); + } + @Test + public void noDefaultNeededTest2() { + DashModule d = test("noDefaultNeeded2"); + List result = Arrays.asList(new String[]{"Root/C"}); + assertTrue(d.getDefaults("Root").equals(result)); + } + + @Test + public void noSrcDest1() { + DashModule d = test("noSrcDest1"); + assertTrue(src(d,"Root/t1").equals("Root")); + assertTrue(dest(d,"Root/t1").equals("Root")); + } + @Test + public void noSrc1() { + DashModule d = test("noSrc1"); + assertTrue(src(d,"Root/S1/t1").equals("Root/S1")); + assertTrue(dest(d,"Root/S1/t1").equals("Root/S2")); + } + @Test + public void noSrc2() { + DashModule d = test("noSrc2"); + assertTrue(src(d,"Root/S1/t1").equals("Root/S1")); + assertTrue(dest(d,"Root/S1/t1").equals("Root/S2/S3/S4")); + } + + @Test + public void otherSrcDest1() { + DashModule d = test("otherSrcDest1"); + assertTrue(src(d,"Root/S1/t1").equals("Root/S1")); + assertTrue(dest(d,"Root/S1/t1").equals("Root/S2/S3/S4")); + assertTrue(src(d,"Root/S2/t2").equals("Root/S2/S3")); + assertTrue(dest(d,"Root/S2/t2").equals("Root/S2")); + } + + @Test + public void srcDestFQN1() { + DashModule d = test("srcDestFQN1"); + assertTrue(src(d,"Root/S1/t1").equals("Root/S1")); + assertTrue(dest(d,"Root/S1/t1").equals("Root/S1/S7")); + assertTrue(src(d,"Root/S2/S3/S4/t2").equals("Root/S2/S3/S4")); + assertTrue(dest(d,"Root/S2/S3/S4/t2").equals("Root/S1/S7")); + } + + @Test + public void paramSrcDest1() { + DashModule d = test("paramSrcDest1"); + assertTrue(src(d,"Root/A/t1").equals("Root/A[p0_APID]")); + assertTrue(dest(d,"Root/A/t1").equals("Root/A[p0_APID]")); + } + @Test + public void paramSrcDest2() { + DashModule d = test("paramSrcDest2"); + assertTrue(src(d,"Root/A/t1").equals("Root/A[p0_APID]")); + assertTrue(dest(d,"Root/A/t1").equals("Root/B/S1[x]")); + } + + // getAllAnces -------------- + + @Test + public void getAllAnces1() { + DashModule d = test("noSrc1"); + assertTrue(d.getAllAnces("Root/S1").equals(ll(new String[]{"Root", "Root/S1"}))); + } + + // getClosestParamAnces ---------------- + + @Test + public void getClosestParamAnces1() { + DashModule d = test("noSrc1"); + assertTrue(d.getClosestParamAnces("Root/S1").equals("Root")); + assertTrue(d.getClosestParamAnces("Root/S2").equals("Root")); + } + @Test + public void getClosestParamAnces2() { + DashModule d = test("scopeParam2"); + assertTrue(d.getClosestParamAnces("Root/A/B/S1").equals("Root/A/B")); + assertTrue(d.getClosestParamAnces("Root/A/B").equals("Root/A/B")); + } + + + + // getRegion ---------------------- + @Test + public void getRegion1() { + DashModule d = test("getRegion1"); + assertTrue(d.getRegion("Root/S1/S2") + .equals(ll(new String[]{ + "Root", + "Root/S1", + "Root/S1/S2", + "Root/S3", + "Root/S3/S4", + "Root/S3/S4/S5", + "Root/S3/A", + "Root/S3/A/S7", + "Root/S3/A/S7/S8", + "Root/S3/B", + "Root/S3/B/S7" + }))); + } + @Test + public void getRegion2() { + DashModule d = test("getAllNonConcDesc1"); + assertTrue(d.getRegion("Root/S1/S2") + .equals(ll(new String[]{ + "Root", + "Root/S1", + "Root/S1/S2", + "Root/S3", + "Root/S3/S4", + "Root/S3/S4/S5", + "Root/S3/A", + "Root/S3/A/S7", + "Root/S3/B", + "Root/S3/B/S7" + }))); + } + + // allPrefixDashRefs ---------------------- + + + + @Test + public void allPrefixDashRefs1() { + DashModule d = test("scopeParam1"); + assertTrue( + allPrefixDashRefs(d,"Root/A/S1/t1") + .equals(ll(new String[]{ + "Root", + "Root/A[(p0_APID = x => p0_APID else APID)]" + }))); + } + @Test + public void allPrefixDashRefs2() { + DashModule d = test("scopeParam2"); + assertTrue( + allPrefixDashRefs(d, "Root/A/B/S1/t1") + .equals(ll(new String[]{ + "Root", + "Root/A[(p0_APID = x => p0_APID else APID)]", + "Root/A/B[(p0_APID = x => p0_APID else APID), (AND[p0_APID = x, p1_BPID = y] => p1_BPID else BPID)]" + }))); + } + @Test + public void allPrefixDashRefs3() { + DashModule d = test("scopeParam3"); + assertTrue( + allPrefixDashRefs(d, "Root/A/B/S1/t1") + .equals(ll(new String[]{ + "Root", + "Root/A[p0_APID]", + "Root/A/B[p0_APID, p1_BPID]" + }))); + } + @Test + public void allPrefixDashRefs4() { + DashModule d = test("getEntered5"); + assertTrue( + allPrefixDashRefs(d, "Root/S1/t1") + .equals(ll(new String[]{ + "Root", + }))); + } + + // getLeafStatesExited -------------------- + + public List exited(DashModule d, String tfqn) { + return d.exited(tfqn) + .stream() + .map (i -> i.toString()) + .collect(Collectors.toList()); + } + + @Test + public void getLeafStatesExited1() { + DashModule d = test("noSrc1"); + assertTrue( + exited(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S1", + "Root/S2" + }))); + } + @Test + public void getLeafStatesExited2() { + DashModule d = test("noSrc2"); + assertTrue( + exited(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S1", + "Root/S2/S3/S4" + }))); + } + @Test + public void getLeafStatesExited3() { + DashModule d = test("noDefaultNeeded2"); + assertTrue( + exited(d,"Root/C/t1") + .equals(ll(new String[]{ + "Root/C" + }))); + } + @Test + public void getLeafStatesExited4() { + DashModule d = test("noSrcDest1"); + assertTrue( + exited(d,"Root/t1") + .equals(ll(new String[]{ + "Root" + }))); + } + @Test + public void getLeafStatesExited5() { + DashModule d = test("otherSrcDest1"); + assertTrue( + exited(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S1", + "Root/S2/S3/S4" + }))); + assertTrue( + exited(d,"Root/S2/t2") + .equals(ll(new String[]{ + "Root/S2/S3/S4" + }))); + } + @Test + public void getLeafStatesExited6() { + DashModule d = test("paramSrcDest1"); + assertTrue( + exited(d,"Root/A/t1") + .equals(ll(new String[]{ + "Root/A[p0_APID]" + }))); + } + @Test + public void getLeafStatesExited7() { + DashModule d = test("paramSrcDest3"); + assertTrue( + exited(d,"Root/A/t1") + .equals(ll(new String[]{ + "Root/A[APID]", + "Root/B/S1[BPID]" + }))); + } + + // getScope ------------------------------- + @Test + public void getScope1() { + DashModule d = test("scopeParam1"); + assertTrue( + d.getScope("Root/A/S1/t1").toString() + .equals("Root/A[(p0_APID = x => p0_APID else APID)]")); + } + @Test + public void getScope2() { + DashModule d = test("scopeParam2"); + assertTrue( + d.getScope("Root/A/B/S1/t1").toString() + .equals("Root/A/B[(p0_APID = x => p0_APID else APID), (AND[p0_APID = x, p1_BPID = y] => p1_BPID else BPID)]")); + } + @Test + public void getScope3() { + DashModule d = test("scopeParam3"); + assertTrue( + d.getScope("Root/A/B/S1/t1").toString() + .equals("Root/A/B[p0_APID, p1_BPID]")); + } + + // getLeafStatesEntered ----------------- + public List entered(DashModule d, String tfqn) { + return d.getLeafStatesEntered(d.getTransDest(tfqn)) + .stream() + .map (i -> i.toString()) + .collect(Collectors.toList()); + } + + @Test + public void getLeafStatesEntered1() { + DashModule d = test("noSrc1"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2" + }))); + } + @Test + public void getLeafStatesEntered2() { + DashModule d = test("noSrc2"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/S3/S4" + }))); + } + @Test + public void getLeafStatesEntered3() { + DashModule d = test("scopeParam1"); + assertTrue( + entered(d,"Root/A/S1/t1") + .equals(ll(new String[]{ + "Root/A/S2[x]" + }))); + } + @Test + public void getLeafStatesEntered4() { + DashModule d = test("scopeParam2"); + assertTrue( + entered(d,"Root/A/B/S1/t1") + .equals(ll(new String[]{ + "Root/A/B/S2[x, y]" + }))); + } + @Test + public void getLeafStatesEntered5() { + DashModule d = test("getEntered5"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A" + }))); + } + @Test + public void getLeafStatesEntered6() { + DashModule d = test("getEntered6"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/S3" + }))); + } + @Test + public void getLeafStatesEntered7() { + DashModule d = test("getEntered7"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/S3[AID]" + }))); + } + @Test + public void getLeafStatesEntered8() { + DashModule d = test("getEntered8"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/B/S3[AID, BID]", + "Root/S2/A/C[AID, CID]" + }))); + } + @Test + public void getLeafStatesEntered9() { + DashModule d = test("getEntered9"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/B/S3[AID, BID]", + "Root/S2/A/C/S5[AID, CID]", + }))); + } + @Test + public void getLeafStatesEntered10() { + DashModule d = test("getEntered10"); + assertTrue( + entered(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/B/S3[AID, BID]", + "Root/S2/A/C/D/S5[AID, CID, DID]", + "Root/S2/A/C/E/S7[AID, CID, EID]" + }))); + } + @Test + public void getLeafStatesEntered11() { + DashModule d = test("getEntered11"); + assertTrue( + entered(d,"Root/A/S1/t1") + .equals(ll(new String[]{ + "Root/B/S2/C/S3[x, CID]" + }))); + } + + // getLeafStatesEnteredInScope ----------------- + + public List enteredInScope(DashModule d, String tfqn) { + return d.entered(tfqn) + .stream() + .map (i -> i.toString()) + .collect(Collectors.toList()); + } + + @Test + public void getLeafStatesEnteredInScope1() { + DashModule d = test("noSrc1"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2" + }))); + } + @Test + public void getLeafStatesEnteredInScope2() { + DashModule d = test("getEnteredInScope2"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/B/S3", + "Root/A/S2", + }))); + } + @Test + public void getLeafStatesEnteredInScope3() { + DashModule d = test("getEntered5"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A" + }))); + } + @Test + public void getLeafStatesEnteredInScope4() { + DashModule d = test("getEntered6"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/S3" + }))); + } + @Test + public void getLeafStatesEnteredInScope5() { + DashModule d = test("getEntered7"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/S3[AID]" + }))); + } + @Test + public void getLeafStatesEnteredInScope6() { + DashModule d = test("getEntered8"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/B/S3[AID, BID]", + "Root/S2/A/C[AID, CID]" + }))); + } + @Test + public void getLeafStatesEnteredInScope7() { + DashModule d = test("getEntered9"); + assertTrue( + enteredInScope(d,"Root/S1/t1") + .equals(ll(new String[]{ + "Root/S2/A/B/S3[AID, BID]", + "Root/S2/A/C/S5[AID, CID]", + }))); + } + + // connected tests on one model + @Test + public void overall1() { + DashModule d = test("overall1"); + String tfqn = "Root/t1"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[a1, b1]")); + assertTrue( + dest(d, tfqn).equals("Root/C/S2[c1]")); + assertTrue( + d.getScope(tfqn).toString().equals("Root")); + + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[AID, BID]", + "Root/C/S2[CID]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/C/S2[CID - c1]", + "Root/A/B/S1[AID, BID]", + "Root/C/S2[c1]" + }))); + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList())); + } + @Test + public void overall2() { + DashModule d = test("overall2"); + String tfqn = "Root/A/B/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[p0_AID, p1_BID]")); + assertTrue( + dest(d, tfqn).equals("Root/A/S2[a2]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A[(p0_AID = a2 => p0_AID else AID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(p0_AID = a2 => p0_AID else AID), BID]", + "Root/A/S2[(p0_AID = a2 => p0_AID else AID)]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/S2[(p0_AID = a2 => p0_AID else AID) - a2]", + "Root/A/S2[a2]", + }))); + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(0,1))); + } + + @Test + public void overall3() { + DashModule d = test("overall3"); + String tfqn = "Root/A/S2/t1"; + assertTrue( + src(d, tfqn).equals("Root/A/S2[p0_AID]")); + assertTrue( + dest(d, tfqn).equals("Root/A/B/S1[a1, b1]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A[(p0_AID = a1 => p0_AID else AID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(p0_AID = a1 => p0_AID else AID), BID]", + "Root/A/S2[(p0_AID = a1 => p0_AID else AID)]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/S2[(p0_AID = a1 => p0_AID else AID) - a1]", + "Root/A/B/S1[a1, BID - b1]", + "Root/A/B/S1[a1, b1]" + }))); + + tfqn = "Root/A/B/S1/t2"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[p0_AID, p1_BID]")); + assertTrue( + dest(d, tfqn).equals("Root/A/B/S1[p0_AID, p1_BID]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A/B/S1[p0_AID, p1_BID]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[p0_AID, p1_BID]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[p0_AID, p1_BID]" + }))); + + tfqn = "Root/A/B/S1/t3"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[p0_AID, b1]")); + assertTrue( + dest(d, tfqn).equals("Root/A/B/S1[p0_AID, b2]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A/B/S1[p0_AID, (b1 = b2 => b1 else BID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[p0_AID, (b1 = b2 => b1 else BID)]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[p0_AID, (b1 = b2 => b1 else BID) - b2]", + "Root/A/B/S1[p0_AID, b2]" + }))); + + } + + @Test + public void overall4() { + DashModule d = test("overall4"); + String tfqn = "Root/A/B/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[a1, b1]")); + assertTrue( + dest(d, tfqn).equals("Root/A/S2[a2]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A[(a1 = a2 => a1 else AID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a1 = a2 => a1 else AID), BID]", + "Root/A/S2[(a1 = a2 => a1 else AID)]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a1 = a2 => a1 else AID) - a2, BID]", + "Root/A/S2[a2]" + }))); + } + + @Test + public void overall5() { + DashModule d = test("overall5"); + String tfqn = "Root/A/B/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[a1, b1]")); + assertTrue( + dest(d, tfqn).equals("Root/A[a2]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A[(a1 = a2 => a1 else AID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a1 = a2 => a1 else AID), BID]", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a1 = a2 => a1 else AID) - a2, BID]", + "Root/A/B/S1[a2, BID]", + }))); + + tfqn = "Root/t2"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[a3, b3]")); + assertTrue( + dest(d, tfqn).equals("Root/A/B/S1[a4, b4]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A/B/S1[(a3 = a4 => a3 else AID), (AND[a3 = a4, b3 = b4] => b3 else BID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a3 = a4 => a3 else AID), (AND[a3 = a4, b3 = b4] => b3 else BID)]", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a3 = a4 => a3 else AID) - a4, BID]", + "Root/A/B/S1[a4, (AND[a3 = a4, b3 = b4] => b3 else BID) - b4]", + "Root/A/B/S1[a4, b4]" + }))); + + tfqn = "Root/t3"; + assertTrue( + src(d, tfqn).equals("Root/A/B/S1[a5, b5]")); + assertTrue( + dest(d, tfqn).equals("Root/A/B[a6, b6]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/A/B[(a5 = a6 => a5 else AID), (AND[a5 = a6, b5 = b6] => b5 else BID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a5 = a6 => a5 else AID), (AND[a5 = a6, b5 = b6] => b5 else BID)]", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/B/S1[(a5 = a6 => a5 else AID) - a6, BID]", + "Root/A/B/S1[a6, (AND[a5 = a6, b5 = b6] => b5 else BID) - b6]", + "Root/A/B/S1[a6, b6]" + }))); + } + + @Test + public void overall6() { + DashModule d = test("overall6"); + String tfqn = "Root/B/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/B/S1[p0_BID]")); + assertTrue( + dest(d, tfqn).equals("Root/B[p0_BID]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/B[p0_BID]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/B/S1[p0_BID]", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/B/S1[p0_BID]", + }))); + + tfqn = "Root/B/S1/t2"; + assertTrue( + src(d, tfqn).equals("Root/B/S1[p0_BID]")); + assertTrue( + dest(d, tfqn).equals("Root/B[b1]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/B[(p0_BID = b1 => p0_BID else BID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/B/S1[(p0_BID = b1 => p0_BID else BID)]", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/B/S1[(p0_BID = b1 => p0_BID else BID) - b1]", + "Root/B/S1[b1]" + }))); + + tfqn = "Root/B/S1/t3"; + assertTrue( + src(d, tfqn).equals("Root/B/S1[p0_BID]")); + assertTrue( + dest(d, tfqn).equals("Root/C")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/C", + "Root/B/S1[BID]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/C" + }))); + + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(0))); + } + + @Test + public void overall7() { + DashModule d = test("overall7"); + String tfqn = "Root/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/S1")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/S1")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/S1", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/S1", + }))); + + tfqn = "Root/S1/t2"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/B")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A", + "Root/B", + "Root/C[CID]", + "Root/S1", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A", + "Root/C[CID]", + "Root/B", + }))); + + tfqn = "Root/S1/t3"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/C[c1]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A", + "Root/B", + "Root/C[CID]", + "Root/S1", + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/C[CID - c1]", + "Root/A", + "Root/B", + "Root/C[c1]" + }))); + + } + @Test + public void overall8() { + DashModule d = test("overall8"); + String tfqn = "Root/t1"; + assertTrue( + src(d, tfqn).equals("Root/S3")); + assertTrue( + dest(d, tfqn).equals("Root/B/E/S2[e1]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/A/S1[AID]", + "Root/B/C", + "Root/B/D", + "Root/B/E/S2[EID]", + "Root/B/E/S4[EID]", + "Root/S3" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/A/S1[AID]", + "Root/B/E/S4[EID - e1]", + "Root/B/C", + "Root/B/D", + "Root/B/E/S2[e1]" + }))); + } + + @Test + public void overall9() { + DashModule d = test("overall9"); + String tfqn = "Root/t1"; + assertTrue( + src(d, tfqn).equals("Root/B/E/F[e1, f1]")); + assertTrue( + dest(d, tfqn).equals("Root/B/E/G[e2]")); + assertTrue( + d.getScope(tfqn).toString() + .equals("Root/B/E[(e1 = e2 => e1 else EID)]")); + assertTrue( + exited(d,tfqn) + .equals(ll(new String[]{ + "Root/B/E/S2[(e1 = e2 => e1 else EID)]", + "Root/B/E/S4[(e1 = e2 => e1 else EID)]", + "Root/B/E/F[(e1 = e2 => e1 else EID), FID]", + "Root/B/E/G[(e1 = e2 => e1 else EID)]" + }))); + assertTrue( + enteredInScope(d,tfqn) + .equals(ll(new String[]{ + "Root/B/E/S4[(e1 = e2 => e1 else EID) - e2]", + "Root/B/E/F[e2, FID]", + "Root/B/E/G[e2]" + }))); + } + + @Test + public void overall10() { + DashModule d = test("overall10"); + String tfqn = "Root/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/S2")); + } + + @Test + public void overall11() { + DashModule d = test("overall11"); + String tfqn = "Root/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/S2")); + } + + @Test + public void overall12() { + DashModule d = test("overall12"); + String tfqn = "Root/S1/t1"; + assertTrue( + src(d, tfqn).equals("Root/S1")); + assertTrue( + dest(d, tfqn).equals("Root/S1/S7")); + } + + @Test + public void overall13() { + DashModule d = test("overall13"); + String tfqn = "Root/A/B/t1"; + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(0,1))); + tfqn = "Root/A/t2"; + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(0))); + tfqn = "Root/C/t3"; + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(2))); + tfqn = "Root/C/D/t4"; + assertTrue( + d.getTransParamsIdx(tfqn) + .equals(Arrays.asList(2,3))); + assertTrue( + d.getAllParamsInOrder() + .equals(Arrays.asList("AID","BID","BID","AID"))); + } + + // priority + @Test + public void pri1() { + DashModule d = test("pri1"); + String tfqn = "Root/t1"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + + } + @Test + public void pri2() { + DashModule d = test("pri2"); + String tfqn = "Root/t1"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + tfqn = "Root/A/t2"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/t1" + }))); + } + + @Test + public void pri3() { + DashModule d = test("pri3"); + String tfqn = "Root/t1"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + tfqn = "Root/t2"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + tfqn = "Root/t3"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/t1", + "Root/t2" + }))); + } + + @Test + public void pri4() { + DashModule d = test("pri4"); + String tfqn = "Root/t1"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + tfqn = "Root/t2"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/t1" + }))); + + } + + @Test + public void pri5() { + DashModule d = test("pri5"); + String tfqn = "Root/t1"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{}))); + tfqn = "Root/t2"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/t1" + }))); + + } + + @Test + public void pri6() { + DashModule d = test("pri6"); + String tfqn = "Root/A/B/t1"; + + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/A/t2", + "Root/t3" + }))); + + tfqn = "Root/A/t2"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + "Root/t3" + }))); + + tfqn = "Root/t3"; + assertTrue( + d.getHigherPriTrans(tfqn) + .equals(ll(new String[]{ + }))); + } + +} diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashParseFailTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashParseFailTests.java new file mode 100644 index 000000000..bd2a8b960 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashParseFailTests.java @@ -0,0 +1,105 @@ +/* + Tests for appropriate parsing failures. + + It tests every file in src/resources/parsefail + to make sure it fails parsing. +*/ + +package org.alloytools.alloy.dash; + +import java.util.*; +import java.io.IOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.charset.Charset; +import java.util.stream.Stream; +import java.util.stream.IntStream; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + +import java.net.URL; + + +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.ErrorFatal; + +import ca.uwaterloo.watform.core.DashErrors; +import ca.uwaterloo.watform.core.DashOptions; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.DashUtil; + + + + +@RunWith(Parameterized.class) + +public class DashParseFailTests { + + private static String resourcePath = "src/test/resources/parsefail"; + private final String fileName; + + public DashParseFailTests(String f) { + this.fileName = f; + } + + // list of file names that are parameters to test + @Parameterized.Parameters + public static List fileNames() { + File dir = new File(resourcePath); + return Arrays.asList(dir.listFiles()).stream().filter(i -> !i.isHidden()).map (i -> i.getName()).collect(Collectors.toList()); + + } + + @Test + public void test() { + File dir = new File(resourcePath); + String absolutePath = new File(resourcePath).getAbsolutePath(); + assertThrows(ErrorSyntax.class, () -> { + DashUtil.parseEverything_fromFileDash(null,null,absolutePath+"/"+fileName); + }); + } + + + + + // leftover - not used because multiline strings in Java 1.8 are a pain + @Rule + public TemporaryFolder folder= new TemporaryFolder(); + + // leftover - not used because multiline strings in Java 1.8 are a pain + // uses static DashModule parseEverything_fromStringDash(A4Reporter rep, String content) + public DashModule parseFromString(String content) throws IOException { + File tmpFile = folder.newFile("myfile.txt"); + FileUtils.writeStringToFile(tmpFile, content, Charset.defaultCharset()); + return DashUtil.parseEverything_fromFileDash(null, null, tmpFile.getCanonicalPath()); + //Note: File is guaranteed to be deleted after the test finishes. + } + + /* + // src/test/resource is not getting copied to the classpath + // so we'll use an alternative + @Test + public void parseTest1() { + File dir = new File(resourcePath); + int fileCount = countFilesInCurrentDirectory(dir); + assertTrue(fileCount == 1); + // String absolutePath = new File(resourcePath).getAbsolutePath(); + //DashUtil.parseEverything_fromFileDash(null,null,absolutePath+"/test1.dsh"); + } + */ + + + } diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashPassParseWffTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashPassParseWffTests.java new file mode 100644 index 000000000..5ef076690 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashPassParseWffTests.java @@ -0,0 +1,56 @@ +/* + let's check that the tests in the pass directory + pass the parse and wff checks first +*/ + +package org.alloytools.alloy.dash; + +import java.util.*; +import java.io.File; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import ca.uwaterloo.watform.parser.DashUtil; + + + + +@RunWith(Parameterized.class) + +public class DashPassParseWffTests { + + private static String resourcePath = "src/test/resources/pass"; + private final String fileName; + + public DashPassParseWffTests(String f) { + this.fileName = f; + } + + // list of file names that are parameters to test + @Parameterized.Parameters + public static List fileNames() { + File dir = new File(resourcePath); + //int fileCount = countFilesInCurrentDirectory(dir); + // filenaming starts at 0 + return Arrays.asList(dir.listFiles()) + .stream() + .filter(i -> !i.isHidden()) + .map (i -> i.getName()) + .collect(Collectors.toList()); + + } + + @Test + public void test() { + File dir = new File(resourcePath); + String absolutePath = new File(resourcePath).getAbsolutePath(); + DashUtil.parseEverything_fromFileDash(null,null,absolutePath+"/"+fileName); + } + + + } diff --git a/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashWffFailTests.java b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashWffFailTests.java new file mode 100644 index 000000000..434905832 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/java/org/alloytools/alloy/dash/DashWffFailTests.java @@ -0,0 +1,103 @@ +/* + The purpose of these tests is to check that wff errors (DashErrors) are caught. + All files tested here should pass parsing and raise DashErrors during resolveAllDash + All of these raise exceptions. +*/ + + +// junit 4 does not seem to have a way to assert that +// an exception is not thrown +// junit 5 has assertAll() + +package org.alloytools.alloy.dash; + +import java.util.*; +import java.io.File; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.A4Reporter; + +import static ca.uwaterloo.watform.core.DashErrors.*; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.parser.DashModule; +import ca.uwaterloo.watform.parser.DashUtil; +import ca.uwaterloo.watform.mainfunctions.MainFunctions; + +@RunWith(Parameterized.class) + +public class DashWffFailTests { + + private static String resourcePath = "src/test/resources/wfffail"; + + public static void test(String fileName) { + File dir = new File(resourcePath); + String absolutePath = new File(resourcePath).getAbsolutePath(); + A4Reporter rep = new A4Reporter(); + DashModule d = MainFunctions.parseAndResolveDashFile(absolutePath+"/"+fileName, rep); + } + + private final String fileName; + private final String msg; + + public DashWffFailTests(String f, String msg) { + this.fileName = f; + this.msg = msg; + } + + // list of file names that are parameters to test + @Parameterized.Parameters + public static Collection fileNameMsg() { + return Arrays.asList(new Object[][] { + {"noStates1", noStatesMsg}, + {"noStates2", noStatesMsg}, + {"onlyOneState1", onlyOneStateMsg}, + {"onlyOneState2", onlyOneStateMsg}, + {"noTrans1", noTransMsg}, // 4 + {"noTrans2", noTransMsg}, + {"noDefaultState1", noDefaultStateMsg}, + {"noDefaultState2", noDefaultStateMsg}, + {"tooManyDefaultStates1", tooManyDefaultStatesMsg}, + {"tooManyDefaultStates2", tooManyDefaultStatesMsg}, + {"allConcDefaultStates1",allConcDefaultStatesMsg}, + {"allConcDefaultStates2",allConcDefaultStatesMsg}, //11 + {"stateNameCantBeFQN1", stateNameCantBeFQNMsg}, + {"stateNameCantBeFQN2", stateNameCantBeFQNMsg}, + {"dupSiblingNames1", dupSiblingNamesMsg}, + {"dupSiblingNames2", dupSiblingNamesMsg}, + {"dupTransName1", dupTransNameMsg}, + {"dupTransName2", dupTransNameMsg}, // 17 + {"moreThanOneSrcDest1", tooManyMsg}, + {"moreThanOneSrcDest2", tooManyMsg}, // 19 + {"moreThanOneSrcDest3", tooManyMsg}, + //{"unknownSrcDest1", unknownSrcDestMsg}, + //{"unknownSrcDest2", unknownSrcDestMsg}, + //{"unknownSrcDest3", unknownSrcDestMsg}, + {"unknownSrcDest4", unknownStateMsg}, //21 + {"fqnSrcDestMustHaveRightNumberParams1", wrongNumberParamsMsg}, //22 + {"srcDestCantHaveParam1", wrongNumberParamsMsg}, //23 + {"ambiguousSrcDest1", ambiguousRefMsg}, + {"ambiguousSrcDest2", ambiguousRefMsg}, + {"test11",ambiguousRefMsg} + }); + } + + @Test + public void test() { + Exception exception = assertThrows(ErrorSyntax.class, () -> { + test(fileName + ".dsh"); + }); + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(msg)); + } + + } diff --git a/org.alloytools.alloy.dash/src/test/resources/parsefail/test11.dsh b/org.alloytools.alloy.dash/src/test/resources/parsefail/test11.dsh new file mode 100644 index 000000000..8ef96437d --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/parsefail/test11.dsh @@ -0,0 +1,5 @@ +conc Root { + conc A { + trans t1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/parsefail/trivial-param-state-error.dsh b/org.alloytools.alloy.dash/src/test/resources/parsefail/trivial-param-state-error.dsh new file mode 100644 index 000000000..605bdcca3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/parsefail/trivial-param-state-error.dsh @@ -0,0 +1,6 @@ +sig A {} + +fact {} + +// should fail +state Root [A] {} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/event1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/event1.dsh new file mode 100644 index 000000000..76eae2f33 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/event1.dsh @@ -0,0 +1,7 @@ +state Root { + event ev1 {} + trans t1 { + on ev1 + send ev1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/event2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/event2.dsh new file mode 100644 index 000000000..6c1ba2cfe --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/event2.dsh @@ -0,0 +1,5 @@ +state Root { + event ev1 {} + trans t1 { + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/event3.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/event3.dsh new file mode 100644 index 000000000..f495a9e8a --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/event3.dsh @@ -0,0 +1,6 @@ +state Root { + event ev1 {} + trans t1 { + on ev1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getAllNonConcDesc1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getAllNonConcDesc1.dsh new file mode 100644 index 000000000..e0ee9d16a --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getAllNonConcDesc1.dsh @@ -0,0 +1,21 @@ +state Root { + default state S1 { + state S2 { + trans t1 {} + } + } + state S3 { + default state S4 { + state S5 {} + } + conc A { + state S7 {} + } + conc B { + state S7 {} + } + conc C [CPID] { + state S7{} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered10.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered10.dsh new file mode 100644 index 000000000..2a3ea3285 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered10.dsh @@ -0,0 +1,24 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A [AID] { + conc B [BID] { + default state S3 {} + state S4 {} + } + conc C [CID] { + conc D [DID] { + default state S5 {} + state S6 {} + } + conc E [EID] { + state S7 {} + } + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered11.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered11.dsh new file mode 100644 index 000000000..c21323b1f --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered11.dsh @@ -0,0 +1,16 @@ +state Root { + conc A [AID] { + state S1 { + trans t1 { + goto Root/B[x] + } + } + } + conc B [BID] { + state S2 { + conc C [CID] { + state S3 {} + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered5.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered5.dsh new file mode 100644 index 000000000..6829b5357 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered5.dsh @@ -0,0 +1,10 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered6.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered6.dsh new file mode 100644 index 000000000..5f3d2260e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered6.dsh @@ -0,0 +1,13 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A { + default state S3 {} + state S4 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered7.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered7.dsh new file mode 100644 index 000000000..0343c3924 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered7.dsh @@ -0,0 +1,13 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A [AID] { + default state S3 {} + state S4 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered8.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered8.dsh new file mode 100644 index 000000000..51aaa564f --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered8.dsh @@ -0,0 +1,16 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A [AID] { + conc B [BID] { + default state S3 {} + state S4 {} + } + conc C [CID] {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEntered9.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered9.dsh new file mode 100644 index 000000000..74873ef2b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEntered9.dsh @@ -0,0 +1,18 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 { + conc A [AID] { + conc B [BID] { + default state S3 {} + state S4 {} + } + conc C [CID] { + state S5 {} + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getEnteredInScope2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getEnteredInScope2.dsh new file mode 100644 index 000000000..9db8415e2 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getEnteredInScope2.dsh @@ -0,0 +1,13 @@ +state Root { + default state S1 { + trans t1 { + goto Root/A/S2 + } + } + conc A { + state S2 {} + } + conc B { + state S3 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/getRegion1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/getRegion1.dsh new file mode 100644 index 000000000..7e3d0950c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/getRegion1.dsh @@ -0,0 +1,23 @@ +state Root { + default state S1 { + state S2 { + trans t1 {} + } + } + state S3 { + default state S4 { + state S5 {} + } + conc A { + state S7 { + state S8 {} + } + } + conc B { + state S7 {} + } + conc C [CPID] { + state S7{} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded1.dsh new file mode 100644 index 000000000..9c9be1b51 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded1.dsh @@ -0,0 +1,7 @@ +state Root { + // no need to say this is default + state S { + trans t1 { + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded2.dsh new file mode 100644 index 000000000..0046882cf --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/noDefaultNeeded2.dsh @@ -0,0 +1,7 @@ +state Root { + // no need to say this is default + conc C { + trans t1 { + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/noSrc1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/noSrc1.dsh new file mode 100644 index 000000000..4de72f15d --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/noSrc1.dsh @@ -0,0 +1,8 @@ +state Root { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/noSrc2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/noSrc2.dsh new file mode 100644 index 000000000..9e6682c3e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/noSrc2.dsh @@ -0,0 +1,12 @@ +state Root { + default state S1 { + trans t1 { + goto S4 + } + } + state S2 { + state S3 { + state S4 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/noSrcDest1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/noSrcDest1.dsh new file mode 100644 index 000000000..4d78f7aaa --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/noSrcDest1.dsh @@ -0,0 +1,3 @@ +state Root { + trans t1 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/otherSrcDest1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/otherSrcDest1.dsh new file mode 100644 index 000000000..a0226b9a7 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/otherSrcDest1.dsh @@ -0,0 +1,17 @@ +state Root { + default state S1 { + trans t1 { + from Root/S1 + goto S4 + } + } + state S2 { + state S3 { + state S4 {} + } + trans t2 { + from S3 + goto S2 + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall1.dsh new file mode 100644 index 000000000..f2a9120b3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall1.dsh @@ -0,0 +1,16 @@ +state Root { + event ev1 {} + conc A [AID] { + conc B [BID] { + state S1 {} + } + } + conc C [CID] { + state S2 {} + } + trans t1 { + from Root/A/B/S1[a1,b1] + goto Root/C/S2[c1] + on ev1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall10.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall10.dsh new file mode 100644 index 000000000..da881495e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall10.dsh @@ -0,0 +1,8 @@ +state Root { + conc S1 { + trans t1 { + goto S2 + } + } + conc S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall11.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall11.dsh new file mode 100644 index 000000000..a11815988 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall11.dsh @@ -0,0 +1,9 @@ + +state Root { + conc S1 { + trans t1 { + goto S2 + } + } + default state S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall12.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall12.dsh new file mode 100644 index 000000000..e79a4994c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall12.dsh @@ -0,0 +1,17 @@ +state Root { + conc S1 { + state S7 {} + trans t1 { + goto S7 + } + } + default state S2 { + state S3{ + state S4{ + trans t2 { + goto S7 + } + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall13.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall13.dsh new file mode 100644 index 000000000..07da21824 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall13.dsh @@ -0,0 +1,14 @@ +state Root { + conc A [AID] { + conc B [BID] { + trans t1 {} + } + trans t2 {} + } + conc C [BID] { + trans t3 {} + conc D [AID] { + trans t4 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall2.dsh new file mode 100644 index 000000000..0e7679a62 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall2.dsh @@ -0,0 +1,12 @@ +state Root { + conc A [AID] { + conc B [BID] { + state S1 { + trans t1 { + goto Root/A/S2[a2] + } + } + } + default state S2 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall3.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall3.dsh new file mode 100644 index 000000000..394d4505b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall3.dsh @@ -0,0 +1,18 @@ +state Root { + conc A [AID] { + conc B [BID] { + state S1 { + trans t2 {} + trans t3 { + from Root/A/B/S1[p0_AID, b1] + goto Root/A/B/S1[p0_AID, b2] + } + } + } + default state S2 { + trans t1 { + goto Root/A/B/S1[a1,b1] + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall4.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall4.dsh new file mode 100644 index 000000000..4807a6004 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall4.dsh @@ -0,0 +1,14 @@ +state Root { + conc A [AID] { + default conc B [BID] { + state S1 { + trans t1 { + from Root/A/B/S1[a1,b1] + goto Root/A/S2[a2] + } + } + } + state S2 {} + } + +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall5.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall5.dsh new file mode 100644 index 000000000..36c19df76 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall5.dsh @@ -0,0 +1,20 @@ +state Root { + conc A [AID] { + conc B [BID] { + state S1 { + trans t1 { + from Root/A/B/S1[a1, b1] + goto Root/A[a2] + } + } + } + } + trans t2 { + from Root/A/B/S1[a3,b3] + goto Root/A/B/S1[a4,b4] + } + trans t3 { + from Root/A/B/S1[a5,b5] + goto Root/A/B[a6,b6] + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall6.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall6.dsh new file mode 100644 index 000000000..2c44239eb --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall6.dsh @@ -0,0 +1,16 @@ +state Root { + default state C {} + conc B [BID] { + state S1 { + trans t1 { + goto Root/B[p0_BID] + } + trans t2 { + goto Root/B[b1] + } + trans t3 { + goto Root/C + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall7.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall7.dsh new file mode 100644 index 000000000..e951638ff --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall7.dsh @@ -0,0 +1,20 @@ +state Root { + default conc A { + + } + default conc B { + + } + default conc C [CID] { + + } + state S1 { + trans t1 {} + trans t2 { + goto Root/B + } + trans t3 { + goto Root/C[c1] + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall8.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall8.dsh new file mode 100644 index 000000000..e8fdb22a1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall8.dsh @@ -0,0 +1,18 @@ +state Root { + default conc A [AID] { + state S1 {} + } + default conc B { + conc C {} + conc D {} + conc E [EID]{ + state S2 {} + default state S4 {} + } + } + state S3 {} + trans t1 { + from Root/S3 + goto Root/B/E/S2[e1] + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/overall9.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/overall9.dsh new file mode 100644 index 000000000..95708acfd --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/overall9.dsh @@ -0,0 +1,20 @@ +state Root { + default conc A [AID] { + state S1 {} + } + default conc B { + conc C {} + conc D {} + conc E [EID]{ + state S2 {} + default state S4 {} + conc F [FID] {} + conc G {} + } + } + state S3 {} + trans t1 { + from Root/B/E/F[e1,f1] + goto Root/B/E/G[e2] + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest1.dsh new file mode 100644 index 000000000..2b91ad6a0 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest1.dsh @@ -0,0 +1,5 @@ +state Root { + conc A [APID] { + trans t1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest2.dsh new file mode 100644 index 000000000..54a36800e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest2.dsh @@ -0,0 +1,10 @@ +state Root { + conc A [APID] { + trans t1 { + goto Root/B/S1[x] + } + } + conc B [BPID] { + state S1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest3.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest3.dsh new file mode 100644 index 000000000..56d85b71b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/paramSrcDest3.dsh @@ -0,0 +1,10 @@ +state Root { + conc A [APID] { + trans t1 { + from Root/B/S1[x] + } + } + conc B [BPID] { + state S1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri1.dsh new file mode 100644 index 000000000..4d78f7aaa --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri1.dsh @@ -0,0 +1,3 @@ +state Root { + trans t1 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri2.dsh new file mode 100644 index 000000000..46d700e5f --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri2.dsh @@ -0,0 +1,6 @@ +state Root { + trans t1 {} + state A { + trans t2 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri3.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri3.dsh new file mode 100644 index 000000000..9c981f521 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri3.dsh @@ -0,0 +1,9 @@ +state Root { + trans t1 {} + trans t2 {} + state A {} + trans t3 { + from A + goto A + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri4.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri4.dsh new file mode 100644 index 000000000..9f1fec672 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri4.dsh @@ -0,0 +1,13 @@ +state Root { + state A { + state B {} + } + trans t1 { + from A + goto B + } + trans t2 { + from B + goto B + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri5.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri5.dsh new file mode 100644 index 000000000..4fc90f96f --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri5.dsh @@ -0,0 +1,13 @@ +state Root { + conc A [AID] { + conc B [BID] {} + } + trans t1 { + from A [a1] + goto B [a1,b1] + } + trans t2 { + from B [a2,b3] + goto B [a5, b6] + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/pri6.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/pri6.dsh new file mode 100644 index 000000000..42aebd3a0 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/pri6.dsh @@ -0,0 +1,9 @@ +state Root { + conc A [AID] { + conc B [BID] { + trans t1 {} + } + trans t2 {} + } + trans t3 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/process-ref.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/process-ref.dsh new file mode 100644 index 000000000..a6a981241 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/process-ref.dsh @@ -0,0 +1,5 @@ +state Root { + trans t1 { + on Elevator[e0]/direction + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam1.dsh new file mode 100644 index 000000000..93133c63c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam1.dsh @@ -0,0 +1,10 @@ +state Root { + conc A [APID] { + default state S1 { + trans t1 { + goto Root/A/S2[x] + } + } + state S2 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam2.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam2.dsh new file mode 100644 index 000000000..2183e0e97 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam2.dsh @@ -0,0 +1,12 @@ +state Root { + conc A [APID] { + conc B [BPID] { + default state S1 { + trans t1 { + goto Root/A/B/S2[x,y] + } + } + state S2 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam3.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam3.dsh new file mode 100644 index 000000000..878266bbf --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/scopeParam3.dsh @@ -0,0 +1,12 @@ +state Root { + conc A [APID] { + conc B [BPID] { + default state S1 { + trans t1 { + goto S2 + } + } + state S2 {} + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/srcDestFQN1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/srcDestFQN1.dsh new file mode 100644 index 000000000..2895c957e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/srcDestFQN1.dsh @@ -0,0 +1,17 @@ +state Root { + conc S1 { + state S7 {} + trans t1 { + goto S7 + } + } + default state S2 { + state S3{ + state S4{ + trans t2 { + goto Root/S1/S7 + } + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/pass/test1.dsh b/org.alloytools.alloy.dash/src/test/resources/pass/test1.dsh new file mode 100644 index 000000000..431e2c1e1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/pass/test1.dsh @@ -0,0 +1,11 @@ +state Root { + trans t1 { + do { + one n: Node - this | { + Elevator[n]/direction = Up + Elevator[e0]/direction = Up + N[n]/message' = this -> level + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates1.dsh new file mode 100644 index 000000000..acaa4bd1a --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates1.dsh @@ -0,0 +1,6 @@ +state Root { + default conc S3 {} + state S1 {} + conc S2 {} + default conc S4 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates2.dsh new file mode 100644 index 000000000..4d9bdeeba --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/allConcDefaultStates2.dsh @@ -0,0 +1,7 @@ +state Root { + default conc S3 {} + state S1 {} + default conc S2 {} + default conc S4 {} + conc S5 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest1.dsh new file mode 100644 index 000000000..9fb98e50c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest1.dsh @@ -0,0 +1,13 @@ +state Root { + state S1 { + state S2 {} + } + default state S3 { + state S1 {} + trans t1 { + from S1 + goto S2 // ambiguous + } + } + state S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest2.dsh new file mode 100644 index 000000000..c2f7c27b5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/ambiguousSrcDest2.dsh @@ -0,0 +1,8 @@ +state Root { + state S1 { + state S1 {} + trans t1 { + goto S1 + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-2-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-2-error.dsh new file mode 100644 index 000000000..07ba19ecf --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-2-error.dsh @@ -0,0 +1,15 @@ +state Root { + state S { + trans t1 { + // goto B // this works + //goto C // 'The name "Root_S_C" cannot be found.' + //goto D // 'The name "Root_S_D" cannot be found.' + goto Root/B/C/D // error + } + } + default state B { + conc C { + default state D {} + } + } +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-error.dsh new file mode 100644 index 000000000..8874ca22f --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/and-cross-trans-error.dsh @@ -0,0 +1,12 @@ +state Root { + conc state A { + state A1 { + trans t1 { + goto Root/B/B1 + } + } + } + conc state B { + state B1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/buffer-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/buffer-error.dsh new file mode 100644 index 000000000..10171085b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/buffer-error.dsh @@ -0,0 +1,7 @@ +sig A, B {} + +state S1 { + b1 : buf[A] + b2 : buf[B] + env b3 : buf[B] +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames1.dsh new file mode 100644 index 000000000..30dd5bf55 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames1.dsh @@ -0,0 +1,5 @@ +state Root { + conc A {} + state A {} + conc B {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames2.dsh new file mode 100644 index 000000000..e8c75c16a --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupSiblingNames2.dsh @@ -0,0 +1,4 @@ +state Root { + state A {} + state A {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName1.dsh new file mode 100644 index 000000000..77b30ab43 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName1.dsh @@ -0,0 +1,4 @@ +state Root { + trans t1 {} + trans t1 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName2.dsh new file mode 100644 index 000000000..393ed1f41 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/dupTransName2.dsh @@ -0,0 +1,6 @@ +state Root { + trans t1 {} + trans t2 {} + trans t3 {} + trans t1 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/fqnSrcDestMustHaveRightNumberParams1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/fqnSrcDestMustHaveRightNumberParams1.dsh new file mode 100644 index 000000000..e59ade166 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/fqnSrcDestMustHaveRightNumberParams1.dsh @@ -0,0 +1,10 @@ +state Root { + conc A [APID] { + trans t1 { + goto Root/B/S1[x,y] + } + } + conc B [BPID] { + state S1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest1.dsh new file mode 100644 index 000000000..1b8131f41 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest1.dsh @@ -0,0 +1,8 @@ +state Root { + state S1 {} + trans t1 { + from S1 + goto S1 + from S1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest2.dsh new file mode 100644 index 000000000..ad10b887c --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest2.dsh @@ -0,0 +1,16 @@ +state Root { + state C { + trans t1 { + from C + } + trans t2 { + from C + goto S + } + trans t3 { + goto S + goto S + } + } + default state S {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest3.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest3.dsh new file mode 100644 index 000000000..2af30a223 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/moreThanOneSrcDest3.dsh @@ -0,0 +1,7 @@ +state Root { + trans t1 { + goto Root + from Root + goto Root + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultNeeded-traces.als b/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultNeeded-traces.als new file mode 100644 index 000000000..e69de29bb diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState1.dsh new file mode 100644 index 000000000..e88eb6c98 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState1.dsh @@ -0,0 +1,4 @@ +state Root { + state S1 {} + state S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState2.dsh new file mode 100644 index 000000000..e053920b1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noDefaultState2.dsh @@ -0,0 +1,4 @@ +state Root { + state S1 {} + conc S2 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates1.dsh new file mode 100644 index 000000000..a4dbe000a --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates1.dsh @@ -0,0 +1 @@ +sig A {} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates2.dsh new file mode 100644 index 000000000..2fa66576b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noStates2.dsh @@ -0,0 +1,7 @@ +module X + +sig A {} + +fact jj { + 1 = 1 +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans1.dsh new file mode 100644 index 000000000..28aaa2174 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans1.dsh @@ -0,0 +1 @@ +state Root {} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans2.dsh new file mode 100644 index 000000000..19c8f1931 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/noTrans2.dsh @@ -0,0 +1,8 @@ +sig A {} + +sig B {} + +state S {} + + + diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/one-guard.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/one-guard.dsh new file mode 100644 index 000000000..37c9924c7 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/one-guard.dsh @@ -0,0 +1,16 @@ +enum status {x, y} + +state Top { + env input: one status + default state OFF { } + state ON {} + trans t0 { + when input = x + goto ON + } + trans t1 { + when input = y + goto OFF + } + +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState1.dsh new file mode 100644 index 000000000..dcd326e82 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState1.dsh @@ -0,0 +1,7 @@ +sig A {} + +state Root1 {} + +fact R {} + +state Root2 {} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState2.dsh new file mode 100644 index 000000000..ac96cc895 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/onlyOneState2.dsh @@ -0,0 +1,2 @@ +state Root1 {} +state Root2 {} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/open1-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/open1-error.dsh new file mode 100644 index 000000000..19fc6e717 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/open1-error.dsh @@ -0,0 +1,7 @@ +sig A {} + +state S1 { + b1 : buf[A] + b2 : buf[B] + env b3 : buf[B] +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/open2-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/open2-error.dsh new file mode 100644 index 000000000..933126d96 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/open2-error.dsh @@ -0,0 +1,11 @@ + + +module X + +sig A {} + +state S1 { + b1 : buf[A] + b2 : buf[B] + env b3 : buf[B] +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/open3-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/open3-error.dsh new file mode 100644 index 000000000..2dcf2d993 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/open3-error.dsh @@ -0,0 +1,13 @@ + + +module X + +open util/boolean + +sig A {} + +state S1 { + b1 : buf[A] + b2 : buf[B] + env b3 : buf[B] +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/open4-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/open4-error.dsh new file mode 100644 index 000000000..8deb980e5 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/open4-error.dsh @@ -0,0 +1,9 @@ +open util/boolean + +sig A {} + +state S1 { + b1 : buf[A] + b2 : buf[B] + env b3 : buf[B] +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestCantHaveParam1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestCantHaveParam1.dsh new file mode 100644 index 000000000..869ecb6e3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestCantHaveParam1.dsh @@ -0,0 +1,10 @@ +state Root { + conc A [APID] { + trans t1 { + goto Root[x,y] + } + } + conc B [BPID] { + state S1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestUnknown4-traces.als b/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestUnknown4-traces.als new file mode 100644 index 000000000..ef803898e --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/srcDestUnknown4-traces.als @@ -0,0 +1,81 @@ +open util/ordering[Snapshot] as Snapshot +abstract sig StateLabel {} +sig Root extends StateLabel {} +abstract sig Root_S1 extends Root {} +sig Root_S1_S7 extends Root_S1 {} +abstract sig Root_S2 extends Root {} +abstract sig Root_S2_S3 extends Root_S2 {} +abstract sig Root_S2_S3_S4 extends Root_S2_S3 {} + +abstract sig TransitionLabel {} +one sig Root_S1_t1 extends TransitionLabel {} +one sig Root_S2_S3_S4_t2 extends TransitionLabel {} + +sig Snapshot { + taken0 : set TransitionLabel, + conf0 : set StateLabel, + stable : one boolean/Bool +} + +pred Root_S1_t1_pre[s : one Snapshot] { + +} + + +pred Root_S1_t1_post[s : one Snapshot, sNext : one Snapshot] { + +} + +pred Root_S1_t1_semantics[s : one Snapshot, sNext : one Snapshot] { + (stable = boolean/True => + sNext. (taken0) = Root_S1_t1 + else { + sNext. (taken0) = { s. (taken0) + Root_S1_t1 } } +) +} + + +pred Root_S1_t1_isEnabledAfterStep[s : one Snapshot, sNext : one Snapshot, t : one TransitionLabel] { + +} + + +pred Root_S1_t1[s : one Snapshot, sNext : one Snapshot] { + s. (Root_S1_t1_pre) + sNext. (s. (Root_S1_t1_post)) + sNext. (s. (Root_S1_t1_semantics)) +} + +pred Root_S2_S3_S4_t2_pre[s : one Snapshot] { + +} + + +pred Root_S2_S3_S4_t2_post[s : one Snapshot, sNext : one Snapshot] { + +} + +pred Root_S2_S3_S4_t2_semantics[s : one Snapshot, sNext : one Snapshot] { + (stable = boolean/True => + sNext. (taken0) = Root_S2_S3_S4_t2 + else { + sNext. (taken0) = { s. (taken0) + Root_S2_S3_S4_t2 } } +) +} + + +pred Root_S2_S3_S4_t2_isEnabledAfterStep[s : one Snapshot, sNext : one Snapshot, t : one TransitionLabel] { + +} + + +pred Root_S2_S3_S4_t2[s : one Snapshot, sNext : one Snapshot] { + s. (Root_S2_S3_S4_t2_pre) + sNext. (s. (Root_S2_S3_S4_t2_post)) + sNext. (s. (Root_S2_S3_S4_t2_semantics)) +} + +pred small_step[s : one Snapshot, sNext : one Snapshot] { + { sNext. (s. (Root_S1_t1)) or sNext. (s. (Root_S2_S3_S4_t2)) } +} + diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN1.dsh new file mode 100644 index 000000000..5689a0696 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN1.dsh @@ -0,0 +1,4 @@ +state Root { + state Root/A {} + state B {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN2.dsh new file mode 100644 index 000000000..dab7c7f34 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/stateNameCantBeFQN2.dsh @@ -0,0 +1,4 @@ +state Root { + state A {} + conc Root/B/C {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test0.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test0.dsh new file mode 100644 index 000000000..cb42f3d71 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test0.dsh @@ -0,0 +1,5 @@ +state Root { + trans t1 { + do N[n,y]/message' = this -> level + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test10.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test10.dsh new file mode 100644 index 000000000..251fe39b6 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test10.dsh @@ -0,0 +1,27 @@ + + +state Top { + state Outer { + default state s0 { + trans t0 { + goto s1 + } + } + state s1 { + trans t1 { + goto s0 + } + } + trans t4 { + from s2 + } + trans t5 { + from s0 + } + } + default state s2 { + trans t3 { + goto Outer + } + } +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test11.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test11.dsh new file mode 100644 index 000000000..f796693b1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test11.dsh @@ -0,0 +1,18 @@ +state Root { + conc S1 { + state S7 {} + trans t1 { + goto S7 + } + } + default state S2 { + state S3{ + state S5{ + trans t2 { + goto S7 + } + } + } + } + state S7 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test2.dsh new file mode 100644 index 000000000..fd6b14205 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test2.dsh @@ -0,0 +1,8 @@ +state A { + trans t1 { + // these are all allowed + send ev1 + send P[x]/ev1 + on P[x]/ev1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test3.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test3.dsh new file mode 100644 index 000000000..55a97b6c3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test3.dsh @@ -0,0 +1,9 @@ +state A { + trans t1 { + // these are all allowed + send ev1 + send P[x]/ev1 + send x.y.ev1 + on x.y.ev1 + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test5.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test5.dsh new file mode 100644 index 000000000..27ae28dec --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test5.dsh @@ -0,0 +1,35 @@ +// Identifiers are declared by translation + +state Root { + conc state A [AId] { + conc state A1 [A1ID] { + state S1 {} + default state S2 { + conc state C[CId] { + state C1 {} + default state C2 {} + trans t0 { + from C2 + goto C1 + } + } + } + trans t3 { + from S2 + goto S1 + } + trans t1 { + from S1 + goto S2 + } + } + } + conc state B [BId] { + state B1 {} + default state B2 {} + trans t2 { + from B1 + goto B2 + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test6.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test6.dsh new file mode 100644 index 000000000..3f99a3c6d --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test6.dsh @@ -0,0 +1,24 @@ + + +state Top { + conc state Outer { + default state s0 { + trans t0 { + goto s1 + } + } + state s1 { + trans t1 { + goto s0 + } + } + trans t4 { + goto s2 + } + } + default state s2 { + trans t3 { + goto Outer + } + } +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test7.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test7.dsh new file mode 100644 index 000000000..882c052c1 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test7.dsh @@ -0,0 +1,28 @@ +state Root { +conc state p1 { + + default state p1s0 { + trans p1t0 { + goto p1s1 + } + } + state p1s1 { + trans p1t1 { + goto p1s0 + } + } + +} +conc state p2 { + default state p2s0 { + trans p2t0 { + goto p2s1 + } + } + state p2s1 { + trans p2t1 { + goto p2s0 + } + } +} +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test8.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test8.dsh new file mode 100644 index 000000000..ea87bd45b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test8.dsh @@ -0,0 +1,19 @@ + + +state Top { + default state s0 { + trans t0 { + goto s1 + } + } + state s1 { + trans t1 { + goto s2 + } + } + state s2 { + trans t3 { + goto s1 + } + } +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/test9.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/test9.dsh new file mode 100644 index 000000000..f7ce1fd52 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/test9.dsh @@ -0,0 +1,24 @@ + + +state Top { + state Outer { + default state s0 { + trans t0 { + goto s1 + } + } + state s1 { + trans t1 { + goto s0 + } + } + trans t4 { + goto s2 + } + } + default state Outer { + trans t3 { + goto s1 + } + } +} diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates1.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates1.dsh new file mode 100644 index 000000000..bb758f0cc --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates1.dsh @@ -0,0 +1,5 @@ +state Root { + default state S1 {} + state S2 {} + default state S3 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates2.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates2.dsh new file mode 100644 index 000000000..dfe0c75a9 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/tooManyDefaultStates2.dsh @@ -0,0 +1,6 @@ +state Root { + state S1 {} + conc S2 {} + default state S3 {} + default conc S4 {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-2-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-2-error.dsh new file mode 100644 index 000000000..d1fa8a008 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-2-error.dsh @@ -0,0 +1,13 @@ +sig A {} + +fact {} + +state Root { + // not correct because must have substates + conc state A { + state A1 {} + } + conc state B { + state B1 {} + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-error.dsh new file mode 100644 index 000000000..fd1689d6b --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-conc-error.dsh @@ -0,0 +1,9 @@ +sig A {} + +fact {} + +state Root { + // not correct because must have substates + conc A {} + conc B {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-hier-error.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-hier-error.dsh new file mode 100644 index 000000000..99196d2d3 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/trivial-hier-error.dsh @@ -0,0 +1,9 @@ +sig A {} + +fact {} + + +state Root { + state A {} + state B {} +} \ No newline at end of file diff --git a/org.alloytools.alloy.dash/src/test/resources/wfffail/unknownSrcDest4.dsh b/org.alloytools.alloy.dash/src/test/resources/wfffail/unknownSrcDest4.dsh new file mode 100644 index 000000000..8a501d596 --- /dev/null +++ b/org.alloytools.alloy.dash/src/test/resources/wfffail/unknownSrcDest4.dsh @@ -0,0 +1,14 @@ +state Root { + conc A [APID] { + conc B [BPID] { + default state S1 { + trans t1 { + goto S2 + } + } + conc C [CPID] { + state S2 {} + } + } + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.dist/.classpath b/org.alloytools.alloy.dist/.classpath index bcafe71e5..ae30f860a 100644 --- a/org.alloytools.alloy.dist/.classpath +++ b/org.alloytools.alloy.dist/.classpath @@ -1,12 +1,19 @@ - - - - + + + + + + + + + - + + + diff --git a/org.alloytools.alloy.dist/.project b/org.alloytools.alloy.dist/.project index 49081730a..abea09f05 100644 --- a/org.alloytools.alloy.dist/.project +++ b/org.alloytools.alloy.dist/.project @@ -10,6 +10,11 @@ + + org.eclipse.buildship.core.gradleprojectbuilder + + + bndtools.core.bndbuilder @@ -19,5 +24,17 @@ org.eclipse.jdt.core.javanature bndtools.core.bndnature + org.eclipse.buildship.core.gradleprojectnature + + + 1687449709325 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/org.alloytools.alloy.dist/.settings/org.eclipse.buildship.core.prefs b/org.alloytools.alloy.dist/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/org.alloytools.alloy.dist/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/org.alloytools.alloy.dist/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.dist/.settings/org.eclipse.jdt.core.prefs index 6f9e91618..9eadd7a45 100644 --- a/org.alloytools.alloy.dist/.settings/org.eclipse.jdt.core.prefs +++ b/org.alloytools.alloy.dist/.settings/org.eclipse.jdt.core.prefs @@ -26,9 +26,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=17 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -91,7 +91,7 @@ org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning -org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning @@ -133,7 +133,7 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.processAnnotations=disabled -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME @@ -142,6 +142,7 @@ org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 org.eclipse.jdt.core.formatter.align_type_members_on_columns=true org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 @@ -149,21 +150,24 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_c org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_assignment=2 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=2 org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=2 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=2 org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=2 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 @@ -255,11 +259,12 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -290,6 +295,8 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -314,13 +321,17 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -368,6 +379,8 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do no org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -404,9 +417,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -445,10 +461,14 @@ org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=true org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/org.alloytools.alloy.dist/bnd.bnd b/org.alloytools.alloy.dist/bnd.bnd index a5f310311..7886f63e7 100644 --- a/org.alloytools.alloy.dist/bnd.bnd +++ b/org.alloytools.alloy.dist/bnd.bnd @@ -1,25 +1,41 @@ -Main-Class: edu.mit.csail.sdg.alloy4whole.Alloy +Main-Class: org.alloytools.alloy.core.infra.Alloy +JPM-Command: alloy -buildpath: \ org.alloytools.alloy.application,\ - org.alloytools.alloy.core,\ + org.alloytools.alloy.core,\ + org.alloytools.alloy.dash,\ org.alloytools.alloy.extra,\ + org.alloytools.api,\ aQute.libg, \ slf4j.api, \ - slf4j.simple - + slf4j.simple,\ + org.alloytools.alloy.lsp -sources: false --conditionalpackage: aQute.lib*, org.apache.commmons.cli, slf4j* +-conditionalpackage: aQute.*, org.apache.commmons.cli, slf4j* -includeresource: \ + @${repo;org.alloytools.api}, \ @${repo;org.alloytools.alloy.application}, \ @${repo;org.alloytools.alloy.core}, \ + @${repo;org.alloytools.alloy.dash}, \ @${repo;org.alloytools.alloy.extra}, \ + @${repo;org.alloytools.alloy.lsp}, \ @${repo;org.alloytools:pardinus.core}, \ @${repo;org.alloytools:pardinus.nativesat}, \ @${repo;org.sat4j.core}, \ @${repo;org.sat4j.maxsat}, \ @${repo;org.sat4j.pb}, \ + @${repo;slf4j.api}, \ + @${repo;slf4j.simple}, \ + @${repo;org.eclipse.lsp4j}, \ + @${repo;org.eclipse.lsp4j.jsonrpc}, \ + @${repo;com.google.gson}, \ + @${repo;org.eclipse.equinox.common}, \ + @${repo;org.apache.commons.io}, \ + @${repo;com.io7m.jpplib.io7m-jpplib-core}, \ LICENSES + +-dependson: * diff --git a/org.alloytools.alloy.extra/.classpath b/org.alloytools.alloy.extra/.classpath index bcafe71e5..ae30f860a 100644 --- a/org.alloytools.alloy.extra/.classpath +++ b/org.alloytools.alloy.extra/.classpath @@ -1,12 +1,19 @@ - - - - + + + + + + + + + - + + + diff --git a/org.alloytools.alloy.extra/.project b/org.alloytools.alloy.extra/.project index 1fdd108b6..a6cfe8577 100644 --- a/org.alloytools.alloy.extra/.project +++ b/org.alloytools.alloy.extra/.project @@ -10,6 +10,11 @@ + + org.eclipse.buildship.core.gradleprojectbuilder + + + bndtools.core.bndbuilder @@ -19,5 +24,17 @@ org.eclipse.jdt.core.javanature bndtools.core.bndnature + org.eclipse.buildship.core.gradleprojectnature + + + 1687449709338 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/org.alloytools.alloy.extra/.settings/org.eclipse.buildship.core.prefs b/org.alloytools.alloy.extra/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/org.alloytools.alloy.extra/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/org.alloytools.alloy.extra/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.extra/.settings/org.eclipse.jdt.core.prefs index 6f9e91618..978ab1820 100644 --- a/org.alloytools.alloy.extra/.settings/org.eclipse.jdt.core.prefs +++ b/org.alloytools.alloy.extra/.settings/org.eclipse.jdt.core.prefs @@ -26,9 +26,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=17 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -91,7 +91,7 @@ org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning -org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning @@ -133,7 +133,8 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.processAnnotations=disabled -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME @@ -142,6 +143,7 @@ org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 org.eclipse.jdt.core.formatter.align_type_members_on_columns=true org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 @@ -149,21 +151,24 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_c org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 org.eclipse.jdt.core.formatter.alignment_for_assignment=2 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=2 org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=2 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=2 org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=2 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 @@ -255,11 +260,12 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -290,6 +296,8 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -314,13 +322,17 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -368,6 +380,8 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do no org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -404,9 +418,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -445,10 +462,14 @@ org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=true org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error diff --git a/org.alloytools.alloy.extra/extra/help/a4.html b/org.alloytools.alloy.extra/extra/help/a4.html index 309faf5ba..7915d9fe5 100644 --- a/org.alloytools.alloy.extra/extra/help/a4.html +++ b/org.alloytools.alloy.extra/extra/help/a4.html @@ -194,7 +194,7 @@

Additional Changes

For example, if the following model is /Desktop/MyProject/main.als,
then we will infer that the "helper" module is - located at /Desktop/MyProject/additonal/helper.als + located at /Desktop/MyProject/additional/helper.als

    module MyProject/main
@@ -218,8 +218,8 @@ 

Additional Changes

Example 2: -

In this example, the first line is optional. But its presense - or absense will affect where Alloy 4 searches for imported modules. +

In this example, the first line is optional. But its presence + or absence will affect where Alloy 4 searches for imported modules.

module MyProject/main
open MyProject/library/helper
@@ -250,7 +250,7 @@

Additional Changes

  check NOTEQUAL for 3

These are called "anonymous" assertions and predicates.
- Alternatively, you can prepend an explcit label if you wish.
+ Alternatively, you can prepend an explicit label if you wish.
For example:

somelabel: check { A != B } for 3
diff --git a/org.alloytools.alloy.extra/extra/help/gui.html b/org.alloytools.alloy.extra/extra/help/gui.html index a2a4170bc..c93116c26 100644 --- a/org.alloytools.alloy.extra/extra/help/gui.html +++ b/org.alloytools.alloy.extra/extra/help/gui.html @@ -140,7 +140,7 @@

Options and Preferences

  • Record the Kodkod Input/output: If this option is enabled, after executing any command,
    then Alloy Analyzer will record the Kodkod input model generated for that command,
    - as well as the Kodkod solution correspoding to that command. + as well as the Kodkod solution corresponding to that command.

  • diff --git a/org.alloytools.alloy.extra/extra/help/skolem.html b/org.alloytools.alloy.extra/extra/help/skolem.html index d77a2c241..5924f4c6b 100644 --- a/org.alloytools.alloy.extra/extra/help/skolem.html +++ b/org.alloytools.alloy.extra/extra/help/skolem.html @@ -24,7 +24,7 @@

    Introduction

    }

    The "some" formula may be equivalently expressed as:

        x' in A && no x'.r 
    -

    x' is the skolem reation in this case. The existential quantifier "some" is not needed because the analysis will search for the existence of the skolem realtion x'.

    +

    x' is the skolem relation in this case. The existential quantifier "some" is not needed because the analysis will search for the existence of the skolem relationx'.

     

    Determining the names of skolem relations

    The Alloy Analyzer automatically generates and assigns names to skolem relations.
    diff --git a/org.alloytools.alloy.extra/extra/help/treeview.html b/org.alloytools.alloy.extra/extra/help/treeview.html index 9d19b0ddd..cfc092443 100644 --- a/org.alloytools.alloy.extra/extra/help/treeview.html +++ b/org.alloytools.alloy.extra/extra/help/treeview.html @@ -16,7 +16,7 @@

    Tree View

    The nodes of the tree may be expanded/collapsed to reveal/hide the values of relations. A relation node (such as that for a signature or a field) is expanded to reveal its tuples, and an atom may be expanded to reveal -the value of joining the atom with the fields defined in its correponding +the value of joining the atom with the fields defined in its corresponding signature.

    diff --git a/org.alloytools.alloy.extra/extra/help/util.html b/org.alloytools.alloy.extra/extra/help/util.html index 1e3153da3..98e61d3e3 100644 --- a/org.alloytools.alloy.extra/extra/help/util.html +++ b/org.alloytools.alloy.extra/extra/help/util.html @@ -28,7 +28,7 @@

    Utility Modules

    module util/graph[node]
    - Utilities for common operations and contraints on graphs. + Utilities for common operations and constraints on graphs.
    module util/integer diff --git a/org.alloytools.alloy.extra/extra/models/examples/algorithms/messaging.als b/org.alloytools.alloy.extra/extra/models/examples/algorithms/messaging.als index a69df8d6e..47e1db6c4 100644 --- a/org.alloytools.alloy.extra/extra/models/examples/algorithms/messaging.als +++ b/org.alloytools.alloy.extra/extra/models/examples/algorithms/messaging.als @@ -104,7 +104,7 @@ fact MsgMovementConstraints { // Return addresses are correct all n: Node | t.sent[n].state.from in n - // messages sent to a node on a tick become visible to that node on some subseqent tick, + // messages sent to a node on a tick become visible to that node on some subsequent tick, // and permanently stop being visible to that node on the tick after that node reads the message all n: Node, m: Msg | { // message starts being visible to node n no earlier than it is sent; diff --git a/org.alloytools.alloy.extra/extra/models/examples/algorithms/opt_spantree.als b/org.alloytools.alloy.extra/extra/models/examples/algorithms/opt_spantree.als index e7e44ceb3..488416065 100644 --- a/org.alloytools.alloy.extra/extra/models/examples/algorithms/opt_spantree.als +++ b/org.alloytools.alloy.extra/extra/models/examples/algorithms/opt_spantree.als @@ -5,7 +5,7 @@ module examples/algorithms/opt_spantree * over arbitrary network topologies * * Each process has a parent and a level, both of which are - * initally null. A distinct root node exists at which the + * initially null. A distinct root node exists at which the * algorithm starts. In the first step, the root assigns itself * the level of zero and sends its level to its neighbors. * Subsequently, if a node reads a message with level k, it sets @@ -17,7 +17,7 @@ module examples/algorithms/opt_spantree * * We model communication through a state-reading model, in which * nodes can directly read the state of their neighbors. Messages - * are not explicity modelled. This makes no difference for this + * are not explicitly modelled. This makes no difference for this * algorithm since once a node sends a message, the state of the * node stays the same as the contents of the message. */ diff --git a/org.alloytools.alloy.extra/extra/models/examples/algorithms/stable_mutex_ring.als b/org.alloytools.alloy.extra/extra/models/examples/algorithms/stable_mutex_ring.als index 4fc875652..4b93ebdd2 100644 --- a/org.alloytools.alloy.extra/extra/models/examples/algorithms/stable_mutex_ring.als +++ b/org.alloytools.alloy.extra/extra/models/examples/algorithms/stable_mutex_ring.als @@ -72,7 +72,7 @@ sig Tick { val: Process -> one Val, runs: set Process, // processes scheduled to run on this tick // for visualization - priv: set Process // the set of priviledged processes on this tick + priv: set Process // the set of privileged processes on this tick } { priv = { p : Process | Privileged[p, this] } diff --git a/org.alloytools.alloy.extra/extra/models/examples/case_studies/chordbugmodel.als b/org.alloytools.alloy.extra/extra/models/examples/case_studies/chordbugmodel.als index 586338339..95b5006f5 100644 --- a/org.alloytools.alloy.extra/extra/models/examples/case_studies/chordbugmodel.als +++ b/org.alloytools.alloy.extra/extra/models/examples/case_studies/chordbugmodel.als @@ -175,7 +175,7 @@ there is exactly one node. What happens here is that the model requires that a closest preceding finger node has a distinct identifier from the input identifier, but this cannot happen if there is exactly one node and if the input -identifer equals that of the node. +identifier equals that of the node. \subsection faulty \tt diff --git a/org.alloytools.alloy.lsp/.classpath b/org.alloytools.alloy.lsp/.classpath new file mode 100644 index 000000000..bcafe71e5 --- /dev/null +++ b/org.alloytools.alloy.lsp/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.alloytools.alloy.lsp/.project b/org.alloytools.alloy.lsp/.project new file mode 100644 index 000000000..2f98f1715 --- /dev/null +++ b/org.alloytools.alloy.lsp/.project @@ -0,0 +1,23 @@ + + + org.alloytools.alloy.application + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.alloytools.alloy.lsp/.settings/org.eclipse.core.resources.prefs b/org.alloytools.alloy.lsp/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..99f26c020 --- /dev/null +++ b/org.alloytools.alloy.lsp/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.alloytools.alloy.lsp/.settings/org.eclipse.core.runtime.prefs b/org.alloytools.alloy.lsp/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 000000000..5a0ad22d2 --- /dev/null +++ b/org.alloytools.alloy.lsp/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..2f809de6d --- /dev/null +++ b/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,456 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes= +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=true +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_assignment=2 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=2 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=140 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=true +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.ui.prefs b/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..5ba47fdd1 --- /dev/null +++ b/org.alloytools.alloy.lsp/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,135 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=false +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=false +cleanup.convert_to_enhanced_for_loop=false +cleanup.correct_indentation=false +cleanup.format_source_code=false +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=false +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=false +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_modifiers=false +cleanup.remove_redundant_semicolons=false +cleanup.remove_redundant_type_arguments=false +cleanup.remove_trailing_whitespaces=false +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=false +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=false +cleanup.use_this_for_non_static_field_access_only_if_necessary=true +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup.use_type_arguments=false +cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Alloy +formatter_settings_version=14 +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.javadoc=false +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=false +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/org.alloytools.alloy.lsp/bnd.bnd b/org.alloytools.alloy.lsp/bnd.bnd new file mode 100644 index 000000000..b608c0af9 --- /dev/null +++ b/org.alloytools.alloy.lsp/bnd.bnd @@ -0,0 +1,16 @@ + +-buildpath: \ + org.alloytools.alloy.application;version=latest,\ + org.alloytools.alloy.core;version=latest,\ + org.eclipse.lsp4j,\ + org.eclipse.lsp4j.jsonrpc,\ + com.google.gson,\ + org.eclipse.equinox.common,\ + org.apache.commons.io,\ + org.alloytools.api,\ + aQute.libg + +-testpath: \ + biz.aQute.wrapper.junit, \ + biz.aQute.wrapper.hamcrest, \ + org.sat4j.core \ No newline at end of file diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyAppUtil.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyAppUtil.java new file mode 100644 index 000000000..755f4a03b --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyAppUtil.java @@ -0,0 +1,128 @@ +package org.alloytools.alloy.lsp.provider; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.alloy4.OurDialog; +import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Module; +import edu.mit.csail.sdg.ast.Sig; +import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.sim.SimInstance; +import edu.mit.csail.sdg.sim.SimTuple; +import edu.mit.csail.sdg.sim.SimTupleset; +import edu.mit.csail.sdg.translator.A4Solution; +import edu.mit.csail.sdg.translator.A4Tuple; +import edu.mit.csail.sdg.translator.A4TupleSet; + +public class AlloyAppUtil { + + /** + * This variable caches the result of alloyHome() function call. + */ + private static String alloyHome = null; + + /** + * Find a temporary directory to store Alloy files; it's guaranteed to be a + * canonical absolute path. + */ + public static synchronized String alloyHome() { + if (alloyHome != null) + return alloyHome; + String temp = System.getProperty("java.io.tmpdir"); + if (temp == null || temp.length() == 0) + OurDialog.fatal(null, "Error. JVM need to specify a temporary directory using java.io.tmpdir property."); + String username = System.getProperty("user.name"); + File tempfile = new File(temp + File.separatorChar + "alloy4tmp40-" + (username == null ? "" : username)); + tempfile.mkdirs(); + String ans = Util.canon(tempfile.getPath()); + if (!tempfile.isDirectory()) { + OurDialog.fatal(null, "Error. Cannot create the temporary directory " + ans); + } + if (!Util.onWindows()) { + String[] args = { + "chmod", "700", ans + }; + try { + Runtime.getRuntime().exec(args).waitFor(); + } catch (Throwable ex) { + } // We only intend to make a best effort. + } + return alloyHome = ans; + } + + /** + * Create an empty temporary directory for use, designate it "deleteOnExit", + * then return it. It is guaranteed to be a canonical absolute path. + */ + public static String maketemp() { + Random r = new Random(new Date().getTime()); + while (true) { + int i = r.nextInt(1000000); + String dest = AlloyAppUtil.alloyHome() + File.separatorChar + "tmp" + File.separatorChar + i; + File f = new File(dest); + if (f.mkdirs()) { + f.deleteOnExit(); + return Util.canon(dest); + } + } + } + + /** Converts an A4TupleSet into a SimTupleset object. */ + public static SimTupleset convert(Object object) throws Err { + if (!(object instanceof A4TupleSet)) + throw new ErrorFatal("Unexpected type error: expecting an A4TupleSet."); + A4TupleSet s = (A4TupleSet) object; + if (s.size() == 0) + return SimTupleset.EMPTY; + List list = new ArrayList(s.size()); + int arity = s.arity(); + for (A4Tuple t : s) { + String[] array = new String[arity]; + for (int i = 0; i < t.arity(); i++) + array[i] = t.atom(i); + list.add(SimTuple.make(array)); + } + return SimTupleset.make(list); + } + + /** Converts an A4Solution into a SimInstance object. */ + public static SimInstance convert(Module root, A4Solution ans) throws Err { + SimInstance ct = new SimInstance(root, ans.getBitwidth(), ans.getMaxSeq()); + for (Sig s : ans.getAllReachableSigs()) { + if (!s.builtin) + ct.init(s, convert(ans.eval(s))); + for (Field f : s.getFields()) + if (!f.defined) + ct.init(f, convert(ans.eval(f))); + } + for (ExprVar a : ans.getAllAtoms()) + ct.init(a, convert(ans.eval(a))); + for (ExprVar a : ans.getAllSkolems()) + ct.init(a, convert(ans.eval(a))); + return ct; + } + + + public interface Func0 { + + public T call() throws Exception; + } + + public static T uncheckedRun(Func0 func) { + try { + return func.call(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessage.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessage.java new file mode 100644 index 000000000..bc68a87a6 --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessage.java @@ -0,0 +1,23 @@ +package org.alloytools.alloy.lsp.provider; + +public class AlloyLSMessage { + public AlloyLSMessageType messageType; + public String message; + public String link; + + public boolean bold; + public boolean replaceLast; + public boolean lineBreak = true; + + public AlloyLSMessage(AlloyLSMessageType messageType, String message, String link) { + this.messageType = messageType; + this.message = message; + this.link = link; + } + + public AlloyLSMessage(AlloyLSMessageType messageType, String message) { + this(messageType, message, null); + } + +} + diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessageType.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessageType.java new file mode 100644 index 000000000..6bcff5ff8 --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLSMessageType.java @@ -0,0 +1,9 @@ +package org.alloytools.alloy.lsp.provider; + +enum AlloyLSMessageType{ + RunStarted, + RunInProgress, + RunResult, + RunCompleted, + Warning +} \ No newline at end of file diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageClient.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageClient.java new file mode 100644 index 000000000..0138af37b --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageClient.java @@ -0,0 +1,35 @@ +package org.alloytools.alloy.lsp.provider; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.lsp4j.Command; +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification; +import org.eclipse.lsp4j.services.LanguageClient; + +public interface AlloyLanguageClient extends LanguageClient { + @JsonNotification("alloy/showExecutionOutput") + CompletableFuture showExecutionOutput(AlloyLSMessage params); + + @JsonNotification("alloy/commandsListResult") + CompletableFuture commandsListResult(CommandsListResult commands); + + public class CommandsListResult{ + public List commands; + + public CommandsListResult(List commands) { + this.commands = commands; + } + + } + public class CommandsListResultItem{ + public String title; + public Command command; + + public CommandsListResultItem(String title, Command command) { + this.title = title; + this.command = command; + } + + } +} diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServer.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServer.java new file mode 100644 index 000000000..4e0c39691 --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServer.java @@ -0,0 +1,135 @@ +package org.alloytools.alloy.lsp.provider; + +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.fileUriToPath; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +import org.eclipse.lsp4j.CodeLensOptions; +import org.eclipse.lsp4j.DocumentLinkOptions; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.jsonrpc.Launcher; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.launch.LSPLauncher; +import org.eclipse.lsp4j.launch.LSPLauncher.Builder; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageClientAware; +import org.eclipse.lsp4j.services.LanguageServer; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.eclipse.lsp4j.services.WorkspaceService; + +public class AlloyLanguageServer implements LanguageServer, LanguageClientAware { + + private AlloyLanguageClient client; + private AlloyTextDocumentService alloyTextDocumentService; + + @Override + public CompletableFuture initialize(InitializeParams params) { + + service().directory = params.getRootUri() != null ? fileUriToPath(params.getRootUri()) : null; + + InitializeResult res = new InitializeResult(); + ServerCapabilities caps = new ServerCapabilities(); + + caps.setTextDocumentSync(Either.forLeft(TextDocumentSyncKind.Full)); + + caps.setDefinitionProvider(true); + caps.setHoverProvider(true); + caps.setCodeLensProvider(new CodeLensOptions()); + caps.setDocumentLinkProvider(new DocumentLinkOptions()); + caps.setReferencesProvider(true); + caps.setRenameProvider(true); + //caps.setDocumentHighlightProvider(true); + caps.setWorkspaceSymbolProvider(true); + caps.setDocumentSymbolProvider(true); + + res.setCapabilities(caps); + return CompletableFuture.completedFuture(res); + } + + @Override + public CompletableFuture shutdown() { + return CompletableFuture.completedFuture(null); + } + + @Override + public void exit() { + System.exit(0); + } + + @Override + public TextDocumentService getTextDocumentService() { + return service(); + } + + private AlloyTextDocumentService service() { + if (alloyTextDocumentService == null) + alloyTextDocumentService = new AlloyTextDocumentService(client); + return alloyTextDocumentService; + } + + @Override + public WorkspaceService getWorkspaceService() { + return service(); + } + + // LanguageClientAware + @Override + public void connect(LanguageClient client) { + System.err.println("AlloyLanguageServer.connect() called"); + Class< ? >[] interfaces = client.getClass().getInterfaces(); + + this.client = (AlloyLanguageClient) client; + + if (this.alloyTextDocumentService != null) { + this.alloyTextDocumentService.connect(this.client); + } + + } + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + int port = Integer.parseInt(args[0]); + InputStream inputStream; + OutputStream outputStream; + AlloyLanguageServer langserv = new AlloyLanguageServer(); + try (java.net.Socket socket = new Socket("localhost", port)) { + inputStream = socket.getInputStream(); + outputStream = socket.getOutputStream(); + System.err.println("connected!"); + Launcher launcher = createServerLauncher(langserv, AlloyLanguageClient.class, inputStream, outputStream); + System.err.println("Starting Alloy Language Server!"); + langserv.connect(launcher.getRemoteProxy()); + Future res = launcher.startListening(); + System.err.println("Alloy Language Server Started!"); + res.get(); + System.err.println("########Exited Alloy Language Server!"); + } + } else { + AlloyLanguageServer server = new AlloyLanguageServer(); + Launcher l = new LSPLauncher.Builder().setLocalService(server).setRemoteInterface(AlloyLanguageClient.class).setInput(System.in).setOutput(System.out).create(); + server.connect(l.getRemoteProxy()); + Future< ? > startListening = l.startListening(); + startListening.get(); + } + } + + /** + * Create a new Launcher for a language server and an input and output stream. + * + * @param server - the server that receives method calls from the remote client + * @param in - input stream to listen for incoming messages + * @param out - output stream to send outgoing messages + */ + public static Launcher createServerLauncher(LanguageServer server, Class< ? extends TLangClient> clientType, InputStream in, OutputStream out) { + return new Builder().setLocalService(server).setRemoteInterface(clientType).setInput(in).setOutput(out).create(); + } +} + + diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServerUtil.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServerUtil.java new file mode 100644 index 000000000..47393148b --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyLanguageServerUtil.java @@ -0,0 +1,94 @@ +package org.alloytools.alloy.lsp.provider; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Paths; + +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.messages.Either; + +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.alloy4whole.SimpleGUI; + +public class AlloyLanguageServerUtil { + public static Pos positionToPos(Position position) { + return positionToPos(position, null); + } + + public static Pos positionToPos(Position position, String fileName) { + return new Pos(fileName, position.getCharacter() + 1, position.getLine() + 1); + } + + public static Location posToLocation(Pos pos){ + Location res= new Location(); + res.setRange(createRangeFromPos(pos)); + res.setUri(filePathToUri(pos.filename)); + return res; + } + + public static org.eclipse.lsp4j.Position posToPosition(edu.mit.csail.sdg.alloy4.Pos pos) { + Position position = new Position(); + position.setLine(pos.y - 1); + position.setCharacter(pos.x - 1); + return position; + } + public static Range createRange(Position start, Position end) { + Range res = new Range(); + res.setStart(start); + res.setEnd(end); + return res; + } + public static Range createRangeFromPos(Pos pos) { + Range res = new Range(); + res.setStart(posToPosition(pos)); + + Position endPosition = new Position(); + endPosition.setLine(pos.y2 - 1); + endPosition.setCharacter(pos.x2 - 1 + 1 /* end position appears to be exclusive in Range */); + + res.setEnd(endPosition); + return res; + } + + public static String filePathToUri(String absolutePath) { + return Paths.get(absolutePath).toUri().toString(); + } + + public static String fileUriToPath(String fileUri) { + try { + File file = new File(new URI(fileUri)); + try { + return file.getCanonicalPath(); + } catch (IOException ex) { + return file.getAbsolutePath(); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public static String filePathResolved(String filename) { + return filename.replace(Util.jarPrefix(), SimpleGUI.alloyHome(null) + fs); + } + + /** + * Return .getLeft() of the Either object, or throw .getRight() + * @return .getLeft() of the Either object if it isLeft() + * @throws TErr + */ + public static TRes getResult(Either val) throws TErr{ + if (val.isRight()) throw val.getRight(); + return val.getLeft(); + } + + /** + * The system-specific file separator (forward-slash on UNIX, back-slash on + * Windows, etc.) + */ + public static final String fs = System.getProperty("file.separator"); + +} \ No newline at end of file diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyTextDocumentService.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyTextDocumentService.java new file mode 100644 index 000000000..06b3e18e7 --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/AlloyTextDocumentService.java @@ -0,0 +1,1599 @@ +package org.alloytools.alloy.lsp.provider; + +import static edu.mit.csail.sdg.alloy4.A4Preferences.CoreGranularity; +import static edu.mit.csail.sdg.alloy4.A4Preferences.CoreMinimization; +import static edu.mit.csail.sdg.alloy4.A4Preferences.ImplicitThis; +import static edu.mit.csail.sdg.alloy4.A4Preferences.InferPartialInstance; +import static edu.mit.csail.sdg.alloy4.A4Preferences.NoOverflow; +import static edu.mit.csail.sdg.alloy4.A4Preferences.RecordKodkod; +import static edu.mit.csail.sdg.alloy4.A4Preferences.SkolemDepth; +import static edu.mit.csail.sdg.alloy4.A4Preferences.Solver; +import static edu.mit.csail.sdg.alloy4.A4Preferences.SubMemory; +import static edu.mit.csail.sdg.alloy4.A4Preferences.SubStack; +import static edu.mit.csail.sdg.alloy4.A4Preferences.Unrolls; +import static edu.mit.csail.sdg.alloy4.A4Preferences.VerbosityPref; +import static edu.mit.csail.sdg.alloy4.A4Preferences.WarningNonfatal; +import static org.alloytools.alloy.lsp.provider.AlloyLSMessageType.RunCompleted; +import static org.alloytools.alloy.lsp.provider.AlloyLSMessageType.RunResult; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.createRange; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.createRangeFromPos; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.filePathResolved; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.filePathToUri; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.fileUriToPath; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.fs; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.getResult; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.posToLocation; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.posToPosition; +import static org.alloytools.alloy.lsp.provider.AlloyLanguageServerUtil.positionToPos; +import static org.alloytools.alloy.lsp.provider.Lsp4jUtil.newDiagnostic; +import static org.alloytools.alloy.lsp.provider.Lsp4jUtil.newMessageParams; +import static org.alloytools.alloy.lsp.provider.Lsp4jUtil.newPublishDiagnosticsParams; +import static org.alloytools.alloy.lsp.provider.Lsp4jUtil.newSymbolInformation; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Scanner; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.alloytools.alloy.core.AlloyCore; +import org.alloytools.alloy.lsp.provider.AlloyLanguageClient.CommandsListResult; +import org.alloytools.alloy.lsp.provider.AlloyLanguageClient.CommandsListResultItem; +import org.apache.commons.io.FilenameUtils; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.CodeLens; +import org.eclipse.lsp4j.CodeLensParams; +import org.eclipse.lsp4j.Command; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.CompletionParams; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.DidChangeConfigurationParams; +import org.eclipse.lsp4j.DidChangeTextDocumentParams; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.DidCloseTextDocumentParams; +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.DidSaveTextDocumentParams; +import org.eclipse.lsp4j.DocumentFormattingParams; +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentHighlightKind; +import org.eclipse.lsp4j.DocumentLink; +import org.eclipse.lsp4j.DocumentLinkParams; +import org.eclipse.lsp4j.DocumentOnTypeFormattingParams; +import org.eclipse.lsp4j.DocumentRangeFormattingParams; +import org.eclipse.lsp4j.DocumentSymbolParams; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.MessageType; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.RenameParams; +import org.eclipse.lsp4j.SignatureHelp; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.TextDocumentPositionParams; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.WorkspaceSymbolParams; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageClientAware; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.eclipse.lsp4j.services.WorkspaceService; + +import com.google.gson.Gson; +import com.google.gson.JsonPrimitive; + +import edu.mit.csail.sdg.alloy4.A4Preferences.Verbosity; +import edu.mit.csail.sdg.alloy4.A4Reporter; +import edu.mit.csail.sdg.alloy4.Computer; +import edu.mit.csail.sdg.alloy4.ConstList; +import edu.mit.csail.sdg.alloy4.Err; +import edu.mit.csail.sdg.alloy4.ErrorFatal; +import edu.mit.csail.sdg.alloy4.ErrorSyntax; +import edu.mit.csail.sdg.alloy4.ErrorType; +import edu.mit.csail.sdg.alloy4.ErrorWarning; +import edu.mit.csail.sdg.alloy4.OurDialog; +import edu.mit.csail.sdg.alloy4.Pair; +import edu.mit.csail.sdg.alloy4.Pos; +import edu.mit.csail.sdg.alloy4.Util; +import edu.mit.csail.sdg.alloy4.Version; +import edu.mit.csail.sdg.alloy4.WorkerEngine; +import edu.mit.csail.sdg.alloy4.WorkerEngine.WorkerCallback; +import edu.mit.csail.sdg.alloy4.XMLNode; +import edu.mit.csail.sdg.alloy4viz.VizGUI; +import edu.mit.csail.sdg.alloy4whole.SimpleGUI; +import edu.mit.csail.sdg.alloy4whole.SimpleReporter.SimpleTask1; +import edu.mit.csail.sdg.alloy4whole.SimpleReporter.SimpleTask2; +import edu.mit.csail.sdg.ast.Assert; +import edu.mit.csail.sdg.ast.Clause; +import edu.mit.csail.sdg.ast.Expr; +import edu.mit.csail.sdg.ast.ExprBad; +import edu.mit.csail.sdg.ast.ExprConstant; +import edu.mit.csail.sdg.ast.ExprVar; +import edu.mit.csail.sdg.ast.Func; +import edu.mit.csail.sdg.ast.Module; +import edu.mit.csail.sdg.ast.Sig; +import edu.mit.csail.sdg.ast.Sig.Field; +import edu.mit.csail.sdg.ast.VisitQueryOnce; +import edu.mit.csail.sdg.parser.CompModule; +import edu.mit.csail.sdg.parser.CompUtil; +import edu.mit.csail.sdg.parser.Macro; +import edu.mit.csail.sdg.sim.SimInstance; +import edu.mit.csail.sdg.translator.A4Options; +import edu.mit.csail.sdg.translator.A4Solution; +import edu.mit.csail.sdg.translator.A4SolutionReader; + +class AlloyTextDocumentService implements TextDocumentService, WorkspaceService, LanguageClientAware { + + public AlloyLanguageClient client; + public String directory; + private int subMemoryNow; + private int subStackNow; + + public AlloyTextDocumentService(AlloyLanguageClient client) { + this.client = client; + } + + // LanguageClientAware + @Override + public void connect(LanguageClient client) { + log("AlloyTextDocumentService.connect() called"); + this.client = (AlloyLanguageClient) client; + } + + @Override + public CompletableFuture,CompletionList>> completion(CompletionParams position) { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture resolveCompletionItem(CompletionItem unresolved) { + return CompletableFuture.completedFuture(unresolved); + } + + Either cachedCompModuleForFileUri = null; + + /** + * the file uri of the cached module. If this is not null, the cached module is + * valid for the uri + */ + String cachedCompModuleForFileUri_Uri = null; + + CompModule getCompModuleForFileUri(String uri) { + // log("getCompModuleForFileUri (" + uri + ")"); + if (uri.equals(cachedCompModuleForFileUri_Uri)) { + return getResult(cachedCompModuleForFileUri); + } + + try { + String path = fileUriToPath(uri); + + // Try to return a nullModule object for non-AlloyMarkdown files. + // Not a big deal if the file has not been cached + String contents = fileContents.get(uri); + if (contents != null && !isAlloyFile(path, contents)) { + return CompUtil.nullModule(); + } + + cachedCompModuleForFileUri = Either.forLeft(CompUtil.parseEverything_fromFile(null, fileContentsPathBased(), path, 2)); + + } catch (Err err) { + log("getCompModuleForFileUri(): error in parsing: " + err.toString()); + fileUrisOfLastPublishedDiagnostics.add(uri); + + client.publishDiagnostics(toPublishDiagnosticsParams(err)); + + if (err instanceof ErrorSyntax) + latestFileUrisWithSyntaxError.add(uri); + + cachedCompModuleForFileUri = Either.forRight(err); + throw err; + } + + if (latestFileUrisWithSyntaxError.contains(uri)) { + client.publishDiagnostics(newPublishDiagnosticsParams(uri, Arrays.asList())); + latestFileUrisWithSyntaxError.remove(uri); + } + cachedCompModuleForFileUri_Uri = uri; + return getResult(cachedCompModuleForFileUri); + } + + @Override + public CompletableFuture hover(TextDocumentPositionParams position) { + //log("hover request"); + String hoverStr = null; + try { + + String uri = position.getTextDocument().getUri(); + String text = fileContents.get(uri); + CompModule module = getCompModuleForFileUri(uri); + + Pos pos = positionToPos(position.getPosition()); + Expr expr = module.find(pos); + if (expr instanceof ExprBad) { + hoverStr = expr.toString(); + } else if (expr != null) { + Clause referenced = expr.referenced(); + if (referenced != null) { + hoverStr = referenced.explain(); + } else if (expr instanceof ExprConstant) { + String token = pos.substring(text); + if (token != null) { + String match = expr.toString(); + if (!Objects.equals(token, match)) + hoverStr = match; + } + } + } + } catch (Exception e) { + // ignore compile errors etc. + } + if (hoverStr != null) { + MarkupContent markupContent = new MarkupContent(); + markupContent.setKind("markdown"); + + hoverStr = "```\n" + hoverStr + "\n```"; + + markupContent.setValue(hoverStr); + Hover res = new Hover(); + res.setContents(markupContent); + return CompletableFuture.completedFuture(res); + } else { + return CompletableFuture.completedFuture(null); + } + } + + @Override + public CompletableFuture signatureHelp(TextDocumentPositionParams position) { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture> definition(TextDocumentPositionParams position) { + try { + String uri = position.getTextDocument().getUri(); + String text = fileContents.get(uri); + String path = fileUriToPath(uri); + + CompModule module = getCompModuleForFileUri(uri); + Pos pos = positionToPos(position.getPosition(), path); + pos = getCurrentWordSelectionAsPos(text, pos); + Expr expr = module.find(pos); + + log("definition request for: " + expr); + + if (expr != null) { + Clause clause = expr.referenced(); + if (clause != null) { + Pos where = clause.pos(); + + //if path includes the jar, replace it by the created temp dir containing alloy models + String fileName = filePathResolved(where.filename); + + String targetUri = where.sameFile(module.pos()) ? uri : filePathToUri(fileName); + Location res = Lsp4jUtil.newLocation(createRangeFromPos(where), targetUri); + return CompletableFuture.completedFuture(Arrays.asList(res)); + } + } + + } catch (Exception ex) { + System.err.println("Error in providing definition: " + ex.toString()); + } + return CompletableFuture.completedFuture(Arrays.asList()); + } + + + + @Override + public CompletableFuture> references(ReferenceParams params) { + + String uri = params.getTextDocument().getUri(); + String text = fileContents.get(uri); + String path = fileUriToPath(uri); + + try { + CompModule module = getCompModuleForFileUri(params.getTextDocument().getUri()); + + Pos pos = getPosOfSymbolFromPositionInOpenDoc(params.getTextDocument().getUri(), params.getPosition()); + pos = getCurrentWordSelectionAsPos(text, pos).withFilename(path); + + String dir = this.directory != null ? this.directory : new File(path).getParent(); + List res = findAllReferencesGlobally(module, pos, dir, true, true).stream().map(ref -> posToLocation(ref)).collect(Collectors.toList()); + return CompletableFuture.completedFuture(res); + } catch (Err err) { + client.showMessage(newMessageParams("There are errors. Fix them first.", MessageType.Warning)); + return CompletableFuture.completedFuture(null); + } + } + + @Override + public CompletableFuture rename(RenameParams params) { + String uri = params.getTextDocument().getUri(); + String text = fileContents.get(uri); + String path = fileUriToPath(uri); + + try { + CompModule module = getCompModuleForFileUri(uri); + + Pos pos = getPosOfSymbolFromPositionInOpenDoc(uri, params.getPosition()); + pos = getCurrentWordSelectionAsPos(text, pos).withFilename(path); + + Expr expr = module.find(pos); + Pos targetPos = expr.referenced() != null ? expr.referenced().pos() : expr.pos; + + CompModule targetModule = CompUtil.parseEverything_fromFile(null, fileContentsPathBased(), filePathResolved(targetPos.filename)); + + Expr targetExpr = targetModule.find(targetPos); + + Map> changes = new HashMap<>(); + + String dir = this.directory != null ? this.directory : new File(path).getParent(); + List refs = findAllReferencesGlobally(module, pos, dir, false, false); + + if (targetExpr instanceof Sig) { + targetPos = ((Sig) targetExpr).labelPos; + } else if (targetExpr instanceof Field) { + targetPos = ((Field) targetExpr).labelPos; + } else if (targetExpr instanceof Func) { + targetPos = ((Func) targetExpr).labelPos; + } else if (targetExpr instanceof Assert) { + targetPos = ((Assert) targetExpr).labelPos; + } else if (targetExpr instanceof Macro) { + targetPos = ((Macro) targetExpr).namePos; + } + + WorkspaceEdit wEdit = new WorkspaceEdit(); + Stream.concat(refs.stream().distinct(), Stream.of(targetPos)).forEach(refPos -> { + TextEdit edit = new TextEdit(); + + edit.setRange(createRangeFromPos(refPos)); + edit.setNewText(params.getNewName()); + + String refUri = filePathToUri(filePathResolved(refPos.filename)); + + if (!changes.containsKey(refUri)) + changes.put(refUri, new ArrayList<>()); + changes.get(refUri).add(edit); + }); + + wEdit.setChanges(changes); + + return CompletableFuture.completedFuture(wEdit); + + } catch (Err err) { + client.showMessage(newMessageParams("Cannot rename symbol while there are errors. Fix the errors first.", MessageType.Warning)); + return CompletableFuture.completedFuture(null); + } + } + + Pos getPosOfSymbolFromPositionInOpenDoc(String uri, Position position) { + String path = fileUriToPath(uri); + String text = fileContents.get(uri); + + Pos pos = positionToPos(position, path); + pos = getCurrentWordSelectionAsPos(text, pos); + return pos; + } + + @Override + public CompletableFuture> documentHighlight(TextDocumentPositionParams position) { + + try { + CompModule module = getCompModuleForFileUri(position.getTextDocument().getUri()); + + Pos pos = getPosOfSymbolFromPositionInOpenDoc(position.getTextDocument().getUri(), position.getPosition()); + List refs = findAllReferences(module, pos, true); + + String path = fileUriToPath(position.getTextDocument().getUri()); + List res = refs.stream().filter(ref -> path.equals(ref.pos.filename)).map(ref -> { + DocumentHighlight highlight = new DocumentHighlight(); + + highlight.setKind(DocumentHighlightKind.Text); + highlight.setRange(createRangeFromPos(ref.pos)); + return highlight; + }).collect(Collectors.toList()); + + return CompletableFuture.completedFuture(res); + + } catch (Exception ex) { + return CompletableFuture.completedFuture(null); + } + } + + @Override + public CompletableFuture> documentSymbol(DocumentSymbolParams params) { + try { + CompModule module = getCompModuleForFileUri(params.getTextDocument().getUri()); + return CompletableFuture.completedFuture(moduleSymbols(module)); + } catch (Exception ex) { + return CompletableFuture.completedFuture(null); + } + } + + private List folderSymbols(String dir) { + List res = new ArrayList<>(); + + for (File child : alloyFilesInDir(dir)) { + String filePath = fileUriToPath(child.toURI().toString()); + try { + CompModule module = CompUtil.parseEverything_fromFile(null, fileContentsPathBased(), filePath); + res.addAll(moduleSymbols(module)); + } catch (Exception ex) { + log("error parsing " + child); + } + } + + return res; + } + + private static List moduleSymbols(CompModule module) { + Stream commands = module.getAllCommands().stream().map(c -> newSymbolInformation(c.label, posToLocation(c.pos), SymbolKind.Event)); + + Stream sigs = module.getAllSigs().makeConstList().stream().map(sig -> newSymbolInformation(sig.label, posToLocation(sig.pos), sig.isEnum != null ? SymbolKind.Enum : sig.isEnumMember() ? SymbolKind.EnumMember : sig.isOne != null || sig.isLone != null ? SymbolKind.Object : SymbolKind.Class)); + + Stream fields = module.getAllSigs().makeConstList().stream().flatMap(sig -> sig.getFields().makeConstList().stream()).map(field -> { + SymbolInformation symbolInfo = newSymbolInformation(field.label, posToLocation(field.pos), SymbolKind.Field); + symbolInfo.setContainerName(removeThisPrefix(field.sig.label)); + return symbolInfo; + }); + + Stream funcs = module.getAllFunc().makeConstList().stream().map(func -> newSymbolInformation(func.label, posToLocation(func.pos), func.isPred ? SymbolKind.Boolean : SymbolKind.Function)); + + Stream macros = module.getAllMacros().makeConstList().stream().map(macro -> newSymbolInformation(macro.name, posToLocation(macro.pos), SymbolKind.Constructor)); + + Stream assertions = module.getAllAssertions().stream().map(assertion -> newSymbolInformation(assertion.label, posToLocation(assertion.pos), SymbolKind.Property)); + + return Stream.of(commands, sigs, fields, funcs, assertions, macros).flatMap(x -> x).map(x -> { + x.setName(removeThisPrefix(x.getName())); + return x; + }) + //.sorted((sym1,sym2) -> positionCompare(sym1.getLocation().getRange().getStart(), sym2.getLocation().getRange().getStart())) + .collect(Collectors.toList()); + } + + @Override + public CompletableFuture> codeAction(CodeActionParams params) { + return CompletableFuture.completedFuture(null); + } + + List> getCommands(String uri) { + CompModule module; + + try { + module = getCompModuleForFileUri(uri); + } catch (Exception e) { + return Arrays.asList(); + } + + ConstList commands = module.getAllCommands(); + + ArrayList> res = new ArrayList<>(); + + for (int i = 0; i < commands.size(); i++) { + edu.mit.csail.sdg.ast.Command command = commands.get(i); + Position position = posToPosition(command.pos); + CodeLens codeLens = new CodeLens(); + codeLens.setRange(createRange(position, position)); + Command vsCommand = new Command("Execute", "ExecuteAlloyCommand"); + vsCommand.setArguments(Arrays.asList(uri, i, position.getLine(), position.getCharacter())); + codeLens.setCommand(vsCommand); + + res.add(new Pair<>(command, vsCommand)); + } + + if (latestFileUrisWithSyntaxError.contains(uri)) { + client.publishDiagnostics(newPublishDiagnosticsParams(uri, Arrays.asList())); + latestFileUrisWithSyntaxError.remove(uri); + } + return res; + } + + @Override + public CompletableFuture> codeLens(CodeLensParams params) { + + List res = getCommands(params.getTextDocument().getUri()).stream().map(pair -> { + edu.mit.csail.sdg.ast.Command command = pair.a; + Command vsCommand = pair.b; + + CodeLens codeLens = new CodeLens(); + codeLens.setRange(createRangeFromPos(command.pos)); + codeLens.setCommand(vsCommand); + + return codeLens; + }).collect(Collectors.toList()); + + return CompletableFuture.completedFuture(res); + } + + @Override + public CompletableFuture> documentLink(DocumentLinkParams params) { + + List links = getCommands(params.getTextDocument().getUri()).stream().map(pair -> { + edu.mit.csail.sdg.ast.Command command = pair.a; + Command vsCommand = pair.b; + + DocumentLink link = new DocumentLink(); + link.setRange(createRangeFromPos(command.commandKeyword.pos)); + List args = vsCommand.getArguments(); + Gson gson = new Gson(); + try { + java.net.URI path = new java.net.URI((String) args.get(0)); + args.set(0, path.toString()); + System.err.println("gson.toJson(args): " + gson.toJson(args)); + link.setTarget("command:" + vsCommand.getCommand() + "?" + gson.toJson(args)); + // URLEncoder.encode(gson.toJson(args), "UTF-8") ); + // } catch (UnsupportedEncodingException e1) { + } catch (URISyntaxException e) { + } + + return link; + }).collect(Collectors.toList()); + + return CompletableFuture.completedFuture(links); + + } + + @JsonRequest + public CompletableFuture ListAlloyCommands(JsonPrimitive documentUri) { + log("ListAlloyCommands called with " + documentUri + ", of type " + documentUri.getClass().getName()); + List res = getCommands(documentUri.getAsString()).stream().map(pair -> new CommandsListResultItem(pair.a.toString(), pair.b)).collect(Collectors.toList()); + + client.commandsListResult(new CommandsListResult(res)); + return CompletableFuture.completedFuture(null); + } + + private final HashSet fileUrisOfLastPublishedDiagnostics = new HashSet<>(); + private final Set latestFileUrisWithSyntaxError = new HashSet<>(); + + @JsonRequest + public CompletableFuture ExecuteAlloyCommand(com.google.gson.JsonArray params) { + log("ExecuteAlloyCommand() called with " + params + ", " + params.getClass()); + String uri = params.get(0).getAsString(); + int ind = params.get(1).getAsInt(); + int line = params.get(2).getAsInt(), character = params.get(3).getAsInt(); + + Position position = new Position(line, character); + Pos pos = positionToPos(position); + String fileString = fileContents.get(uri); + // Ugly hack to make the uri look like what it was if invoked through links + // if (fileString == null) { + // java.net.URI uriObj = new java.net.URI(uri); + // String newPath = uriObj.getRawPath().replace(":", "%3A"); + // String newUri = uriObj.getScheme() + newPath; + // fileString = fileContents.get(newUri); + // } + // Another ugly hack to make things work if invoked through links (which makes the uri look different) + if (fileString == null) { + String uriPath = fileUriToPath(uri); + for (Map.Entry entry : fileContents.entrySet()) { + if (fileUriToPath(entry.getKey()).equals(uriPath)) { + fileString = entry.getValue(); + uri = entry.getKey(); + break; + } + } + } + if (fileString == null) { + System.err.println("Error in ExecuteAlloyCommand: failed to retrieve file contents for " + uri); + return CompletableFuture.completedFuture(null); + } + CompModule module = CompUtil.parseOneModule(fileString); + ConstList commands = module.getAllCommands(); + edu.mit.csail.sdg.ast.Command command = commands.stream().filter(comm -> comm.pos().y == pos.y && comm.pos.x == pos.x).findFirst().orElse(null); + if (command != null || ind == -1) { + String uriToShutUpStupidJava = uri; + CompletableFuture.runAsync(() -> doRun(uriToShutUpStupidJava, ind)); + } else { + System.err.println("no matching command found"); + } + + return CompletableFuture.completedFuture(null); + } + + @JsonRequest + public CompletableFuture StopExecution(Object o) { + log("Stop req received"); + doStop(2); + + AlloyLSMessage alloyMsg = new AlloyLSMessage(RunCompleted, "Stopped"); + alloyMsg.bold = true; + client.showExecutionOutput(alloyMsg); + + return CompletableFuture.completedFuture(null); + } + + @JsonRequest + public CompletableFuture OpenModel(com.google.gson.JsonPrimitive link) { + log("OpenModel() called with " + link.getAsString()); + log(" , of type" + link.getClass().getName()); + doVisualize(link.getAsString()); + return CompletableFuture.completedFuture(null); + } + + + + @Override + public CompletableFuture resolveCodeLens(CodeLens unresolved) { + return CompletableFuture.completedFuture(unresolved); + } + + @Override + public CompletableFuture> formatting(DocumentFormattingParams params) { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture> rangeFormatting(DocumentRangeFormattingParams params) { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture> onTypeFormatting(DocumentOnTypeFormattingParams params) { + return CompletableFuture.completedFuture(null); + } + + + private Map fileContentsPathBased() { + HashMap res = new HashMap(); + fileContents.entrySet().stream().forEach(entry -> res.put(fileUriToPath(entry.getKey()), entry.getValue())); + return res; + } + + private HashMap fileContents = new HashMap<>(); + + @Override + public void didOpen(DidOpenTextDocumentParams params) { + String text = params.getTextDocument().getText(); + String uri = params.getTextDocument().getUri(); + fileContents.put(uri, text); + } + + @Override + public void didChange(DidChangeTextDocumentParams params) { + // https://raw.githubusercontent.com/eclipse/eclipse.jdt.ls/0ed1bf259b3edb4f184804a9df14c95ef468d4e9/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/DocumentLifeCycleHandler.java + String text = params.getContentChanges().get(0).getText(); + String uri = params.getTextDocument().getUri(); + fileContents.put(uri, text); + + cachedCompModuleForFileUri = null; + cachedCompModuleForFileUri_Uri = null; + } + + @Override + public void didSave(DidSaveTextDocumentParams params) { + String text = params.getText(); + + if (text != null) { + String uri = params.getTextDocument().getUri(); + fileContents.put(uri, text); + + cachedCompModuleForFileUri = null; + cachedCompModuleForFileUri_Uri = null; + } + } + + // WorkspaceService methods + @Override + public void didClose(DidCloseTextDocumentParams params) { + fileContents.remove(params.getTextDocument().getUri()); + } + + @Override + public CompletableFuture> symbol(WorkspaceSymbolParams params) { + + if (this.directory == null) + return CompletableFuture.completedFuture(null); + + List res = folderSymbols(this.directory).stream().filter(symbol -> { + return symbol.getName().toLowerCase().contains(params.getQuery().toLowerCase()); + }).collect(Collectors.toList()); + + return CompletableFuture.completedFuture(res); + } + + @Override + public void didChangeConfiguration(DidChangeConfigurationParams params) { + } + + @Override + public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { + } + + static String removeThisPrefix(String name) { + if (name.startsWith("this/")) { + return name.substring("this/".length()); + } + return name; + } + + private PublishDiagnosticsParams toPublishDiagnosticsParams(Err err) { + return toPublishDiagnosticsParamsList(Arrays.asList(err)).get(0); + } + + private List toPublishDiagnosticsParamsList(List errors) { + + Map> map = errors.stream().collect(Collectors.groupingBy(warning -> warning.pos.filename)); + return map.entrySet().stream().map(entry -> { + + List diags = entry.getValue().stream().map(err -> { + Diagnostic diag = newDiagnostic(err.msg, createRangeFromPos(err.pos)); + diag.setSeverity(err instanceof ErrorWarning ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error); + + return diag; + }).collect(Collectors.toList()); + + return newPublishDiagnosticsParams(filePathToUri(entry.getKey()), diags); + }).collect(Collectors.toList()); + } + + private String newInstance; + private VizGUI viz; + + // edu.mit.csail.sdg.alloy4whole.SimpleGUI.doRun(Integer) + private void doRun(String fileURI, Integer commandIndex) { + CompModule module = CompUtil.parseOneModule(fileContents.get(fileURI)); + ConstList commands = module.getAllCommands(); + + final int index = commandIndex; + if (WorkerEngine.isBusy() || (commands == null)) + return; + if (commands.size() == 0 && index != -2 && index != -3) { + // log.logRed("There are no commands to execute.\n\n"); + return; + } + int i = index; + if (i >= commands.size()) + i = commands.size() - 1; + // SimpleCallback1 cb = new SimpleCallback1(this, null, log, + // VerbosityPref.get().ordinal(), latestAlloyVersionName, latestAlloyVersion); + SimpleTask1 task = new SimpleTask1(); + A4Options opt = new A4Options(); + opt.tempDirectory = SimpleGUI.alloyHome(null) + fs + "tmp"; + opt.solverDirectory = SimpleGUI.alloyHome(null) + fs + "binary"; + opt.recordKodkod = RecordKodkod.get(); + opt.noOverflow = NoOverflow.get(); + opt.unrolls = Version.experimental ? Unrolls.get() : (-1); + opt.skolemDepth = SkolemDepth.get(); + opt.coreMinimization = CoreMinimization.get(); + opt.inferPartialInstance = InferPartialInstance.get(); + opt.coreGranularity = CoreGranularity.get(); + + log("cwd :" + Paths.get("").toAbsolutePath()); + + String fileNameDecoded; + try { + fileNameDecoded = URIUtil.toFile(new URI(fileURI)).getPath(); + + } catch (Exception ex) { + System.err.println("failed to parse uri"); + return; + } + log("fileNameDecoded:" + fileNameDecoded); + + opt.originalFilename = fileNameDecoded;// new File(decodeUrl(uri)).getPath();// Util.canon(decodeUrl(uri)); + opt.solver = Solver.get(); + task.bundleIndex = i; + task.bundleWarningNonFatal = WarningNonfatal.get(); + // task.map = text.takeSnapshot(); + task.options = opt.dup(); + task.resolutionMode = (Version.experimental && ImplicitThis.get()) ? 2 : 1; + task.tempdir = SimpleGUI.maketemp(null); + + try { + int newmem = SubMemory.get(), newstack = SubStack.get(); + if (newmem != subMemoryNow || newstack != subStackNow) + WorkerEngine.stop(); + + WorkerCallback cb = getWorkerCallback(); + + log("actually running the task"); + // if (AlloyCore.isDebug() && VerbosityPref.get() == Verbosity.FULLDEBUG) + //WorkerEngine.runLocally(task, cb); + // else + WorkerEngine.run(task, newmem, newstack, SimpleGUI.alloyHome(null) + fs + "binary", "", cb); + subMemoryNow = newmem; + subStackNow = newstack; + } catch (Throwable ex) { + WorkerEngine.stop(); + System.err.println("Fatal Error: Solver failed due to unknown reason. exception: \n" + ex.toString()); + // log.logBold("Fatal Error: Solver failed due to unknown reason.\n" + "One + // possible cause is that, in the Options menu, your specified\n" + "memory size + // is larger than the amount allowed by your OS.\n" + "Also, please make sure + // \"java\" is in your program path.\n"); + // log.logDivider(); + // log.flush(); + doStop(2); + } + return; + } + + private WorkerCallback getVizWorkerCallback() { + return new WorkerCallback() { + + @Override + public void fail() { + AlloyLSMessage alloyMsg = new AlloyLSMessage(AlloyLSMessageType.RunCompleted, "failure"); + client.showExecutionOutput(alloyMsg); + + } + + @Override + public void done() { + viz.loadXML(newInstance, true); + + } + + @Override + public void callback(Object msg) { + Either,Err> alloyMsgOrWarning = solverCallbackMsgToAlloyMsg(msg); + + if (alloyMsgOrWarning.isLeft()) { + for (AlloyLSMessage alloyMsg : alloyMsgOrWarning.getLeft()) { + if (alloyMsg.message != null && !alloyMsg.message.isEmpty()) + //client.showExecutionOutput(alloyMsg); + client.logMessage(newMessageParams(alloyMsg.message, MessageType.Log)); + } + + } else { + //warnings.add(alloyMsgOrWarning.getRight()); + } + + } + }; + } + + private WorkerCallback getWorkerCallback() { + return new WorkerCallback() { + + List warnings = new ArrayList<>(); + + @Override + public void callback(Object msg) { + + // MessageParams messageParams= new MessageParams(); + // messageParams.setMessage(solverCallbackMsgToString(msg)); + // client.showMessage(messageParams); + // if(messageParams.getMessage() != null && !messageParams.getMessage().isEmpty()) + // client.showAlloyOutput(messageParams); + + Either,Err> alloyMsgOrWarning = solverCallbackMsgToAlloyMsg(msg); + + if (alloyMsgOrWarning.isLeft()) { + for (AlloyLSMessage alloyMsg : alloyMsgOrWarning.getLeft()) { + if (alloyMsg.message != null && !alloyMsg.message.isEmpty()) + client.showExecutionOutput(alloyMsg); + } + + } else { + Err err = alloyMsgOrWarning.getRight(); + + if (Pos.UNKNOWN.equals(err.pos) || err.pos == null) { + AlloyLSMessage errMsg = new AlloyLSMessage(AlloyLSMessageType.Warning, err.msg + "\n"); + errMsg.bold = true; + client.showExecutionOutput(errMsg); + } + warnings.add(alloyMsgOrWarning.getRight()); + } + } + + @Override + public void done() { + // MessageParams messageParams= new MessageParams(); + // messageParams.setMessage("done"); + // client.showMessage(messageParams); + // client.showAlloyOutput(messageParams); + if (warnings.size() > 0) + client.showExecutionOutput(new AlloyLSMessage(AlloyLSMessageType.RunResult, "There were errors/warnings!")); + + client.showExecutionOutput(new AlloyLSMessage(AlloyLSMessageType.RunCompleted, "")); + + publishDiagnostics(); + } + + @Override + public void fail() { + AlloyLSMessage alloyMsg = new AlloyLSMessage(AlloyLSMessageType.RunCompleted, "failure"); + client.showExecutionOutput(alloyMsg); + publishDiagnostics(); + } + + void publishDiagnostics() { + + //cleaning previously reported diagnostics + if (fileUrisOfLastPublishedDiagnostics != null) + fileUrisOfLastPublishedDiagnostics.stream().forEach(item -> { + PublishDiagnosticsParams diagnostics = new PublishDiagnosticsParams(); + diagnostics.setUri(item); + client.publishDiagnostics(diagnostics); + }); + + List diagnosticsParamsList = toPublishDiagnosticsParamsList(warnings); + + diagnosticsParamsList.forEach(diagsParams -> client.publishDiagnostics(diagsParams)); + + fileUrisOfLastPublishedDiagnostics.clear(); + fileUrisOfLastPublishedDiagnostics.addAll(diagnosticsParamsList.stream().map(item -> item.getUri()).collect(Collectors.toList())); + + } + + }; + } + + // edu.mit.csail.sdg.alloy4whole.SimpleReporter.SimpleCallback1.callback(Object) + public Either,Err> solverCallbackMsgToAlloyMsg(Object msg) { + StringBuilder span = new StringBuilder(); + AlloyLSMessage alloyMsg = new AlloyLSMessage(AlloyLSMessageType.RunInProgress, null); + + List resMsgs = new ArrayList<>(); + resMsgs.add(alloyMsg); + + final int verbosity = 0; + if (msg == null) { + span.append("Done\n"); + } else if (msg instanceof String) { + span.append(((String) msg).trim() + "\n"); + } else if (msg instanceof Throwable) { + for (Throwable ex = (Throwable) msg; ex != null; ex = ex.getCause()) { + if (ex instanceof OutOfMemoryError) { + span.append("\nFatal Error: the solver ran out of memory!\n" + "Try simplifying your model or reducing the scope,\n" + "or increase memory under the Options menu.\n"); + } + if (ex instanceof StackOverflowError) { + span.append("\nFatal Error: the solver ran out of stack space!\n" + "Try simplifying your model or reducing the scope,\n" + "or increase stack under the Options menu.\n"); + } + } + if (msg instanceof Err) { + log("Err msg from solver: " + msg.toString()); + Err ex = (Err) msg; + String text = "fatal"; + boolean fatal = false; + if (ex instanceof ErrorSyntax) + text = "syntax"; + else if (ex instanceof ErrorType) + text = "type"; + else + fatal = true; + if (ex.pos == Pos.UNKNOWN) + span.append("A " + text + " error has occurred: "); + else + span.append("A " + text + " error has occurred: " + "POS: " + ex.pos.x + " " + ex.pos.y + " " + ex.pos.x2 + " " + ex.pos.y2 + " " + ex.pos.filename); + // if (verbosity > 2) { + // span.log("(see the "); + // span.logLink("stacktrace", "MSG: " + ex.dump()); + // span.log(")\n"); + // } else { + // span.log("\n"); + // } + span.append(ex.msg.trim()); // logIndented + return Either.forRight(ex); + //span.append("\n"); + // if (fatal && latestVersion > Version.buildNumber()) + // span.logBold("\nNote: You are running Alloy build#" + Version.buildNumber() + ",\nbut the most recent is Alloy build#" + latestVersion + ":\n( version " + latestName + " )\nPlease try to upgrade to the newest version," + "\nas the problem may have been fixed already.\n"); + + // if (!fatal) + // gui.doVisualize("POS: " + ex.pos.x + " " + ex.pos.y + " " + ex.pos.x2 + " " + ex.pos.y2 + " " + ex.pos.filename); + } else /* if (msg instanceof Throwable) */ { + log("exception msg from solver: " + msg.toString()); + Throwable ex = (Throwable) msg; + span.append(ex.toString().trim() + "\n"); + // span.flush(); + } + } else if ((msg instanceof Object[])) { + Object[] array = (Object[]) msg; + if (array[0].equals("pop")) { + // span.setLength(len2); + String x = (String) (array[1]); + span.append(x); + alloyMsg.replaceLast = true; + // if (viz != null && x.length() > 0) + // OurDialog.alert(x); + } + if (array[0].equals("declare")) { + //gui.doSetLatest((String) (array[1])); + newInstance = (String) (array[1]); + // ========== + } + if (array[0].equals("S2")) { + // len3 = len2 = span.getLength(); + span.append("" + array[1]); + } + if (array[0].equals("R3")) { + //span.setLength(len3); + span.append("" + array[1]); + } + if (array[0].equals("link")) { + log("link message!!!"); + //span.logLink((String) (array[1]), (String) (array[2])); + span.append(array[1].toString()); + alloyMsg.link = (String) array[2]; + alloyMsg.messageType = AlloyLSMessageType.RunResult; + + } + if (array[0].equals("bold")) { + span.append("" + array[1]); + alloyMsg.bold = true; + //alloyMsg.replaceLast = true; + } + if (array[0].equals("")) { + span.append("" + array[1]); + } + if (array[0].equals("scope") && verbosity > 0) { + span.append(" " + array[1]); + } + if (array[0].equals("bound") && verbosity > 1) { + span.append(" " + array[1]); + } + if (array[0].equals("resultCNF")) { + // results.add(null); + // span.setLength(len3); + // span.log(" File written to " + array[1] + "\n\n"); + } + if (array[0].equals("debug") && verbosity > 2) { + span.append(" " + array[1] + "\n"); + // len2 = len3 = span.getLength(); + } + if (array[0].equals("translate")) { + span.append(" " + array[1]); + // len3 = span.getLength(); + span.append(" Generating CNF...\n"); + } + if (array[0].equals("solve")) { + // span.setLength(len3); + span.append(" " + array[1]); + // len3 = span.getLength(); + span.append(" Solving...\n"); + } + if (array[0].equals("warnings")) { + // if (warnings.size() == 0) + // span.setLength(len2); + // else if (warnings.size() > 1) + // span.logBold("Note: There were " + warnings.size() + " compilation warnings. Please scroll up to see them.\n\n"); + // else + // span.append("Note: There was 1 compilation wrearning. Please scroll up to see + // them.\n\n"); + // span.append("There were warnings!"); + // if (warnings.size() > 0 && Boolean.FALSE.equals(array[1])) { + // Pos e = warnings.iterator().next().pos; + // gui.doVisualize("POS: " + e.x + " " + e.y + " " + e.x2 + " " + e.y2 + " " + e.filename); + // span.logBold("Warnings often indicate errors in the model.\n" + "Some warnings can affect the soundness of the analysis.\n" + "To proceed despite the warnings, go to the Options menu.\n"); + // } + } + if (array[0].equals("warning")) { + ErrorWarning e = (ErrorWarning) (array[1]); + // if (!warnings.add(e)) + // return; + Pos p = e.pos; + // span.logLink("Warning #" + warnings.size(), "POS: " + p.x + " " + p.y + " " + p.x2 + " " + p.y2 + " " + p.filename); + span.append("Warning " + e.msg.trim());// #" + warnings.size(), "POS: " + p.x + " " + p.y + " " + p.x2 + + // " " + p.y2 + " " + p.filename); + return Either.forRight(e); + // span.log("\n"); + // span.logIndented(e.msg.trim()); + // span.log("\n\n"); + } + if (array[0].equals("sat")) { + boolean chk = Boolean.TRUE.equals(array[1]); + int expects = (Integer) (array[2]); + String filename = (String) (array[3]), formula = (String) (array[4]); + // results.add(filename); + (new File(filename)).deleteOnExit(); + // gui.doSetLatest(filename); + // span.setLength(len3); + span.append(" "); + // span.logLink(chk ? "Counterexample" : "Instance", "XML: " + filename); + span.append(chk ? "Counterexample" : "Instance");// , "XML: " + filename); + alloyMsg.link = "XML: " + filename; + alloyMsg.messageType = AlloyLSMessageType.RunResult; + alloyMsg.replaceLast = true; + alloyMsg.bold = true; + span.append(" found. "); + // span.logLink(chk ? "Assertion" : "Predicate", formula); + span.append(chk ? "Assertion" : "Predicate");// , formula); + span.append(chk ? " is invalid" : " is consistent"); + if (expects == 0) + span.append(", contrary to expectation"); + else if (expects == 1) + span.append(", as expected"); + span.append(". "); + //span.append(". " + array[5] + "ms.\n\n"); + alloyMsg.lineBreak = false; + resMsgs.add(new AlloyLSMessage(AlloyLSMessageType.RunResult, array[5] + "ms.\n\n")); + } + if (array[0].equals("metamodel")) { + // String outf = (String) (array[1]); + // span.setLength(len2); + // (new File(outf)).deleteOnExit(); + // gui.doSetLatest(outf); + // span.logLink("Metamodel", "XML: " + outf); + // span.log(" successfully generated.\n\n"); + } + if (array[0].equals("minimizing")) { + boolean chk = Boolean.TRUE.equals(array[1]); + // int expects = (Integer) (array[2]); + // span.setLength(len3); + // span.log(chk ? " No counterexample found." : " No instance found."); + span.append(chk ? " No counterexample found. " : " No instance found. "); + if (chk) + span.append(" Assertion may be valid"); + else + span.append(" Predicate may be inconsistent"); + // if (expects == 1) + // span.log(", contrary to expectation"); + // else if (expects == 0) + // span.log(", as expected"); + span.append(". " + array[4] + "ms.\n"); + // span.logBold(" Minimizing the unsat core of " + array[3] + " entries...\n"); + } + if (array[0].equals("unsat")) { + boolean chk = Boolean.TRUE.equals(array[1]); + int expects = (Integer) (array[2]); + String formula = (String) (array[4]); + // span.setLength(len3); + alloyMsg.messageType = AlloyLSMessageType.RunResult; + alloyMsg.replaceLast = true; + alloyMsg.bold = true; + span.append(chk ? " No counterexample found. " : " No instance found. "); + span.append(chk ? "Assertion" : "Predicate");// , formula); + span.append(chk ? " may be valid" : " may be inconsistent"); + if (expects == 1) + span.append(", contrary to expectation"); + else if (expects == 0) + span.append(", as expected"); + if (array.length == 5) { + span.append(". "); + alloyMsg.lineBreak = false; + resMsgs.add(new AlloyLSMessage(RunResult, array[3] + "ms.\n\n")); + // span.flush(); + } else { + String core = (String) (array[5]); + int mbefore = (Integer) (array[6]), mafter = (Integer) (array[7]); + span.append(". " + array[3] + "ms.\n"); + if (core.length() == 0) { + // results.add(""); + span.append(" No unsat core is available in this case. "); + + resMsgs.add(new AlloyLSMessage(RunResult, array[8] + "ms.\n\n")); + // span.flush(); + } else { + + // results.add(core); + (new File(core)).deleteOnExit(); + span.append(" "); + //span.append("Core");// , core); + + AlloyLSMessage coreLinkMsg = new AlloyLSMessage(RunResult, "core"); + coreLinkMsg.link = core; + resMsgs.add(coreLinkMsg); + + AlloyLSMessage nextMsg = new AlloyLSMessage(RunResult, null); + if (mbefore <= mafter) + nextMsg.message = (" contains " + mafter + " top-level formulas. " + array[8] + "ms.\n\n"); + else + nextMsg.message = (" reduced from " + mbefore + " to " + mafter + " top-level formulas. " + array[8] + "ms.\n\n"); + resMsgs.add(nextMsg); + } + } + } + } + alloyMsg.message = span.toString(); + return Either.forLeft(resMsgs); + } + + /** + * This method stops the current run or check (how==0 means DONE, how==1 means + * FAIL, how==2 means STOP). + */ + void doStop(Integer how) { + int h = how; + if (h != 0) { + if (h == 2 && WorkerEngine.isBusy()) { + WorkerEngine.stop(); + //log.logBold("\nSolving Stopped.\n"); + //log.logDivider(); + } + WorkerEngine.stop(); + } + // runmenu.setEnabled(true); + // runbutton.setVisible(true); + // showbutton.setEnabled(true); + // stopbutton.setVisible(false); + // if (latestAutoInstance.length() > 0) { + // String f = latestAutoInstance; + // latestAutoInstance = ""; + // if (subrunningTask == 2) + // viz.loadXML(f, true); + // else if (AutoVisualize.get() || subrunningTask == 1) + // doVisualize("XML: " + f); + // } + } + + // edu.mit.csail.sdg.alloy4whole.SimpleGUI.doVisualize(String) for handling + // instance visualization links + + private void doVisualize(String arg) { + log("doVisualize() called with " + arg); + if (arg.startsWith("CORE: ")) { // CORE: filename + String filename = Util.canon(arg.substring(6)); + Pair,Set> hCore; + // Set lCore; + InputStream is = null; + ObjectInputStream ois = null; + try { + is = new FileInputStream(filename); + ois = new ObjectInputStream(is); + hCore = (Pair,Set>) ois.readObject(); + // lCore = (Set) ois.readObject(); + List errs = Stream.concat(hCore.a.stream().map(pos -> new ErrorWarning(pos, "part of unsat core")), hCore.b.stream().map(pos -> new ErrorWarning(pos, "possibly part of unsat core"))).collect(Collectors.toList()); + + List publishDiags = this.toPublishDiagnosticsParamsList(errs); + + fileUrisOfLastPublishedDiagnostics.clear(); + fileUrisOfLastPublishedDiagnostics.addAll(publishDiags.stream().map(PublishDiagnosticsParams::getUri).collect(Collectors.toList())); + + publishDiags.forEach(client::publishDiagnostics); + + } catch (Throwable ex) { + System.err.println("Error reading or parsing the core \"" + filename + "\"\n"); + // return null; + } finally { + Util.close(ois); + Util.close(is); + } + + + + // text.clearShade(); + // text.shade(hCore.b, subCoreColor, false); + // text.shade(hCore.a, coreColor, false); + // // shade again, because if not all files were open, some shadings + // // will have no effect + // text.shade(hCore.b, subCoreColor, false); + // text.shade(hCore.a, coreColor, false); + } + if (arg.startsWith("POS: ")) { // POS: x1 y1 x2 y2 filename + Scanner s = new Scanner(arg.substring(5)); + int x1 = s.nextInt(), y1 = s.nextInt(), x2 = s.nextInt(), y2 = s.nextInt(); + String f = s.nextLine(); + if (f.length() > 0 && f.charAt(0) == ' ') + f = f.substring(1); // Get rid of the space after Y2 + Pos p = new Pos(Util.canon(f), x1, y1, x2, y2); + + } + if (arg.startsWith("CNF: ")) { // CNF: filename + String filename = Util.canon(arg.substring(5)); + try { + String text = Util.readAll(filename); + OurDialog.showtext("Text Viewer", text); + } catch (IOException ex) { + System.err.println("Error reading the file \"" + filename + "\"\n"); + } + } + if (arg.startsWith("XML: ")) { // XML: filename + + // from SimpleGui + // VizGUI viz = new VizGUI(false, "", windowmenu2, enumerator, evaluator); + if (viz == null) + viz = new VizGUI(false, "", null, enumerator, evaluator, 2); + viz.loadXML(Util.canon(arg.substring(5)), false); + } + } + + /** This object performs solution enumeration. */ + private final Computer enumerator = new Computer() { + + @Override + public String compute(Object input) { + final String[] arg = (String[]) input; + //OurUtil.show(frame); + if (WorkerEngine.isBusy()) + throw new RuntimeException("Alloy4 is currently executing a SAT solver command. Please wait until that command has finished."); + //SimpleCallback1 cb = new SimpleCallback1(SimpleGUI.this, viz, log, VerbosityPref.get().ordinal(), latestAlloyVersionName, latestAlloyVersion); + WorkerCallback cb = getVizWorkerCallback(); + SimpleTask2 task = new SimpleTask2(); + task.filename = arg[0]; + task.index = Integer.valueOf(arg[1]); + try { + if (AlloyCore.isDebug()) + WorkerEngine.runLocally(task, cb); + else + WorkerEngine.run(task, SubMemory.get(), SubStack.get(), SimpleGUI.alloyHome(null) + fs + "binary", "", cb); + // task.run(cb); + } catch (Throwable ex) { + WorkerEngine.stop(); + System.err.println("Fatal Error: Solver failed due to unknown reason.\n" + "One possible cause is that, in the Options menu, your specified\n" + "memory size is larger than the amount allowed by your OS.\n" + "Also, please make sure \"java\" is in your program path.\n"); + //log.logBold("Fatal Error: Solver failed due to unknown reason.\n" + "One possible cause is that, in the Options menu, your specified\n" + "memory size is larger than the amount allowed by your OS.\n" + "Also, please make sure \"java\" is in your program path.\n"); + //log.logDivider(); + //log.flush(); + doStop(2); + return arg[0]; + } + /* + * subrunningTask + * = + * 2; + * runmenu + * . + * setEnabled + * ( + * false + * ) + * ; + * runbutton + * . + * setVisible + * ( + * false + * ) + * ; + * showbutton + * . + * setEnabled + * ( + * false + * ) + * ; + * stopbutton + * . + * setVisible + * ( + * true + * ) + * ; + */ + return arg[0]; + } + }; + + + /** This object performs expression evaluation. */ + private static Computer evaluator = new Computer() { + + private String filename = null; + + @Override + public final Object compute(final Object input) throws Exception { + if (input instanceof File) { + filename = ((File) input).getAbsolutePath(); + return ""; + } + if (!(input instanceof String[])) + return ""; + final String[] strs = (String[]) input; + if (strs[0].trim().length() == 0) + return ""; // Empty line + Module root = null; + A4Solution ans = null; + try { + Map fc = new LinkedHashMap(); + XMLNode x = new XMLNode(new File(filename)); + if (!x.is("alloy")) + throw new Exception(); + String mainname = null; + for (XMLNode sub : x) + if (sub.is("instance")) { + mainname = sub.getAttribute("filename"); + break; + } + if (mainname == null) + throw new Exception(); + for (XMLNode sub : x) + if (sub.is("source")) { + String name = sub.getAttribute("filename"); + String content = sub.getAttribute("content"); + fc.put(name, content); + } + root = CompUtil.parseEverything_fromFile(A4Reporter.NOP, fc, mainname, (Version.experimental && ImplicitThis.get()) ? 2 : 1); + ans = A4SolutionReader.read(root.getAllReachableSigs(), x); + for (ExprVar a : ans.getAllAtoms()) { + root.addGlobal(a.label, a); + } + for (ExprVar a : ans.getAllSkolems()) { + root.addGlobal(a.label, a); + } + } catch (Throwable ex) { + throw new ErrorFatal("Failed to read or parse the XML file."); + } + try { + Expr e = CompUtil.parseOneExpression_fromString(root, strs[0]); + if (AlloyCore.isDebug() && VerbosityPref.get() == Verbosity.FULLDEBUG) { + SimInstance simInst = SimpleGUI.convert(root, ans); + if (simInst.wasOverflow()) + return simInst.visitThis(e).toString() + " (OF)"; + } + return ans.eval(e, Integer.valueOf(strs[1])).toString(); + } catch (Exception ex) { + throw new ErrorType("Parsing ", ex); + } + } + }; + + static Pos getCurrentWordSelectionAsPos(String text, Pos pos) { + int[] sel = getCurrentWordSelection(text, pos); + pos = Pos.toPos(text, sel[0], sel[1]); + return pos; + } + + // from OurSyntaxWidget + static int[] getCurrentWordSelection(String text, Pos pos) { + + int[] startEnd = pos.toStartEnd(text); + int selectionStart = startEnd[0]; + int selectionEnd = startEnd[1]; + + if (!isValidSelection(text, selectionStart, selectionEnd)) + return null; + + while (isValidSelection(text, selectionStart - 1, selectionEnd) && inWord(text.charAt(selectionStart - 1))) + selectionStart--; + + while (isValidSelection(text, selectionStart, selectionEnd + 1) && inWord(text.charAt(selectionEnd))) + selectionEnd++; + + if (!isValidSelection(text, selectionStart, selectionEnd)) + return null; + return new int[] { + selectionStart, selectionEnd + }; + } + + // from OurSyntaxWidget + static boolean isValidSelection(String text, int start, int end) { + return start >= 0 && start <= end && end >= start && end <= text.length(); + } + + // from OurSyntaxWidget + private static boolean inWord(char c) { + return Character.isAlphabetic(c) || Character.isDigit(c) || Character.isIdentifierIgnorable(c) || Character.isJavaIdentifierPart(c) || c == '\'' || c == '"'; + } + + + private static void log(String s) { + System.err.println("thread: " + Thread.currentThread().getId() + "| " + s); + } + + + static List findAllReferences(CompModule module, Pos pos, boolean includeSelf) { + + List references = new ArrayList(); + + if (module == null) + return references; + Expr expr = module.find(pos); + if (expr == null) + return references; + Expr referencedExpr = expr.referenced() != null ? module.find(expr.referenced().pos()) : expr; + + + if (includeSelf) + references.add(referencedExpr); + module.visitExpressionsResilient(new VisitQueryOnce() { + + @Override + public boolean visited(Expr expr) { + boolean visited = super.visited(expr); + if (visited) + return visited; + + if (expr.referenced() != null && expr.referenced().pos().equals(referencedExpr.pos)) { + log("reference: " + expr.toString()); + references.add(expr); + } + return visited; + } + }); + return references; + } + + List findAllReferencesGlobally(CompModule module, Pos pos, String rootDir, boolean includeSelf, boolean continueOnError) throws Err { + + List references = new ArrayList(); + + Expr expr = module.find(pos); + + log("finding references to " + pos.toRangeString() + ", expr: " + expr); + + if (expr == null) + return references; + + if (expr.referenced() != null) + log("expr.referenced(): " + expr.referenced().toString()); + + + Pos targetPos = expr.referenced() != null ? expr.referenced().pos() : expr.pos; + log("targetPos: " + targetPos.toRangeString()); + + if (targetPos.equals(Pos.UNKNOWN)) + return references; + + if (includeSelf) + references.add(targetPos); + + for (File child : alloyFilesInDir(rootDir)) { + + String filePath = fileUriToPath(child.toURI().toString()); + try { + CompModule childModule = getCompModuleForFileUri(child.toURI().toString()); + + childModule.visitExpressionsResilient(new VisitQueryOnce() { + + @Override + public boolean visited(Expr expr) { + boolean visited = super.visited(expr); + if (visited) + return visited; + + if (expr.referenced() != null) { + Pos rpos = expr.referenced().pos(); + if (rpos.equals(targetPos)) { + log("reference: " + expr.toString() + "; to file: " + rpos.filename); + references.add(expr.pos); + } + } + return visited; + } + }); + } catch (Exception ex) { + log("exception parsing" + child.toString() + ": " + ex.toString()); + if (!continueOnError) + throw ex; + } + } + return references; + } + + static List alloyFilesInDir(String dir) { + File[] directoryListing = new File(dir).listFiles(); + return Arrays.stream(directoryListing).filter(child -> child.isFile() && (FilenameUtils.isExtension(child.getAbsolutePath(), new String[] { + "als" + }) || isAlloyMarkdownFile(child.getAbsolutePath()))).collect(Collectors.toList()); + } + + static boolean isAlloyMarkdownFile(String filename) { + if (!FilenameUtils.isExtension(filename, new String[] { + "md" + })) + return false; + + try (BufferedReader br = new BufferedReader(new FileReader(filename))) { + return "---".equals(br.readLine()); + } catch (IOException ex) { + return false; + } + } + + static boolean isAlloyFile(String filename, String contents) { + if (FilenameUtils.isExtension(filename, new String[] { + "als" + }) || (FilenameUtils.isExtension(filename, new String[] { + "md" + }) && contents.startsWith("---"))) + return true; + + return false; + } + + +} diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/CLIFacade.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/CLIFacade.java new file mode 100644 index 000000000..031b39b0d --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/CLIFacade.java @@ -0,0 +1,23 @@ +package org.alloytools.alloy.lsp.provider; + +import org.alloytools.alloy.infrastructure.api.AlloyMain; + +import aQute.lib.getopt.Arguments; +import aQute.lib.getopt.Description; +import aQute.lib.getopt.Options; + +@AlloyMain( + name = "lsp" ) +public class CLIFacade { + + @Description("Language Server for Alloy. " ) + @Arguments( + arg = "[port]" ) + interface LSPOptions extends Options { + + } + + public void _lsp(LSPOptions options) throws Exception { + AlloyLanguageServer.main(options._arguments().toArray(new String[0])); + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/Lsp4jUtil.java b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/Lsp4jUtil.java new file mode 100644 index 000000000..09280c713 --- /dev/null +++ b/org.alloytools.alloy.lsp/src/main/java/org/alloytools/alloy/lsp/provider/Lsp4jUtil.java @@ -0,0 +1,59 @@ +package org.alloytools.alloy.lsp.provider; + +import java.util.List; + +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; + +public class Lsp4jUtil { + public static PublishDiagnosticsParams newPublishDiagnosticsParams(String uri, List diagnostics) { + PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(); + diagnosticsParams.setDiagnostics(diagnostics); + diagnosticsParams.setUri(uri); + return diagnosticsParams; + } + + public static Diagnostic newDiagnostic(String message, Range range) { + Diagnostic res = new Diagnostic(); + res.setMessage(message); + res.setRange(range); + return res; + } + + public static MessageParams newMessageParams(String message, MessageType type) { + MessageParams res = new MessageParams(); + res.setMessage(message); + res.setType(type); + return res; + } + + public static Location newLocation(Range range, String uri) { + Location location = new Location(); + location.setRange(range); + location.setUri(uri); + return location; + } + + public static SymbolInformation newSymbolInformation(String name, Location location, SymbolKind kind) { + SymbolInformation symbolInfo = new SymbolInformation(); + symbolInfo.setLocation(location); + symbolInfo.setName(name); + symbolInfo.setKind(kind); + return symbolInfo; + } + + + public static int positionCompare(Position p1, Position p2){ + return p1.getLine() < p2.getLine() ? -1 : p1.getLine() > p2.getLine() ? 1 : + p1.getCharacter() < p2.getCharacter() ? -1 : + p1.getCharacter() > p2.getCharacter() ? 1 : + 0; + } +} \ No newline at end of file diff --git a/org.alloytools.alloy.lsp/src/test/java/.gitignore b/org.alloytools.alloy.lsp/src/test/java/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.resources.prefs b/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.resources.prefs index 1554c6f84..99f26c020 100644 --- a/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.resources.prefs +++ b/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.resources.prefs @@ -1,2 +1,2 @@ eclipse.preferences.version=1 -encoding/bnd.bnd=UTF-8 +encoding/=UTF-8 diff --git a/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.runtime.prefs b/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 000000000..5a0ad22d2 --- /dev/null +++ b/org.alloytools.alloy.wrappers/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.core.prefs index af07d5f5e..2f809de6d 100644 --- a/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.core.prefs +++ b/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,456 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes= +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=true +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_assignment=2 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=2 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=140 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=true +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.ui.prefs b/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..4282c280f --- /dev/null +++ b/org.alloytools.alloy.wrappers/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,131 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=false +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=false +cleanup.convert_to_enhanced_for_loop=false +cleanup.correct_indentation=false +cleanup.format_source_code=false +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=false +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=false +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_type_arguments=true +cleanup.remove_trailing_whitespaces=false +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=false +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=false +cleanup.use_this_for_non_static_field_access_only_if_necessary=true +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup.use_type_arguments=false +cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Alloy +formatter_settings_version=14 +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.javadoc=false +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/org.alloytools.api/.classpath b/org.alloytools.api/.classpath new file mode 100644 index 000000000..bcafe71e5 --- /dev/null +++ b/org.alloytools.api/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.alloytools.api/.project b/org.alloytools.api/.project new file mode 100644 index 000000000..8ad83fa6d --- /dev/null +++ b/org.alloytools.api/.project @@ -0,0 +1,23 @@ + + + org.alloytools.api + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.alloytools.api/.settings/org.eclipse.core.resources.prefs b/org.alloytools.api/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..99f26c020 --- /dev/null +++ b/org.alloytools.api/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.alloytools.api/.settings/org.eclipse.core.runtime.prefs b/org.alloytools.api/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 000000000..5a0ad22d2 --- /dev/null +++ b/org.alloytools.api/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.alloytools.api/.settings/org.eclipse.jdt.core.prefs b/org.alloytools.api/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..2f809de6d --- /dev/null +++ b/org.alloytools.api/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,456 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes= +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=4 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=true +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=51 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=50 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_assignment=2 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=2 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=51 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=2 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=2 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=2 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=2 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=50 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=2 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=2 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=140 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=true +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/org.alloytools.api/.settings/org.eclipse.jdt.ui.prefs b/org.alloytools.api/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..4282c280f --- /dev/null +++ b/org.alloytools.api/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,131 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=false +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=false +cleanup.convert_to_enhanced_for_loop=false +cleanup.correct_indentation=false +cleanup.format_source_code=false +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=false +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=false +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_type_arguments=true +cleanup.remove_trailing_whitespaces=false +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=false +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=false +cleanup.use_this_for_non_static_field_access_only_if_necessary=true +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup.use_type_arguments=false +cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Alloy +formatter_settings_version=14 +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.javadoc=false +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/org.alloytools.api/bnd.bnd b/org.alloytools.api/bnd.bnd new file mode 100644 index 000000000..da51f16cb --- /dev/null +++ b/org.alloytools.api/bnd.bnd @@ -0,0 +1,4 @@ +-includepackage *;from:=classes +-buildpath: \ + org.osgi.annotation.bundle,\ + osgi.annotation \ No newline at end of file diff --git a/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/AlloyContext.java b/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/AlloyContext.java new file mode 100644 index 000000000..8865d4286 --- /dev/null +++ b/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/AlloyContext.java @@ -0,0 +1,9 @@ +package org.alloytools.alloy.context.api; + + +public interface AlloyContext { + + boolean isDebug(); + + +} diff --git a/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/package-info.java b/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/package-info.java new file mode 100644 index 000000000..956dc28cd --- /dev/null +++ b/org.alloytools.api/src/main/java/org/alloytools/alloy/context/api/package-info.java @@ -0,0 +1,7 @@ +@Version("1.0.0" ) +@Export +package org.alloytools.alloy.context.api; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; + diff --git a/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/AlloyMain.java b/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/AlloyMain.java new file mode 100644 index 000000000..cc3f754b7 --- /dev/null +++ b/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/AlloyMain.java @@ -0,0 +1,41 @@ +package org.alloytools.alloy.infrastructure.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.osgi.annotation.bundle.Capability; + +/** + * + * @author aqute + * + */ + +@Capability( + namespace = AlloyMain.NAMESPACE, + attribute = { + AlloyMain.FQN + "=${@class}" + } ) +@Retention(RetentionPolicy.RUNTIME ) +@Target(ElementType.TYPE ) +@Repeatable(AlloyMain.AlloyMains.class ) +public @interface AlloyMain { + + @Retention(RetentionPolicy.RUNTIME ) + @Target(ElementType.TYPE ) + @interface AlloyMains { + + AlloyMain[] value(); + } + + String NAMESPACE = "alloy.main"; + String FQN = "fqn"; + + + String name(); + + boolean isDefault() default false; +} diff --git a/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/package-info.java b/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/package-info.java new file mode 100644 index 000000000..74809842f --- /dev/null +++ b/org.alloytools.api/src/main/java/org/alloytools/alloy/infrastructure/api/package-info.java @@ -0,0 +1,7 @@ +@Version("1.0.0" ) +@Export +package org.alloytools.alloy.infrastructure.api; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; + diff --git a/pbuild.sh b/pbuild.sh new file mode 100755 index 000000000..ba8291580 --- /dev/null +++ b/pbuild.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# tmp while working on grammar/parser + +# copy DashFilter.java, DashUtil.java +cd org.alloytools.alloy.dash/src/main/java/ca/uwaterloo/watform/parser +./install-alloy-files.sh +cd ../../../../../../../../ + +# build Dash.cup, Dash.lex +cd org.alloytools.alloy.dash/parser +./install-alloy-files.sh +cd ../.. + +./gradlew build \ No newline at end of file diff --git a/xt.sh b/xt.sh new file mode 100755 index 000000000..67424d702 --- /dev/null +++ b/xt.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./gradlew build -x test \ No newline at end of file