diff --git a/.gitignore b/.gitignore index 133e971bdcf8c70942e6eb5d1e807165158de17a..a8e24ffc77db3ada78d67fd26e26cf5e512ab137 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bin/ class/ test-class/ +.apt_generated/ dist/ test-bin/ */screenshots diff --git a/.travis.yml b/.travis.yml index 93f8c9148bf519f309ca183f35149a3bb853bf6e..15ba1acc6b4c9fde2d27bfe993dd0b33511df248 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: required dist: trusty language: java - jdk: oraclejdk8 + jdk: openjdk11 install: true env: diff --git a/DEVELOPING.md b/DEVELOPING.md new file mode 100644 index 0000000000000000000000000000000000000000..2eec764ce3d69169293ac446595ac2d6b0bd284e --- /dev/null +++ b/DEVELOPING.md @@ -0,0 +1,56 @@ +Development Notes +================= + +Firstly this is not complete. If this doesn't have information you need, please +engage with tlaplus contributors on Github +and add new knowledge, instructions, insights, or tips back to this document to +help the next potential contributor +(or even yourself a few months down the track once you've forgotten everything). + + +Building TLC / `tlatools.jar` +============================= + +Firstly, make sure that you're using Java 11+. +If you're using a lower version you'll see compilation errors. + +All of the commands below assume you're in the `tlatools` directory +so begin with: + +```sh +cd tlatools +``` + +To build, test, and create `tlatools.jar`: + +```sh +ant -f customBuild.xml +``` + +If you're using Linux or OSX, you can install `entr`, +then run the following to watch for and automatically recompile changes: + +```sh +find src | entr -ac ant -f customBuild.xml compile +``` + + +Building the Toolbox +==================== + +To build and test the Toolbox (well, everything really), run: + +```sh +mvn verify +``` + +On completion you'll find the toolbox distributables in `org.lamport.tla.toolbox.product.product/target/products/` + +``` +> ls -l org.lamport.tla.toolbox.product.product/target/products/ +total 475224 +drwxr-xr-x 5 golly users 4096 May 19 09:20 org.lamport.tla.toolbox.product.product +-rw-r--r-- 1 golly users 164468054 May 19 09:21 TLAToolbox-1.5.8-linux.gtk.x86_64.zip +-rw-r--r-- 1 golly users 160402860 May 19 09:21 TLAToolbox-1.5.8-macosx.cocoa.x86_64.zip +-rw-r--r-- 1 golly users 161739828 May 19 09:21 TLAToolbox-1.5.8-win32.win32.x86_64.zip +``` diff --git a/README.md b/README.md index 5e06bd854fd2f8d8993d0e1d9b65a5aa80e822f3..8e7c9b9826dca9843bc3de7a10c8bed908f6a61d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[](https://travis-ci.org/tlaplus/tlaplus) [](https://twitter.com/tlaplus) +[](https://travis-ci.org/tlaplus/tlaplus) For more information, visit https://research.microsoft.com/en-us/um/people/lamport/tla/tla.html diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000000000000000000000000000000000..8f6c7cadd20e066e539f8afbfaf2d6fde20889cb --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,65 @@ +# Maven +# Build your Java project and run tests with Apache Maven. +# Add steps that analyze code, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/java + +jobs: + +- job: Linux + timeoutInMinutes: 0 + + pool: + vmImage: 'Ubuntu-16.04' + + steps: + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m -Dmaven.test.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn' + options: '-fae -B' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + testResultsFiles: '**/surefire-reports/TEST-*.xml' + goals: 'verify' + + +- job: Windows + timeoutInMinutes: 0 + + pool: + vmImage: 'vs2017-win2016' + + steps: + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m -Dmaven.test.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn' + options: '-fae -B' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + testResultsFiles: '**/surefire-reports/TEST-*.xml' + goals: 'verify' + + +- job: Mac + timeoutInMinutes: 0 + + pool: + vmImage: 'macOS-10.13' + + steps: + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m -Dmaven.test.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn' + options: '-fae -B' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + testResultsFiles: '**/surefire-reports/TEST-*.xml' + goals: 'verify' diff --git a/examples/.project b/examples/.project deleted file mode 100644 index a906cee0cc56db32975f8b5da58a6990b2c94e65..0000000000000000000000000000000000000000 --- a/examples/.project +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>examples</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - </buildSpec> - <natures> - </natures> -</projectDescription> diff --git a/general/docs/changelogs/ch1_6_0.md b/general/docs/changelogs/ch1_6_0.md new file mode 100644 index 0000000000000000000000000000000000000000..5fa6e390fd2eb109ca4328cc1b85ebe32cac92c7 --- /dev/null +++ b/general/docs/changelogs/ch1_6_0.md @@ -0,0 +1,110 @@ +### Changelog +The high level changelog is available at http://research.microsoft.com/en-us/um/people/lamport/tla/toolbox.html#release. The [1.6.0 milestone](https://github.com/tlaplus/tlaplus/issues?q=is%3Aissue+milestone%3A1.6.0+is%3Aclosed) lists all completed issues. + +### Additional noteworthy changes + +#### TLC Profiler +* Identify bottlenecks by marking expensive expressions and actions in terms of complexity ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/TLCProfiler.mp4)) +* Implicitly fixes [Coverage result of zero included for set of variables "vars"](https://github.com/tlaplus/tlaplus/issues/152) + +#### TLC +* [Invalid violation](https://github.com/tlaplus/tlaplus/issues/201) of a liveness property because of bidirectional transitions in liveness graph due to inverse action e9ccb77b8cdaa613560d3ab9dc9582cd434d314f +* Evaluate Initial Predicate expressions ```A /\ B /\ C``` in given order instead of ```A /\ C /\ B``` eb5d554d405d891fdc98cc448184df50ee7e2e24 +* Print error message when length of a behavior exceeds ```2^15``` states on-disk or ```2^31``` in-memory 28a0117c5038bf0470841498fe8987275bc790bb +* Reduce fingerprint collision probability by [randomly selecting irreducible polynomial](https://github.com/tlaplus/tlaplus/issues/212) at TLC startup (unless set on command-line with ```fp``` parameter) +* [Correctly recreate error traces](https://github.com/tlaplus/tlaplus/issues/169) for specs using ```RandomElement``` [operator](https://github.com/tlaplus/tlaplus/blob/9dce6c7404552d70f728332c85aaa3af2aed719a/tlatools/src/tla2sany/StandardModules/TLC.tla#L80-L96) from TLC's standard module +* Expose TLC runtime statistics and control in specs ```(diameter, states, distinct states, runtime, level, exit)``` through [named registers for TLCGet and TLCSet](https://github.com/tlaplus/tlaplus/blob/9dce6c7404552d70f728332c85aaa3af2aed719a/tlatools/src/tlc2/module/TLC.java#L168-L212) 592056f265db02ba47c51ec30191b15c0203cd01 43e2b745537726bb0b4f8ad75d52cec6edd5f1d0 + * Warning: Using named registers can introduce [unintended non-determinism](https://github.com/tlaplus/tlaplus/issues/266) +* Improve readability of progress output by showing [thousands delimiters](https://github.com/tlaplus/tlaplus/pull/240) Contributor: [P. White](https://github.com/philipmw) +* Visualize SANY's semantic graph with [GraphViz](https://www.graphviz.org/): ```java -cp /path/to/tla2tools.jar tla2sany.SANY -d Spec.tla dot``` [Screenshot](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/sany-semantic-graph.jpeg) +* Indicate TLC's process id (pid) in startup banner ea70206be3be2846255a8fa6307e7e16127a9dc0 +* Inspection hatch to monitor states generated by a running TLC process: ```java -cp /path/to/tla2tools.jar tlc2.tool.management.StateMonitor [interval]``` 9ddffad5f5e1adb44195010560d85f20c4f40532 b4834400e0af29f384af1ce06da2f2a58c221492 ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/StateMonitor.gif)) +* Support suspension of (breadth-first) model checking via JMX API +* Opt-in [usage data reporting](https://usage-data.tlapl.us) +* Warn user if TLC is slowed down fa71d52e7b20cf87780b6827722dfee8ba8298b6 34c91e95a21ed34bbada509c3b210cb1cc258f59 34c91e95a21ed34bbada509c3b210cb1cc258f59 + +##### Performance & Scalability +* [Multi-Threaded Simulation Mode](https://github.com/tlaplus/tlaplus/issues/147) 83559207381b08472f1d1dcf8bb07d08a7f9b089 Contributor: [will62794](https://github.com/will62794) +* More efficiently generate the set of subsets for the TLA+ expression (SUBSET S) 4a62e5b48c9c42265cf1836de901523b4399a733 +* Reduce worker contention by separating the trace file into N partial trace files where N is the number of workers 548ce71f5856d03200b594c98b3a7f5f7a2c0591 +* Speed-up TLC shutdown by calculating 'actual fingerprint collision probability' only if 'calculated probability' exceeds ```1E-10``` f12b10e796f775c10b764b3c0afdde0bcc328620 +* Increase TLC throughput by ~10% by refactoring hot code-paths e6c8f6ce9c17e0fe72e827f9f62a2fb840743650 1bc2ab15e688e720e9b626463df008a4eaa2ca42 +* Show active fingerprint set and state queue implementation in startup banner e9745331763dba7914c95c74676d3d4d2116cd21 ea3feb5b6a4ad5f91bebe22b994f2660af024969 +* ByteArrayQueue prototype to increases throughput by reducing the critical section of the queue of unseen states 01b0e984fc58a3bb90e696a6231662a0a4368c13 + * Activate with ```-Dtlc2.tool.ModelChecker.BAQueue=true``` Java system property + +##### Command-line +* [Accept absolute spec path](https://github.com/tlaplus/tlaplus/issues/24) on command-line +* Make tlc2.TLC the main-class attribute of the tla2tools.jar fac02ee54066ecb83442d21973d01aab31f2936c + * Set executable bit for ```tla2tools.jar``` to simplify command-line on Linux: ```/path/to/tla2tools.jar /path/to/spec``` +* Command-line TLC users please always pass ```-XX:+UseParallelGC``` Java 11 flag to not [suffer performance penalty](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/Java11UseParallelGC.jpeg) + * [OpenJ9](https://www.eclipse.org/openj9/) has been [identified](https://github.com/eclipse/openj9/issues/4516) to provide worst performance in [JVM shoot-out](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/JVMVendorComparison.jpeg) +* Retire tla.zip in favor of tla2tools.jar 2da02d38a0a2c5350c90acdc2e87949c6df614ca + * TLC's [tla-bin](https://github.com/pmer/tla-bin) scripts [have been updated](https://github.com/pmer/tla-bin/issues/2) accordingly +* Exit status is now non-zero in the case of any errors or property violations [#277](https://github.com/tlaplus/tlaplus/issues/277) + + +##### CloudTLC +* Switch to [Azure service principal](https://tla.msr-inria.inria.fr/tlatoolbox/doc/cloudtlc/) authentication + * Automatically handle Azure resource deletion as part of instance termination 5be0e770e8f80f46f4afa3247bd85a1ea92da998 +* Gracefully terminate cloud resources when a CloudTLC run is terminated prematurely d593d0e4eb24ba71cf4db15c5b8ea3064afbe183 +* Power-off instead of terminate CloudTLC instances tagged ```power_off``` to speed-up subsequent restart 22a7385453497e19828642287e0b1c1d929db2ac +* Adds support for packet.net's [t1.small.x86](https://www.packet.com/cloud/servers/t1-small/) budget baremetal instances 71a253087ff8ce30a2e9b789c71dfe49197aad56 + +#### Toolbox + +##### Model Editor +* [Better visualize coverage by coloring the editor](https://github.com/tlaplus/tlaplus/issues/60) 881f2e676d9f99c329f621790d2151438448761f +* [Usability improvements to the model editor](https://github.com/tlaplus/tlaplus/issues/49) including: + * What was previously the "Advanced Options" page [has been split into two pages](https://github.com/tlaplus/tlaplus/issues/282) with the Advanced TLC Options occupying its own page now. + * Neither of these pages are visible by default, and are accessed by hyperlink on the main model page; their open-or-closed state [are saved with the model](https://github.com/tlaplus/tlaplus/issues/287) so that subsequent model openings will restore the view to the configuration last seen by the user. + * The selection of the behavior spec is now performed via pulldown, as seen in [this accompanying screencast.](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/160_model_editor_1.gif). + * The "How to run?" section of the main page has been simplified, as can be seen in the same screencast as above. Checkpoint related TLC options have been moved to the Advanced TLC Options page. A given worker, memory, and disk storage file count configuration can be saved as the default configuration to be used with new models. + * Init and Next fields of the "What is the Behavior Spec" accept [multi-line expressions](https://github.com/tlaplus/tlaplus/issues/168) + * The "How to run" and the "What to check?" sections on the main page have been given full width of the page. + * Similarly, the "State Constraint" section on the "Advance Options" page have been given full width. + * The tables in the "Statistics" section of the "Model Checking Results" page now expand to fill the width of the page, and resize their columns to consume the available width when those tables resize. + * The "General" section of the "Model Checking Results" page has been condensed to two lines. The top line, always visible, will show: + * an "Awaiting..." text for an un-executed model. + * once running, or ran, a Start time, an End time, a status, and potentially a last checkpoint time, and a mode denotation for Depth-first or Simulation runs. + * ... and the second line will be visible should their be errors in execution, information about fingerprint collision, and/or zero counts on coverage. + * The Evaluate Constant Expression section in the Results page can be moved to its own tab in the model editor via a preference checkbox in `TLA+ Preferences → TLC Model Checker`. + * The Evaluate Constant Expression now features a toggle button to more easily jump in and out of Evaluate Constant model check mode (No behavior spec selected.) + +##### TLA+ editor +* [Add a preference to disable spec file modification history footer](https://github.com/tlaplus/tlaplus/issues/157) b7c1970888d05330f2e1380898a23012c104beb1 Contributor: [C Jones](https://github.com/porglezomp) + +##### Spec Explorer +* Support deletion of [additional modules](https://github.com/tlaplus/tlaplus/issues/195) + +##### Trace Explorer +* TETrace operator to support [self-referential error trace expression](https://github.com/tlaplus/tlaplus/issues/267) + * Allows to e.g. export [error traces](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/shiviz-visualization.jpeg) to [ShiViz visualization tool](https://bitbucket.org/bestchai/shiviz) +* [Supporting naming](https://github.com/tlaplus/tlaplus/issues/265) to compose trace expressions a34ef2cbae44b2a208fe0a38b00458f1c86f4a6a ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/55184925-88734500-5150-11e9-9c1b-35a91757c21b.gif)) +* Map SANY errors back to Toolbox expression locations 9ae65abe9131abb351b28bd84d4965e8d933889b ([Screenshot](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/SanyLocation2TraceExplorerLocation.png)) +* Add [syntax highlighting and redo/undo](https://github.com/tlaplus/tlaplus/issues/264) in input boxes +* Allow [customizable fonts](https://github.com/tlaplus/tlaplus/issues/162) for the Toolbox's Error Trace viewer +* Add header button to error trace to toggle tree expansion between collapse and expand all. Shift+Click returns to default two-level expansion 864093625174fe9bc5ba73d854f772f00d45fdac ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/52dfa170dc119e5d036eb8df2e30d673240149eb.gif)) +* The edit button is enabled if the table contains one formula, regardless of whether that formula is selected; formulas are able to be drag reordered; changes (addition, editing, removal, and reordering) are now saved automatically. ([All covered by Issue #9](https://github.com/tlaplus/tlaplus/issues/9)) +* There is a button in the Error-Trace section header which allows the 'linking' of the trace viewer with the spec editor; in the same way that one could previously double-click on a trace location to reveal the section of the specification in the spec editor, while the editor is linked this action can be done by a single click, as well as by navigating with the keyboard arrow keys. ([Issue #289](https://github.com/tlaplus/tlaplus/issues/289)) + + +##### Misc +* [Bundle Java 11 with the Toolbox](https://github.com/tlaplus/tlaplus/issues/176) to free users from installing Java manually +* The Toolbox application now has its custom icon displayed for it 4c7d0d5dad54bdfc623c84277716c1c6c3abcc7e +* Show actual TLC command-line in .log file upon TLC launch 1efd390b2efcd48021f7ca863f0df6c17b7406ce +* Improve GraphViz/dot output of state graph for better compatibility with 3rd party tool [Cytoscape](http://www.cytoscape.org/) 50e83b357ff7251d42527fc2e2478bc4a179843c +* [Additional modules can be removed from a specification](https://github.com/tlaplus/tlaplus/issues/195) by right clicking and choosing "Delete"; note that this removes them from the Toolbox specification, it **does not** affect them on the filesystem. cf4e03821a677114fced1aa9a54d9d090b0e10ed +* Add [TLA+ user/discussion group](http://discuss.tlapl.us/) to Toolbox's list of [default RSS feeds](https://github.com/tlaplus/tlaplus/issues/233) +* Let Toolbox updater (p2) [reject incompatible updates](https://github.com/tlaplus/tlaplus/issues/252) (skipping releases) to not break the installation +* Add new spec and its models from a zip file (zip names has to match root module name) d5d1960505f619aa8b7499c411c7bfc054d6d3bc ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/AddNewSpecFromZip.gif)) +* Ship a set of specs as introductory examples with the Toolbox +* Sign Toolbox with official Apple certificate on macOS +* [Homebrew cask versions](https://github.com/Homebrew/homebrew-cask-versions) for [nightly Toolbox](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/tla-plus-toolbox-nightly.rb) +* Models from foreign specs (another spec which exists in the Spec Explorer) [can be cloned into the currently open spec](https://github.com/tlaplus/tlaplus/issues/211) via the `TLC Model Checker → Clone Model → Foreign Model...` menu item. + +### ++++ TLA+ conference 09/12/2019 in St. Louis, USA ++++ +Please check out the upcoming TLA+ conf at [http://conf.tlapl.us/](http://conf.tlapl.us/home) + +### A note to macOS users +Startup on macOS version 10.14 (Mojave) will fail with "TLA+ Toolbox can't be opened because Apple cannot check it for malicious software.". Please make sure to follow the instructions outlined in [GitHub issue #320](https://github.com/tlaplus/tlaplus/issues/320) to address this problem. diff --git a/general/docs/changelogs/gh-1_6_0.jq b/general/docs/changelogs/gh-1_6_0.jq new file mode 100644 index 0000000000000000000000000000000000000000..726247b01fbea81f622fcad86cfc51318310ecfc --- /dev/null +++ b/general/docs/changelogs/gh-1_6_0.jq @@ -0,0 +1,7 @@ +{ + "tag_name": "v1.6.0", + "name": "The Zenobius release", + "draft": true, + "prerelease": false, + "body": $changelog +} \ No newline at end of file diff --git a/general/docs/changelogs/readme.txt b/general/docs/changelogs/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c6fa22873fb8c341ee64685aee3a28e49f6fcc4 --- /dev/null +++ b/general/docs/changelogs/readme.txt @@ -0,0 +1,34 @@ +The script below shows how the .jq and .md files are combined and turned into +a GitHub release. A copy of this script is executed by our build machine when +a release build has been manually approved. In an ideal world, this would be +integrated into the maven build but it is probably not worth it. + +----------------- + +#!/bin/bash + +cd $WORKSPACE/general/docs/changelogs + +## Convert the Markdown changelog into a single JSON string. +#cat ch1_5_8.md | jq --raw-input --slurp . > ch1_5_8.json + +## Read the converted markdown into the Github release JSON template +#jq -n --argjson changelog "$(cat ch1_5_8.json)" -f gh-1_5_8.jq > gh-1_5_8.json + +## Two above as one-liner without intermediate file. +$(jq -n --argjson changelog "$(cat ch1_5_8.md | jq --raw-input --slurp .)" -f gh-1_5_8.jq > gh-1_5_8.json) + +## Post the new release to Github and read the release ID from the response. +#DRAFT_RELEAES=$(curl -sS -H "Authorization: token 123456790" https://api.github.com/repos/tlaplus/tlaplus/releases -d @gh-1_5_8.json -X POST --header "Content-Type: application/json" | jq '.| select(.draft==true and .name=="The Zenobius release") | .id') + +## Get id of existing draft release with given name. +DRAFT_RELEASE=$(curl -sS -H "Authorization: token 1234567890" https://api.github.com/repos/tlaplus/tlaplus/releases --header "Content-Type: application/json" | jq '.[]| select(.draft==true and .name=="The Zenobius release") | .id') +echo $DRAFT_RELEASE + +## Update draft release with latest changelog in case it changed. +## https://developer.github.com/v3/repos/releases/#edit-a-release +curl -sS -H "Authorization: token 1234567890" https://api.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE -d @gh-1_5_8.json -X PATCH --header "Content-Type: application/json" + +## iterate over zips and tla2tools.jar and upload to release (reverse order for TLA* to show up first). +cd /home/jenkins/jobs/Release-HEAD-Toolbox.product.standalone/configurations/axis-os/master/lastStable/archive +for f in $(find . \( -name "*.zip" -o -name "tla2tools.jar" \) | tac); do BASE=$(basename $f) && curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token 1234567890" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=$BASE --upload-file $f; done diff --git a/general/docs/changelogs/screencasts/160_model_editor_1.gif b/general/docs/changelogs/screencasts/160_model_editor_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..b465cafcbd5ba01a9da2dcb49afeb262d41cb701 Binary files /dev/null and b/general/docs/changelogs/screencasts/160_model_editor_1.gif differ diff --git a/general/docs/changelogs/screencasts/52dfa170dc119e5d036eb8df2e30d673240149eb.gif b/general/docs/changelogs/screencasts/52dfa170dc119e5d036eb8df2e30d673240149eb.gif new file mode 100644 index 0000000000000000000000000000000000000000..495c875267b60f0c23f5580f3c6720c9c562f809 Binary files /dev/null and b/general/docs/changelogs/screencasts/52dfa170dc119e5d036eb8df2e30d673240149eb.gif differ diff --git a/general/docs/changelogs/screencasts/55184925-88734500-5150-11e9-9c1b-35a91757c21b.gif b/general/docs/changelogs/screencasts/55184925-88734500-5150-11e9-9c1b-35a91757c21b.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad7f0dba0b7fa7f7a163e300602e0ad6887616fd Binary files /dev/null and b/general/docs/changelogs/screencasts/55184925-88734500-5150-11e9-9c1b-35a91757c21b.gif differ diff --git a/general/docs/changelogs/screencasts/AddNewSpecFromZip.gif b/general/docs/changelogs/screencasts/AddNewSpecFromZip.gif new file mode 100644 index 0000000000000000000000000000000000000000..fff83ca24734be38a39eb7d223b6275050364076 Binary files /dev/null and b/general/docs/changelogs/screencasts/AddNewSpecFromZip.gif differ diff --git a/general/docs/changelogs/screencasts/JVMVendorComparison.jpeg b/general/docs/changelogs/screencasts/JVMVendorComparison.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4b32ff5302ecf24a1a0d55212aa6158460092e86 Binary files /dev/null and b/general/docs/changelogs/screencasts/JVMVendorComparison.jpeg differ diff --git a/general/docs/changelogs/screencasts/Java11UseParallelGC.jpeg b/general/docs/changelogs/screencasts/Java11UseParallelGC.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..93543ab56e709d695f6f8913ec3a306ce1d09ca2 Binary files /dev/null and b/general/docs/changelogs/screencasts/Java11UseParallelGC.jpeg differ diff --git a/general/docs/changelogs/screencasts/SanyLocation2TraceExplorerLocation.png b/general/docs/changelogs/screencasts/SanyLocation2TraceExplorerLocation.png new file mode 100644 index 0000000000000000000000000000000000000000..351c47728999099474b795db1d87efcb10375e27 Binary files /dev/null and b/general/docs/changelogs/screencasts/SanyLocation2TraceExplorerLocation.png differ diff --git a/general/docs/changelogs/screencasts/StateMonitor.gif b/general/docs/changelogs/screencasts/StateMonitor.gif new file mode 100644 index 0000000000000000000000000000000000000000..ac6c29f6b8ad50daf84a5f36818d9efb8a3895ed Binary files /dev/null and b/general/docs/changelogs/screencasts/StateMonitor.gif differ diff --git a/general/docs/changelogs/screencasts/TLCProfiler.mp4 b/general/docs/changelogs/screencasts/TLCProfiler.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..13e1c92579c25fc50135dc48ef586183be48f9ad Binary files /dev/null and b/general/docs/changelogs/screencasts/TLCProfiler.mp4 differ diff --git a/general/docs/changelogs/screencasts/sany-semantic-graph.jpeg b/general/docs/changelogs/screencasts/sany-semantic-graph.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..380b1829ed0368cb88eee222993718156da2bdae Binary files /dev/null and b/general/docs/changelogs/screencasts/sany-semantic-graph.jpeg differ diff --git a/general/docs/changelogs/screencasts/shiviz-visualization.jpeg b/general/docs/changelogs/screencasts/shiviz-visualization.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..755873a966a03da1dbb5121b6f64cf1bf43ac157 Binary files /dev/null and b/general/docs/changelogs/screencasts/shiviz-visualization.jpeg differ diff --git a/general/docs/contributions.md b/general/docs/contributions.md index 38a438978a1f9f8d9db9447f1997b410bfeaba0a..e8e5adfc1a8dd28ea1874c774a3cee440b614702 100644 --- a/general/docs/contributions.md +++ b/general/docs/contributions.md @@ -5,7 +5,7 @@ Please also consult the [issues tracker](https://github.com/tlaplus/tlaplus/issu TLC model checker ----------------- -#### Concurrent search for strongly connected components (difficulty: high) (skills: Java, TLA+) +#### ([In Progress](https://bitbucket.org/parvmor/tarjanconcurrentscc/)) Concurrent search for strongly connected components (difficulty: high) (skills: Java, TLA+) One part of TLC's procedure to check liveness properties, is to find the liveness graph's [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) (SCC). TLC's implementation uses [Tarjan's](https://en.wikipedia.org/wiki/Strongly_connected_component) canonical solution to this problem. Tarjan's algorithm is a sequential algorithm that runs in linear time. While the time complexity is acceptable, its sequential nature causes TLC's liveness checking not to scale. Recently, concurrent variants of the algorithm have been proposed and studied in the scope of other model checkers ([Multi-Core On-The-Fly SCC Decomposition](https://github.com/utwente-fmt/ppopp16) & [Concurrent On-the-Fly SCC Detection for Automata-Based Model Checking with Fairness Assumption](http://ieeexplore.ieee.org/document/7816578/)). This work will require writing a TLA+ specification and ideally a formal proof of the algorithm's correctness. #### Liveness checking under symmetry (difficulty: high) (skills: Java, TLA+) diff --git a/general/docs/java-toolbox-installation.md b/general/docs/java-toolbox-installation.md new file mode 100644 index 0000000000000000000000000000000000000000..eed43d7ff1546cfb7ea2ac5a342d964ca9ec2b2e --- /dev/null +++ b/general/docs/java-toolbox-installation.md @@ -0,0 +1,13 @@ +### TLA Tools and Toolbox and the 2019 Oracle change of license + +Oracle's [January 2019 license update](https://www.java.com/en/download/release_notice.jsp) for Oracle Java SE effectively means that Oracle Java SE will not be available for business, commercial or production use without a commercial license (see e.g. [Jetbrain's announcement](https://blog.jetbrains.com/idea/2018/09/using-java-11-in-production-important-things-to-know/) for background information). Thus, all affected TLA+ users that do not purchase a license from Oracle will have to switch to an alternative Java distribution such as [Zulu](https://www.azul.com/downloads/zulu/), [Amazon](https://aws.amazon.com/corretto/), [RedHat](), [OpenJDK](http://jdk.java.net/), [AdoptOpenJDK](https://adoptopenjdk.net/)... (see [Stephen Colebourne's blog post](https://blog.joda.org/2018/09/time-to-look-beyond-oracles-jdk.html) for details). + +### AdoptOpenJDK + +At the time of writing, the best choice is the [OpenJDK 8 (LTS) Hotspot](https://adoptopenjdk.net/releases.html) JRE distributions which is available for [Windows](https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u192-b12/OpenJDK8U-jre_x64_windows_hotspot_8u192b12.zip), [macOS](https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u192-b12/OpenJDK8U-jre_x64_mac_hotspot_8u192b12.tar.gz), and [Linux](https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u192-b12/OpenJDK8U-jre_x64_linux_hotspot_8u192b12.tar.gz). + + + +The TLA+ project has retroactively checked compatibility of its [1.5.7 Toolbox release](https://github.com/tlaplus/tlaplus/releases/tag/v1.5.7) and will immediately shift testing of future releases to run on the AdoptOpenJDK distribution. Additionally, [issue #176](https://github.com/tlaplus/tlaplus/issues/176) lays out the plan to include Java in future Toolbox releases to free TLA+ users from manually installing Java. Until then please manually download the AdoptOpenJDK distribution. Afterwards extract the downloaded AdoptOpenJDK zip file into a newly created ```jre/``` folder under Toolbox's ```toolbox``` directory. The Toolbox will automatically run with the AdoptOpenJDK distribution. The [screencast](https://www.youtube.com/watch?v=TBjVTOy_rcE) below outlines all steps from downloading, installing to running the Toolbox with AdoptOpenJDK. + +[](https://www.youtube.com/watch?v=TBjVTOy_rcE) diff --git a/general/ide/README.md b/general/ide/README.md index 62b103e25fcc569639bd1751a7006e80d95cb5df..bb1e1dcbc520cb8af927cc66819f7d70c534d69c 100644 --- a/general/ide/README.md +++ b/general/ide/README.md @@ -2,12 +2,12 @@ Eclipse Oomph is a tool to simplify and automate the setup of Eclipse developmen [A screencast is available that captures the written instructions below.](https://vimeo.com/190224035) -0. Requires a recent - at the time of writing this is 1.8 - JDK (Java Development Environment) +0. Requires a recent - at the time of writing this is 11 - JDK (Java Development Environment) - OpenJDK is recommended. 1. Install the Oomph Eclipse installer from https://wiki.eclipse.org/Eclipse_Installer 2. Start the downloaded Oomph installer 3. Switch to "Advanced Mode" by clicking the button in the right upper corner depicted with three horizontal lines 4. Select "Eclipse Platform" on the Product list (expand "Eclipse.org" node) - 1. Choose "Oxygen" as the product version at the bottom  + 1. Choose "2018-12" as the product version at the bottom  5. On the next screen, expand "Github Project" in the tree and select the check-box left to "TLA+" 1. Verify that "TLA+" shows up under "Project" at the bottom table and that the "Master" stream is selected  6. On the next page, select whether to use anonymous Github access (read-only) from the "TLA+ Github Repository" dropdown list  diff --git a/general/ide/TLA.setup b/general/ide/TLA.setup index 9b003e053c2d464fff36756e040be9d96d5315c3..0174e1d053971b46bd1a86e984c9a774c0b2542c 100644 --- a/general/ide/TLA.setup +++ b/general/ide/TLA.setup @@ -17,8 +17,8 @@ label="TLA+"> <setupTask xsi:type="jdt:JRETask" - version="JavaSE-1.8" - location="${jre.location-1.8}"> + version="JavaSE-11" + location="${jre.location-11}"> <description>Define the JRE needed to compile and run the Java projects of ${scope.project.label}</description> </setupTask> <setupTask @@ -52,7 +52,7 @@ <setupTask xsi:type="setup:VariableTask" name="eclipse.target.platform" - defaultValue="Mars" + defaultValue="2018-09" storageURI="scope://Workspace"/> <setupTask xsi:type="setup.p2:P2Task"> @@ -69,8 +69,14 @@ name="org.eclipse.pde.feature.group"/> <requirement name="org.eclipse.egit.feature.group"/> + <requirement + name="org.eclipse.e4.tools.spies.feature.feature.group"/> <requirement name="com.abstratt.eclipsegraphviz.feature.feature.group"/> + <requirement + name="org.eclipse.rcptt.platform.feature.group"/> + <requirement + name="de.loskutov.BytecodeOutline.feature.feature.group"/> <repository url="http://download.eclipse.org/technology/swtbot/releases/latest/"/> <repository @@ -78,7 +84,13 @@ <repository url="http://download.eclipse.org/technology/m2e/releases/"/> <repository - url="jar:http://repository-textuml.forge.cloudbees.com/snapshot/com/abstratt/mdd/com.abstratt.mdd.oss.repository/2.1/com.abstratt.mdd.oss.repository-2.1.zip!/"/> + url="http://download.eclipse.org/e4/snapshots/org.eclipse.e4.tools/latest/"/> + <repository + url="jar:https://dl.bintray.com/abstratt-oss/abstratt-oss/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.5.201812/com.abstratt.eclipsegraphviz.repository-2.5.201812.zip!/"/> + <repository + url="https://download.eclipse.org/rcptt/release/2.4.1/repository/"/> + <repository + url="http://andrei.gmxhome.de/eclipse/"/> <description>Install the tools needed in the IDE to work with the source code for ${scope.project.label}</description> </setupTask> <setupTask diff --git a/general/performance/Bloemen/BloemenSCC.tla b/general/performance/Bloemen/BloemenSCC.tla new file mode 100644 index 0000000000000000000000000000000000000000..b09e4d85be8b3f676f1050c446047a09e078882b --- /dev/null +++ b/general/performance/Bloemen/BloemenSCC.tla @@ -0,0 +1,557 @@ +------------------------------- MODULE BloemenSCC ------------------------------ +(** + Multi-core on-the-fly SCC decomposition + Vincent Bloemen, Alfons Laarman, Jaco van de Pol + doi: 10.1145/2851141.2851161 + https://dl.acm.org/citation.cfm?id=2851161 + + Spec author: Parv Mor (https://github.com/parvmor) +**) +EXTENDS Integers, Sequences, TLC + +CONSTANTS Nodes, Edges, Threads +ASSUME Edges \subseteq Nodes \X Nodes + +\* The set of edges that are outgoing from the node. +OutgoingEdges(node) == + { e \in Edges : e[1] = node } + +(******* +\* The algorith maintains partially computed SCCs using union find +\* data structure. Each set a has a representative node (root). +\* The root contains all threads processing any node in the set. +\* Also a set of live elements is maintained for every set which can +\* be used to keep track of all nodes that are not dead. +--algorithm BloemenSCC { + \* Shared variables of the algorithm + \* 1) ufStatus : Denotes the status of a set. Can be either + \* uf-live or uf-dead. + \* 2) parent : Used to find root of a set from a node in the set. + \* 3) workerSet : Keeps track of all threads processing a node in set. + \* 4) liveElements : Set of all live elements in a set. + variables ufStatus = [node \in Nodes |-> "uf-live"], + parent = [node \in Nodes |-> node], + workerSet = [node \in Nodes |-> {}], + liveElements = [node \in Nodes |-> {node}] + + define { + \* Find the root/representative of the set. + find(node) == + LET RECURSIVE PF(_) + PF(x) == IF parent[x] = x THEN x + ELSE PF(parent[x]) + IN PF(node) + \* Find if x and y are in the same set. + sameSet(x, y) == find(x) = find(y) + + \* Checks if a node in the set is dead. + isDead(node) == ufStatus[find(node)] = "uf-dead" + \* Set of all nodes in set of x. + ufSet(x) == { node \in Nodes : sameSet(node, x) } + + \* Set of all nodes whose set is not dead. + undeadNodes == { node \in Nodes : ufStatus[find(node)] # "uf-dead" } + } + + \* push x onto the stack. + macro push(x, stack) { + stack := << x >> \o stack; + } + + \* pop an element from the stack. + macro pop(stack) { + stack := Tail(stack); + } + + \* makeClaim decides what a thread should do + \* with a newly discovered node. + \* Post macro results are: + \* 1) claim-dead : The set of node is dead and + \* hence no point in processing it. + \* 2) claim-found : The thread has previously discovered this set + \* and hence a cycle is found. + \* 3) claim-success : The node/node's set is new to the thread and + \* do a search on this node. + macro makeClaim(node) { + root := find(node); + if (isDead(root)) { + claimed := "claim-dead"; + } else { + if (self \in workerSet[root]) { + claimed := "claim-found"; + } else { + workerSet[root] := workerSet[root] \cup {self}; + claimed := "claim-success"; + } + } + } + + \* The node has been completely explored by a thread. + \* So remove it from set of live elements. + macro remove(node) { + root := find(node); + if (node \in liveElements[root]) { + liveElements[root] := liveElements[root] \ {node}; + } + } + + \* Picks a live node from the set of given node. + \* If no node found then declare the set as dead. + macro pickFromSet(node) { + root := find(node); + if (liveElements[root] = {}) { + ufStatus[root] := "uf-dead"; + } else { + with (node \in liveElements[root]) { + vp := node; + } + } + } + + \* Merge the sets of a and b along with + \* the worker sets and live elements. + procedure unite(a, b) + variables ra, rb { + label13: + ra := find(a) || rb := find(b); + if (ra # rb) { + parent[ra] := rb || + workerSet[rb] := workerSet[rb] \cup workerSet[ra] || + liveElements[rb] := liveElements[rb] \cup liveElements[ra]; + }; + label15: + return; + } + + fair process (T \in Threads) + \* Local variables of the thread. + \* 1) recursionStack : Simulates recursion. + \* 2) rootStack : Simulates the stack from Naive Tarjan algorithm. + \* 3) edgesUnexplored : Map from nodes to set of unexplored edges by this thread. + variables recursionStack = << >>, + rootStack = << >>, + backtrack = FALSE, + v = CHOOSE node \in Nodes : TRUE, + w = v, vp = v, root = v, + edgesUnexplored = [node \in Nodes |-> OutgoingEdges(node)], + claimed = "claim-dead"; + { + label1: + \* Pick an unexplored node here. + while (undeadNodes # {}) { + with (node \in undeadNodes) { + v := node; + }; + makeClaim(v); + + label2: + \* Start a new DFS call if we are not backtracking + if (backtrack = FALSE) { + push(v, rootStack); + }; + + label3: + if (backtrack = FALSE) { + label4: + \* The new and old root might be in same set. + if (Len(recursionStack) # 0 /\ sameSet(Head(recursionStack)[2], v)) { + goto label6; + } else { + \* Obtain a live element from set of v. + \* If not able to pick then set is dead. + \* Else found a new element to start exploring it. + pickFromSet(v); + if (isDead(v)) { + goto label6; + } + } + } else { + label5: + \* Restore the state back while backtracking. + vp := Head(recursionStack)[1] || v := Head(recursionStack)[2]; + pop(recursionStack); + backtrack := FALSE; + label7: + \* Check if the set is dead. + if (isDead(v)) { + remove(vp); + goto label3; + } + }; + + label8: + while (edgesUnexplored[vp] # {}) { + with (edge \in edgesUnexplored[vp]) { + edgesUnexplored[vp] := edgesUnexplored[vp] \ {edge}; + w := edge[2]; + }; + + \* Self loop found + label10: + if (w = vp) { + goto label8; + } else { + \* Decide what to do with node w. + makeClaim(w); + if (claimed = "claim-dead") { + goto label8; + } else if (claimed = "claim-success") { + push(<< vp, v >>, recursionStack); + v := w; + goto label2; + } else { + \* claim-found and hence unite nodes in the cycle. + label11: + if (sameSet(w, v) = FALSE) { + root := Head(rootStack); + pop(rootStack); + call unite(Head(rootStack), root); + label16: + goto label11; + } + }; + + label14: + goto label8; + } + }; + + label12: + \* Node vp is processed and hence can be removed from live elements. + remove(vp); + goto label3; + + label6: + if (Head(rootStack) = v) { + pop(rootStack); + }; + + if (Len(recursionStack) # 0) { + backtrack := TRUE; + goto label2; + }; + }; + } +} +******) + +\* BEGIN TRANSLATION +CONSTANT defaultInitValue +VARIABLES ufStatus, parent, workerSet, liveElements, pc, stack + +(* define statement *) +find(node) == + LET RECURSIVE PF(_) + PF(x) == IF parent[x] = x THEN x + ELSE PF(parent[x]) + IN PF(node) + +sameSet(x, y) == find(x) = find(y) + + +isDead(node) == ufStatus[find(node)] = "uf-dead" + +ufSet(x) == { node \in Nodes : sameSet(node, x) } + + +undeadNodes == { node \in Nodes : ufStatus[find(node)] # "uf-dead" } + +VARIABLES a, b, ra, rb, recursionStack, rootStack, backtrack, v, w, vp, root, + edgesUnexplored, claimed + +vars == << ufStatus, parent, workerSet, liveElements, pc, stack, a, b, ra, rb, + recursionStack, rootStack, backtrack, v, w, vp, root, + edgesUnexplored, claimed >> + +ProcSet == (Threads) + +Init == (* Global variables *) + /\ ufStatus = [node \in Nodes |-> "uf-live"] + /\ parent = [node \in Nodes |-> node] + /\ workerSet = [node \in Nodes |-> {}] + /\ liveElements = [node \in Nodes |-> {node}] + (* Procedure unite *) + /\ a = [ self \in ProcSet |-> defaultInitValue] + /\ b = [ self \in ProcSet |-> defaultInitValue] + /\ ra = [ self \in ProcSet |-> defaultInitValue] + /\ rb = [ self \in ProcSet |-> defaultInitValue] + (* Process T *) + /\ recursionStack = [self \in Threads |-> << >>] + /\ rootStack = [self \in Threads |-> << >>] + /\ backtrack = [self \in Threads |-> FALSE] + /\ v = [self \in Threads |-> CHOOSE node \in Nodes : TRUE] + /\ w = [self \in Threads |-> v[self]] + /\ vp = [self \in Threads |-> v[self]] + /\ root = [self \in Threads |-> v[self]] + /\ edgesUnexplored = [self \in Threads |-> [node \in Nodes |-> OutgoingEdges(node)]] + /\ claimed = [self \in Threads |-> "claim-dead"] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> "label1"] + +label13(self) == /\ pc[self] = "label13" + /\ /\ ra' = [ra EXCEPT ![self] = find(a[self])] + /\ rb' = [rb EXCEPT ![self] = find(b[self])] + /\ IF ra'[self] # rb'[self] + THEN /\ /\ liveElements' = [liveElements EXCEPT ![rb'[self]] = liveElements[rb'[self]] \cup liveElements[ra'[self]]] + /\ parent' = [parent EXCEPT ![ra'[self]] = rb'[self]] + /\ workerSet' = [workerSet EXCEPT ![rb'[self]] = workerSet[rb'[self]] \cup workerSet[ra'[self]]] + ELSE /\ TRUE + /\ UNCHANGED << parent, workerSet, liveElements >> + /\ pc' = [pc EXCEPT ![self] = "label15"] + /\ UNCHANGED << ufStatus, stack, a, b, recursionStack, + rootStack, backtrack, v, w, vp, root, + edgesUnexplored, claimed >> + +label15(self) == /\ pc[self] = "label15" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ ra' = [ra EXCEPT ![self] = Head(stack[self]).ra] + /\ rb' = [rb EXCEPT ![self] = Head(stack[self]).rb] + /\ a' = [a EXCEPT ![self] = Head(stack[self]).a] + /\ b' = [b EXCEPT ![self] = Head(stack[self]).b] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + recursionStack, rootStack, backtrack, v, w, + vp, root, edgesUnexplored, claimed >> + +unite(self) == label13(self) \/ label15(self) + +label1(self) == /\ pc[self] = "label1" + /\ IF undeadNodes # {} + THEN /\ \E node \in undeadNodes: + v' = [v EXCEPT ![self] = node] + /\ root' = [root EXCEPT ![self] = find(v'[self])] + /\ IF isDead(root'[self]) + THEN /\ claimed' = [claimed EXCEPT ![self] = "claim-dead"] + /\ UNCHANGED workerSet + ELSE /\ IF self \in workerSet[root'[self]] + THEN /\ claimed' = [claimed EXCEPT ![self] = "claim-found"] + /\ UNCHANGED workerSet + ELSE /\ workerSet' = [workerSet EXCEPT ![root'[self]] = workerSet[root'[self]] \cup {self}] + /\ claimed' = [claimed EXCEPT ![self] = "claim-success"] + /\ pc' = [pc EXCEPT ![self] = "label2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << workerSet, v, root, claimed >> + /\ UNCHANGED << ufStatus, parent, liveElements, stack, a, b, + ra, rb, recursionStack, rootStack, backtrack, + w, vp, edgesUnexplored >> + +label2(self) == /\ pc[self] = "label2" + /\ IF backtrack[self] = FALSE + THEN /\ rootStack' = [rootStack EXCEPT ![self] = << v[self] >> \o rootStack[self]] + ELSE /\ TRUE + /\ UNCHANGED rootStack + /\ pc' = [pc EXCEPT ![self] = "label3"] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, backtrack, + v, w, vp, root, edgesUnexplored, claimed >> + +label3(self) == /\ pc[self] = "label3" + /\ IF backtrack[self] = FALSE + THEN /\ pc' = [pc EXCEPT ![self] = "label4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label5"] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, rootStack, + backtrack, v, w, vp, root, edgesUnexplored, + claimed >> + +label4(self) == /\ pc[self] = "label4" + /\ IF Len(recursionStack[self]) # 0 /\ sameSet(Head(recursionStack[self])[2], v[self]) + THEN /\ pc' = [pc EXCEPT ![self] = "label6"] + /\ UNCHANGED << ufStatus, vp, root >> + ELSE /\ root' = [root EXCEPT ![self] = find(v[self])] + /\ IF liveElements[root'[self]] = {} + THEN /\ ufStatus' = [ufStatus EXCEPT ![root'[self]] = "uf-dead"] + /\ vp' = vp + ELSE /\ \E node \in liveElements[root'[self]]: + vp' = [vp EXCEPT ![self] = v[self]] + /\ UNCHANGED ufStatus + /\ IF isDead(v[self]) + THEN /\ pc' = [pc EXCEPT ![self] = "label6"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label8"] + /\ UNCHANGED << parent, workerSet, liveElements, stack, a, b, + ra, rb, recursionStack, rootStack, backtrack, + v, w, edgesUnexplored, claimed >> + +label5(self) == /\ pc[self] = "label5" + /\ /\ v' = [v EXCEPT ![self] = Head(recursionStack[self])[2]] + /\ vp' = [vp EXCEPT ![self] = Head(recursionStack[self])[1]] + /\ recursionStack' = [recursionStack EXCEPT ![self] = Tail(recursionStack[self])] + /\ backtrack' = [backtrack EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "label7"] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, rootStack, w, root, + edgesUnexplored, claimed >> + +label7(self) == /\ pc[self] = "label7" + /\ IF isDead(v[self]) + THEN /\ root' = [root EXCEPT ![self] = find(vp[self])] + /\ IF vp[self] \in liveElements[root'[self]] + THEN /\ liveElements' = [liveElements EXCEPT ![root'[self]] = liveElements[root'[self]] \ {vp[self]}] + ELSE /\ TRUE + /\ UNCHANGED liveElements + /\ pc' = [pc EXCEPT ![self] = "label3"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label8"] + /\ UNCHANGED << liveElements, root >> + /\ UNCHANGED << ufStatus, parent, workerSet, stack, a, b, ra, + rb, recursionStack, rootStack, backtrack, v, w, + vp, edgesUnexplored, claimed >> + +label8(self) == /\ pc[self] = "label8" + /\ IF edgesUnexplored[self][vp[self]] # {} + THEN /\ \E edge \in edgesUnexplored[self][vp[self]]: + /\ edgesUnexplored' = [edgesUnexplored EXCEPT ![self][vp[self]] = edgesUnexplored[self][vp[self]] \ {edge}] + /\ w' = [w EXCEPT ![self] = edge[2]] + /\ pc' = [pc EXCEPT ![self] = "label10"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label12"] + /\ UNCHANGED << w, edgesUnexplored >> + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, rootStack, + backtrack, v, vp, root, claimed >> + +label10(self) == /\ pc[self] = "label10" + /\ IF w[self] = vp[self] + THEN /\ pc' = [pc EXCEPT ![self] = "label8"] + /\ UNCHANGED << workerSet, recursionStack, v, root, + claimed >> + ELSE /\ root' = [root EXCEPT ![self] = find(w[self])] + /\ IF isDead(root'[self]) + THEN /\ claimed' = [claimed EXCEPT ![self] = "claim-dead"] + /\ UNCHANGED workerSet + ELSE /\ IF self \in workerSet[root'[self]] + THEN /\ claimed' = [claimed EXCEPT ![self] = "claim-found"] + /\ UNCHANGED workerSet + ELSE /\ workerSet' = [workerSet EXCEPT ![root'[self]] = workerSet[root'[self]] \cup {self}] + /\ claimed' = [claimed EXCEPT ![self] = "claim-success"] + /\ IF claimed'[self] = "claim-dead" + THEN /\ pc' = [pc EXCEPT ![self] = "label8"] + /\ UNCHANGED << recursionStack, v >> + ELSE /\ IF claimed'[self] = "claim-success" + THEN /\ recursionStack' = [recursionStack EXCEPT ![self] = << (<< vp[self], v[self] >>) >> \o recursionStack[self]] + /\ v' = [v EXCEPT ![self] = w[self]] + /\ pc' = [pc EXCEPT ![self] = "label2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label11"] + /\ UNCHANGED << recursionStack, + v >> + /\ UNCHANGED << ufStatus, parent, liveElements, stack, a, b, + ra, rb, rootStack, backtrack, w, vp, + edgesUnexplored >> + +label14(self) == /\ pc[self] = "label14" + /\ pc' = [pc EXCEPT ![self] = "label8"] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, + rootStack, backtrack, v, w, vp, root, + edgesUnexplored, claimed >> + +label11(self) == /\ pc[self] = "label11" + /\ IF sameSet(w[self], v[self]) = FALSE + THEN /\ root' = [root EXCEPT ![self] = Head(rootStack[self])] + /\ rootStack' = [rootStack EXCEPT ![self] = Tail(rootStack[self])] + /\ /\ a' = [a EXCEPT ![self] = Head(rootStack'[self])] + /\ b' = [b EXCEPT ![self] = root'[self]] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "unite", + pc |-> "label16", + ra |-> ra[self], + rb |-> rb[self], + a |-> a[self], + b |-> b[self] ] >> + \o stack[self]] + /\ ra' = [ra EXCEPT ![self] = defaultInitValue] + /\ rb' = [rb EXCEPT ![self] = defaultInitValue] + /\ pc' = [pc EXCEPT ![self] = "label13"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label14"] + /\ UNCHANGED << stack, a, b, ra, rb, rootStack, + root >> + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + recursionStack, backtrack, v, w, vp, + edgesUnexplored, claimed >> + +label16(self) == /\ pc[self] = "label16" + /\ pc' = [pc EXCEPT ![self] = "label11"] + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, + rootStack, backtrack, v, w, vp, root, + edgesUnexplored, claimed >> + +label12(self) == /\ pc[self] = "label12" + /\ root' = [root EXCEPT ![self] = find(vp[self])] + /\ IF vp[self] \in liveElements[root'[self]] + THEN /\ liveElements' = [liveElements EXCEPT ![root'[self]] = liveElements[root'[self]] \ {vp[self]}] + ELSE /\ TRUE + /\ UNCHANGED liveElements + /\ pc' = [pc EXCEPT ![self] = "label3"] + /\ UNCHANGED << ufStatus, parent, workerSet, stack, a, b, ra, + rb, recursionStack, rootStack, backtrack, v, + w, vp, edgesUnexplored, claimed >> + +label6(self) == /\ pc[self] = "label6" + /\ IF Head(rootStack[self]) = v[self] + THEN /\ rootStack' = [rootStack EXCEPT ![self] = Tail(rootStack[self])] + ELSE /\ TRUE + /\ UNCHANGED rootStack + /\ IF Len(recursionStack[self]) # 0 + THEN /\ backtrack' = [backtrack EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "label2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "label1"] + /\ UNCHANGED backtrack + /\ UNCHANGED << ufStatus, parent, workerSet, liveElements, + stack, a, b, ra, rb, recursionStack, v, w, vp, + root, edgesUnexplored, claimed >> + +T(self) == label1(self) \/ label2(self) \/ label3(self) \/ label4(self) + \/ label5(self) \/ label7(self) \/ label8(self) + \/ label10(self) \/ label14(self) \/ label11(self) + \/ label16(self) \/ label12(self) \/ label6(self) + +Next == (\E self \in ProcSet: unite(self)) + \/ (\E self \in Threads: T(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in Threads : WF_vars(T(self)) /\ WF_vars(unite(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +\* Set of SCCs found by the pluscal algorithm. +SCCsFromAlgo == { ufSet(node) : node \in Nodes } + +\* SCCs by definition + +\* Set of outgoing nodes from given set S via an edge. +\* Excludes the nodes from S. +OutgoingNodes(S) == + UNION { { y \in Nodes \ S : << x, y >> \in Edges } : x \in S } + +\* Denotes whether x is reachable from y. +\* Defined recursively using a BFS approach. +Reachable(x, y) == + LET RECURSIVE RF(_) + RF(S) == LET NS == OutgoingNodes(S) + IN IF y \in S THEN TRUE + ELSE IF NS = {} THEN FALSE + ELSE RF(S \cup NS) + IN RF({x}) + +\* Set of SCCs of the graph generated by the definition of SCCs. +SCCsByDef == + LET RECURSIVE M(_, _) + M(Partial, Rest) == + IF Rest = {} THEN Partial + ELSE LET x == CHOOSE x \in Rest : TRUE + C == {y \in Rest : /\ Reachable(x, y) + /\ Reachable(y, x)} + IN M(Partial \cup{C}, Rest \ C) + IN M({}, Nodes) + +\* Algorithm terminates iff program counter is every thread is Done. +Terminated == \A self \in ProcSet: pc[self] = "Done" +\* A safety property of the algorithm that establishes the correctness. +\* Note that this does not gaurantees termination. +\* For termination we need to check a liveness property: +\* <> \forall self \in ProcSet: pc[self] = "Done" +Correct == Terminated => SCCsFromAlgo = SCCsByDef + +================================================================================ diff --git a/general/performance/Bloemen/MC.cfg b/general/performance/Bloemen/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..efdb6a558b0f8203f456d5dd8844c1aa82578ff6 --- /dev/null +++ b/general/performance/Bloemen/MC.cfg @@ -0,0 +1,12 @@ +CONSTANT p1 = p1 +CONSTANT p2 = p2 +CONSTANT defaultInitValue = defaultInitValue + +CONSTANT Edges <- CartEdges +CONSTANT Nodes = {1,2,3} + +CONSTANT Threads = {p1, p2} +SYMMETRY SymmetryThreads + +SPECIFICATION Spec +INVARIANT Correct diff --git a/general/performance/Bloemen/MC.tla b/general/performance/Bloemen/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..eca00481a78ea140628a0d04dafbd0154b103b8b --- /dev/null +++ b/general/performance/Bloemen/MC.tla @@ -0,0 +1,7 @@ +---- MODULE MC ---- +EXTENDS BloemenSCC, TLC + +SymmetryThreads == Permutations(Threads) + +CartEdges == Nodes \X Nodes +============================================================================= diff --git a/general/performance/measure.sh b/general/performance/measure.sh index c2c1b9c50d003037277c0b268fcac6928c839e08..0313db73fb8333f9497b5a10063f5b1deb1ae511 100755 --- a/general/performance/measure.sh +++ b/general/performance/measure.sh @@ -50,8 +50,7 @@ for i in {1..3}; do TLC_OUTPUT_FILE=$REV-$i-$w-tlc.txt /usr/bin/time --append --output=$TIME_OUTPUT_FILE \ - java -XX:+UnlockCommercialFeatures \ - -XX:+FlightRecorder \ + java -XX:StartFlightRecording=settings=default \ -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,dumponexit=true,dumponexitpath=$JFR_OUTPUT_FILE,maxage=12h,settings=$TLATOOLS_HOME/jfr/tlc.jfc \ -javaagent:$TLATOOLS_HOME/jfr/jmx2jfr.jar=$TLATOOLS_HOME/jfr/jmxprobes.xml \ -Xmx$HEAP_MEM -Xms$HEAP_MEM \ diff --git a/general/performance/measureFPSet.sh b/general/performance/measureFPSet.sh index 881fed40c8072753f07ee39059aa30eacacf12a6..17b43341a32519afe69cc09824fc08fafca6c57d 100755 --- a/general/performance/measureFPSet.sh +++ b/general/performance/measureFPSet.sh @@ -34,10 +34,9 @@ for i in {1..3}; do /usr/bin/time --append --output=$MSB_TIME_OUTPUT_FILE \ java \ - -XX:+UnlockCommercialFeatures \ -XX:+UnlockDiagnosticVMOptions \ -XX:+DebugNonSafepoints \ - -XX:+FlightRecorder \ + -XX:StartFlightRecording=settings=default \ -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,dumponexit=true,dumponexitpath=$MSB_JFR_OUTPUT_FILE,maxage=12h,settings=$TLATOOLS_HOME/jfr/tlc.jfc \ -javaagent:$TLATOOLS_HOME/jfr/jmx2jfr.jar=$TLATOOLS_HOME/jfr/jmxprobes.xml \ -Xmx$HEAP_MEM -Xms$HEAP_MEM \ @@ -56,10 +55,9 @@ for i in {1..3}; do /usr/bin/time --append --output=$TIME_OUTPUT_FILE \ java \ - -XX:+UnlockCommercialFeatures \ -XX:+UnlockDiagnosticVMOptions \ -XX:+DebugNonSafepoints \ - -XX:+FlightRecorder \ + -XX:StartFlightRecording=settings=default \ -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,dumponexit=true,dumponexitpath=$JFR_OUTPUT_FILE,maxage=12h,settings=$TLATOOLS_HOME/jfr/tlc.jfc \ -javaagent:$TLATOOLS_HOME/jfr/jmx2jfr.jar=$TLATOOLS_HOME/jfr/jmxprobes.xml \ -XX:MaxDirectMemorySize=$DIRECT_MEM \ diff --git a/general/settings/codetemplates.xml b/general/settings/codetemplates.xml deleted file mode 100644 index c48f382060626476b70464734af3b0eb355b3945..0000000000000000000000000000000000000000 --- a/general/settings/codetemplates.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?><templates><template autoinsert="true" context="catchblock_context" deleted="false" description="Code in new catch blocks" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.catchblock" name="catchblock">// ${todo} Auto-generated catch block -${exception_var}.printStackTrace();</template></templates> \ No newline at end of file diff --git a/general/settings/dictionary b/general/settings/dictionary deleted file mode 100644 index 172bd203120367dff9250ace1c45e369d5d879a9..0000000000000000000000000000000000000000 --- a/general/settings/dictionary +++ /dev/null @@ -1,16 +0,0 @@ -simon -zambrovski -spec -toolbox -multi -tla -registry -leslie -config -registry -enablement -whitespaces -programmatically -popup -retargetable - diff --git a/general/settings/eclipse-formatter.xml b/general/settings/eclipse-formatter.xml deleted file mode 100644 index 3a16f425fed8ab51ab4d507f6344f4bb04e55f7b..0000000000000000000000000000000000000000 --- a/general/settings/eclipse-formatter.xml +++ /dev/null @@ -1,267 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<profiles version="11"> -<profile kind="CodeFormatterProfile" name="TLA Tools" version="11"> -<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> -<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/> -<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> -<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/> -<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/> -</profile> -</profiles> diff --git a/general/settings/tla-formatter.xml b/general/settings/tla-formatter.xml deleted file mode 100644 index b621efbec4bf82ed7838d3009decd2c0d4cf815a..0000000000000000000000000000000000000000 --- a/general/settings/tla-formatter.xml +++ /dev/null @@ -1,269 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<profiles version="11"> -<profile kind="CodeFormatterProfile" name="TLA Tools" version="11"> -<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> -<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/> -<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/> -<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/> -<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/> -<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/> -<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/> -<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/> -<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> -<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> -<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/> -<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> -</profile> -</profiles> diff --git a/org.lamport.tla.distributed.consumer/.project b/org.lamport.tla.distributed.consumer/.project deleted file mode 100644 index b93f3cbbdcd99d2a365740ae9e08114afd38cb54..0000000000000000000000000000000000000000 --- a/org.lamport.tla.distributed.consumer/.project +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>org.lamport.tla.distributed.consumer</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - </buildSpec> - <natures> - </natures> -</projectDescription> diff --git a/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF index 9def4af82f3faf4b40790d8ce0b2a62710384e78..a5742ae4f249b81a93337cbe8ee153aeefadebf2 100644 --- a/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF @@ -12,3 +12,4 @@ Require-Bundle: org.lamport.tla.toolbox;bundle-version="1.0.0", org.eclipse.help.ui;bundle-version="4.0.100", org.eclipse.core.resources;bundle-version="3.10.1" Bundle-Activator: org.lamport.tla.toolbox.doc.HelpActivator +Automatic-Module-Name: org.lamport.tla.toolbox.doc diff --git a/org.lamport.tla.toolbox.doc/draft/EMailResult.png b/org.lamport.tla.toolbox.doc/draft/EMailResult.png deleted file mode 100644 index 147d787f4946c5d02fe96952e1df96764e324403..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/EMailResult.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/FinalResultLoaded.png b/org.lamport.tla.toolbox.doc/draft/FinalResultLoaded.png deleted file mode 100644 index fbaf57facc9d61c4289ca9902e1bc619481fa0de..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/FinalResultLoaded.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/LoadIntoResultPageB.png b/org.lamport.tla.toolbox.doc/draft/LoadIntoResultPageB.png deleted file mode 100644 index c897f36477d75736a0df7447e320e249c87fc1fd..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/LoadIntoResultPageB.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/LoadResultIntoToolbox.png b/org.lamport.tla.toolbox.doc/draft/LoadResultIntoToolbox.png deleted file mode 100644 index 285f9ed43ae2b2a157c78dd86dea89a51a5c398e..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/LoadResultIntoToolbox.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/MCoutInBrowser.png b/org.lamport.tla.toolbox.doc/draft/MCoutInBrowser.png deleted file mode 100644 index 0bc03dbabe6587f8548d2e1ee669306a1f1b7e75..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/MCoutInBrowser.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ModelEditorA.png b/org.lamport.tla.toolbox.doc/draft/ModelEditorA.png deleted file mode 100644 index 19a7bbc5cd804d00e10b63f9ceaec1bf6aa77acd..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ModelEditorA.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ModelEditorB.png b/org.lamport.tla.toolbox.doc/draft/ModelEditorB.png deleted file mode 100644 index 66e048b02970cc3fe9acdf63fb0841a48588e4cd..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ModelEditorB.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ModelEditorC.png b/org.lamport.tla.toolbox.doc/draft/ModelEditorC.png deleted file mode 100644 index 59f7007d3c797be14f3b2c8caccb3c1789930cbd..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ModelEditorC.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ModelEditorD.png b/org.lamport.tla.toolbox.doc/draft/ModelEditorD.png deleted file mode 100644 index 72e6d60265b0973e067463c0b4879a6a482fcf3e..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ModelEditorD.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ProgressBar.png b/org.lamport.tla.toolbox.doc/draft/ProgressBar.png deleted file mode 100644 index a43792da480bea604e5193d82b0b51b50f9aea75..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ProgressBar.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/ProgressBarFinal.png b/org.lamport.tla.toolbox.doc/draft/ProgressBarFinal.png deleted file mode 100644 index a2a5230bb30ec08f5dff324c029803a74677888e..0000000000000000000000000000000000000000 Binary files a/org.lamport.tla.toolbox.doc/draft/ProgressBarFinal.png and /dev/null differ diff --git a/org.lamport.tla.toolbox.doc/draft/README.txt b/org.lamport.tla.toolbox.doc/draft/README.txt deleted file mode 100644 index e91c5fb91f23cc876ce4482fef84a7bc13dda08d..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.doc/draft/README.txt +++ /dev/null @@ -1 +0,0 @@ -Expect this folder to disappear soon once this content has been transferred into the proper HTML documentation. \ No newline at end of file diff --git a/org.lamport.tla.toolbox.doc/draft/cloudtlc.lyx b/org.lamport.tla.toolbox.doc/draft/cloudtlc.lyx deleted file mode 100644 index 8eba4f2fb35174c10655ee3adb975470ad9f539d..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.doc/draft/cloudtlc.lyx +++ /dev/null @@ -1,843 +0,0 @@ -#LyX 2.0 created this file. For more info see http://www.lyx.org/ -\lyxformat 413 -\begin_document -\begin_header -\textclass article -\use_default_options true -\maintain_unincluded_children false -\language english -\language_package default -\inputencoding auto -\fontencoding global -\font_roman default -\font_sans default -\font_typewriter default -\font_default_family default -\use_non_tex_fonts false -\font_sc false -\font_osf false -\font_sf_scale 100 -\font_tt_scale 100 - -\graphics default -\default_output_format default -\output_sync 0 -\bibtex_command default -\index_command default -\paperfontsize default -\use_hyperref false -\papersize default -\use_geometry false -\use_amsmath 1 -\use_esint 1 -\use_mhchem 1 -\use_mathdots 1 -\cite_engine basic -\use_bibtopic false -\use_indices false -\paperorientation portrait -\suppress_date false -\use_refstyle 1 -\index Index -\shortcut idx -\color #008000 -\end_index -\secnumdepth 3 -\tocdepth 3 -\paragraph_separation indent -\paragraph_indentation default -\quotes_language english -\papercolumns 1 -\papersides 1 -\paperpagestyle default -\tracking_changes false -\output_changes false -\html_math_output 0 -\html_css_as_file 0 -\html_be_strict false -\end_header - -\begin_body - -\begin_layout Title -Cloud based distributed TLC -\end_layout - -\begin_layout Section -Motivation -\end_layout - -\begin_layout Itemize -Move long running model checking off local machine into the cloud (Short - running models not ideal because instance spin-up time is approximately - five minutes) -\end_layout - -\begin_layout Itemize -Maximize cloud instance resource utilization by providing fine-tuned TLC - parameter pre-sets optimized for the given cloud instance type -\end_layout - -\begin_layout Itemize -Minimizes costs by terminating cloud instances immediately after TLC model - checking has ended -\end_layout - -\begin_deeper -\begin_layout Itemize -Unless email delivery of model checking result fails (n this case the machine - remains running for the user to pick up the result manually) -\end_layout - -\begin_layout Itemize -User then has to terminate the instance manually! -\end_layout - -\end_deeper -\begin_layout Section -Warning -\end_layout - -\begin_layout Standard -Using cloud based TLC launches compute instances at your cloud provider - which may incur costs. - While the cloud based distributed TLC tries to minimize costs by terminating - instances as soon as possible, do not rely on it. - Always check if cloud instances have been correctly terminated. -\end_layout - -\begin_layout Section -Limitation -\end_layout - -\begin_layout Itemize -Only supports a single cloud provider ( -\begin_inset CommandInset href -LatexCommand href -name "Amazon EC2" -target "http://aws.amazon.com/ec2/" - -\end_inset - -) as of now -\end_layout - -\begin_layout Itemize -Runs TLC in non-distributed mode on a single cloud instance only as of now -\end_layout - -\begin_layout Itemize -Only a single instance type ( -\begin_inset CommandInset href -LatexCommand href -name "m4.2xlarge" -target "http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud#Instance_types" - -\end_inset - -) supported as of now -\end_layout - -\begin_layout Itemize -Cloud based distributed TLC cannot recover from a checkpoint -\end_layout - -\begin_layout Section -Usage -\end_layout - -\begin_layout Enumerate -Set -\begin_inset CommandInset href -LatexCommand href -name "AWS access key and secret" -target "http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html" - -\end_inset - - as -\begin_inset CommandInset href -LatexCommand href -name "environment variables" -target "http://en.wikipedia.org/wiki/Environment_variable" - -\end_inset - - prior to launching the Toolbox. - See the example with dummy keys below. -\end_layout - -\begin_deeper -\begin_layout Enumerate -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -export AWS_ACCESS_KEY_ID=AKIA7D89HCLJKHZASD7F -\end_layout - -\begin_layout Plain Layout - -export AWS_SECRET_ACCESS_KEY=6FDASAIG7DAS976TYDKHCGQAS5D -\backslash -FA77 -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -set AWS_ACCESS_KEY_ID=AKIA7D89HCLJKHZASD7F -\end_layout - -\begin_layout Plain Layout - -set AWS_SECRET_ACCESS_KEY=6FDASAIG7DAS976TYDKHCGQAS5D -\backslash -FA77 -\end_layout - -\end_inset - - -\end_layout - -\end_deeper -\begin_layout Enumerate -Create a specification and a model -\end_layout - -\begin_layout Enumerate -Open your model in the model editor -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename ModelEditorA.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Model Editor -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Expand the -\begin_inset Quotes eld -\end_inset - -How to run -\begin_inset Quotes erd -\end_inset - - section of the -\begin_inset Quotes eld -\end_inset - -Model Overview -\begin_inset Quotes erd -\end_inset - - page -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename ModelEditorB.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -How to run section -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Select -\begin_inset Quotes eld -\end_inset - -aws-ec2 -\begin_inset Quotes erd -\end_inset - - from the -\begin_inset Quotes eld -\end_inset - -Run in distributed mode -\begin_inset Quotes erd -\end_inset - - drop down -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename ModelEditorC.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Select your cloud provider -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Enter an email address into -\begin_inset Quotes eld -\end_inset - -Result mailto address -\begin_inset Quotes erd -\end_inset - - at which you want to receive the model checking result -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename ModelEditorD.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Enter your email address -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Click -\begin_inset Quotes eld -\end_inset - -Run TLC -\begin_inset Quotes erd -\end_inset - - to start model checking in the cloud and wait for the start-up to finish - (it takes approximately five minutes to set-up the cloud instance) -\end_layout - -\begin_deeper -\begin_layout Enumerate -The Toolbox switches to the -\begin_inset Quotes eld -\end_inset - -Model checking results -\begin_inset Quotes erd -\end_inset - - page and opens a progress dialog indicating the state of cloud instance - provisioning -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout - -\end_layout - -\begin_layout Plain Layout -\begin_inset Graphics - filename ProgressBar.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Progress Dialog -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -After provisioning the cloud instance, the Toolbox prompts the user to open - a website in a browser. - -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename ProgressBarFinal.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Progress Dialog Final -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - This website is hosted on the cloud instance and shows the TLC process - output as well as runtime statistics similar to Toolbox stats -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename MCoutInBrowser.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -TLC runtime statistics in your browser -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\end_deeper -\begin_layout Enumerate -Walk out and enjoy the weekend while TLC is busy checking -\end_layout - -\begin_layout Enumerate -On Monday, expect to find an email in your inbox -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout - -\end_layout - -\begin_layout Plain Layout -\begin_inset Graphics - filename EMailResult.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Email Result -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Save MC.out file somewhere to disc -\end_layout - -\begin_layout Enumerate -Switch back to the Toolbox and open the model editor -\end_layout - -\begin_layout Enumerate -Open the -\begin_inset Quotes eld -\end_inset - -Model Checking Results -\begin_inset Quotes erd -\end_inset - - page -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename LoadResultIntoToolbox.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Load result into Toolbox -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -\begin_inset CommandInset label -LatexCommand label -name "enu:Import-the-MC.out" - -\end_inset - -Import the MC.out from disc -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename LoadIntoResultPageB.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Load into results page -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Enumerate -Voilá -\begin_inset Float figure -placement H -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\begin_inset Graphics - filename FinalResultLoaded.png - width 100line% - -\end_inset - - -\begin_inset Caption - -\begin_layout Plain Layout -Final result loaded -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Section -Common problems -\end_layout - -\begin_layout Itemize -The Toolbox fails to start the cloud instance -\end_layout - -\begin_deeper -\begin_layout Itemize -Re-check your credentials -\end_layout - -\begin_layout Itemize -If your credentials are correct, please turn on debug logging (start the - Toolbox executable with “toolbox -console -consolelog”) and send us the - output. - You might have encountered a bug in cloud based distributed TLC. -\end_layout - -\end_deeper -\begin_layout Itemize -The runtime statistics (web browser) indicate that TLC has finished model - checking, but no result is sent via email. -\end_layout - -\begin_deeper -\begin_layout Itemize -Check your email spam folder if the model checking result has incorrectly - been classified as spam -\end_layout - -\begin_layout Itemize -Another reason why mail delivery might fail are too strict spam counter - measures at the mail server level. - You might want to try to use a different email address (domain part) in - the future. -\end_layout - -\begin_deeper -\begin_layout Itemize -Copy & paste the MC.out content from the browser window into a plain text - file and load it from there (see -\begin_inset CommandInset ref -LatexCommand ref -reference "enu:Import-the-MC.out" - -\end_inset - -) -\end_layout - -\end_deeper -\end_deeper -\begin_layout Standard -\begin_inset Note Note -status collapsed - -\begin_layout Section -TODO -\end_layout - -\begin_layout Itemize -Even though it is called cloud-based -\emph on -distributed -\emph default - TLC, it can do non-distributed liveness checking. -\end_layout - -\begin_layout Section -Leslie -\end_layout - -\begin_layout Itemize - -\strikeout on -I noticed that there's a window named "Cloud TLC" that says "Clicking OK - opens a status page in a browser" but doesn't say what clicking Cancel - does. - I presume it just doesn't open the browser page, but I'm not positive that - it doesn't cancel the distributed TLC job. - You probably want to remove that ambiguity. -\end_layout - -\begin_layout Itemize -This says nothing about what to do if you're not using aws-ec2. - I presume that's selected with the "ad hoc" choice in Figure 3. - That needs to be documented. - Does it work like the present system? If so, you can just incorporate the - existing instructions in some way -\end_layout - -\begin_layout Itemize -I presume in bullet 2 of section 3, "non-distribute mode" is some EC2 jargon - that doesn't mean what a TLC user would expect it to. - This should be made more clear to non-EC2 users. -\end_layout - -\begin_layout Itemize - -\strikeout on -In the 3rd bullet, if "(m4.2xlarge)" naming is the single instance type, - then it should be moved immediately after "type". -\end_layout - -\begin_layout Itemize - -\strikeout on -Section 4.1. - I presume those keys are dummies. -\end_layout - -\begin_layout Itemize -Step 13 of section 4 isn't clear. - I presume the importing is done from the file chooser in Figure 10, but - I don't know how that chooser is raised. -\end_layout - -\begin_layout Itemize - -\strikeout on -Section 6. - I presume you mean that it does non-distributed liveness-checking? If so, - say so. - -\end_layout - -\begin_layout Itemize -netcat/jna/ssh-agent/pageant native depedencies -\end_layout - -\begin_deeper -\begin_layout Itemize -\begin_inset Flex URL -status collapsed - -\begin_layout Plain Layout - -https://github.com/ymnk/jsch-agent-proxy/blob/master/README.md#dependencies -\end_layout - -\end_inset - - -\end_layout - -\end_deeper -\end_inset - - -\end_layout - -\end_body -\end_document diff --git a/org.lamport.tla.toolbox.doc/html/cloudtlc/index.html b/org.lamport.tla.toolbox.doc/html/cloudtlc/index.html index 9740f4365009c194bb78ffeb10bac356790dfc49..f426ce967bbc1c223317cdf89abdb05d68084a00 100644 --- a/org.lamport.tla.toolbox.doc/html/cloudtlc/index.html +++ b/org.lamport.tla.toolbox.doc/html/cloudtlc/index.html @@ -1,53 +1,42 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta name="generator" content= - "HTML Tidy for Linux (vers 25 March 2009), see www.w3.org" /> + "HTML Tidy for HTML5 for Linux version 5.2.0" /> <meta http-equiv="Content-Type" content= - "text/html; charset=us-ascii" /> + "text/html; charset=utf-8" /> <meta name="generator" content="http://www.nongnu.org/elyxer/" /> <meta name="create-date" content="2014-07-18" /> <link href="../style.css" rel="stylesheet" type="text/css" /> - <title>Cloud based distributed TLC</title> </head> - <body> <div id="globalWrapper"> <h1 class="title">Cloud based distributed TLC</h1> - <h1 class="Section"><a class="toc" name="toc-Section-1" id= "toc-Section-1">1</a> Motivation</h1> - <ul> <li>Move long running model checking off local machine into the cloud (Short running models not ideal because instance spin-up time is approximately five minutes)</li> - <li>Maximize cloud instance resource utilization by providing fine-tuned TLC parameter pre-sets optimized for the given cloud instance type</li> - <li>Minimizes costs by terminating cloud instances immediately after TLC model checking has ended - <ul> <li>Unless email delivery of model checking result fails (n this case the machine remains running for the user to pick up the result manually)</li> - <li>User then has to terminate the instance manually!</li> </ul> </li> </ul> - <h1 class="Section"><a class="toc" name="toc-Section-2" id= "toc-Section-2">2</a> Warning</h1> - <div class="Unindented"> Using cloud based TLC launches compute instances at your cloud provider which may incur costs. While the cloud based @@ -55,16 +44,13 @@ instances as soon as possible, do not rely on it. Always check if cloud instances have been correctly terminated. </div> - <h1 class="Section"><a class="toc" name="toc-Section-3" id= "toc-Section-3">3</a> Limitation</h1> - <ul> <li>Only supports two cloud providers (<a class="URL" href= "http://aws.amazon.com/ec2/">Amazon EC2</a> and <a class= "URL" href="https://azure.microsoft.com/en-us/">Microsoft Azure</a>) as of now - <ul> <li>On Azure, the VM instances just stoppes but does not <a class="URL" href= @@ -74,24 +60,19 @@ finishes.</li> </ul> </li> - <li>Runs TLC in non-distributed mode on a single cloud instance only as of now</li> - <li>Only a single instance type per cloud (<a class="URL" href= "http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud#Instance_types">m4.2xlarge</a> and <a class="URL" href= "https://azure.microsoft.com/en-us/pricing/details/virtual-machines/"> D14</a>) supported as of now</li> - <li>Cloud based distributed TLC cannot recover from a checkpoint</li> </ul> - <h1 class="Section"><a class="toc" name="toc-Section-4" id= "toc-Section-4">4</a> Usage</h1> - <div align="left"> <div align="center" style= "width:500px;height:45px;border:1px solid #000;"> @@ -100,7 +81,6 @@ introductory video</a> online</em>. </div> </div> - <ol> <li>Set <a class="URL" href= "http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html"> @@ -108,7 +88,6 @@ "http://en.wikipedia.org/wiki/Environment_variable">environment variables</a> prior to launching the Toolbox. See the example with dummy keys below. - <div style="margin-left: 2em"> <ul> <li style="list-style: none; display: inline"> @@ -119,183 +98,158 @@ export AWS_SECRET_ACCESS_KEY=6FDASAIG7DAS976TYDKHCGQAS5D\FA77 </pre> </div> </li> - - <li>Alternatively for Azure, first create a certificate - (the command below uses keytool which is part of the - Java installation to create the azure.p12 file): - -<!-- "https://web.archive.org/web/20150321180025/http://azure.microsoft.com/en-us/documentation/articles/java-create-azure-website-using-java-sdk/#create-a-certificate" --> - - <div class="listing"> - <pre class="listing"> -/absolute/path/to/Java/installation/bin/keytool -genkey -alias TLAToolbox - -keystore /absolute/path/to/the/azure.p12 -storepass ThePasswordUsedForTheCertificate - -validity 3650 -keyalg RSA -keysize 2048 -storetype pkcs12 - -dname "CN=TLAToolbox" -</pre> - </div>Next, create the azure.cer file from the - azure.p12 file. - - <div class="listing"> - <pre class="listing"> -/absolute/path/to/Java/installation/bin/keytool -export -alias TLAToolbox - -storetype pkcs12 -keystore /absolute/path/to/the/azure.p12 - -storepass ThePasswordUsedForTheCertificate -rfc -file /absolute/path/to/the/azure.cer -</pre> - </div> - </li> - - <li> - Upload azure.cer to <a href="portal.azure.com">portal.azure.com</a> as described in <a href="https://docs.microsoft.com/en-us/azure/azure-api-management-certs">Upload an Azure Management API Management Certificate</a>. + <li style="list-style: none; display: inline"> + <hr /> </li> - - <li> - Finally configure the Azure specific environment variables as shown below for Command Prompt and PowerShell. + <li>Alternatively for Azure (assuming you already have + an Azure subscription), please follow <a href= + "https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal"> + Use the portal to create an Azure AD application and + service principal that can access resources</a>.<br /> + As <i>Sign-on URL</i> you can choose the TLA+ GitHub + URL: <i>https://github.com/tlaplus/tlaplus</i></li> + <li>Finally configure the Azure specific environment + variables as shown below for Command Prompt and + PowerShell. <div class="listing"> <pre class="listing"> -export AZURE_COMPUTE_CREDENTIALS=ThePasswordUsedForTheCertificate (The "password" supplied during certificate creation) -export AZURE_COMPUTE_IDENTITY=/absolute/path/to/the/azure.p12 -export AZURE_COMPUTE_SUBSCRIPTION=YourAzureSubscriptionId (Extract the ID from the <a class="URL" -href= -"https://ms.portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade">Azure portal under "Subscriptions"</a>) +## Called "Application ID" in the Azure manual +export AZURE_COMPUTE_SERVICE_PRINCIPAL=TheAzureApplicationID +## Called "Value" in the Azure manual +export AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD=TheAzureApplicationKeyValue +## Called "Directory ID" in the Azure manual +export AZURE_COMPUTE_TENANT=TheAzureDirectoryId + +## The "Subscription ID" shown in the overview section of <a href= +"https://ms.portal.azure.com/#blade/Microsoft_Azure_Billing/ModernBillingMenuBlade/Overview">"Cost Management + Billing"</a> in Azure Portal +export AZURE_COMPUTE_SUBSCRIPTION=YourAzureSubscriptionId </pre> </div> </li> - <li>On Windows in the Command Prompt, set the environment variable with: <pre class="listing"> -set AZURE_COMPUTE_CREDENTIALS=ThePasswordUsedForTheCertificate -set AZURE_COMPUTE_IDENTITY=C:\absolute\path\to\the\azure.p12 +set AZURE_COMPUTE_SERVICE_PRINCIPAL=TheAzureApplicationID +set AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD=TheAzureApplicationKey +set AZURE_COMPUTE_TENANT=TheAzureDirectoryId set AZURE_COMPUTE_SUBSCRIPTION=YourAzureSubscriptionId </pre>If you prefer PowerShell, do (notice the quotes): <pre class="listing"> -$env:AZURE_COMPUTE_CREDENTIALS="ThePasswordUsedForTheCertificate" -$env:AZURE_COMPUTE_IDENTITY="C:\absolute\path\to\the\azure.p12" +$env:AZURE_COMPUTE_SERVICE_PRINCIPAL="ThePasswordUsedForTheCertificate" +$env:AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD="TheAzureApplicationKey" +$env:AZURE_COMPUTE_TENANT="TheAzureDirectoryId" $env:AZURE_COMPUTE_SUBSCRIPTION="YourAzureSubscriptionId" </pre>To set the variables permanently, use the <a href="https://technet.microsoft.com/en-us/library/cc755104(v=ws.11).aspx"> setx</a> command. - <p>DO NOT use Cygwin shell to set the environment variables and launch the Toolbox. It will lead to obscure exceptions at runtime.</p> </li> + <li style="list-style: none; display: inline"> + <hr /> + </li> + <li>Besides AWS and Azure, <a href= + "https://www.packet.com/cloud/servers/t1-small/">packet.net's</a> + t1.small.x86 baremetal instances provide a budget + environment to run Cloud TLC. + <div class="listing"> + <pre class="listing"> +## Called "API Key" in app.packet.net +export PACKET_NET_APIKEY=YourPacketNetAPIKey +## Called "Organization ID" in app.packet.net +export PACKET_NET_PROJECT_ID=YourOrganizationId + </pre> + </div> + </li> </ul> </div> </li> - <li>Create a specification and a model</li> - <li>Open your model in the model editor - <div class="float"> <a class="Label" name="Figure-1" id="Figure-1"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ModelEditorA.png" alt= "figure ModelEditorA.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 1 Model Editor </div> </div> </div> </li> - - <li>Expand the “How to run” section of the - “Model Overview” page - + <li>Expand the “How to run” section of the “Model Overview” + page <div class="float"> <a class="Label" name="Figure-2" id="Figure-2"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ModelEditorB.png" alt= "figure ModelEditorB.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 2 How to run section </div> </div> </div> </li> - - <li>Select “aws-ec2” from the “Run in - distributed mode” drop down - + <li>Select “aws-ec2” from the “Run in distributed mode” drop + down <div class="float"> <a class="Label" name="Figure-3" id="Figure-3"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ModelEditorC.png" alt= "figure ModelEditorC.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 3 Select your cloud provider </div> </div> </div> </li> - - <li>Enter an email address into “Result mailto - address” at which you want to receive the model - checking result - + <li>Enter an email address into “Result mailto address” at + which you want to receive the model checking result <div class="float"> <a class="Label" name="Figure-4" id="Figure-4"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ModelEditorD.png" alt= "figure ModelEditorD.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 4 Enter your email address </div> </div> </div> </li> - - <li>Click “Run TLC” to start model checking in - the cloud and wait for the start-up to finish (it takes - approximately five minutes to set-up the cloud instance) - + <li>Click “Run TLC” to start model checking in the cloud and + wait for the start-up to finish (it takes approximately five + minutes to set-up the cloud instance) <ol> - <li>The Toolbox switches to the “Model checking - results” page and opens a progress dialog - indicating the state of cloud instance provisioning - + <li>The Toolbox switches to the “Model checking results” + page and opens a progress dialog indicating the state of + cloud instance provisioning <div class="float"> <a class="Label" name="Figure-5" id="Figure-5"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ProgressBar.png" alt= "figure ProgressBar.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 5 Progress Dialog </div> </div> </div> </li> - <li>After provisioning the cloud instance, the Toolbox prompts the user to open a website in a browser. - <div class="float"> <a class="Label" name="Figure-6" id="Figure-6"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="ProgressBarFinal.png" alt= "figure ProgressBarFinal.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 6 Progress Dialog Final </div> @@ -303,95 +257,72 @@ $env:AZURE_COMPUTE_SUBSCRIPTION="YourAzureSubscriptionId" </div>This website is hosted on the cloud instance and shows the TLC process output as well as runtime statistics similar to Toolbox stats - <div class="float"> <a class="Label" name="Figure-7" id="Figure-7"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="MCoutInBrowser.png" alt= "figure MCoutInBrowser.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> - Figure 7 TLC runtime statistics - in your browser + Figure 7 TLC runtime statistics in your browser </div> </div> </div> </li> </ol> </li> - <li>Walk out and enjoy the weekend while TLC is busy checking</li> - <li>On Monday expect to find an email in your inbox - <div class="float"> <a class="Label" name="Figure-8" id="Figure-8"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="EMailResult.png" alt= "figure EMailResult.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 8 Email Result </div> </div> </div> </li> - <li>Save MC.out file somewhere to disc</li> - <li>Switch back to the Toolbox and open the model editor</li> - - <li>Open the “Model Checking Results” page - + <li>Open the “Model Checking Results” page <div class="float"> <a class="Label" name="Figure-9" id="Figure-9"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="LoadResultIntoToolbox.png" alt="figure LoadResultIntoToolbox.png" style= "max-width: 800px; max-height: 600px;" /> - <div class="caption"> Figure 9 Load result into Toolbox </div> </div> </div> </li> - <li> <a class="Label" name="enu:Import-the-MC.out" id= "enu:Import-the-MC.out"></a>Import the MC.out from disc - <div class="float"> <a class="Label" name="Figure-10" id="Figure-10"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="LoadIntoResultPageB.png" alt= "figure LoadIntoResultPageB.png" style= "max-width: 1073px; max-height: 791px;" /> - <div class="caption"> Figure 10 Load into results page </div> </div> </div> </li> - - <li>Voilá - + <li>Voilá <div class="float"> <a class="Label" name="Figure-11" id="Figure-11"></a> - <div class="figure" style="max-width: 100%;"> <img class="figure" src="FinalResultLoaded.png" alt= "figure FinalResultLoaded.png" style= "max-width: 1074px; max-height: 789px;" /> - <div class="caption"> Figure 11 Final result loaded </div> @@ -399,25 +330,19 @@ $env:AZURE_COMPUTE_SUBSCRIPTION="YourAzureSubscriptionId" </div> </li> </ol> - <h1 class="Section"><a class="toc" name="toc-Section-5" id= "toc-Section-5">5</a> Common problems</h1> - <ul> <li>The Toolbox fails to start the cloud instance - <ul> <li>Re-check your credentials</li> - <li>If your credentials are correct, please turn on debug - logging (start the Toolbox executable with - "toolbox -console - -consolelog") and send us the output. You - might have encountered a bug in cloud based distributed + logging (start the Toolbox executable with "toolbox + -console -consolelog") and send us the output. You might + have encountered a bug in cloud based distributed TLC.</li> </ul> </li> - <li>The cloud instance sends "system notification" emails warning that the remaining disc space is at a critical level: <pre class="listing"> @@ -425,7 +350,6 @@ $env:AZURE_COMPUTE_SUBSCRIPTION="YourAzureSubscriptionId" CRITICALs: / is 92.23..."</i> </pre> - <ul> <li>A long running TLC process writes unexplored states to the system disk for later exploration. With very large @@ -436,12 +360,10 @@ $env:AZURE_COMPUTE_SUBSCRIPTION="YourAzureSubscriptionId" "http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-add-volume-to-instance.html"> attach a larger disk to your VM</a> and continue TLC by recovering from the checkpoint. - <ul> <li><a class="URL" href= "http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-connect-to-instance-linux.html#using-putty"> Connect to the cloud instance with ssh</a></li> - <li> <pre class="listing"> # Download a jmx commandline client @@ -449,7 +371,6 @@ wget http://crawler.archive.org/cmdline-jmxclient/cmdline-jmxclient-0.10.3.jar </pre> </li> - <li> <pre class="listing"> # Connect to the locally running TLC and have it create a checkpoint @@ -457,10 +378,8 @@ java -jar cmdline-jmxclient-0.10.3.jar - localhost:5400 tlc2.tool:type=ModelChec </pre> </li> - <li>Re-attach to the screen session running TLC and terminate TLC wth CTRL^C</li> - <li> <pre class="listing"> # Restart TLC and have it recover from the checkpoint created @@ -472,36 +391,29 @@ java -jar tla2tools.jar -recover /path/to/states/15-12-16-12-16-04/ </li> </ul> </li> - <li style="list-style: none; display: inline"> <ul> <li>The cloud instance sends "system notification" email warnings directly after startup. - <ul> <li>Ignore these emails :-).</li> - <li>This happens primarily on Azure when the monitoring runs too earlier before the cloud instance is fully started.</li> </ul> </li> - <li>The runtime statistics (web browser) indicate that TLC has finished model checking, but no result is sent via email. - <ul> <li>Check your email spam folder if the model checking result has incorrectly been classified as spam</li> - <li>Another reason why mail delivery might fail, are too strict spam counter measures at the mail server level. You might want to try to use a different email address (domain part) in the future. For Azure, it works best to use an Outlook.com email address.</li> - <li style="list-style: none; display: inline"> <ul> <li>Copy & paste the MC.out content from the @@ -516,5 +428,11 @@ java -jar tla2tools.jar -recover /path/to/states/15-12-16-12-16-04/ </li> </ul> </div> + +<!-- navigation back to model overview --> +<hr> +<a href = "../model/overview-page.html">↑ Model Overview Page</a> +</hr> + </body> </html> diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html index 2482258ed498a4a042896510f49a863bcd97a140..71d562303c9289f7a5bd9392feb58f653f5b33f0 100644 --- a/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html +++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html @@ -21,7 +21,9 @@ time is the Welcome View. If you are new to the Toolbox, you should read the <A href="help.html"><em>Using Help</em></A> and <A -href="views.html"><em>Managing Views</em></A> help pages. +href="views.html"><em>Managing Views</em></A> help pages. +If you're new to TLA+, try opening an example specification in the Toolbox by +clicking on one of the the buttons at the bottom of the Welcome Page. </P> <P> @@ -35,11 +37,13 @@ the Toolbox <A href="preferences.html"><em>Preferences</em></A>. </p> <p>For further information about TLA<sup>+</sup> and the TLA<sup>+</sup> tools, see the <A href="resources.html"><em>TLA+ Resources</em></A> help page. + +<!-- When using the Toolbox, TLA<sup>+</sup> means TLA<sup>+2</sup>, the revised version of the language; see the <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla2.html" target="_blank">TLA+2 web page</a>. - +--> </p> <p> diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/module-editor-preferences.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/module-editor-preferences.html index 16aed307c6bb610c78e86955552b0e3376b690b4..ab6a212b369402d803ec546cf1060deb72646e1f 100644 --- a/org.lamport.tla.toolbox.doc/html/gettingstarted/module-editor-preferences.html +++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/module-editor-preferences.html @@ -34,6 +34,11 @@ Controls whether or not the highlighting of symbol uses produced by the <a href="../spec/editing-modules.html#showUses"><code>Show Uses</code></a> command is cleared when the specification is re-parsed. +<h3>Add a modification history comment to new specs</h3> + +Adds information about the creation date and modification dates of the module +just after the end of newly created modules. + <h2><a name="renumber">Renumber Proof Command Preferences Section</a></h2> There are two options that are explained in the description of the <i>Renumber Proof</i> diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html index dffbbc5c90bb1506a8ca4cb317e13fb0fff31e62..43b035b883868b9fafa40abc448fec7a2686640b 100644 --- a/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html +++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html @@ -13,12 +13,12 @@ <h1>Preferences</h1> - <P> + <P> The Toolbox's main <samp>file</samp> menu contains a <samp>Preferences</samp> -item. +item. Clicking on it raises a dialog for setting various Toolbox -preferences. +preferences. The dialog presents the following high-level choices. @@ -36,41 +36,45 @@ the <a href="../spec/editing-modules.html">Module Editor</a>: <li> The <samp>Appearance / Colors and Fonts</samp> page lets you control the font used in the <em>Error View</em> section of the <i><a href="../model/executing-tlc.html#error-reports">TLC Errors -View</a></i>. This can be quite useful because on some systems, the +View</a></i>, and the <em>User Output</em> and <em>Progress Output</em> +sections of the <i><a href="../model/results-page.html">Model Check Results</a></i>. + This can be quite useful because on some systems, the default font can appear very tiny. -<p> -<li> <samp>Text Editors</samp> has a <samp>Show line numbers</samp> option. +<li> The <samp>Appearance / Colors and Fonts</samp> page lets you +also control the font used in the <em>Error-Trace viewer</em> section of the <i><a +href="../model/executing-tlc.html#error-reports">TLC Errors +View</a></i>. + +<li> The <samp>Editors / Text Editors</samp> has a <samp>Show line numbers</samp> option. It also has an <samp>Insert spaces for tabs</samp> option that should be selected. Several Toolbox commands do not work properly on modules containing tab characters. A spec with tabs may not even mean what it appears to mean. (See page 287 of <i>Specifying Systems</i>.) <b>Do not use tabs in your specs.</b> -<p> -<li>The <samp>Keys</samp> page allows you to change what commands are -bound to what keys. +<li> The <samp>Keys</samp> page allows you to change what commands are +bound to what keys. Most of the useful ones are described <a href="../spec/editing-modules.html#key-bindings">here</a>, and most of the others do nothing. However, you may find a few useful ones that are not listed elsewhere. -</li> </ul> - - - -<h3>Help</h3> +</li> -This isn't very useful. +<li> The <samp>News</samp> page lets you choose whether you want the Toolbox to inform you about news from +TLA+ RSS feeds; there are two feeds enabled by default. +</li></ul> +</p> <h3><a href="tla-preferences.html">TLA+ Preferences</a></h3> <p> -See the <a href="tla-preferences.html">help page</a> for that +See the <a href="tla-preferences.html">help page</a> for that preference menu. Clicking on the <samp>+</samp> next to the item -reveals the following subpages. +reveals the following subpages. Click on the appropriate item in the following list to see what options these preference pages provide you with. @@ -83,18 +87,18 @@ these preference pages provide you with. <li> <a href="../model/executing-tlc.html#preferences">TLC Model Checker Preferences</a></li> </ul> -<hr> +<hr> <!-- delete rest of line to comment out <dl> <dt><b><font color=#0000c0>Topics</font></b></dt> <dd> <A href=""> TOPIC </A></dd> <dd> <A href=""> TOPIC </A></dd> </dl> - --> -<!-- delete rest of line to comment out --> + --> +<!-- delete rest of line to comment out --> <a href = "gettingstarted.html">↑ Getting Started</a> -<!-- --> +<!-- --> </hr> </body> -</html> \ No newline at end of file +</html> diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/resources.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/resources.html index cf4f63f96e4d0e5a3592ea4a19e43d1b95ef8d52..a8a965fe71d03d899c11874f3310ca9f768f2298 100644 --- a/org.lamport.tla.toolbox.doc/html/gettingstarted/resources.html +++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/resources.html @@ -13,25 +13,34 @@ <h1>TLA+ Resources</h1> <P> - The best place to begin learning about TLA+, its tools, and the Toolbox is - in the - <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/hyperbook.html" target="_blank">TLA+ Hyperbook</a>, - which is only partially written. - -The textbook and reference manual for the TLA+ language -is <em><a href= -"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> -Specifying Systems</a></em>. - -Changes to the language since that book was written are described -<a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla2.html" + Everything you need to know about TLA+, its tools, and the Toolbox is on + <a href="https://lamport.azurewebsites.net/tla/tla.html">The TLA+ Web Site</a>. + Resources for learning about TLA+ are on the web site's + <a href="https://lamport.azurewebsites.net/tla/learning.html">Learning TLA+</a> page. + A few of the documents mentioned there can be obtained by clicking on the Toolbox's + <code>Help</code> button. + </P> + +<!-- + The best place to begin learning about TLA+, its tools, and the Toolbox is + in the + <a href="http://lamport.azurewebsites.net/video/videos.html">TLA+ Video Course</a>. + + The textbook and reference manual for the TLA+ language + is <em><a href= + "http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> + Specifying Systems</a></em>. + + Changes to the language since that book was written are described + <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla2.html" target="_blank">here</a>. -The latest news about the TLA+ tools and the Toolbox -can be found on -<a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla.html" target="_blank">the home page of the TLA+ -community</a>. - </P> + The latest news about the TLA+ tools and the Toolbox + can be found on + <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla.html" target="_blank">the home page of the TLA+ + community</a>. +--> + <hr> diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/tla-preferences.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/tla-preferences.html index 0ebbe851215970037082d348642a12c19a7327a5..5456ae2117cc7bd51a4967b2f2516d96ac9f155e 100644 --- a/org.lamport.tla.toolbox.doc/html/gettingstarted/tla-preferences.html +++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/tla-preferences.html @@ -30,7 +30,7 @@ When that folder becomes sufficiently large, its size is shown near the bottom right-hand corner of the Toolbox window. This parameter specifies how large (in kilobytes) <em>sufficiently large</em> -is. +is. The default is 50 megabytes. </p> @@ -45,11 +45,11 @@ if TLC is stopped or finds an error. A TLC execution that takes several days can create a checkpoint with more than a gigabyte of data. -When a spec uses a lot of space, you should view the +When a spec uses a lot of space, you should view the <A href="../model/about-models.html">TLC models</A> you have created for it to see if any have large checkpoints. -See <A href="../model/overview-page.html#checkpoint">Checkpoint +See <A href="../model/overview-page.html#checkpoint">Checkpoint Recovery</A> to learn how you can find out how large a checkpoint is and how you can delete a checkpoint. </p> @@ -57,7 +57,7 @@ is and how you can delete a checkpoint. <h3><a name="library-folders">Library Folders</a></h3> This specifies a list of library folders that are for modules that may -be used in more than one specification. +be used in more than one specification. When a specification imports a module (with an <code>EXTENDS</code> or <code>INSTANCE</code> statement), the parser searches for that module @@ -69,19 +69,23 @@ particular spec with a different list in the spec's <a href="../spec/opening-closing.html#spec-explorer"><em>Spec Explorer</em> </a> entry. +<br/> -<hr> +The growing effort of <a href="https://github.com/tlaplus/CommunityModules">Community Modules</a> +can be leveraged through this importing. + +<hr> <!-- delete rest of line to comment out <dl> <dt><b><font color=#0000c0>Topics</font></b></dt> <dd> <A href=""> TOPIC </A></dd> <dd> <A href=""> TOPIC </A></dd> </dl> - --> -<!-- delete rest of line to comment out --> + --> +<!-- delete rest of line to comment out --> <a href = "preferences.html">↑ Preferences</a> -<!-- --> +<!-- --> </hr> </body> -</html> \ No newline at end of file +</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/about-models.html b/org.lamport.tla.toolbox.doc/html/model/about-models.html index fb4ea01ad0106ab9fb5cfde4fb34b87534b9d510..fbc81a64be9894e66db769b3a9dd40be87cd130a 100644 --- a/org.lamport.tla.toolbox.doc/html/model/about-models.html +++ b/org.lamport.tla.toolbox.doc/html/model/about-models.html @@ -24,8 +24,9 @@ that you must explicitly choose:</p> <li>What values to substitute for constant parameters.</li> </ul> <p> - The <em><a href="overview-page.html">Model Overview Page</a></em> - and <em><a href="advanced-page.html">Advanced Options Page</a></em> + The <em><a href="overview-page.html">Model Overview</a></em>, + <em><a href="spec-options-page.html">Spec Options</a></em>, + and <em><a href="tlc-options-page.html">TLC Options</a></em> help pages describe all the things that can go into a model. </p> @@ -39,87 +40,87 @@ Checker</samp> menu. Alternatively, you can use the <a -href="../spec/opening-closing.html">Spec Explorer</a>. +href="../spec/opening-closing.html">Spec Explorer</a>. To create a new model, open the <a href="../spec/opening-closing.html">Spec Explorer</a> and right-click -on the currently open spec. +on the currently open spec. To open an existing model, open the spec's menu item (by clicking on the <samp>+</samp> ) and double-clicking on the -model. +model. Right-clicking on the model also gives you the options of renaming it, deleting it, and creating a clone. </p> <p> -A convenient way to examine all the spec's models +A convenient way to examine all the spec's models is by selecting <a name="quick-access"><em>Quick Access</em></a> on the <em>Window</em> menu or typing <code>Control+Shift+A</code>. This raises a window showing the models and the beginning of their <em>Model Description</em> fields. Double-clicking -on a model opens it. +on a model opens it. You can also open imported modules from that window. Check out the window's <em>options</em> menu. </p> <p> -When you model check a spec, you should begin with a very small model--that is, a model for which the -values substituted for constants (and perhaps a <a href="advanced-page.html#state">constraint</a>) +When you model check a spec, you should begin with a very small model--that is, a model for which the +values substituted for constants (and perhaps a <a href="spec-options-page.html#state">constraint</a>) yield a small set of reachable states. Before you've model checked it, your spec almost surely contains quite a few errors. Using a small model, TLC can find the trivial ones very quickly. When it finds no errors in a small model, you can then gradually increase the size of the model. </p> -<p> +<p> As you run your spec on larger and larger models, it's easy to forget -what you've done. +what you've done. Instead of changing a model and running it again, create a new model and keep the old one. (This is easy to do by cloning the model, -as described above.) +as described above.) You can identify your models with the <em>Model Description</em> field, -which is shown +which is shown It will be easier to identify your models if you put the important contents of the model in the model name--for example, you can name a model </p> <pre> N=3,Proc={a1,a2,a3} </pre> <A name="locking"> -The model is always locked while it is being run by TLC. This means that +The model is always locked while it is being run by TLC. This means that you can't view information in sections of a running model that are closed. It's therefore a good idea to open all sections of the model that you might want to look at before starting a TLC run that will -take a significant amount of time. +take a significant amount of time. If you forget to do this, you can clone the running model and examine the clone. <p> -The Toolbox saves a -copy of the version of the spec on which the model was run or checked, so you can look at it even after you +The Toolbox saves a +copy of the version of the spec on which the model was run or checked, so you can look at it even after you have changed the spec. You can examine any modules in the saved version by clicking on the <i>Open Saved Module</i> command on the -<i>TLC Model Checker</i> menu when the model is selected. (The model is selected when one of its pages has the focus.) The +<i>TLC Model Checker</i> menu when the model is selected. (The model is selected when one of its pages has the focus.) The <a href="executing-tlc.html#MC">How TLC is Run</a> help-page section tells you where those saved modules are saved. </p> -<hr> -<!-- delete rest of line to comment out +<hr> +<!-- delete rest of line to comment out <dl> <dt><b><font color=#0000c0>Subtopics</font></b></dt> <dd> <A href=""> TOPIC </A></dd> <dd> <A href=""> TOPIC </A></dd> </dl> ---> -<!-- delete rest of line to comment out --> +--> +<!-- delete rest of line to comment out --> <a href = "model.html">↑ Model Checking</a> -<!-- --> +<!-- --> </hr> </body> -</html> \ No newline at end of file +</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/advanced-page.html b/org.lamport.tla.toolbox.doc/html/model/advanced-page.html deleted file mode 100644 index 42f5b0f8525ecc8082f68a91e67c58a5ade906f8..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.doc/html/model/advanced-page.html +++ /dev/null @@ -1,355 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<!-- This is file org.lamport.tla.toobox.doc/html/model/advanced-page.html --> - - -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> - <LINK href="../style.css" rel="stylesheet" type="text/css"> - -<title>Advanced Options Page</title> -</head> -<!-- a comment here --> - -<body> -<h1>Advanced Options Page</h1> - - -<pre> -Contents - <a href="#additional">Additional Definitions</a> - <a href="#state">State Constraint</a> - <a href="#model">Model Values</a> - <a href="#override">Definition Override</a> - <a href="#action">Action Constraint</a> - <a href="#launching">TLC Options</a> -</pre> - -<P> -This model editor page allows you to add less-often -used parts of a model. It's a good idea to browse -this page just to see what options it provides, since -some of the features are not ones you would expect. - </P> - -<h2><a name="additional">Additional Definitions</a></h2> - -<p> -It is sometimes convenient to define operators just -for use in the expressions that specify a model. For -example, you might want to define an operator that -you use can use in more than one invariant. If you -don't want those definitions to be part of the spec, -you can put them in this section of the page. These -definitions can use any operator or parameters that -can be used in the the root module, as well as any -<a href="model-values.html">model value</a> that is -declared in the model. -</p> - -<p> -In addition to definitions, in this section you can also -put assumptions (<code>ASSUME</code> statements) -for TLC to check. Putting other -things in this section, such as declarations, -will result in mysterious TLC errors. - -</p> -<h2><a name="state">State Constraint</a></h2> - -<p> -Many behavior specifications have an infinite set of reachable -states. For example, message queues could get arbitrarily large. -TLC will run forever (or until your computer runs out -of disk space) on such a behavior spec. You could just let it -run and keep looking for violations of safety properties such as invariance. -However, it's a better idea to limit the set of states by entering -a state constraint here. -</p> - -<p> -A state constraint is a state predicate, which is a -Boolean-valued expression that contains unprimed variables. -When computing the set of reachable states, TLC will not -explore successor states of any state it finds that does -<em>not</em> satisfy the state constraint. For example, -specifying <code>len < 3</code> essentially -limits the set of reachable states that TLC finds to ones -that can be reached by a sequence of states in which -the value of the variable <code>len</code> -is less than 3. See Section 14.3 (page 240) of -<em><a href= -"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> -Specifying Systems</a></em> for an explanation of how TLC -computes reachable states. Note that there is no need -for multiple state constraints because they can simply be -conjoined to form a single constraint. -</p> - -<!-- -<p>A state constraint has an effect only in model checking mode. (See -<a href="#launching">TLC Options</a>.) -</p> - --> - -<h2><a name="model">Model Values</a></h2> - -You can enter here a set of model values, which you can then -use in expressions that define the model--for example, in -the value substituted for a declared constant. See the -<A href="model-values.html"><em>Model Values and Symmetry</em></A> help -page for an explanation of what model values are and how they -are used. - -<h2><a name="override">Definition Override</a></h2> -<p> -We want our specifications to be as simple and easy to understand as -possible. Sometimes this leads to a definition that TLC cannot evaluate, -or that it can evaluate only very inefficiently. In that case, we -must <em>override</em> the definition by telling TLC to replace it with -a new definition. To do this, click on the section's <samp>Add</samp> -button, select the operator whose definition you want to override, and -click <samp>OK</samp> . (You can also double-click on the -operator name.) This will raise a dialog in which you can specify -the overriding. -</p> - -<p> -If the operator whose definition you are overriding has arguments, -you will be presented with a form for writing the new definition in -the obvious way. If it has no arguments, you have two -options. With the <em>Ordinary assignment</em> option, you just -write the new definition. The <em>Model value</em> option -defines the operator to equal a model value of the same name. -See the -<A href="model-values.html"><em>Model Values and Symmetry</em></A> help -page for an explanation of model values and the most common -reason why you would want to override the definition in this way. -</p> - -<p> -You can override definitions made in modules other than the root module. -If a definition is in a module imported with an <samp>INSTANCE</samp> -statement, then the name of the module may be indicated. -</p> - -<p> -You can edit or remove an overriding specification in the obvious way: by selecting it and -using the <samp>Edit</samp> or <samp>Remove</samp> button. -(Editing is also selected by double-clicking on the item.) -</p> - -<p fontsize=80%> -<b>Some Fine Print</b> -<font size=-1> -When overriding a definition, -the new definition can use any operator or parameters that -can be used in the the root module, as well as any -<a href="model-values.html">model value</a> that is -declared in the model. This means that you can override -a definition with an expression that -contains operators that are undefined at the point where the -original definition occurred. -TLC evaluates overridden definitions in the -obvious way, and bizarre overriding can -lead to strange results. For example, if <samp>Fact</samp> is defined by -<pre> - Fact(n) == IF n = 0 THEN 1 ELSE n * Bar(n-1) -</pre> -and the definition of <samp>Bar</samp> is overridden with -<pre> - Bar(n) <- Fact(n) -</pre> -then TLC will evaluate <samp>Fact(n)</samp> to -equal <samp>n!</samp> for any natural -number <samp>n</samp> . -There is no good reason to use such bizarre overriding.</font> -</p> - - -<h2><a name="action">Action Constraint</a></h2> - -An action constraint is much like a <a href="#state">state constraint</a>, except -that the constraint formula may also include primed variables. -See Section 14.3 (page 240) of -<em><a href= -"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> -Specifying Systems</a></em> for an explanation of how TLC uses an -action constraint. - -<h2><a name="launching">TLC Options</a></h2> - -You can choose between two basic ways of running TLC: - -<h3><a name="model-mode">Model-checking mode</a></h3> -<p> -This is the normal method of running TLC, in which it -essentially tries to check all possible behaviors allowed -by the behavior spec. Its default method of doing this -is to find the graph of all reachable states using -breadth-first search. This has the advantage that if -TLC finds a violation of a safety property, then it will -produce a shortest possible behavior that exhibits the -error. You can direct TLC to use a depth-first search -by choosing the <em>Depth-first</em> option and specifying -the depth of its search. (Limiting the depth ensures -that only a finite set of states is explored, even if -the complete set of reachable states is infinite.) -With depth-first search, TLC will usually not produce -a shortest-length error trace. When running in depth-first -mode, TLC does not compute the entire state graph and does not use a state -queue, so it does not produce any - <i>Diameter</i> or <i>Queue size</i> - statistics. -</p> -<p> -<b>Warning:</b> Depth-first search is an experimental TLC -option that has not been used much. We don't even know -if it really works, let alone if it offers any advantages. -If you do try it, let us know what you discover. -</p> - -<p> -You can also specify a <em>View</em> to be used in model-checking -mode. If you're curious about what that is and how it is used, -see Section 14.3.3 (page 243) of -<em><a href= -"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> -Specifying Systems</a></em>. -</p> -<h3>Simulation Mode</h3> - -<p> -In simulation mode, TLC does not try to examine all reachable states. -Instead, it checks an unending series of behaviors, each of which it constructs by -starting from a randomly choosen initial state and repeatedly making a random -choice of a possible next state. (In this mode, you stop TLC by clicking the -<samp>Cancel</samp> button on the dialog that the Toolbox pops up when it -runs TLC.) You specify the maximum length of each behavior that it generates. -If you want to know what specifying the <em>Seed</em> and <em>Aril</em> does, -look them up in -<em><a href= -"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> -Specifying Systems</a></em>. When run in simulation mode, the only -statistics TLC reports are for <i>States Found</i>. -</p> - -<h3>Verify temporal properties upon termination only</h3> -<p> -Defer the verification of temporal properties (liveness) to the end of model checking. -<b>This reduces the overall model checking time</b> with the additional side effect that invariant (safety) -violations will always be found first. In other words, check liveness only after the <em>complete</em> -state space has been checked for safety violations. -If unchecked, temporal properties are checked periodically on the <em>incomplete</em> -state graph. Defering verification of temporal properties is especially useful if it is highly -likely that the model does not violate its temporal properties (e.g. a smaller instance -of the model has successfully been verified for liveness violations). - -<h3>Fingerprint seed index</h3> -<p> -TLC saves only 64-bit fingerprints (hashes) of the reachable states that it finds, not the -complete states. If two different reachable states have the same fingerprint, a situtation -called a <em>collision</em>, TLC may not find all reachable states. -At the -end of a run, TLC prints estimates of how likely it was that a collision occurred. -If you're worried that a collision might have occurred, you can re-run the model with a -different fingerprint function. The fingerprint seed index specifies which of 64 fingerprint -functions TLC should use. If the two runs produce different numbers of reachable -states, then there was a collision in at least one of the runs. If not, the probability -that there was a collision in both is the square of the probability that either one had -a collision--a probability that is probably very, very small. - -<h3>Log base 2 of number of disk storage files</h3> - -If your computer has multiple disk drives, setting this parameter to a value greater -than 0 might make it possible to reduce the time -TLC spends writing to disk on a model with a very large number of reachable states. - -Contact us for more information. - -<h3> Cardinality of largest enumerable set</h3> - -If TLC tries to enumerate the elements of a set, it will report an error if the set -contains more than this number of elements. - -<h3>Visualize state graph after completion of model checking</h3> -<p> -Visualize the generated state graph graphically after completion of model checking. The -visualization helps to better understand the system being specified. Initial states are represented by gray vertices. -<p><b>Warning: </b>Can reasonably only visualize small state graphs with a few dozen to hundred states.</b></p> -<p> -In order to visualize a state graph, the path to the <em>dot</em> executable of the -<a href="http://www.graphviz.org/">GraphViz</a> project has to be set under <em>Specify dot command</em> on the <em>PDF viewer</em> preference -page on the File/Preferences menu. On macOS dot is most easily installed via the ports system. Homebrew has a Graphviz port too. -On Windows, GraphViz can be obtained through Cygwin or installed standalone. On most Linux derivatives, GraphViz can be installed via the package manager. -After installation, the the dot binary can usually be found at: -</p> - -<p> -<table> - <tr> - <td>OS</td> - <td>Default path</td> - </tr> - <tr> - <td>Windows (Cygwin)</td> - <td>C:\cygwin\bin\dot.exe</td> - <tr> - <td>Windows (standalone)</td> - <td>C:\Program Files (x86)\Graphviz2.38\bin\dot.exe</td> - </tr> - <tr> - <td>macOS (ports)</td> - <td>/opt/local/bin/dot</td> - </tr> - <tr> - <td>Linux</td> - <td>/usr/bin/dot</td> - </tr> -<table> -</p> -<p> -On Windows and Linux the state graph will be visualized with either the built-in or standalone PDF viewer -depending on which is selected on the PDF viewer preference page -(selecting a standalone viewer is advised for best results). -</p> - -<h3><A name="jvmargs">JVM arguments</A></h3> - -These are the arguments given to the Java Virtual Machine when TLC is run on the model. -Certain parameters for running TLC in -<a href="distributed-mode.html">distributed mode</a> are specified this way. -Only sophisticated users who know what they are doing should specify other JVM arguments. - -<h3>TLC command line parameters</h3> - -These are options given to TLC when it is run on the model. -A complete list of TLC options can be found in the - <code>tlatools > src > tlc2 > TLC.java</code> -file in the - <a href="https://tlaplus.codeplex.com/SourceControl/latest">CodePlex repository on - the web</a>. -An option specified here can override an option otherwise specified by the rest of the model, -which can cause strange things to happen. You should therefore use this -feature with care. - - -</p> - -<!-- I don't know what I'm saving the following for -<h2><a name="how">How to run?</a></h2> -<hr> -<!-- delete rest of line to comment out -<dl> -<dt><b><font color=#0000c0>Subtopics</font></b></dt> -<dd> <A href=""> TOPIC </A></dd> -<dd> <A href=""> TOPIC </A></dd> -</dl> - --> -<!-- delete rest of line to comment out --> -<a href = "creating-model.html">↑ Creating a Model</a> -<!-- --> -</hr> - -</body> -</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/creating-model.html b/org.lamport.tla.toolbox.doc/html/model/creating-model.html index c71fc78d0d44ef555ffac0041cc3ca3245106901..40773dd549bc49b69ad2d6a425aaa255c4de0996 100644 --- a/org.lamport.tla.toolbox.doc/html/model/creating-model.html +++ b/org.lamport.tla.toolbox.doc/html/model/creating-model.html @@ -1,62 +1,67 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<!-- This is file org.lamport.tla.toobox.doc/html/model/creating-model.html --> - - -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> - <LINK href="../style.css" rel="stylesheet" type="text/css"> - -<title>Creating a Model</title> -</head> -<!-- a comment here --> - -<body> -<h1>Creating a Model</h1> - -<P> -When you open a model, you open it in a <em>model editor</em>. The model editor -has three pages: The <A href="overview-page.html"> Model Overview Page</A> and -<A href="advanced-page.html">Advanced Options Page</A> specify the model. -The <A href="results-page.html"> Model Checking Results Page</A> shows you either what -the model checker is doing while it runs, or what it did the last time it was -run. You can switch between the pages using the tabs at the upper-left of the -model editor <a href="../gettingstarted/views.html">view</a>, or with the -<samp>Alt+PageUp</samp> and -<samp>Alt+PageDown</samp> keys. - </P> - -<p>You edit these pages in the usual way. Sections can be opened or closed by clicking -the -<samp>+</samp> or -<samp>-</samp> . When entering text in fields, you can use your system's -standard editing commands. -</p> - - -<p>Whenever you enter a TLA<sup>+</sup> expression as part of the model, -that expression can use any -symbols that you could use in a new definition placed at the end of the spec's root module. -It can also contain any <a href="model-values.html">model values</a> that are declared -in the model, as well as additional definitions entered in the -<a href="advanced-page.html#additional">Additional Definitions</a> section -of the <A href="advanced-page.html">Advanced Options Page</A>. -</p> - -<hr> -<!-- delete rest of line to comment out --> -<dl> -<dt><b><font color=#0000c0>Subtopics</font></b></dt> -<dd> <A href="overview-page.html"> Model Overview Page</A></dd> -<dd> <A href="advanced-page.html"> Advanced Options Page</A></dd> -<dd> <A href="results-page.html"> Model Checking Results Page</A></dd> - -</dl> -<!-- --> -<!-- delete rest of line to comment out --> -<a href = "model.html">↑ Model Checking</a> -<!-- --> -</hr> - -</body> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/model/creating-model.html --> + + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Creating a Model</title> +</head> +<!-- a comment here --> + +<body> +<h1>Creating a Model</h1> + +<P> +When you open a model, you open it in a <em>model editor</em>. The model editor then +shows two pages: The <A href="overview-page.html"> Model Overview Page</A> and +the <A href="results-page.html"> Model Checking Results Page</A> that shows you either what +the model checker is doing while it runs, or what it did the last time it was +run. The Model Overview Page contains links that open two other pages, +the <A href="spec-options-page.html">Spec Options</A> and +<A href="tlc-options-page.html">TLC Options</A> pages that allow you to specify +additional parameters for running TLC. + +You can switch between the pages using the tabs at the upper-left of the +model editor <a href="../gettingstarted/views.html">view</a>, or with the +<samp>Alt+PageUp</samp> and +<samp>Alt+PageDown</samp> keys. + </P> + +<p>You edit these pages in the usual way. Sections can be opened or closed by clicking +the +<samp>+</samp> or +<samp>-</samp> . When entering text in fields, you can use your system's +standard editing commands. +</p> + + +<p>Whenever you enter a TLA<sup>+</sup> expression as part of the model, +that expression can use any +symbols that you could use in a new definition placed at the end of the spec's root module. +It can also contain any <a href="model-values.html">model values</a> that are declared +in the model, as well as additional definitions entered in the +<a href="spec-options-page.html#additional">Additional Definitions</a> section +of the Spec Options page. +</p> + +<hr> +<!-- delete rest of line to comment out --> +<dl> +<dt><b><font color=#0000c0>Subtopics</font></b></dt> +<dd> <A href="overview-page.html"> Model Overview Page</A></dd> +<dd> <A href="results-page.html"> Model Checking Results Page</A></dd> +<dd> <A href="spec-options-page.html">Spec Options Page</A></dd> +<dd> <A href="tlc-options-page.html">TLC Options Page</A></dd> + +</dl> +<!-- --> +<!-- delete rest of line to comment out --> +<a href = "model.html">↑ Model Checking</a> +<!-- --> +</hr> + +</body> </html> \ No newline at end of file diff --git a/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html b/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html index bff2c62754fe0e44491bb09b529c48ddf4a8bf59..7daa46ff50c85153ead071abb48e94fb8a9d05e0 100644 --- a/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html +++ b/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html @@ -122,17 +122,17 @@ For distributed mode, you may also want to add special arguments to the command that launches the JVM that runs the master. As explained <a href="#possible-problem">below</a>, one such argument may be needed for the master and the workers to communicate. The -arguments are put in the <A href="advanced-page.html#jvmargs">JVM arguments</A> field -of the model's Advanced Options page. +arguments are put in the <A href="tlc-options-page.html#jvmargs">JVM arguments</A> field +of the model's TLC Options page, which may be opened via a link on the Model Overview page. </p> <p> -If your model will run for a long time (days or weeks), you may not want to -keep the Toolbox open for the entire run. Instead, you can run TLC from -a command line. +If your model will run for a long time (days or weeks), you may not want to +keep the Toolbox open for the entire run. Instead, you can run TLC from +a command line. The easiest way to do this is to create the model -in the Toolbox, and <a href="executing-tlc.html#validating">validate it</a>. +in the Toolbox, and <a href="executing-tlc.html#validating">validate it</a>. You can then run distributed TLC with the following command, where <code>tool-path</code> is the complete pathname of the directory containing the file <code>tla2tools.jar</code> @@ -174,7 +174,7 @@ communicate with one another and with the machine running the master and the Toolbox. We assume that there is some some remote management/administration system installed on the computers that run the workers. Examples of such a system are Remote Desktop (Windows), -ssh, rsh, and telnet. A Java Runtime Environment (JRE), version 1.5 +ssh, rsh, and telnet. A Java Runtime Environment (JRE), version 11 or later, must also be installed on the machines. </p> @@ -290,7 +290,7 @@ worker not to be able to communicate with the master because they are using different IP addresses. To solve this problem, choose one of those IP addresses--say <code>192.168.1.10</code>. Use that address as the master-computer name in the instructions above for running the -workers, add the following <A href="advanced-page.html#jvmargs">JVM argument</A> +workers, add the following <A href="tlc-options-page.html#jvmargs">JVM argument</A> to the model: <pre> @@ -302,16 +302,15 @@ to the model: Currently, workers are single threaded. You can take advantage of multi-core computers by running multiple workers on the same computer, using one of the previous methods to start each of the workers. -The major disadvantage of doing this is that a separate copy of +The major disadvantage of doing this is that a separate copy of the worker code is loaded into memory for each worker. END COMMENTED OUT --> - + <a name="limitations"></a><h2>Limitations of Distributed Mode</h2> -When run in distributed mode, TLC cannot check liveness properties. +When run in distributed mode, TLC cannot check liveness properties. Nor does it use depth-first mode or simulation mode, even if one of -those modes is selected on the - <a href="advanced-page.html">Advanced Options Page</a>. +those modes is selected on the <a href="tlc-options-page.html">TLC Options Page</a>. Coverage information is not provided. You should therefore check a smaller model in ordinary non-distributed mode to make sure that the diff --git a/org.lamport.tla.toolbox.doc/html/model/ete_add_edit_explore.gif b/org.lamport.tla.toolbox.doc/html/model/ete_add_edit_explore.gif new file mode 100644 index 0000000000000000000000000000000000000000..c6af5ae4d42ded4a8436b8b180edc6404e26ccc9 Binary files /dev/null and b/org.lamport.tla.toolbox.doc/html/model/ete_add_edit_explore.gif differ diff --git a/org.lamport.tla.toolbox.doc/html/model/evaluate-consant-expression.html b/org.lamport.tla.toolbox.doc/html/model/evaluate-consant-expression.html new file mode 100644 index 0000000000000000000000000000000000000000..e2dd14063595aec7539c6e08fc02f1b8e740623e --- /dev/null +++ b/org.lamport.tla.toolbox.doc/html/model/evaluate-consant-expression.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/model/evaluate-constant-expression.html --> + + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Evaluate Constant Expression</title> +</head> + +<body> +<h1>Evaluate Constant Expression</h1> + +<p> +This functionality may exist either constain on the Model Checking Results page of the Model +Editor, or on its own page, depending on how the user has configured the Toolbox +<a href="executing-tlc.html#preferences">via the preferences.</a> +</p> + +<p> +Entering a constant expression in the <em>Expression</em> +field of this section, and selecting the toggle button above and to the right +of this field, will cause the value of +that expression to appear in the <em>Value</em> field when TLC is run. +The expression can use any constant operators defined or declared in +the spec or elsewhere in the model. +Used with the +<em><a href="overview-page.html#what-is-behavior">No behavior +spec</a></em> option on +the <a href="overview-page.html">Model Overview Page</a>, this +turns TLC into a mathematical calculator--one that computes arbitrary +TLA<sup>+</sup> expressions. +</p> +</body> +</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html b/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html index fee8a4a213595b7e864fffbec4556ee7238ac7a7..1f68e2a256c769df6e46654f1c4904da5f29165a 100644 --- a/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html +++ b/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html @@ -1,7 +1,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <!-- This is file org.lamport.tla.toobox.doc/html/model/executing-tlc.html --> - + <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> @@ -22,16 +22,16 @@ Contents <a href="#crash">If Something Crashes</a> <a href="#MC">How TLC is Run</a> <a href="#console">The TLC Console View</a> - + </pre> - <P> -You run the TLC model checker by clicking on the <IMG SRC="run-icon.gif" Align="bottom"/> button. + <P> +You run the TLC model checker by clicking on the <IMG SRC="run-icon.gif" Align="bottom"/> button. This button -appears at the top of each model editor page. +appears at the top of each model editor page. You can also run it from the <em>TLC Model Checker</em> menu or by pressing the F11 key. Before running TLC on the model, -the Toolbox first <em>validates</em> the model, checking it for errors. +the Toolbox first <em>validates</em> the model, checking it for errors. Clicking on the <IMG SRC="validate-icon.gif" Align="bottom"/> button causes the Toobox to validate the model without running TLC on it. @@ -51,9 +51,9 @@ by placing error balloons like this messages for the page. </p> -<p> +<p> The Toolbox might report some model errors as being parsing errors in a -module named <code>MC</code> . See the section +module named <code>MC</code> . See the section <em><a href="#MC">How TLC is Run</a></em> below to find out how to interpret such an error message. </p> @@ -70,13 +70,13 @@ dialog while TLC is running: <IMG SRC="running-tlc.gif" Align="bottom"/> </blockquote> <p> -You can view the progress of the run on the model +You can view the progress of the run on the model editor's <em><a href="results-page.html">Model Checking Results Page</a></em>. That page is automatically displayed when TLC starts running. </p> -<p>Note: If you check <i>Always run in background</i> on the dialog shown above, -that dialog will stop popping up when you run TLC. +<p>Note: If you check <i>Always run in background</i> on the dialog shown above, +that dialog will stop popping up when you run TLC. To get it back, go to <code>File/Preferences/General</code> and uncheck the <i>Always run in background</i> preference.</p> @@ -95,19 +95,19 @@ If TLC finds an error, it stops and the Toolbox raises the <em>TLC Errors View</ (If you close the view, you can reopen it from the <em>TLC Model Checker</em> menu.) This view consists of the following two sections. (The relative sizes of those two sections can be changed by moving the cursor between them until it changes to -an up-and-down arrow, +an up-and-down arrow, and then clicking and dragging.) </p> <h4><a name="error-view">The Error View</a></h4> -This view displays the error message that TLC reports. +This view displays the error message that TLC reports. If an invariant or property is violated, the Toolbox will also put this warning icon <IMG SRC="warning.gif" Align="bottom"/> near the part of the model containing that invariant or property. Otherwise, the error probably occurred because TLC could not evaluate -an expression. +an expression. If you're lucky, the error message will contain the location of that expression--or a list of locations indicating the hierarchy of @@ -116,8 +116,8 @@ expressions that TLC was evaluating when it found the error. Clicking on a location jumps to the appropriate point in the spec, where that location is highlighted. -If you are model-checking a PlusCal algorithm, control-clicking on -the location will try to take you to the source of the error in +If you are model-checking a PlusCal algorithm, CTRL-clicking, or ⌘-clicking on macOS, on +the location will try to take you to the source of the error in the PlusCal code. @@ -135,27 +135,52 @@ Run</a></em> below. <h4>The Trace View</h4> <p> -This section contains three subsections: an error-trace explorer, an error-trace viewer, +This section contains three subsections: the Error-Trace Explorer, the Error-Trace viewer, and an expression view box. -The error-trace explorer can be opened or closed with the <samp>+</samp> -and <samp>-</samp> symbols; the relative sizes of these subsections can also be changed by dragging the boundary +The error-trace explorer can be opened or closed with the <samp>+</samp> +and <samp>-</samp> symbols. The relative sizes of these subsections can also be changed by dragging the boundary between them. You can drag the entire TLC Errors view out of the Toolbox window and make it a separate window, which you can enlarge if you want to see more of the error trace at once. </p> <p> -The error-trace viewer shows a structured view of the error trace -produced by TLC. The view box shows the TLA+ version of the expression selected in -the error trace. (It is ordinary text that can be copied and pasted elsewhere.) +The Error-Trace Explorer allows the user to add expressions which will be evaluated at each state, and whose result will be +included in the output seen in the Error-Trace viewer in bold text. Expressions can be: +<ul> + <li>added by clicking the "Add" button</li> + <li>edited by highlighting it in the list and then clicking the "Edit" button</li> + <li>removed by highlighting it in the list and then clicking the "Remove" button</li> + <li>enabled and disabled via the checkbox next to expression in the list</li> +</ul> +If at least one expression is enabled, the "Explore" button will be enabled; clicking this button will run the model checking including the +evaluation of the enabled expressions.<br/> +After a checking has been run including evaluated expressions, the list of expressions and "Add," "Edit," and "Remove," will +be disabled until the user clicks on the "Restore" button.<br/> +Additionally, formulas may be drag-reordered in the list. +</p> + +<img src="ete_add_edit_explore.gif" style="max-width: 100%; height: auto;" /> + +<p> +The Error-Trace viewer shows a structured view of the error trace +produced by TLC. The view box shows the TLA+ version of the expression selected in +the error trace. (It is ordinary text that can be copied and pasted elsewhere.) </p> -<p> -The error trace consists of a sequence of states, where a state is a TLA+ expression +<p> +The error trace consists of a sequence of states, where a state is a TLA+ expression that describes the values of the variables. The trace viewer provides a tree-structured -view of the state, allowing you to examine the value of each variable and of each -subexpression of that value. (Left-click on the <samp>+</samp> +view of the state, allowing you to examine the value of each variable and of each +subexpression of that value. (Left-click on the <samp>+</samp> and <samp>-</samp> symbols to expand and hide subexpressions.) -This is helpful in viewing complex values. +This is helpful in viewing complex values.<br/> +Double clicking on a state line location will open up the spec window editor and highlight +that section of the spec; similar to in the Error View, holding down the CTRL, or ⌘ on macOS, key +while doing this will jump to the PlusCal original code if it exists. +Pressing the button with two horizontal arrows next to the +'Expand/Collapse All' button will "link" and "unlink" the trace viewer with the spec +editor; when linked, a single click on a location, or using the keyboard's arrow keys, +will change highlighted position like a double-click. </p> <p> @@ -180,7 +205,7 @@ the values of their subexpressions from one state to the next. The color <p> The top line of a state's display in the error trace gives the location of the sub-action of the next-state relation that generated the state (except for the first state, which is generated by the -initial predicate). +initial predicate). Double-clicking on that line takes you to the indicated location. </p> @@ -188,8 +213,8 @@ Double-clicking on that line takes you to the indicated location. The error-trace explorer allows you to view the values of expressions in each step of the trace. You just enter one or more expressions, which can contain primed as well as unprimed variables, and click on <samp>Explore</samp>. The values -of the expressions will then be shown in the error trace. Clicking on -<samp>Restore</samp> restores the original error trace. +of the expressions will then be shown in the error trace. Clicking on +<samp>Restore</samp> restores the original error trace. </p> <p> @@ -210,7 +235,7 @@ allows you to select the following: <h3>Always pop up TLC errors view</h3> <p> Controls whether or not the <a href="#error-reports">TLC Errors View</a> is automatically -popped up when running TLC produces an error. You will almost certainly want to +popped up when running TLC produces an error. You will almost certainly want to use the default, which is to pop up the view. </p> @@ -224,10 +249,17 @@ The model is automatically saved when you run or validate it, so you will probably have no reason to save it explicitly. </p> +<h3>Show Evaluate Constant Expression in its own tab</h3> +<p> +By default, the user can enter constant expressions to evaluate in a section on the Model Checking +Results page; by selecting this option, this section will be moved to its own page +within the Model Editor. +</p> + <h3>Number of model snapshots to keep</h3> <p> Re-running a model erases the corresponding model checking results if any. With snapshots -activate, the Toolbox maintains a history of the N most recent model runs. The value N is defined +activate, the Toolbox maintains a history of the N most recent model runs. The value N is defined by <samp>Number of model snapshots to keep</samp> where zero disables snapshots completely. The history allows one to trace back the evolution of the specification and corresponding model. </p> @@ -246,12 +278,12 @@ model editor's Overview Page help page. <p> The maximum number of states of a trace that is displayed in the Trace Explorer when -TLC reports an error. +TLC reports an error. If the trace has more states, only the last ones are shown. Double-clicking at the beginning of the trace displays additional states. The default value is 10000. -</p> +</p> <h2><a name="crash">If Something Crashes</a></h2> <!-- @@ -260,8 +292,8 @@ If TLC crashes (a very rare occurrence), or if the Toolbox or your computer cra you restart the Toolbox, you could find the Toolbox in a state in which it says that TLC has crashed. In that case, you will see a <em>Repair</em> button at the top right of the model editor. Click on it. Instead of saying that TLC has crashed, -the Toolbox might say that -TLC is still running even though it's not. If that happens, open the +the Toolbox might say that +TLC is still running even though it's not. If that happens, open the <a href="../spec/opening-closing.html"><em>Spec Explorer</em></a>, click on the <code>+</code> next to the open spec, right-click on the model in question, and select the <code>Repair</code> option. This should fix the problem. @@ -271,8 +303,8 @@ select the <code>Repair</code> option. This should fix the pro If you stop the Toolbox in some abnormal way while it is running TLC--for example, by using an operating system tool to kill its process--you may leave TLC running as a disembodied process. In that case, you should kill the TLC process. -Otherwise, strange things will happen if you restart -the Toolbox and try to run TLC from it on the model. +Otherwise, strange things will happen if you restart +the Toolbox and try to run TLC from it on the model. </p> <h2><a name="MC">How TLC is Run</a></h2> @@ -288,9 +320,9 @@ files are written in the subfolder <code>SpecName.toolbox/ModName</code>&n <p> At the same time that it writes those files, the Toolbox also writes into the same -folder a copy of each of the spec's module files. +folder a copy of each of the spec's module files. These allow you to see the version -of the spec on which TLC was run, even after you have modified the spec. +of the spec on which TLC was run, even after you have modified the spec. You can view that version of the spec by selecting (any page of) the model, clicking on the <code>TLC Model Checker</code> menu at the top of the Toolbox window, and then clicking on <code>Open Saved Module</code>. @@ -300,12 +332,12 @@ and then clicking on <code>Open Saved Module</code>. <p> It is a sad fact of life that most computer programs, including the Toolbox, have bugs. A Toolbox bug may cause TLC to stop running without either indicating that -it succeeded or reporting an error. (You know that the TLC run succeeded +it succeeded or reporting an error. (You know that the TLC run succeeded if the <em>General</em> section of the <a href="results-page.html"><em>Model Checking Results Page</em></a> says that -TLC is not running and the top entry of its <em>Statistics</em> section's -<em>State space progress</em> table shows a queue size of 0.) +TLC is not running and the top entry of its <em>Statistics</em> section's +<em>State space progress</em> table shows a queue size of 0.) If that page's <em>Progress Output</em> section doesn't explain what happened, the place to look next is the Toolbox's <em>TLC Console View</em>. You can open that view from the Toolbox's <em>TLC Model Checker</em> menu. @@ -313,7 +345,7 @@ You can open that view from the Toolbox's <em>TLC Model Checker</em> menu. <p> The TLC Console View contains all the output that TLC has produced when running this -model. (You can clear the console with the view's +model. (You can clear the console with the view's <IMG SRC="clear-icon.gif" Align="bottom"/> botton.) However, each TLC output message appears between pairs of lines such as: <pre> @@ -324,21 +356,21 @@ appears between pairs of lines such as: </p> <p> -We hope that Toolbox bugs will soon become sufficiently rare that there will be -no need for the TLC Console View. -You can help make that happen by <a href="../trouble/trouble.html#reporting">reporting problems</a>. +Toolbox bugs that would cause you to look at +the TLC Console View are quite rare. +You can help make that even rarer by <a href="../trouble/trouble.html#reporting">reporting problems</a>. </p> -<hr> -<!-- delete rest of line to comment out +<hr> +<!-- delete rest of line to comment out <dl> <dt><b><font color=#0000c0>Subtopics</font></b></dt> <dd> <A href=""> TOPIC </A></dd> <dd> <A href=""> TOPIC </A></dd> </dl> - --> -<!-- delete rest of line to comment out --> + --> +<!-- delete rest of line to comment out --> <a href = "model.html">↑ Model Checking</a> -<!-- --> +<!-- --> </hr> </body> diff --git a/org.lamport.tla.toolbox.doc/html/model/model-values.html b/org.lamport.tla.toolbox.doc/html/model/model-values.html index 168d36d29c415135a07f9cc99be23dff72b340fc..bc231a3cf638cbeb5a228ebe0e8e2b782d9d7bca 100644 --- a/org.lamport.tla.toolbox.doc/html/model/model-values.html +++ b/org.lamport.tla.toolbox.doc/html/model/model-values.html @@ -58,8 +58,8 @@ it cannot evaluate the unbounded <code>CHOOSE</code> expression.&nbs To allow TLC to handle the spec, you need to substitute a model value for <code>NotANat</code> . The best model value to substitute for it is one named <code>NotANat</code> . This is done in the -<a href="advanced-page.html#override">Definition Override</a> section of -the <a href="advanced-page.html">Advanced Options Page</a>. The Toolbox will +<a href="spec-options-page.html#override">Definition Override</a> section of +the <a href="spec-options-page.html">Spec Options Page</a>. The Toolbox will create the appropriate entry in that section when it creates a model if it finds a definition having the precise syntax above or the syntax @@ -75,21 +75,21 @@ can be any identifiers. <p> There are some uses of model values that can't be specified with the <a href="overview-page.html#what-is-model">What is the model?</a> -section of the <A href="overview-page.html">Model Overview Page</A>. +section of the <A href="overview-page.html">Model Overview Page</A>. If you encounter such a problem, you can declare your own set of model values -with the <A href="advanced-page.html#additional">Additional Definitions</a> section -of the <A href="advanced-page.html"> Advanced Options Page</A> and then use them +with the <A href="spec-options-page.html#additional">Additional Definitions</a> section +of the <A href="spec-options-page.html"> Spec Options Page</A> and then use them as ordinary values in expressions of the model. </p> <h2><a name="typed-values">Typed Model Values</a></h2> <p> -Suppose that, by mistake, you write the +Suppose that, by mistake, you write the expression <code>p=2</code> where <code>p</code> is a process. If you substitute a set of ordinary model values for the set of processes, TLC will simply obtain the value <code>FALSE</code> -if it evalutes this expression, since it considers an ordinary model value +if it evalutes this expression, since it considers an ordinary model value to be different from any other value. To allow TLC to detect this kind of error, you can use a set of <em>typed</em> model values. TLC considers a typed model value to be unequal to any other model value of the same type. However, it produces an @@ -128,16 +128,16 @@ option of that section. <p> Model values can be declared in the following places: <ul> -<li>When assigning a value to a constant parameter in the +<li>When assigning a value to a constant parameter in the <a href="overview-page.html#what-is-model">What is the model?</a> section of the <em>Model Overview Page</em>, by choosing the <em>Model value</em> or <em>Set of model values</em> option.</li> -<li>When overriding a definition in the <a href="advanced-page.html#override">Definition override</a> -section of the <em>Advanced Options Page</em>, by choosing the <em>Model value</em> option. +<li>When overriding a definition in the <a href="spec-options-page.html#override">Definition override</a> +section of the <em>Spec Options Page</em>, by choosing the <em>Model value</em> option. </li> <li> -In the <a href="advanced-page.html#model">Model Values</a> section of the <em>Advanced Options Page</em>. +In the <a href="spec-options-page.html#model">Model Values</a> section of the <em>Spec Options Page</em>. </li> </ul> @@ -207,13 +207,13 @@ is not symmetric for <code>{v1, v2, v3}</code>. <p> -Symmetry sets should not be used when checking liveness properties. -Doing so can make TLC fail to find errors, or to report nonexistent errors. +<b>Symmetry sets should not be used when checking liveness properties. +Doing so can make TLC fail to find errors, or to report nonexistent errors.</b> </p> <!-- <p> -Symmetry sets are used only in <a href="advanced-page.html#model-mode">model-checking mode</a>. +Symmetry sets are used only in <a href="spec-options-page.html#model-mode">model-checking mode</a>. See Section 14.3.4 (page 245) of <em><a href= "http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> diff --git a/org.lamport.tla.toolbox.doc/html/model/model.html b/org.lamport.tla.toolbox.doc/html/model/model.html index 6a3b725e36a2a43a1df165f493a5f7f96681c1b4..555b054e09453501bdb601811620d94758840b9f 100644 --- a/org.lamport.tla.toolbox.doc/html/model/model.html +++ b/org.lamport.tla.toolbox.doc/html/model/model.html @@ -1,49 +1,49 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<!-- This is file org.lamport.tla.toobox.doc/html/.html --> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> - <LINK href="../style.css" rel="stylesheet" type="text/css"> - -<title>Model Checking</title> -</head> -<!-- a comment --> - -<body> -<h1>Model Checking</h1> - - <P> -The Toolbox uses the TLC model checker to model check the current spec. -More precisely, TLC checks a <em>model</em> of the specification. -The <a href="about-models.html"><em>Models</em></A> help page explains what a model -is and how to manage models. The -<A href="creating-model.html"><em>Creating a Model</em></A> page explains how to -create a model. The <A href="executing-tlc.html"><em>Checking a Model</em></A> page -explains how to run TLC and what to do when it reports an error. - </P> - -<p> -TLC can make use of multiple processors, getting speedups that are almost linear in -the number of processors. It can use multiple processors (cores) in a single -computer, and multiple networked computers. See the <a href="overview-page.html#how-to-run">How to run</a> -section of the <a <a href="overview-page.html">Model Overview Page</a> and -<a href="distributed-mode.html">Running TLC in Distributed Mode</a>. - -</p> -<hr> -<!-- delete rest of line to comment out --> -<dl> -<dt><b><font color=#0000c0>Subtopics</font></b></dt> -<dd> <A href="about-models.html">Models </A></dd> -<dd> <A href="creating-model.html">Creating a Model </A></dd> -<dd> <A href="executing-tlc.html">Checking a Model </A></dd> -</dl> -<!-- --> -<!-- delete rest of line to comment out -<a href = ".html">↑ HIGHER_LEVEL_TOPIC</a> ---> -<a href = "../contents.html">↑ TLA+ Toolbox User's Guide</a> -</hr> - -</body> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/.html --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Model Checking</title> +</head> +<!-- a comment --> + +<body> +<h1>Model Checking</h1> + + <P> +The Toolbox uses the TLC model checker to model check the current spec. +More precisely, TLC checks a <em>model</em> of the specification. +The <a href="about-models.html"><em>Models</em></A> help page explains what a model +is and how to manage models. The +<A href="creating-model.html"><em>Creating a Model</em></A> page explains how to +create a model. The <A href="executing-tlc.html"><em>Checking a Model</em></A> page +explains how to run TLC and what to do when it reports an error. + </P> + +<p> +TLC can make use of multiple processors, getting speedups that are almost linear in +the number of processors. It can use multiple processors (cores) in a single +computer, and multiple networked computers. See the <a href="overview-page.html#how-to-run">How to run</a> +section of the <a href="overview-page.html">Model Overview Page</a> and +<a href="distributed-mode.html">Running TLC in Distributed Mode</a>. + +</p> +<hr> +<!-- delete rest of line to comment out --> +<dl> +<dt><b><font color=#0000c0>Subtopics</font></b></dt> +<dd> <A href="about-models.html">Models </A></dd> +<dd> <A href="creating-model.html">Creating a Model </A></dd> +<dd> <A href="executing-tlc.html">Checking a Model </A></dd> +</dl> +<!-- --> +<!-- delete rest of line to comment out +<a href = ".html">↑ HIGHER_LEVEL_TOPIC</a> +--> +<a href = "../contents.html">↑ TLA+ Toolbox User's Guide</a> +</hr> + +</body> </html> \ No newline at end of file diff --git a/org.lamport.tla.toolbox.doc/html/model/overview-page.html b/org.lamport.tla.toolbox.doc/html/model/overview-page.html index 4df87407a9a7d9e247d09aaccfe1b7f983665ef7..ede1e5fa2e947ebb7b6997a9eba0e196c80c1506 100644 --- a/org.lamport.tla.toolbox.doc/html/model/overview-page.html +++ b/org.lamport.tla.toolbox.doc/html/model/overview-page.html @@ -21,13 +21,18 @@ Contents <a href="#what-to-check">What to check?</a> <a href="#what-is-model">What is the model?</a> <a href="#how-to-run">How to run?</a> - <a href="#distributed">Running in Distributed Mode</a> </pre> <P> -This model editor page is usually the only one you will use to create -and run your model. Here are what the different sections of the +This model editor page allows you to make the most common choices +of the parameter values with which TLC is to be run. +It contains links to the <a href="spec-options-page.html">Spec Options Page</a> +for specifying additional +options for telling TLC what spec behaviors to check and +to the <a href="tlc-options-page.html">TLC Options Page</a> for specifying additional +ways to control the execution of TLC. +Here are what the different sections of the Model Overview page are for. </P> @@ -114,7 +119,7 @@ help page.) </dd> <br></br> <dt><b>Set of model values</b></dt> -<dd>You must enter comma-separated list of legal model-value names, +<dd>You must enter a comma-separated list of legal model-value names, optionally enclosed by <code>{</code> and <code>}</code>. You will have the option of making them a symmetry set. @@ -137,99 +142,101 @@ help page to learn about typed values and symmetry sets. </dl> <h2><a name="how-to-run">How to run?</a></h2> -Here, you specify the following two aspects of how TLC should -be run. (See the <a href="advanced-page.html#launching">TLC Options</a> section -of the <a href="advanced-page.html"><em>Advanced Options Page</em></a> help page for -additional ways to run TLC.) +There are two basic ways to run TLC: locally on the computer running the +Toolbox and remotely using multiple computers. For local execution, you can choose +from a small number of useful options. See the <a href="tlc-options-page.html">TLC Options Page</a> for +additional choices of how to run TLC. Remote execution offers the possibility of +greatly speeding up execution through the use of a network of computers. +For information about the remote execution +options, see <a href="distributed-mode.html">Running TLC in Distributed Mode</a>. -<h3>TLC Parameters</h3> -There are two parameters that you can set here: - -<h4>Number of worker threads</h4> - -TLC's algorithm for computing the set (actually the graph) of reachable states -is highly parallelizable, and it can make good use of arbitrarily many processors. -This parameter specifies the number of separate threads that TLC will spawn to -perform that computation. You should not set it to be greater than the number of -separate processors (cores) on your computer; the Toolbox will warn you if you do. - -<h4>Fraction of physical memory allocated to TLC</h4> - -This determines how large a heap TLC will use. If you make it too small, TLC -could run out of heap space and crash. If you make it too large, your machine will not have -enough memory and everything will run slowly. The slider's color warns you if -you are giving TLC too little or too much memory. -TLC can keep the set of reachable states it has found -on disk, so having too many reachable states can't run it out of memory. -However, it runs much faster when it can keep those states in memory. -TLC can run out of heap space if it takes too much memory to represent the -set of initial states or the set of successor states of a single state. -If TLC does run out of memory in the middle of a long run, -you can give it more and restart it from a checkpoint. - -<p> - -Setting the this parameter too large may produce a -<em>Could not create the Java virtual machine</em> error. - - -<A name="checkpoint"></A><h3>Checkpoint Recovery</h3></A> - - <p> -TLC takes regular checkpoints, from which it can be restarted if it is -stopped for any reason--for example, if your computer crashes. - -The <em>Recover from checkpoint</em> option tells TLC to start from where it -was when the last checkpoint was taken. - -This option is enabled if the last time you ran TLC, it ran long enough to -produce a checkpoint. The Toolbox will fill in the <em>Checkpoint -id</em> for you. - </p> - <p> -Warning: If you exit the Toolbox, it will stop any executions of TLC that are -in process. - -However, it is possible to stop the Toolbox in some drastic fashion that -leaves TLC running as a background process. - -Restarting from a checkpoint while the TLC process that created it is still -running can cause the checkpoint to be destroyed, making recovery -impossible. - -If you have reason to believe TLC was not stopped, check to see if it is -still running before trying to recover from a checkpoint. - </p> - <p> -The checkpoint TLC produces after a short run does not take up -much space. - -However, if TLC finds an error after running for a long time, the -checkpoint files could take up a lot of space--sometimes on the order -of a gigabyte for a model that has run for several days. - -These files are deleted if the model is re-run and a new checkpoint is -produced, or if the model is validated when the -<em>Recover from checkpoint</em> option is not selected. - -When TLC has created a checkpoint, the <em>How to Run</em> section -of the Model Overview page displays how much storage the checkpoint -occupies. - -It also provides a button that you can click to delete the checkpoint. - </p> - -<p> -Checkpointing does not yet work when TLC is run in distributed mode. </p> -<a name="distributed"></a><h3>Running in Distributed Mode</h3> -<p> -TLC can be run with worker threads run on multiple machine, -considerably speeding up its execution. -See <a href="distributed-mode.html">Running TLC in Distributed Mode</a> +<!-- MOVED TO TLC OPTIONS PAGE + <h3>TLC Parameters</h3> + There are two parameters that you can set here: + + + <h4>Number of worker threads</h4> + + TLC's algorithm for computing the set (actually the graph) of reachable states + is highly parallelizable, and it can make good use of arbitrarily many processors. + This parameter specifies the number of separate threads that TLC will spawn to + perform that computation. You should not set it to be greater than the number of + separate processors (cores) on your computer; the Toolbox will warn you if you do. + + <h4>Fraction of physical memory allocated to TLC</h4> + + This determines how large a heap TLC will use. If you make it too small, TLC + could run out of heap space and crash. If you make it too large, your machine will not have + enough memory and everything will run slowly. The slider's color warns you if + you are giving TLC too little or too much memory. + TLC can keep the set of reachable states it has found + on disk, so having too many reachable states can't run it out of memory. + However, it runs much faster when it can keep those states in memory. + TLC can run out of heap space if it takes too much memory to represent the + set of initial states or the set of successor states of a single state. + If TLC does run out of memory in the middle of a long run, + you can give it more and restart it from a checkpoint. + + <p> + + Setting the this parameter too large may produce a + <em>Could not create the Java virtual machine</em> error. + + + + <A name="checkpoint"></A><h3>Checkpoint Recovery</h3></A> + + <p> + TLC takes regular checkpoints, from which it can be restarted if it is + stopped for any reason--for example, if your computer crashes. + + The <em>Recover from checkpoint</em> option tells TLC to start from where it + was when the last checkpoint was taken. + + This option is enabled if the last time you ran TLC, it ran long enough to + produce a checkpoint. The Toolbox will fill in the <em>Checkpoint + id</em> for you. + </p> + <p> + Warning: If you exit the Toolbox, it will stop any executions of TLC that are + in process. + + However, it is possible to stop the Toolbox in some drastic fashion that + leaves TLC running as a background process. + + Restarting from a checkpoint while the TLC process that created it is still + running can cause the checkpoint to be destroyed, making recovery + impossible. + + If you have reason to believe TLC was not stopped, check to see if it is + still running before trying to recover from a checkpoint. + </p> + <p> + The checkpoint TLC produces after a short run does not take up + much space. + + However, if TLC finds an error after running for a long time, the + checkpoint files could take up a lot of space--sometimes on the order + of a gigabyte for a model that has run for several days. + + These files are deleted if the model is re-run and a new checkpoint is + produced, or if the model is validated when the + <em>Recover from checkpoint</em> option is not selected. + + When TLC has created a checkpoint, the <em>How to Run</em> section + of the Model Overview page displays how much storage the checkpoint + occupies. + + It also provides a button that you can click to delete the checkpoint. + </p> + + <p> + Checkpointing does not yet work when TLC is run in distributed mode. + </p> +--> -</p> <hr> <!-- delete rest of line to comment out --> diff --git a/org.lamport.tla.toolbox.doc/html/model/profiler.png b/org.lamport.tla.toolbox.doc/html/model/profiler.png new file mode 100644 index 0000000000000000000000000000000000000000..626dc95bca6eb2ecbe1b28d1e1fc0eaa54a2c44d Binary files /dev/null and b/org.lamport.tla.toolbox.doc/html/model/profiler.png differ diff --git a/org.lamport.tla.toolbox.doc/html/model/profiling.html b/org.lamport.tla.toolbox.doc/html/model/profiling.html new file mode 100644 index 0000000000000000000000000000000000000000..1dcc46ed239658a191c27ff4703afa8b428fef3c --- /dev/null +++ b/org.lamport.tla.toolbox.doc/html/model/profiling.html @@ -0,0 +1,106 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/model/profiling.html --> + + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Profiling</title> +</head> +<!-- a comment here --> + +<body> +<h1>Profiling</h1> + +<pre> +Contents + <a href="#how-it-works">What can the profiler do?</a> + <a href="#modes">Profiling Modes</a> + <a href="#ui">Profiler UI</a> + <a href="#limitations">Limitations</a> +</pre> + + +<a name="how-it-works"></a><h2>What can the profiler do?</h2> + +<p> +Profiling a specification is similar to profiling implementation +code: During model checking, the profiler collects evaluation +metrics about the invocation of expressions, their costs, as well +as action metrics. The number of invocations equals the number +of times an expression has been evaluated by the model checker. +Assuming an identical, fixed cost for all expressions allows to +identify the biggest contributor to overall model checking time +by looking at the number of invocations. This assumption however +does not hold for expressions that require the model checker to +explicitly enumerate data structures as part of their evaluation. +For example, let S be a set of natural numbers from N to M such +that N << M and \A s \in SUBSET S : s \subseteq S be a +expression. This expression will clearly be a major contributor +to model checking time even if its number of invocations is low. +More concretely, its cost equals the number of operations +required by the model checker to enumerate the powerset of S. +Users can override such operators with more efficient variants. +Specifically, TLC allows operators to be overridden with Java +code which can usually be evaluated orders of magnitudes faster. +</p> +<p> +Evaluation metrics are captured globally and at the call-chain +level. In other words, the metrics for an expression such as a +operator, that occurs in two or more expressions, will be +reported individually for each occurrence. Metrics are +furthermore sensitive to constants such that the change of a +constant value — across model checker runs — will be detectable +in the metrics unless the constant has no influence at all. +</p> +<p> +Action metrics, which are orthogonal to evaluation metrics and +are not found in an implementation profiler, are the total number +of states and distinct states found which are reported at the +action level. +</p> + +<p> +The profiler neither requires the specification nor the model to +be modified in order to collect metrics. +</p> + +<a name="modes"></a><h2>Profiling modes</h2> + +The profiler can be turned On to collect evaluation and action metrics, restricted to +action metrics only to debug action enablement, or switched off completely. Overhead +of profiling suggests to turn it off when checking large models. The control is located +on the TLC Options page of the Model. + +<a name="ui"></a><h2>Profiling tab of the Model</h2> + +The Toolbox overlays the evaluation and action metrics onto a module by coloring the +exact locations of the corresponding expressions or actions in the Spec Editor. Users +can interactively drill into the call-chain scope by selecting individual expressions. +Heatmaps allow to quickly navigate to the dominant contributors of model checking time +as well as total states and distinct states found. Expressions with zero invocations +and actions whose enablement predicate is never true - which are considered spec errors - +are highlighted specifically. +<p> +<img src="profiler.png" alt="Action and evaluation metrics for the global scope overlayed +onto the Spec Editor. Red boxes indicate action that are never enabled and dead expressions. +The hover help displays detailed metrics for action a. Clicking the 1D heatmap at the bottom +selects the corresponding expression." height="600" width="700" class="center"> +<p> + +<a name="limitations"></a><h2>Limitations</h2> + +<ul> + <li>Profiling only for the Spec and its invariants but not for liveness properties</li> + <li>No support for distributed TLC</li> + <li>Just profiling which incurs overhead, no sampling yet</li> +</ul> + +<hr> +<a href = "overview-page.html">↑ Model Overview Page</a> +</hr> + +</body> +</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/results-page.html b/org.lamport.tla.toolbox.doc/html/model/results-page.html index d39886a96497462976f9f25ed107abca9d14bfdf..14a03a6959d6a1c2f0b7c905dd41f09f5be2026c 100644 --- a/org.lamport.tla.toolbox.doc/html/model/results-page.html +++ b/org.lamport.tla.toolbox.doc/html/model/results-page.html @@ -96,31 +96,21 @@ the actual system being specified. This kind of error leads to a violatio liveness properties, but does not cause any violation of safety. The coverage statistics give you a way of catching such an error even if you're not checking liveness. -</p> +</p> <p>Coverage shows the number of times each sub-action of the next-state relation -has been used to compute a successor state. +has been used to compute a successor state. Don't worry about how TLC decides what a sub-action is; just look at the values reported and the corresponding parts of -the specification to which they refer. A sub-action that is executed zero times +the specification to which they refer. A sub-action that is executed zero times - emphasized by yellow background coloring of the table row - usually indicates an -error in the spec. Left-clicking on an entry takes you to the indicated -location. +error in the spec. Left-clicking on an entry takes you to the indicated +location. </p> <h2><a name="evaluate">Evaluate Constant Expression</a> </h2> <p> -If you enter a constant expression in the <em>Expression</em> -field of this section, running TLC will cause the value of -that expression to appear in the <em>Value</em> field. -The expression can use any constant operators defined or declared in -the spec or elsewhere in the model. -Used with the -<em><a href="overview-page.html#what-is-behavior">No behavior -spec</a></em> option on -the <a href="overview-page.html">Model Overview Page</a>, this -turns TLC into a mathematical calculator--one that computes arbitrary -TLA<sup>+</sup> expressions. +This section is described <a href="evaluate-constant-expression.html">on its own page.</a> </p> <h2><a name="user">User Output</a></h2> diff --git a/org.lamport.tla.toolbox.doc/html/model/spec-options-page.html b/org.lamport.tla.toolbox.doc/html/model/spec-options-page.html new file mode 100644 index 0000000000000000000000000000000000000000..3355187fcc5db7cf8c4c767bd0216e8593542076 --- /dev/null +++ b/org.lamport.tla.toolbox.doc/html/model/spec-options-page.html @@ -0,0 +1,197 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/model/spec-options-page.html --> + + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Spec Options Page</title> +</head> +<!-- a comment here --> + +<body> +<h1>Spec Options Page</h1> + + +<pre> +Contents + <a href="#additional">Additional Definitions</a> + <a href="#state">State Constraint</a> + <a href="#model">Model Values</a> + <a href="#override">Definition Override</a> + <a href="#action">Action Constraint</a> +</pre> + +<P> +This model editor page allows you to add less-often +used parts of a model that describe the spec +that the Toolbox calls TLC to check. It's a good idea to browse +this page just to see what options it provides, since +some of the features are not ones you would expect. +The page is raised from a link on the <a href="overview-page.html">Model Overview Page</a>. + </P> + +<h2><a name="additional">Additional Definitions</a></h2> + +<p> +It is sometimes convenient to define operators just +for use in the expressions that specify a model. For +example, you might want to define an operator that +you use can use in more than one invariant. If you +don't want those definitions to be part of the spec, +you can put them in this section of the page. These +definitions can use any operator or parameters that +can be used in the the root module, as well as any +<a href="model-values.html">model value</a> that is +declared in the model. +</p> + +<p> +In addition to definitions, in this section you can also +put assumptions (<code>ASSUME</code> statements) +for TLC to check. Putting other +things in this section, such as declarations, +will result in mysterious TLC errors. + +</p> +<h2><a name="state">State Constraint</a></h2> + +<p> +Many behavior specifications have an infinite set of reachable +states. For example, message queues could get arbitrarily large. +TLC will run forever (or until your computer runs out +of disk space) on such a behavior spec. You could just let it +run and keep looking for violations of safety properties such as invariance. +However, it's a better idea to limit the set of states by entering +a state constraint here. +</p> + +<p> +A state constraint is a state predicate, which is a +Boolean-valued expression that contains unprimed variables. +When computing the set of reachable states, TLC will not +explore successor states of any state it finds that does +<em>not</em> satisfy the state constraint. For example, +specifying <code>len < 3</code> essentially +limits the set of reachable states that TLC finds to ones +that can be reached by a sequence of states in which +the value of the variable <code>len</code> +is less than 3. See Section 14.3 (page 240) of +<em><a href= +"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> +Specifying Systems</a></em> for an explanation of how TLC +computes reachable states. Note that there is no need +for multiple state constraints because they can simply be +conjoined to form a single constraint. +</p> + +<!-- +<p>A state constraint has an effect only in model checking mode. (See +<a href="#launching">TLC Options</a>.) +</p> + --> + +<h2><a name="model">Model Values</a></h2> + +You can enter here a set of model values, which you can then +use in expressions that define the model--for example, in +the value substituted for a declared constant. See the +<A href="model-values.html"><em>Model Values and Symmetry</em></A> help +page for an explanation of what model values are and how they +are used. + +<h2><a name="override">Definition Override</a></h2> +<p> +We want our specifications to be as simple and easy to understand as +possible. Sometimes this leads to a definition that TLC cannot evaluate, +or that it can evaluate only very inefficiently. In that case, we +must <em>override</em> the definition by telling TLC to replace it with +a new definition. To do this, click on the section's <samp>Add</samp> +button, select the operator whose definition you want to override, and +click <samp>OK</samp> . (You can also double-click on the +operator name.) This will raise a dialog in which you can specify +the overriding. +</p> + +<p> +If the operator whose definition you are overriding has arguments, +you will be presented with a form for writing the new definition in +the obvious way. If it has no arguments, you have two +options. With the <em>Ordinary assignment</em> option, you just +write the new definition. The <em>Model value</em> option +defines the operator to equal a model value of the same name. +See the +<A href="model-values.html"><em>Model Values and Symmetry</em></A> help +page for an explanation of model values and the most common +reason why you would want to override the definition in this way. +</p> + +<p> +You can override definitions made in modules other than the root module. +If a definition is in a module imported with an <samp>INSTANCE</samp> +statement, then the name of the module containing the definition is indicated. +</p> + +<p> +You can edit or remove an overriding specification in the obvious way: by selecting it and +using the <samp>Edit</samp> or <samp>Remove</samp> button. +(Editing is also selected by double-clicking on the item.) +</p> + +<p fontsize=80%> +<b>Some Fine Print</b> +<font size=-1> +When overriding a definition, +the new definition can use any operator or parameters that +can be used in the the root module, as well as any +<a href="model-values.html">model value</a> that is +declared in the model. This means that you can override +a definition with an expression that +contains operators that are undefined at the point where the +original definition occurred. +TLC evaluates overridden definitions in the +obvious way, and bizarre overriding can +lead to strange results. For example, if <samp>Fact</samp> is defined by +<pre> + Fact(n) == IF n = 0 THEN 1 ELSE n * Bar(n-1) +</pre> +and the definition of <samp>Bar</samp> is overridden with +<pre> + Bar(n) <- Fact(n) +</pre> +then TLC will evaluate <samp>Fact(n)</samp> to +equal <samp>n!</samp> for any natural +number <samp>n</samp> . +There is no good reason to use such bizarre overriding.</font> +</p> + + +<h2><a name="action">Action Constraint</a></h2> + +An action constraint is much like a <a href="#state">state constraint</a>, except +that the constraint formula may also include primed variables. +See Section 14.3 (page 240) of +<em><a href= +"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> +Specifying Systems</a></em> for an explanation of how TLC uses an +action constraint. + + +<hr> +<!-- uncomment to add links to any subtopics that are added +<dl> +<dt><b><font color=#0000c0>Subtopics</font></b></dt> +<dd> <A href=""> TOPIC </A></dd> +<dd> <A href=""> TOPIC </A></dd> +</dl> + --> +<!-- delete rest of line to comment out --> + +<a href = "creating-model.html">↑ Creating a Model</a> + +</hr> + +</body> +</html> diff --git a/org.lamport.tla.toolbox.doc/html/model/tlc-options-page.html b/org.lamport.tla.toolbox.doc/html/model/tlc-options-page.html new file mode 100644 index 0000000000000000000000000000000000000000..7db4dc7f0cec9cf0c8ca10278a2d5d5fa6a5e281 --- /dev/null +++ b/org.lamport.tla.toolbox.doc/html/model/tlc-options-page.html @@ -0,0 +1,314 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/model/tlc-options-page.html --> + + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>TLC Options Page</title> +</head> +<!-- a comment here --> + +<body> +<h1>TLC Options Page</h1> + + +<pre> +Contents + <a href="#config">Configuration</a> + <a href="#checking">Checking Mode</a> + <a href="#features">Features</a> + <a href="#parameters">Parameters</a> +</pre> + +<P> +This model editor page allows you to add less-often +used parts of a model. It's a good idea to browse +this page just to see what options it provides, since +some of the features are not ones you would expect. + </P> +<h2><a name="config">Configuration</a> + +<h3>Number of worker threads</h3> + +TLC's algorithm for computing the set (actually the graph) of reachable states +is highly parallelizable, and it can make good use of arbitrarily many processors. +This parameter specifies the number of separate threads that TLC will spawn to +perform that computation. You should not set it to be greater than the number of +separate processors (cores) on your computer; the Toolbox will warn you if you do. + +<h3>Fraction of physical memory allocated to TLC</h3> + +This determines how large a heap TLC will use. If you make it too small, TLC +could run out of heap space and crash. If you make it too large, your machine will not have +enough memory and everything will run slowly. The slider's color warns you if +you are giving TLC too little or too much memory. +TLC can keep the set of reachable states it has found +on disk, so having too many reachable states can't run it out of memory. +However, it runs much faster when it can keep those states in memory. +TLC can run out of heap space if it takes too much memory to represent the +set of initial states or the set of successor states of a single state. +If TLC does run out of memory in the middle of a long run, +you can give it more and restart it from a checkpoint. + +<p> + +Setting the this parameter too large may produce a +<em>Could not create the Java virtual machine</em> error. + + +<h3>Log base 2 of number of disk storage files</h3> + +If your computer has multiple disk drives, setting this parameter to a value greater +than 0 might make it possible to reduce the time +TLC spends writing to disk on a model with a very large number of reachable states. + +Contact us for more information. + +<h3>Saving defaults</h3> + +Clicking on the "Save as default" button in this section will save this configuration and use +it as the configuration in new models. + +<h2><a name="checking">Checking Mode</a></h2> + +You can choose between two basic ways of running TLC: + +<h3><a name="model-mode">Model-checking mode</a></h3> +<p> +This is the normal method of running TLC, in which it +essentially tries to check all possible behaviors allowed +by the behavior spec. Its default method of doing this +is to find the graph of all reachable states using +breadth-first search. This has the advantage that if +TLC finds a violation of a safety property, then it will +produce a shortest possible behavior that exhibits the +error. You can direct TLC to use a depth-first search +by choosing the <em>Depth-first</em> option and specifying +the depth of its search. (Limiting the depth ensures +that only a finite set of states is explored, even if +the complete set of reachable states is infinite.) +With depth-first search, TLC will usually not produce +a shortest-length error trace. When running in depth-first +mode, TLC does not compute the entire state graph and does not use a state +queue, so it does not produce any + <i>Diameter</i> or <i>Queue size</i> + statistics. +</p> +<p> +<b>Warning:</b> Depth-first search is an experimental TLC +option that has not been used much. We don't know +if it offers any advantages. +If you do try it and find it useful, please tell us what you did. +</p> + +<p> +You can also specify a <em>View</em> to be used in model-checking +mode. If you're curious about what that is and how it is used, +see Section 14.3.3 (page 243) of +<em><a href= +"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> +Specifying Systems</a></em>. +</p> +<h3>Simulation Mode</h3> + +<p> +In simulation mode, TLC does not try to examine all reachable states. +Instead, it checks an unending series of behaviors, each of which it constructs by +starting from a randomly choosen initial state and repeatedly making a random +choice of a possible next state. (In this mode, you stop TLC by clicking the +<samp>Cancel</samp> button on the dialog that the Toolbox pops up when it +runs TLC.) You specify the maximum length of each behavior that it generates. +If you want to know what specifying the <em>Seed</em> and <em>Aril</em> does, +look them up in +<em><a href= +"http://research.microsoft.com/en-us/um/people/lamport/tla/book.html" target="_blank"> +Specifying Systems</a></em>. When run in simulation mode, the only +statistics TLC reports are for <i>States Found</i>. +</p> + +<h2><a name="features">Features</a></h2> + + +<A name="checkpoint"></A><h3>Checkpoint Recovery</h3></A> + + <p> +TLC takes regular checkpoints, from which it can be restarted if it is +stopped for any reason--for example, if your computer crashes. + +The <em>Recover from checkpoint</em> option tells TLC to start from where it +was when the last checkpoint was taken. + +This option is enabled if the last time you ran TLC, it ran long enough to +produce a checkpoint. The Toolbox will fill in the <em>Checkpoint +id</em> for you. + </p> + <p> +Warning: If you exit the Toolbox, it will stop any executions of TLC that are +in process. + +However, it is possible to stop the Toolbox in some drastic fashion that +leaves TLC running as a background process. + +Restarting from a checkpoint while the TLC process that created it is still +running can cause the checkpoint to be destroyed, making recovery +impossible. + +If you have reason to believe TLC was not stopped, check to see if it is +still running before trying to recover from a checkpoint. + </p> + <p> +The checkpoint TLC produces after a short run does not take up +much space. + +However, if TLC finds an error after running for a long time, the +checkpoint files could take up a lot of space--sometimes on the order +of a gigabyte for a model that has run for several days. + +These files are deleted if the model is re-run and a new checkpoint is +produced, or if the model is validated when the +<em>Recover from checkpoint</em> option is not selected. + +When TLC has created a checkpoint, the <em>Features</em> section +of the TLC Options page displays how much storage the checkpoint +occupies. + +It also provides a button that you can click to delete the checkpoint. + </p> + +<p> +Checkpointing does not yet work when TLC is run in distributed mode. +</p> + +<A name="profiling"></A><h3>Profiling</h3> +<p>TLC supports detailed profiling at the action as well as the expression level. Profiling helps to identify specification errors such as permanently disabled actions +(compare <i>Enabled</i> predicate in <a href="https://lamport.azurewebsites.net/pubs/lamport-actions.pdf">The Temporal Logic of Actions</a> section 2.7, page 6). +Similarly it helps pinpoint the source of state space explosion by reporting the states found and distinct states on a per action level. +</p> + +<p> +In addition to action profiling, invocation and cost profiling allows to diagnose expensive expressions. Please refer to the +<a href="profiling.html">dedicated profiler documentation</a> for more information. +</p> +<p> +<b>Warning</b>: Profiling negatively impacts model checking performance and should thus be off when checking large models. +</p> + +<h3>Visualize state graph after completion</h3> +<p> +Visualize the generated state graph graphically after completion of model checking. The +visualization helps to better understand the system being specified. Initial states are represented by gray vertices. +<p><b>Warning: </b>Can reasonably display only state graphs with at most around a hundred states.</b></p> +<p> +In order to visualize a state graph, the path to the <em>dot</em> executable of the +<a href="http://www.graphviz.org/">GraphViz</a> project has to be set under <em>Specify dot command</em> on the <em>PDF viewer</em> preference +page on the File/Preferences menu. On macOS dot is most easily installed with the ports system. Homebrew has a Graphviz port too. +On Windows, GraphViz can be obtained through Cygwin or installed standalone. On most Linux derivatives, GraphViz can be installed with the package manager. +After installation, the dot binary can usually be found at: +</p> + +<p> +<table> + <tr> + <td>OS</td> + <td>Default path</td> + </tr> + <tr> + <td>Windows (Cygwin)</td> + <td>C:\cygwin\bin\dot.exe</td> + <tr> + <td>Windows (standalone)</td> + <td>C:\Program Files (x86)\Graphviz2.38\bin\dot.exe</td> + </tr> + <tr> + <td>macOS (ports)</td> + <td>/opt/local/bin/dot</td> + </tr> + <tr> + <td>Linux</td> + <td>/usr/bin/dot</td> + </tr> +<table> +</p> +<p> +On Windows and Linux the state graph will be visualized with either the built-in or standalone PDF viewer +depending on which is selected on the PDF viewer preference page +(selecting a standalone viewer is advised for best results). +</p> + + + +<h2><a name="parameters">Parameters</a></h2> +<h3>Verify temporal properties upon termination only</h3> +<p> +Defer the verification of temporal properties (liveness) to the end of model checking. +<b>This reduces the overall model checking time</b> with the additional side effect that invariant (safety) +violations will always be found first. In other words, check liveness only after the <em>complete</em> +state space has been checked for safety violations. +If unchecked, temporal properties are checked periodically on the <em>incomplete</em> +state graph. Deferring verification of temporal properties is especially useful if it is highly +likely that the model does not violate its temporal properties (e.g. a smaller instance +of the model has successfully been verified for liveness violations). + +<h3>Fingerprint seed index</h3> +<p> +TLC saves only 64-bit fingerprints (hashes) of the reachable states that it finds, not the +complete states. If two different reachable states have the same fingerprint, a situation +called a <em>collision</em>, TLC may not find all reachable states. +At the +end of a run, TLC prints estimates of how likely it was that a collision occurred. +If you're worried that a collision might have occurred, you can re-run the model with a +different fingerprint function. The fingerprint seed index specifies which of 64 fingerprint +functions TLC should use. If the two runs produce different numbers of reachable +states, then there was a collision in at least one of the runs. If not, the probability +that there was a collision in both is the square of the probability that either one had +a collision--a probability that is probably very, very small. By default, which fingerprint +function to use is chosen randomly. + + +<h3> Cardinality of largest enumerable set</h3> + +If TLC tries to enumerate the elements of a set, it will report an error if the set +contains more than this number of elements. + +<h3><A name="jvmargs">JVM arguments</A></h3> + +These are the arguments given to the Java Virtual Machine when TLC is run on the model. +Certain parameters for running TLC in +<a href="distributed-mode.html">distributed mode</a> are specified this way. +Only sophisticated users who know what they are doing should specify other JVM arguments. + +<h3>TLC command line parameters</h3> + +These are options given to TLC when it is run on the model. +A complete list of TLC options can be found in the + <code>tlatools > src > tlc2 > TLC.java</code> +file in the + <a href="https://github.com/tlaplus/tlaplus">GitHub repository on + the web</a>. +An option specified here can override an option otherwise specified by the rest of the model, +which can cause strange things to happen. You should therefore use this +feature with care. + + +</p> + +<!-- I don't know what I'm saving the following for +<h2><a name="how">How to run?</a></h2> +<hr> +<!-- delete rest of line to comment out +<dl> +<dt><b><font color=#0000c0>Subtopics</font></b></dt> +<dd> <A href=""> TOPIC </A></dd> +<dd> <A href=""> TOPIC </A></dd> +</dl> + --> +<!-- delete rest of line to comment out --> +<a href = "creating-model.html">↑ Creating a Model</a> +<!-- --> +</hr> + +</body> +</html> diff --git a/org.lamport.tla.toolbox.doc/html/prover/prover.html b/org.lamport.tla.toolbox.doc/html/prover/prover.html index 9afb9931eae43d18ab324a11e9fc26a52bf92f5a..792bd59d954ccc4c9e38e94d25f41beda59de433 100644 --- a/org.lamport.tla.toolbox.doc/html/prover/prover.html +++ b/org.lamport.tla.toolbox.doc/html/prover/prover.html @@ -54,7 +54,7 @@ describes how to run it from the Toolbox. But before you can run TLAPS, you must install it on your computer. Instructions for doing this, as well as an explanation of how to use -TLAPS, on +TLAPS, are on <A href="https://tla.msr-inria.inria.fr/tlaps/content/Home.html" target="_blank">the TLAPS web page</A>. diff --git a/org.lamport.tla.toolbox.doc/html/spec/editing-modules.html b/org.lamport.tla.toolbox.doc/html/spec/editing-modules.html index 5aaf02cfd3d2f80ba1b20ab201c1cc42a2d6e528..2ec8934cfee40004206e9610b1a0e7f1971904b7 100644 --- a/org.lamport.tla.toolbox.doc/html/spec/editing-modules.html +++ b/org.lamport.tla.toolbox.doc/html/spec/editing-modules.html @@ -72,6 +72,12 @@ However, the line must appear exactly as shown, with no spaces before the <code>\*</code> and exactly one space after it. </p> +<p> +If you want to prevent the Toolbox from adding the modification history comment, +you can disable this in the <samp>TLA+ Preferences/Model Viewer</samp> section of +the <a href="../gettingstarted/preferences.html">Preference</a> menu. +</p> + <p> The Toolbox maintains a history of previous versions of a module. @@ -619,4 +625,4 @@ Insert, Delete, and Move Text</font></TH> </body> -</html> \ No newline at end of file +</html> diff --git a/org.lamport.tla.toolbox.doc/html/spec/parsing.html b/org.lamport.tla.toolbox.doc/html/spec/parsing.html index bf3a8798f75c219bed864e7a0f06422d944f93f6..594738071ca560444b442bb0bbae30020bd75c17 100644 --- a/org.lamport.tla.toolbox.doc/html/spec/parsing.html +++ b/org.lamport.tla.toolbox.doc/html/spec/parsing.html @@ -1,85 +1,85 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<!-- This is file org.lamport.tla.toobox.doc/html/spec/parsing.html --> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> - <LINK href="../style.css" rel="stylesheet" type="text/css"> - -<title>TITLE</title> -</head> -<!-- a comment --> - -<body> -<h1>Parsing</h1> - -<p> -The Toolbox parses a spec upon opening it. The parse status of the currently -open spec is shown in the lower right-hand -corner of the Toolbox window. The status is either: <samp>Parsed</samp>, -meaning it has no parsing -errors; <samp>Unparsed</samp>, meaning that the spec had no errors the last time - it was parsed, but that -one of its files has since been modified and saved; or <samp>Error</samp>, -meaning that an error -was found the last time it was parsed. -</p> - -<p> -Clicking <samp>File/Parse Spec</samp> parses the -spec. Clicking <samp>File/Parse Module</samp> parses the -currently selected module, which -is the one in the most recently selected module editor. -Parsing the spec is equivalent to parsing its root module. -Unless your spec is <font size=+1>VERY BIG</font>, you will want to parse whenever -a module is saved. -See the parsing preferences listed below for how to do this.</p> - -<p> -If there is a parsing error, the Toolbox pops up a Parsing Errors view. For most errors, clicking on -the error takes you to its location in a module editor. The Toolbox also marks the locations of the -errors in the module editor (or editors). There is a preference, described below, that controls -whether or not the Parsing Errors view -automatically pops up. If you set it not to pop up, you can open the view from the -Toolbox's <samp>Window</samp> menu. -</p> - -<h2>Parsing Preferences</h2> - -<h3>Re-parse module on save</h3> - -<p> -Causes a module to be reparsed when you save it from the module editor. It is the default. -</p> - -<h3>Re-parse specification on spec module save</h3> - -<p> - -Causes the entire spec to be reparsed when you save a module, if that module is part -of the spec. More precisely, the spec is reparsed if the Toolbox found the module to be part of the -spec when the spec was -last parsed. This option has no effect unless the <b>Re-parse module on save</b> option is chosen. -It is the default. -</p> - -<h3>Always pop up Parsing Errors view</h3> - -<p> -It is the default. -</p> - -<hr> -<!-- delete rest of line to comment out -<dl> -<dt><b><font color=#0000c0>Subtopics</font></b></dt> -<dd> <A href=""> TOPIC </A></dd> -<dd> <A href=""> TOPIC </A></dd> -</dl> - --> -<!-- delete rest of line to comment out --> -<a href = "spec.html">↑ Managing Your Specifications</a> -<!-- --> -</hr> - -</body> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- This is file org.lamport.tla.toobox.doc/html/spec/parsing.html --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <LINK href="../style.css" rel="stylesheet" type="text/css"> + +<title>Parsing</title> +</head> +<!-- a comment --> + +<body> +<h1>Parsing</h1> + +<p> +The Toolbox parses a spec upon opening it. The parse status of the currently +open spec is shown in the lower right-hand +corner of the Toolbox window. The status is either: <samp>Parsed</samp>, +meaning it has no parsing +errors; <samp>Unparsed</samp>, meaning that the spec had no errors the last time + it was parsed, but that +one of its files has since been modified and saved; or <samp>Error</samp>, +meaning that an error +was found the last time it was parsed. +</p> + +<p> +Clicking <samp>File/Parse Spec</samp> parses the +spec. Clicking <samp>File/Parse Module</samp> parses the +currently selected module, which +is the one in the most recently selected module editor. +Parsing the spec is equivalent to parsing its root module. +Unless your spec is <font size=+1>VERY BIG</font>, you will want to parse whenever +a module is saved. +See the parsing preferences listed below for how to do this.</p> + +<p> +If there is a parsing error, the Toolbox pops up a Parsing Errors view. For most errors, clicking on +the error takes you to its location in a module editor. The Toolbox also marks the locations of the +errors in the module editor (or editors). There is a preference, described below, that controls +whether or not the Parsing Errors view +automatically pops up. If you set it not to pop up, you can open the view from the +Toolbox's <samp>Window</samp> menu. +</p> + +<h2>Parsing Preferences</h2> + +<h3>Re-parse module on save</h3> + +<p> +Causes a module to be reparsed when you save it from the module editor. It is the default. +</p> + +<h3>Re-parse specification on spec module save</h3> + +<p> + +Causes the entire spec to be reparsed when you save a module, if that module is part +of the spec. More precisely, the spec is reparsed if the Toolbox found the module to be part of the +spec when the spec was +last parsed. This option has no effect unless the <b>Re-parse module on save</b> option is chosen. +It is the default. +</p> + +<h3>Always pop up Parsing Errors view</h3> + +<p> +It is the default. +</p> + +<hr> +<!-- delete rest of line to comment out +<dl> +<dt><b><font color=#0000c0>Subtopics</font></b></dt> +<dd> <A href=""> TOPIC </A></dd> +<dd> <A href=""> TOPIC </A></dd> +</dl> + --> +<!-- delete rest of line to comment out --> +<a href = "spec.html">↑ Managing Your Specifications</a> +<!-- --> +</hr> + +</body> </html> \ No newline at end of file diff --git a/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html b/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html index 27b090ce4c394ed7fe21d43fc6e80ff6cfb33c97..ee63a0c0252819198410a9f671cca1f21ec71fef 100644 --- a/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html +++ b/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html @@ -50,11 +50,20 @@ a new pretty-printed version. We have not yet figured out how to solve thi --> <p>There are things you can do to help the pretty printer -produce better output. They are described in the +produce better output. They are described in the <a href="help-print.html">Helping the Pretty-Printer</a> help page. </p> +<p> +A version of the program that does the pretty-printing can be used to add TLA+ and/or +PlusCal code to a LaTeX document. +See the section on the TLATeX Pretty-Printer on +<a href="https://lamport.azurewebsites.net/tla/tools.html#tlatex?unhideBut=hide-tlatex&unhideDiv=tlatex">this page</a> +of the TLA+ Web site. + +</p> + <h3>Preferences</h3> <p> diff --git a/org.lamport.tla.toolbox.doc/html/trouble/trouble.html b/org.lamport.tla.toolbox.doc/html/trouble/trouble.html index 2ec05a5fdba7f3b2f639b1e16aad422a6ec5cf72..dcfcc823900bdb094509673624884cd70abafc30 100644 --- a/org.lamport.tla.toolbox.doc/html/trouble/trouble.html +++ b/org.lamport.tla.toolbox.doc/html/trouble/trouble.html @@ -129,8 +129,8 @@ Please report any problem you encounter--be it a bug or something you found confusing or poorly explained. You can enter a bug report in - <A href="https://tlaplus.codeplex.com/workitem/list/basic", target="_blank">our -CodePlex bug database</A>. + <A href="https://github.com/tlaplus/tlaplus/issues", target="_blank">our +GitHub bug database</A>. However, please search the database first to make sure that we don't already know about it. diff --git a/org.lamport.tla.toolbox.doc/html/update/run-update.html b/org.lamport.tla.toolbox.doc/html/update/run-update.html index a9b80ea46386a9e7eb6ba0f22cb839384bb7fd0d..0e74040b2fdfd6db8960c2a125c7676524c77690 100644 --- a/org.lamport.tla.toolbox.doc/html/update/run-update.html +++ b/org.lamport.tla.toolbox.doc/html/update/run-update.html @@ -49,8 +49,8 @@ To check manually if updates are available, click on that are about to be downloaded and installed are coming from a trusted supplier. You may be prompted to verify digitally signed content once the signature is - detected.</p><br> - <p><b>Warning:</b> Because of the possibility of harmful or even malicious software, + detected.</p> + <b>Warning:</b> Because of the possibility of harmful or even malicious software, you should download software only from parties that you trust.</p></li> <li>Once the software is downloaded and the necessary diff --git a/org.lamport.tla.toolbox.doc/plugin.xml b/org.lamport.tla.toolbox.doc/plugin.xml index a43cad181545e30b6386d0b395132e8f535d09b0..58551ddd5b9d942c11613a42a33496a52e9a448b 100644 --- a/org.lamport.tla.toolbox.doc/plugin.xml +++ b/org.lamport.tla.toolbox.doc/plugin.xml @@ -30,6 +30,11 @@ defaultHandler="org.lamport.tla.toolbox.doc.handler.HelpContentsHandler" id="org.lamport.tla.toolbox.doc.contents" name="Table of Contents"> + <commandParameter + id="org.lamport.tla.toolbox.doc.contents.param" + name="name" + optional="true"> + </commandParameter> </command> <command defaultHandler="org.lamport.tla.toolbox.doc.handler.HelpPDFHandler" @@ -98,19 +103,15 @@ allPopups="false" locationURI="menu:toolbox.menu.help?after=toolbox.command.help.tlaplus"> <command - commandId="org.lamport.tla.toolbox.doc.pdf" + commandId="org.lamport.tla.toolbox.doc.url" label="PlusCal User Manual" mnemonic="P" mode="FORCE_TEXT" style="push" tooltip="Opens the paper "A PlusCal User’s Manual - C-Syntax""> <parameter - name="org.lamport.tla.toolbox.doc.pdf.file" - value="c-manual.pdf"> - </parameter> - <parameter - name="org.lamport.tla.toolbox.doc.pdf.name" - value="PlusCal Manual"> + name="org.lamport.tla.toolbox.doc.url.name" + value="https://lamport.azurewebsites.net/tla/c-manual.pdf"> </parameter> </command> </menuContribution> @@ -119,19 +120,15 @@ allPopups="false" locationURI="menu:toolbox.menu.help?after=toolbox.command.help.tlaplus"> <command - commandId="org.lamport.tla.toolbox.doc.pdf" + commandId="org.lamport.tla.toolbox.doc.url" label="Specifying Systems" mnemonic="S" mode="FORCE_TEXT" style="push" tooltip="Opens the book "Specifying Systems""> <parameter - name="org.lamport.tla.toolbox.doc.pdf.file" - value="book-02-08-08.pdf"> - </parameter> - <parameter - name="org.lamport.tla.toolbox.doc.pdf.name" - value="Specifying Systems"> + name="org.lamport.tla.toolbox.doc.url.name" + value="https://lamport.azurewebsites.net/tla/book-02-08-08.pdf"> </parameter> </command> </menuContribution> @@ -169,6 +166,17 @@ allPopups="false" locationURI="menu:toolbox.menu.help?before=toolbox.command.about"> <menu id="community" label="Community" mnemonic="Y"> + <command + commandId="org.lamport.tla.toolbox.doc.url" + label="TLA+ CommunityModules" + mnemonic="V" + mode="FORCE_TEXT" + style="push"> + <parameter + name="org.lamport.tla.toolbox.doc.url.name" + value="https://github.com/tlaplus/CommunityModules"> + </parameter> + </command> <command commandId="org.lamport.tla.toolbox.doc.url" label="TLA+ user group" diff --git a/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpContentsHandler.java b/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpContentsHandler.java index 8731022f16d9a2c2568d9aa39d2da155c047eeeb..5141ead0b2dcfa3a150dc9f5243e059318d3c454 100644 --- a/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpContentsHandler.java +++ b/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpContentsHandler.java @@ -18,6 +18,7 @@ import org.eclipse.ui.PlatformUI; public class HelpContentsHandler extends AbstractHandler implements IHandler { public Object execute(ExecutionEvent event) throws ExecutionException { + final String url = event.getParameter("org.lamport.tla.toolbox.doc.contents.param"); BusyIndicator.showWhile(null, new Runnable() { public void run() { final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); @@ -28,7 +29,11 @@ public class HelpContentsHandler extends AbstractHandler implements IHandler { final Field f = HelpView.class.getDeclaredField("reusableHelpPart"); f.setAccessible(true); final ReusableHelpPart helpPart = (ReusableHelpPart) f.get(helpView); - helpPart.showPage(ReusableHelpPart.HV_ALL_TOPICS_PAGE, true); + if (url == null) { + helpPart.showPage(ReusableHelpPart.HV_ALL_TOPICS_PAGE, true); + } else { + helpPart.showURL(url, true); + } } catch (final NoSuchFieldException e) { e.printStackTrace(); } catch (final SecurityException e) { diff --git a/org.lamport.tla.toolbox.doc/toc.xml b/org.lamport.tla.toolbox.doc/toc.xml index 3356a3286d33cc7020f29b894e9523bb32da3965..5d791de25257deef386b3e65c986e98ab3c85347 100644 --- a/org.lamport.tla.toolbox.doc/toc.xml +++ b/org.lamport.tla.toolbox.doc/toc.xml @@ -74,8 +74,15 @@ </topic> - <topic label = "Advanced Options Page" - href = "html/model/advanced-page.html"> + <topic label = "Spec Options Page" + href = "html/model/spec-options-page.html"> + </topic> + + <topic label = "TLC Options Page" + href = "html/model/tlc-options-page.html"> + <topic label = "Profiling" + href = "html/model/profiling.html"> + </topic> </topic> <topic label = "Model Checking Results Page" diff --git a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF index 7a7b1296b4369582b97ee1c1e728b391a83cb532..0ecf06ce0e307743000811f6cfd0054aa68b2ee9 100644 --- a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF @@ -26,3 +26,4 @@ Export-Package: org.lamport.tla.toolbox.editor.basic, org.lamport.tla.toolbox.editor.basic.handlers;x-friends:="org.lamport.tla.toolbox", org.lamport.tla.toolbox.editor.basic.tla, org.lamport.tla.toolbox.editor.basic.util +Automatic-Module-Name: org.lamport.tla.toolbox.editor.basic diff --git a/org.lamport.tla.toolbox.editor.basic/plugin.xml b/org.lamport.tla.toolbox.editor.basic/plugin.xml index 9ddc50fef808c322c7b7bcc07f9c68d0bf6589ca..17378f3ca4e58492f8802216d06bc4fd56df0c93 100644 --- a/org.lamport.tla.toolbox.editor.basic/plugin.xml +++ b/org.lamport.tla.toolbox.editor.basic/plugin.xml @@ -565,6 +565,10 @@ commandId="org.lamport.tla.toolbox.editor.basic.gotoPrevUse" style="push"> </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.gotoMatchingParen" + style="push"> + </command> <command commandId="org.lamport.tla.toolbox.editor.basic.gotoPCalSource" style="push"> @@ -572,9 +576,6 @@ </menuContribution> <menuContribution locationURI="popup:#TextEditorContext?after=additions"> - <command - commandId="org.lamport.tla.toolbox.editor.basic.ToggleCommentAction"> - </command> <command commandId="org.lamport.tla.toolbox.editor.basic.Format"> </command> @@ -584,38 +585,45 @@ </menuContribution> <menuContribution locationURI="popup:#TextEditorContext?after=foldCommands"> - <command + <menu + id="org.lamport.tla.toolbox.editor.basic.tlaps" + label="TLA Proof Manager"> + <separator + name="additions"> + </separator> + <command commandId="org.lamport.tla.toolbox.editor.basic.ExpandAllProofs" - style="push"> - </command> - <command + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.FoldAllProofs" - style="push"> - </command> - <command + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.ExpandSubtree" - style="push"> - </command> - <command + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.CollapseSubtree" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.ShowImmediate" - style="push"> - </command> - <command + style="push"> + </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.ShowImmediate" + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.FocusOnStep" - style="push"> - </command> - <command + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.renumberProof" - style="push"> - </command> - <command + style="push"> + </command> + <command commandId="org.lamport.tla.toolbox.editor.basic.DecomposeProof" - style="push"> - </command> + style="push"> + </command> + </menu> <separator name="org.lamport.tla.toolbox.editor.basic.commentseparator" visible="true"> @@ -623,29 +631,31 @@ </menuContribution> <menuContribution locationURI="popup:#TextEditorContext?after=org.lamport.tla.toolbox.editor.basic.commentseparator"> + <menu + label="Comments"> + <command + commandId="org.lamport.tla.toolbox.editor.basic.startBoxedComment" + style="push"> + </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.formatComment" + style="push"> + </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.boxComment" + style="push"> + </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.formatAndBoxComment" + style="push"> + </command> + <command + commandId="org.lamport.tla.toolbox.editor.basic.unboxComment" + style="push"> + </command> + </menu> <command - commandId="org.lamport.tla.toolbox.editor.basic.startBoxedComment" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.formatComment" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.boxComment" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.formatAndBoxComment" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.unboxComment" - style="push"> - </command> - <command - commandId="org.lamport.tla.toolbox.editor.basic.gotoMatchingParen" - style="push"> + commandId="org.lamport.tla.toolbox.editor.basic.ToggleCommentAction"> </command> <separator name="org.lamport.tla.toolbox.editor.basic.commentseparator" diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java index 36e1abb01464f4b8a80be36974a4999c1a168aaf..fdc577c3596658f06ebd915787c31c17252a9dc9 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java @@ -2,6 +2,7 @@ package org.lamport.tla.toolbox.editor.basic; import java.io.File; import java.io.IOException; +import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -16,6 +17,7 @@ import org.eclipse.core.commands.operations.IOperationHistoryListener; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.commands.operations.IUndoableOperation; import org.eclipse.core.commands.operations.OperationHistoryEvent; +import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; @@ -63,8 +65,10 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IURIEditorInput; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; @@ -191,6 +195,10 @@ public class TLAEditor extends TextEditor } } + protected TLASourceViewerConfiguration getTLASourceViewerConfiguration(IPreferenceStore preferenceStore) { + return new TLASourceViewerConfiguration(preferenceStore, this); + } + /* * (non-Javadoc) * @see org.eclipse.ui.texteditor.AbstractTextEditor#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput) @@ -205,26 +213,13 @@ public class TLAEditor extends TextEditor TLAEditorActivator.getDefault().getPreferenceStore(), EditorsUI.getPreferenceStore() }); // set source viewer configuration - setSourceViewerConfiguration(new TLASourceViewerConfiguration(preferenceStore, this)); + setSourceViewerConfiguration(getTLASourceViewerConfiguration(preferenceStore)); // set preference store setPreferenceStore(preferenceStore); - // setup the content description and image of spec root - if (input instanceof FileEditorInput) - { - FileEditorInput finput = (FileEditorInput) input; - if (finput != null) - { - IPath path = finput.getPath(); - setContentDescription(path.toString()); - - if (ResourceHelper.isRoot(finput.getFile())) - { - setTitleImage(rootImage); - } - } - } + initEditorNameAndDescription(input); + // grab context service and activate the context on editor load this.contextService = (IContextService) getSite().getService(IContextService.class); Assert.isNotNull(contextService); @@ -281,6 +276,24 @@ public class TLAEditor extends TextEditor }); } + protected void initEditorNameAndDescription(final IEditorInput input) { + // setup the content description and image of spec root + if (input instanceof FileEditorInput) + { + final FileEditorInput finput = (FileEditorInput) input; + if (finput != null) + { + final IPath path = finput.getPath(); + setContentDescription(path.toString()); + + if (ResourceHelper.isRoot(finput.getFile())) + { + setTitleImage(rootImage); + } + } + } + } + private IUndoContext getUndoContext() { if (getSourceViewer() instanceof ITextViewerExtension6) { IUndoManager undoManager = ((ITextViewerExtension6) getSourceViewer()).getUndoManager(); @@ -842,8 +855,21 @@ public class TLAEditor extends TextEditor * @return */ public String getModuleName() { - IFile moduleFile = ((FileEditorInput) this.getEditorInput()).getFile(); - return ResourceHelper.getModuleName(moduleFile); + final IEditorInput iei = this.getEditorInput(); + if (iei instanceof FileEditorInput) { + final IFile moduleFile = ((FileEditorInput) iei).getFile(); + return ResourceHelper.getModuleName(moduleFile); + } else if (iei instanceof IURIEditorInput) { + final URI uri = ((IURIEditorInput) iei).getURI(); + if (uri != null) { + final IPath path = URIUtil.toPath(uri); + if (path != null) { + final IFile moduleFile = ResourcesPlugin.getWorkspace().getRoot().getFile(path); + return ResourceHelper.getModuleName(moduleFile); + } + } + } + return ""; } public TextViewer getViewer() { @@ -953,33 +979,29 @@ public class TLAEditor extends TextEditor */ public static final class OpenDeclarationHandler extends AbstractHandler { - public OpenDeclarationHandler() - { - } - public Object execute(ExecutionEvent event) throws ExecutionException { + final IEditorPart activeEditor = HandlerUtil.getActiveEditor(event); + final TLAEditor tlaEditor = activeEditor.getAdapter(TLAEditor.class); - TLAEditorAndPDFViewer editor = (TLAEditorAndPDFViewer) HandlerUtil.getActiveEditor(event); - ISourceViewer internalSourceViewer = editor.getTLAEditor().getSourceViewer(); - - ITextSelection selection = (ITextSelection) editor.getTLAEditor().getSelectionProvider().getSelection(); - IRegion region = new Region(selection.getOffset(), selection.getLength()); + final ITextSelection selection = (ITextSelection) tlaEditor.getSelectionProvider().getSelection(); + final IRegion region = new Region(selection.getOffset(), selection.getLength()); // get the detectors - IHyperlinkDetector[] hyperlinkDetectors = editor.getTLAEditor().getSourceViewerConfiguration() + final ISourceViewer internalSourceViewer = tlaEditor.getSourceViewer(); + final IHyperlinkDetector[] hyperlinkDetectors = tlaEditor.getSourceViewerConfiguration() .getHyperlinkDetectors(internalSourceViewer); if (hyperlinkDetectors != null) { for (int i = 0; i < hyperlinkDetectors.length; i++) { // detect - IHyperlink[] hyperlinks = hyperlinkDetectors[i].detectHyperlinks(internalSourceViewer, region, + final IHyperlink[] hyperlinks = hyperlinkDetectors[i].detectHyperlinks(internalSourceViewer, region, false); if (hyperlinks != null && hyperlinks.length > 0) { // open - IHyperlink hyperlink = hyperlinks[0]; + final IHyperlink hyperlink = hyperlinks[0]; hyperlink.open(); break; } @@ -988,5 +1010,4 @@ public class TLAEditor extends TextEditor return null; } } - } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java index 3813f24c934a6316aefb6e478a0df281637008ba..da27349fd29275bcc7e5850406f398f18819f07c 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java @@ -99,12 +99,19 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca FileEditorInput finput = (FileEditorInput) input; if (finput != null) { - if (ResourceHelper.isModule(finput.getFile())) + final IFile file = finput.getFile(); + if (ResourceHelper.isModule(file)) { - this.setPartName(finput.getFile().getName()); + // MAK 04/2019: Strip off filename extension to align with Toolbox's Spec + // Explorer which doesn't show the extension either. The Toolbox only has + // two editors (TLA+ specs and TLC models). Showing the extension thus + // provides little value to users. Aslo the editor description shows the + // full path to the actual file on disk right below where the part name + // is shown. + this.setPartName(file.getName().replaceFirst(".tla$", "")); } - if (ResourceHelper.isRoot(finput.getFile())) + if (ResourceHelper.isRoot(file)) { setTitleImage(rootImage); } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAFastPartitioner.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAFastPartitioner.java index b71d0e6d5fa62a932cd8f442679c7ef0f686b23c..499c507b1be8900de37535b311a01f3d5acf3f62 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAFastPartitioner.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAFastPartitioner.java @@ -125,7 +125,6 @@ import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Platform; - import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.BadPositionCategoryException; import org.eclipse.jface.text.DefaultPositionUpdater; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java index 3082821537850278ddc69b8b3d26cc042be7ed27..b4bc83729a3e963517dbe9fb6213beeb9d440963 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java @@ -33,8 +33,8 @@ import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.lamport.tla.toolbox.editor.basic.pcal.PCalWordDetector; import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; -import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper.WordRegion; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.tool.ToolboxHandle; import tla2sany.modanalyzer.SpecObj; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java index 6d43928f89ef5ba597b6237c4c823ff886046940..0005fd9878f5b9e1868486f937655651975b46f8 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java @@ -52,6 +52,11 @@ public class OpenDeclarationAction extends Action implements IHyperlink ((TLAEditorAndPDFViewer) editor).getTLAEditor().selectAndReveal(location.getOffset(), location.getLength()); } else if (editor instanceof TLAEditor) { ((TLAEditor) editor).selectAndReveal(location.getOffset(), location.getLength()); + } else { + TLAEditor adapter = editor.getAdapter(TLAEditor.class); + if (adapter != null) { + adapter.selectAndReveal(location.getOffset(), location.getLength()); + } } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationInCurrentAction.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationInCurrentAction.java new file mode 100644 index 0000000000000000000000000000000000000000..d0d1fd787fd50418b5e356c6a5f3fb05cf48df48 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationInCurrentAction.java @@ -0,0 +1,67 @@ +package org.lamport.tla.toolbox.editor.basic.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; + +public class OpenDeclarationInCurrentAction extends Action implements IHyperlink { + private final IRegion location; + private final String label; + private final IRegion hyperlinkLocation; + private final TLAEditor editor; + + public OpenDeclarationInCurrentAction(TLAEditor editor, IRegion targetLocation, String hyperlinkLabel, IRegion hyperlinkLocation) { + super(); + this.editor = editor; + this.location = targetLocation; + this.label = hyperlinkLabel; + this.hyperlinkLocation = hyperlinkLocation; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + EditorUtil.setReturnFromOpenDecl(); + this.editor.selectAndReveal(location.getOffset(), location.getLength()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkRegion() + */ + public IRegion getHyperlinkRegion() { + return this.hyperlinkLocation; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkText() + */ + public String getHyperlinkText() { + return this.label; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.hyperlink.IHyperlink#getTypeLabel() + */ + public String getTypeLabel() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.hyperlink.IHyperlink#open() + */ + public void open() { + run(); + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java index 7bfaca14901f3fd5b04c3e570b25303324caf35d..a125190ff2538bed9cc437738c2c5a522b84b14e 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java @@ -35,7 +35,6 @@ import org.lamport.tla.toolbox.editor.basic.TLAEditor; import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.spec.parser.ParserDependencyStorage; import org.lamport.tla.toolbox.util.ResourceHelper; -import org.lamport.tla.toolbox.util.UIHelper; import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ModuleNode; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CursorMovementHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CursorMovementHandler.java index 31cf835f1482fd27c91877345f2f192a40895236..581d1915699e3fb9edb3f60788bbb1b2d5eae69b 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CursorMovementHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CursorMovementHandler.java @@ -7,15 +7,12 @@ */ package org.lamport.tla.toolbox.editor.basic.handlers; -import javax.swing.text.BadLocationException; - import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.lamport.tla.toolbox.editor.basic.TLAEditor; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java index 198372bf412663398ffc599f948370e62ff9563a..5b4f32858b2b35bb1631e2c8c7a98dd05be6ac22 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java @@ -1,4 +1,22 @@ /** + * BUG DISCOVERED in March 2019 by LL + * If an INSTANCE statement implicitly instantiates a module parameter with the identifier + * of the same name (by not specifying an instantiation for it), the Decompose Proof command + * expands definitions from the instantiated module by replacing the parameter by + * the text of the INSTANCE statement. The problem is manifest in a bad argument + * passed to substInNodeToInstanceSub, and that manifestation is explained in comments + * starting around line 5333. (Search for "22 March 2019".) There are also comments containing + * and explaining an unsuccessful attempt to fix the problem. + * + * CHANGE MADE BY LL on 18 March 2019 + * At some point, this class was modified by first creating a new version called + * NewDecomposeProofHandler and then renaming it to be the current version. A lot + * of references to NewDecomposeProofHandler remained, including ones pointing to + * an error at a certain line number of NewDecomposeProofHandler. I changed almost + * all mentions of NewDecompose... to Decompose..., and updated the line numbers of + * the error. I left a couple of NewDecompose... in comments that seemed to accompany + * commented-out code from that file. + * * IN MIDDLE OF * Fixing bug on line 428 of Test.tla. Will try the approach of adding * a global Renaming to the decomposition state to keep track of all renaming in @@ -532,10 +550,8 @@ import tla2sany.semantic.SemanticNode; import tla2sany.semantic.Subst; import tla2sany.semantic.SubstInNode; import tla2sany.semantic.SymbolNode; -import tla2sany.semantic.SymbolTable; import tla2sany.semantic.TheoremNode; import tla2sany.st.Location; -import tla2sany.st.TreeNode; import util.UniqueString; public class DecomposeProofHandler extends AbstractHandler implements @@ -700,7 +716,7 @@ public class DecomposeProofHandler extends AbstractHandler implements * element containing data for the i-th assumption. This is done to make it * easy to replace one assumption by several. Other objects contain pointers * to these vectors, so once the vectors are constructed by - * NewDecomposeProofHandler.execute, they can be modified but must not be + * DecomposeProofHandler.execute, they can be modified but must not be * replaced by new vectors. *************************************************************************/ @@ -810,7 +826,19 @@ public class DecomposeProofHandler extends AbstractHandler implements */ private StringSet declaredIdentifiers; - + /* + * If the command requires expanding a definition obtained through implicit + * instantiation of a module parameter (that is, without an explicit WITH + * substitution), then a bug in the renaming code could incorrectly expand + * that definition. When this is first encountered, a warning is raised. + * However, since most of the time the renaming will be performed correctly, + * it will be a nuisance to raise the warning over and over again. So, + * the warning is raised only once for every launch of the Toolbox. The + * raiseImplicitRenamingWarning flag is used to control this. + * Added by LL on 22 March 2019. + */ + private static String lastModuleWithImplicitRenamingWarning = "" ; + /******************************************************************** * METHODS INVOLVED IN RENAMING *********************************************************************/ @@ -1668,7 +1696,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 1479 of NewDecomposeProofHandler."); + + "line 1678 of DecomposeProofHandler."); return null; } @@ -1688,7 +1716,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 1544 of NewDecomposeProofHandler."); + + "line 1698 of DecomposeProofHandler."); return null; } NodeRepresentation nodeRep = contextStepRep.subNodeRep(contextAssumptions.elementAt(i), @@ -1739,7 +1767,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 1583 of NewDecomposeProofHandler."); + + "line 1749 of DecomposeProofHandler."); return null; } state.goalRep = goalStepRep.subNodeRep(goal, null, null, null, null, false); @@ -1835,7 +1863,7 @@ public class DecomposeProofHandler extends AbstractHandler implements * This method is called when the user issues a the Decompose Proof command. * It launches a synchronous task that calls realExecute() to do most of the * work. However, before doing that, it sets various fields of the - * NewDecomposeProofHandler object that can't be set from the separate + * DecomposeProofHandler object that can't be set from the separate * thread. * * This running of a separate task was done to allow the command to ask the @@ -3275,7 +3303,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 3247 of NewDecomposeProofHandler."); + + "line 3285 of DecomposeProofHandler."); } } @@ -3291,7 +3319,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Sanity check failed at " - + "line 3255 of NewDecomposeProofHandler."); + + "line 3301 of DecomposeProofHandler."); } @@ -3348,7 +3376,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 3275 of NewDecomposeProofHandler."); + + "line 3358 of DecomposeProofHandler."); e.printStackTrace(); } proofBY = new StringSet(); @@ -3835,7 +3863,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 1465 of NewDecomposeProofHandler."); + + "line 3845 of DecomposeProofHandler."); e.printStackTrace(); } @@ -4142,7 +4170,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 2534 of NewDecomposeProofHandler."); + + "line 4152 of DecomposeProofHandler."); } } catch (BadLocationException e) { // TODO Auto-generated catch block @@ -4150,7 +4178,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 2714 of NewDecomposeProofHandler."); + + "line 4160 of DecomposeProofHandler."); return null; } // We now perform the substitutions in result @@ -4229,7 +4257,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 2737 of NewDecomposeProofHandler."); + + "line 4239 of DecomposeProofHandler."); } result = moduleFileDocProvider.getDocument(fileEditorInput); } @@ -4303,7 +4331,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 4178 of NewDecomposeProofHandler."); + + "line 4313 of DecomposeProofHandler."); return null; } OpApplNode oan = (OpApplNode) nodeRepArg.semanticNode; @@ -4380,7 +4408,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 4336 of NewDecomposeProofHandler."); + + "line 4390 of DecomposeProofHandler."); return null; } } @@ -4468,7 +4496,7 @@ public class DecomposeProofHandler extends AbstractHandler implements } else { // nodeRep is the current goal and so the NEW assumptions // will become top-level assumptions and rep.parentVector - // should be set to the NewDecomposeProofHandler's assumeRep + // should be set to the DecomposeProofHandler's assumeRep // vector. rep.setParentVector(this.state.assumeReps); } @@ -4740,7 +4768,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 2842 of NewDecomposeProofHandler."); + + "line 4750 of DecomposeProofHandler."); return result; } // Note: the following code outside the if (mayNeedParens) has @@ -4927,11 +4955,12 @@ public class DecomposeProofHandler extends AbstractHandler implements mayNeedParens = true; } for (int j = 0; j < uses.length; j++) { - if (!(uses[j] instanceof OpApplNode)) { + // "|| (uses[j] instanceof OpArgNode)" added by LL 18 March 2019 + if (!((uses[j] instanceof OpApplNode) || (uses[j] instanceof OpArgNode))) { MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 2842 of NewDecomposeProofHandler."); + + "line 4941 of DecomposeProofHandler."); return result; } // Note: the following code outside the if (mayNeedParens) has @@ -5088,7 +5117,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something that should not happen has occurred in " - + "line 5008 of NewDecomposeProofHandler."); + + "line 5099 of DecomposeProofHandler."); errorFound = true ; } } @@ -5111,7 +5140,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something that should not happen has occurred in " - + "line 5028 of NewDecomposeProofHandler."); + + "line 5122 of DecomposeProofHandler."); errorFound = true ; } } @@ -5298,39 +5327,143 @@ public class DecomposeProofHandler extends AbstractHandler implements OpDeclNode[] paramsArray = OpDeclNodeVectorToArray(isub.params) ; String[] subsArray = StringVectorToArray(isub.substs) ; for (int i = 0; i < substitutes.length; i++) { - Subst subst = substitutes[i] ; - result.params.add(subst.getOp()) ; - NodeRepresentation nodeRep ; - try { - nodeRep = new NodeRepresentation(doc, subst.getExpr()) ; - } catch (BadLocationException e) { - MessageDialog.openError(UIHelper.getShellProvider().getShell(), - "Decompose Proof Command", - "Something unexpected is going on at " - + "line 5277 of NewDecomposeProofHandler."); - return null ; - } - - if (nodeRep.nodeText.length != 1) { - MessageDialog.openError(UIHelper.getShellProvider() - .getShell(), "Decompose Proof Command", - "Cannot handle instantiation of module parameter\n " - + "with multi-line formula."); - return null; - } - - NodeTextRep ntRep = nodeRep.toNodeTextRep() ; - - ntRep = instantiateInNodeText(paramsArray, subsArray, subst.getExpr(), ntRep) ; - ntRep = renameInNodeText(subst.getExpr(), ntRep, isub.prefix, postPrefix) ; - if (ntRep == null) { - return null ; - } - result.substs.add(ntRep.nodeText[0]) ; - } + Subst subst = substitutes[i]; + /* + * The following if / else was added by LL on 22 March 2019 to partially fix the + * bug in expanding definitions imported by instantiations with implicit + * instantiation of one or more module parameters. It simply does no substitution + * for an implicitly instantiated module parameter. This is always OK if this + * is a top-level instantiation--that is, if this substitution is creating + * an expression of the same module as the definition the Decompose Proof + * command is expanding. If this is not the case, and a warning has not + * already been produced for the current module, then a warning is given. + * The one safe case that will produce the warning is if this is not a top-level + * instantiation, but the parameter is also implicitly substituted for in + * all higher-level instantiations. This is likely to be the case for + * instantiations of instantiated definitions--for example, if a low-level + * spec instantiates a middle-level spec which instantiates a high-level + * spec. It's likely that there is some CONSTANT parameter that is the + * same in all three specs and will be instantiated implicitly in both + * INSTANCE statements. This could be checked for by dynamically keeping track + * of all implicit instantiations in all modules examined. But that's + * complicated enough that it would probably be better to fix the entire + * algorithm for expanding instantiated definitions so it gets things right + * even in cases that it now doesn't, as in failing to do proper renaming + * for defined operators. + */ + if (!subst.isImplicit()) { + result.params.add(subst.getOp()); + NodeRepresentation nodeRep; + try { + /* + * The following comments were added by LL on 18 March 2019. They may + * be useful if someone wants to really fix the problem. + * + * The following code was an attempt to fix the bug in the Decompose Proof + * command that causes it to replace implicitly instantiated module parameters + * with the text of the INSTANCE statement. There seemed to be two problems that + * are finessed by the rix. The first is that when the current method is called and the i-th + * module parameter is implicitly instantiated with a parameter of the current module, + * then subIn.substs[i].expr is an ExprOrOpDefNode with its op field identifying that + * parameter, but with its stn field pointing to the text of the INSTANCE + * statement. Except, if that parameter came from an EXTENDed module, that stn + * field points to the parameter's declaration in the instantiated module. In + * the first case, the text of the instantiated parameter was replaced by the + * text of the INSTANCE statement. In the second case, it was replaced by the + * text from the current module that's at the location of the parameter's + * declaration in the EXTENDed module. + * + * Another bug whose effect I don't understand in the current code is that if + * the current module instantiates module A, which instantiates module B, if a + * parameter P in module B is implicitly instantiated by a parameter in module + * A, the instantiation of parameter P in module A is marked as implicit in + * subIn.substs[...].implicit. + * + * In the following code, if subIn.substs[i].implicit is true, + * subIn.substs[i].expr.stn is effectively changed to point to the declaration + * of the parameter in the instantiated module. However, that doesn't work + * because, as in the exceptional case above, the parameter gets replaced by the + * text in the current module at the location of the parameter's declaration in + * the instantiated module. + * + * To fix the bug, one must first understand the complete method of performing + * substitutions in expanding a definition. This will take more time than I + * have. + * + * + */ +// ExprOrOpArgNode substExpr = subst.getExpr() ; +// if (subst.isImplicit()) { +// // set subst.expr.stn to a clone of its current value +// // except with its location set to a location whose beginning +// // is the location of subst.op.stn and its ending location +// // is that location with its column equal to +// // its starting column + length(subst.op.name) - 1 +// // (That's so it doesn't include the "(...)" that's +// // included if this is an operator with arguments. +// OpDeclNode substOp = subst.getOp() ; +// Location opLocation = substOp.getLocation() ; +// String substOpName = substOp.getName().toString() ; +// String opLocationSourceString = opLocation.source() ; +// UniqueString opLocationSource = UniqueString.uniqueStringOf(opLocationSourceString) ; +// Location exprLocation = substExpr.stn.getLocation() ; +// Token t = Token.newToken(substExpr.stn.getKind()) ; +// t.image = substExpr.stn.getImage() ; +// t.beginLine = opLocation.beginLine() ; +// t.endLine = opLocation.endLine() ; +// t.beginColumn = opLocation.beginColumn() ; +// t.endColumn = t.beginColumn + substOpName.length() - 1 ; +// substExpr.stn = new SyntaxTreeNode( +// UniqueString.uniqueStringOf(substOp.stn.getFilename()), +// substExpr.stn.getKind(), t) ; +// } +// nodeRep = new NodeRepresentation(doc, substExpr) ; +// /* +// * END OF FIX. The following line is the old code being +// * replaced by the fix. +// */ + + nodeRep = new NodeRepresentation(doc, subst.getExpr()); + } catch (BadLocationException e) { + MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", + "Something unexpected is going on at " + "line 5356 of DecomposeProofHandler."); + return null; + } + + if (nodeRep.nodeText.length != 1) { + MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", + "Cannot handle instantiation of module parameter\n " + "with multi-line formula."); + return null; + } + + NodeTextRep ntRep = nodeRep.toNodeTextRep(); + + ntRep = instantiateInNodeText(paramsArray, subsArray, subst.getExpr(), ntRep); + ntRep = renameInNodeText(subst.getExpr(), ntRep, isub.prefix, postPrefix); + if (ntRep == null) { + return null; + } + result.substs.add(ntRep.nodeText[0]); + } + else if ( /* This is an implicit instantiation. The following generates a warning + * if a warning has not already been generated for this module and this + * is not a top-level implicit instantiation. + */ + (!this.moduleNode.getName().toString().equals(lastModuleWithImplicitRenamingWarning)) + && (!this.moduleNode.getName().toString().equals( + subst.getExpr().getTreeNode().getFilename()))) { + MessageDialog.openError(UIHelper.getShellProvider().getShell(), + "Decompose Proof Command", + "The implicit instantiation of one or more module parameters in an INSTANCE" + + "\nstatement in an instantiated module may cause the incorrect expansion of" + + "\ndefinitions imported by instantiation. This can be avoided by using" + + "\nWITH clauses to make instantiations explicit." + + "\n\nThis warning will probably not be repeated for this module."); + this.lastModuleWithImplicitRenamingWarning = this.moduleNode.getName().toString(); + } // End of if/else statement added by LL on 22 March 2019 + } return result ; } - /** * The NodeTextRep obtained by performing the substitutions indicated by * isub in the nodeText and mapping fields of nodeRep. The expression @@ -5437,7 +5570,7 @@ public class DecomposeProofHandler extends AbstractHandler implements * element containing data for the i-th assumption. This is done to make * it easy to replace one assumption by several. Other objects contain * pointers to these vectors, so once the vectors are constructed by - * NewDecomposeProofHandler.execute, they can be modified but must not + * DecomposeProofHandler.execute, they can be modified but must not * be replaced by new vectors. *************************************************************************/ /** @@ -5747,7 +5880,7 @@ public class DecomposeProofHandler extends AbstractHandler implements * * - The node is either an element of state.assumeReps. In that case, it * equals h.state.assumeReps.elementAt(j) for the - * NewDecomposeProofHandler object h, and parentVector = + * DecomposeProofHandler object h, and parentVector = * state.assumeReps. * * - the node is state.goalRep and parentVector = null . @@ -5765,7 +5898,7 @@ public class DecomposeProofHandler extends AbstractHandler implements /** * The two methods NodeRepresentation.nodeRepPath and - * NewDecomposeProofHandler.pathToNodeRep() provide a means of + * DecomposeProofHandler.pathToNodeRep() provide a means of * describing a NodeRepresentation object that identifies the "same" * object described by a DecompositionState or by a clone of it. They * are defined as follows: @@ -5789,7 +5922,7 @@ public class DecomposeProofHandler extends AbstractHandler implements * ns.nodeRepPath(), then pathToNodeRep(V) = ns. * * nodeRepPath is defined below. pathToNodeRep is a method in the outer - * NewDecomposeProofHandler class. + * DecomposeProofHandler class. * * @return */ @@ -5816,7 +5949,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 5208 of NewDecomposeProofHandler."); + + "line 5865 of DecomposeProofHandler."); return null; } @@ -6298,7 +6431,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "An error that should not happen has occurred in " - + "line 4310 of NewDecomposeProofHandler."); + + "line 6347 of DecomposeProofHandler."); } } } @@ -6568,7 +6701,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 6509 of NewDecomposeProofHandler."); + + "line 6617 of NDecomposeProofHandler."); return null ; } @@ -6577,7 +6710,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider().getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 6518 of NewDecomposeProofHandler."); + + "line 6626 of DecomposeProofHandler."); return null ; } @@ -6624,7 +6757,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 6477 of NewDecomposeProofHandler."); + + "line 6673 of DecomposeProofHandler."); return null ; } Location firstArgLoc = oaArgs[0].getLocation() ; @@ -6652,7 +6785,7 @@ public class DecomposeProofHandler extends AbstractHandler implements MessageDialog.openError(UIHelper.getShellProvider() .getShell(), "Decompose Proof Command", "Something unexpected is going on at " - + "line 6506 of NewDecomposeProofHandler."); + + "line 6701 of DecomposeProofHandler."); return null ; } } @@ -7122,7 +7255,7 @@ public class DecomposeProofHandler extends AbstractHandler implements addDeclaredSymbols(result, node.parentNode); } else { System.out - .println("Bug found in NewDecomposeProofHandler.addDeclaredSymbols."); + .println("Bug found in DecomposeProofHandler.addDeclaredSymbols."); } } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoNextUseHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoNextUseHandler.java index bfefdcc1c85af1499e7043366925cc0a018caa3f..53e79115d96caaf1e449017aa57ae90e267ee6ad 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoNextUseHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoNextUseHandler.java @@ -11,9 +11,7 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.editors.text.FileDocumentProvider; @@ -25,7 +23,6 @@ import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.ui.handler.OpenSpecHandler; -import org.lamport.tla.toolbox.util.AdapterFactory; import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.UIHelper; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java index b4db12d6600d848bf3f02c36c89235417f2f39e7..177298cfecaa5d2b251d153093779c6cdd7520c6 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java @@ -239,12 +239,6 @@ package org.lamport.tla.toolbox.editor.basic.handlers; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.AbstractSet; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -258,14 +252,7 @@ import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.BadLocationException; @@ -274,34 +261,25 @@ import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTError; -import org.eclipse.swt.browser.Browser; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; import org.eclipse.ui.editors.text.FileDocumentProvider; import org.eclipse.ui.part.FileEditorInput; import org.lamport.tla.toolbox.Activator; //import org.lamport.tla.toolbox.doc.HelpButton; import org.lamport.tla.toolbox.editor.basic.TLAEditor; -import org.lamport.tla.toolbox.editor.basic.handlers.DecomposeProofHandler.NodeRepresentation; import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.spec.parser.IParseConstants; @@ -311,17 +289,15 @@ import org.lamport.tla.toolbox.util.HelpButton; import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.StringHelper; import org.lamport.tla.toolbox.util.UIHelper; -import org.osgi.framework.Bundle; -import org.osgi.framework.FrameworkUtil; - -import pcal.exception.StringVectorToFileException; import tla2sany.parser.SyntaxTreeNode; import tla2sany.semantic.ASTConstants; import tla2sany.semantic.AssumeProveNode; +import tla2sany.semantic.DefStepNode; import tla2sany.semantic.ExprNode; import tla2sany.semantic.ExprOrOpArgNode; import tla2sany.semantic.FormalParamNode; +import tla2sany.semantic.InstanceNode; import tla2sany.semantic.LeafProofNode; import tla2sany.semantic.LevelNode; import tla2sany.semantic.ModuleNode; @@ -334,8 +310,6 @@ import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SubstInNode; import tla2sany.semantic.SymbolNode; import tla2sany.semantic.TheoremNode; -import tla2sany.semantic.DefStepNode; -import tla2sany.semantic.InstanceNode; import tla2sany.st.Location; import util.UniqueString; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java index 0cf70cbb43cc77b9dae9a3e1581e3115d404eb4b..0ed6c78c8ea872125c5612807ded2d4c067b55b3 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java @@ -17,7 +17,6 @@ import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextSelection; -import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.widgets.Shell; import org.lamport.tla.toolbox.Activator; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ReturnFromOpenDeclarationHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ReturnFromOpenDeclarationHandler.java index ad7e7b0351376cdc6ebceec6d601b489c3d58b66..1cbfd8aab86a0cfc006a2d51e1069edbd34b4eb9 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ReturnFromOpenDeclarationHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ReturnFromOpenDeclarationHandler.java @@ -1,21 +1,14 @@ -/** - * - */ package org.lamport.tla.toolbox.editor.basic.handlers; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; -import org.eclipse.jface.text.ITextSelection; import org.lamport.tla.toolbox.spec.Spec; +import org.lamport.tla.toolbox.spec.Spec.Pair; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.util.UIHelper; -/** - * @author lamport - * - */ public class ReturnFromOpenDeclarationHandler extends AbstractHandler implements IHandler { @@ -24,14 +17,12 @@ public class ReturnFromOpenDeclarationHandler extends AbstractHandler implements */ public Object execute(ExecutionEvent event) throws ExecutionException { - Spec spec = ToolboxHandle.getCurrentSpec(); - String fileName = spec.getOpenDeclModuleName(); - ITextSelection its = spec.getOpenDeclSelection(); - if ((fileName != null) && (its != null)) - { - UIHelper.jumpToSelection(fileName, spec.getOpenDeclSelection()); - } - ; + final Spec spec = ToolboxHandle.getCurrentSpec(); + final Pair p = spec.getOpenDeclModuleName(); + if (p != null) { + UIHelper.jumpToSelection(p.editor, p.selection); + //TODO Bring the editor back to top in its editor stack. + } return null; } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAAnnotationHover.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAAnnotationHover.java index 6b15b629a4c6c69c58e26e6d40fef2348218e1c7..7fa437ffa11c484474442e12bded0fd1289e18db 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAAnnotationHover.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAAnnotationHover.java @@ -1,32 +1,91 @@ package org.lamport.tla.toolbox.editor.basic.tla; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationHover; +import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.ui.texteditor.MarkerAnnotation; /** * @author Simon Zambrovski * @version $Id$ */ -public class TLAAnnotationHover implements IAnnotationHover -{ - - /* (non-Javadoc) - * Method declared on IAnnotationHover +public class TLAAnnotationHover implements IAnnotationHover { + /** + * {@inheritDoc} */ - public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) - { - IDocument document = sourceViewer.getDocument(); - - /* - try - { - IRegion info = document.getLineInformation(lineNumber); - return "This is an annotation for: " + document.get(info.getOffset(), info.getLength()); - } catch (BadLocationException x) - { - } -*/ - return null; - } + public String getHoverInfo(final ISourceViewer sourceViewer, final int lineNumber) { + final String[] messages = getMessagesForLine(sourceViewer, lineNumber); + + if (messages.length == 0) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + final String lineSeparator = System.getProperty("line.separator"); + for (int i = 0; i < messages.length; i++) { + sb.append(messages[i]); + if (i < (messages.length - 1)) { + sb.append(lineSeparator); + } + } + + return sb.toString(); + } + + private String[] getMessagesForLine(final ISourceViewer viewer, final int line) { + final IAnnotationModel model = viewer.getAnnotationModel(); + + if (model == null) { + return new String[0]; + } + + final Iterator<Annotation> it = model.getAnnotationIterator(); + final IDocument document = viewer.getDocument(); + final ArrayList<String> messages = new ArrayList<>(); + final HashMap<Position, Set<String>> placeMessagesMap = new HashMap<>(); + while (it.hasNext()) { + final Annotation annotation = it.next(); + if (annotation instanceof MarkerAnnotation) { + final MarkerAnnotation ma = (MarkerAnnotation) annotation; + final Position p = model.getPosition(ma); + if (compareRulerLine(p, document, line)) { + final IMarker marker = ma.getMarker(); + final String message = marker.getAttribute(IMarker.MESSAGE, null); + if ((message != null) && (message.trim().length() > 0)) { + Set<String> priorMessages = placeMessagesMap.get(p); + if (priorMessages == null) { + priorMessages = new HashSet<>(); + placeMessagesMap.put(p, priorMessages); + } + + if (!priorMessages.contains(message)) { + messages.add(message); + priorMessages.add(message); + } + } + } + } + } + return (String[]) messages.toArray(new String[messages.size()]); + } + + private boolean compareRulerLine(final Position position, final IDocument document, final int line) { + try { + if ((position.getOffset() > -1) && (position.getLength() > -1)) { + return (document.getLineOfOffset(position.getOffset()) == line); + } + } catch (final BadLocationException e) { } + return false; + } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java index 1d045fa2ed7d2346a65c901c64a6380b17ba0f5b..eddd9e402598f4db481cd820722bda215b5e9877 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java @@ -20,10 +20,12 @@ import org.eclipse.ui.editors.text.TextFileDocumentProvider; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.IDocumentProvider; -import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; import org.lamport.tla.toolbox.editor.basic.TLAEditorAndPDFViewer; import org.lamport.tla.toolbox.editor.basic.TLAEditorReadOnly; import org.lamport.tla.toolbox.editor.basic.actions.OpenDeclarationAction; +import org.lamport.tla.toolbox.editor.basic.actions.OpenDeclarationInCurrentAction; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.util.ResourceHelper; @@ -88,8 +90,6 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector return null; } - IDocument document = textViewer.getDocument(); - // set currentTokenSpec to the TokenSpec object specifying the // currently selected symbol and its resolution. TokenSpec currentTokenSpec = TokenSpec.findCurrentTokenSpec(region); @@ -134,11 +134,17 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector { csNode = (SyntaxTreeNode) resolvedSymbol.stn.heirs()[0]; // .heirs()[1]; } - for (int i = 0; i < csNode.getAttachedComments().length; i++) - { - TLAEditorActivator.getDefault().logDebug(csNode.getAttachedComments()[i]); - } - + + // Before using the default TLA+ editor below, try to identify and reuse the current + // editor if it shows the same module already. + final TLAEditor tlaEditor = EditorUtil.getTLAEditorWithFocus(); + if (tlaEditor != null && csNode.getLocation().source().equals(tlaEditor.getModuleName())) { + final IDocument document = tlaEditor.getDocumentProvider().getDocument(tlaEditor.getEditorInput()); + final int[] region2 = getRegion(getCS(resolvedSymbol, csNode), document); + return new IHyperlink[] { new OpenDeclarationInCurrentAction(tlaEditor, + new Region(region2[0], region2[1] - region2[0]), label, region) }; + } + IDocumentProvider documentProvider = null; IEditorInput editorInput = null; String editorId = ""; @@ -168,66 +174,10 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector return null; } - // connect to the resource - try - { - documentProvider.connect(editorInput); - document = documentProvider.getDocument(editorInput); - } finally - { - /* - * Once the document has been retrieved, the document provider is - * not needed. Always disconnect it to avoid a memory leak. - * - * Keeping it connected only seems to provide synchronization of - * the document with file changes. That is not necessary in this context. - */ - documentProvider.disconnect(editorInput); - } - - try - { - // Get the location to highlight. If it's an OpDefNode, want - // to get just the symbol from the left-hand side. (Otherwise, - // the user can't execute Goto Declaration immediately followed - // by Show Uses.) - if (resolvedSymbol instanceof OpDefNode && csNode.getHeirs().length >= 1) - { - // Need to pick out the symbol from the left-hand side of - // the definition. - csNode = csNode.getHeirs()[0]; - if (csNode.getKind() == SyntaxTreeConstants.N_IdentLHS) - { - csNode = csNode.getHeirs()[0]; - } else - { - if ((csNode.getKind() == SyntaxTreeConstants.N_InfixLHS) - || (csNode.getKind() == SyntaxTreeConstants.N_PostfixLHS)) - { - csNode = csNode.getHeirs()[1]; - } - } - } else if ((resolvedSymbol instanceof ThmOrAssumpDefNode && csNode.getHeirs().length >= 2) - && ((csNode.getKind() == SyntaxTreeConstants.N_Theorem) || (csNode.getKind() == SyntaxTreeConstants.N_Assumption))) - { - csNode = csNode.getHeirs()[1]; - } - IRegion startLineRegion = document.getLineInformation(csNode.getLocation().beginLine() - 1); - IRegion endLineRegion = document.getLineInformation(csNode.getLocation().endLine() - 1); - - // offsets - int startOffset = startLineRegion.getOffset() + csNode.getLocation().beginColumn() - 1; - int endOffset = endLineRegion.getOffset() + csNode.getLocation().endColumn(); - - return new IHyperlink[] { new OpenDeclarationAction(editorId, editorInput, new Region(startOffset, endOffset - - startOffset), label, region) }; - - } catch (BadLocationException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + final int[] region2 = getDocumentAndRegion(getCS(resolvedSymbol, csNode), documentProvider, editorInput); + return new IHyperlink[] { new OpenDeclarationAction(editorId, editorInput, + new Region(region2[0], region2[1] - region2[0]), label, region) }; + } } catch (CoreException e) { // TODO Auto-generated catch block @@ -235,4 +185,66 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector } return null; } + + private int[] getDocumentAndRegion(SyntaxTreeNode csNode, IDocumentProvider documentProvider, IEditorInput editorInput) + throws CoreException { + IDocument document; + // connect to the resource + try { + documentProvider.connect(editorInput); + document = documentProvider.getDocument(editorInput); + } finally { + /* + * Once the document has been retrieved, the document provider is not needed. + * Always disconnect it to avoid a memory leak. + * + * Keeping it connected only seems to provide synchronization of the document + * with file changes. That is not necessary in this context. + */ + documentProvider.disconnect(editorInput); + } + + return getRegion(csNode, document); + } + + private int[] getRegion(SyntaxTreeNode csNode, IDocument document) { + try { + IRegion startLineRegion = document.getLineInformation(csNode.getLocation().beginLine() - 1); + IRegion endLineRegion = document.getLineInformation(csNode.getLocation().endLine() - 1); + + // offsets + int startOffset = startLineRegion.getOffset() + csNode.getLocation().beginColumn() - 1; + int endOffset = endLineRegion.getOffset() + csNode.getLocation().endColumn(); + + return new int[] { startOffset, endOffset }; + } catch (BadLocationException e) { + e.printStackTrace(); + } + return new int[] { 0, 0 }; + } + + private SyntaxTreeNode getCS(SymbolNode resolvedSymbol, SyntaxTreeNode csNode) { + // Get the location to highlight. If it's an OpDefNode, want + // to get just the symbol from the left-hand side. (Otherwise, + // the user can't execute Goto Declaration immediately followed + // by Show Uses.) + if (resolvedSymbol instanceof OpDefNode && csNode.getHeirs().length >= 1) { + // Need to pick out the symbol from the left-hand side of + // the definition. + csNode = csNode.getHeirs()[0]; + if (csNode.getKind() == SyntaxTreeConstants.N_IdentLHS) { + csNode = csNode.getHeirs()[0]; + } else { + if ((csNode.getKind() == SyntaxTreeConstants.N_InfixLHS) + || (csNode.getKind() == SyntaxTreeConstants.N_PostfixLHS)) { + csNode = csNode.getHeirs()[1]; + } + } + } else if ((resolvedSymbol instanceof ThmOrAssumpDefNode && csNode.getHeirs().length >= 2) + && ((csNode.getKind() == SyntaxTreeConstants.N_Theorem) + || (csNode.getKind() == SyntaxTreeConstants.N_Assumption))) { + csNode = csNode.getHeirs()[1]; + } + return csNode; + } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java index 8b1e5ecd8ba437580e28fd27415b1fa921aad1bd..5e2b42316b76cc43945cb6d003e9f41acce17298 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java @@ -91,6 +91,9 @@ public class TokenSpec return null; } String moduleName = editor.getModuleName(); + if (moduleName == null) { + return null; + } ModuleNode moduleNode = ResourceHelper.getModuleNode(moduleName); if (moduleNode == null) { diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java index e43401a392eaad0d705efc99d723f1d03685b120..b41aab4ace2a987e05470b1ab0b5af31075285ce 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java @@ -83,17 +83,18 @@ public class EditorUtil */ public static TLAEditor getTLAEditorWithFocus() { - IEditorPart activeEditor = UIHelper.getActiveEditor(); - // activeEditor.getAdapter(ITexto) - if (activeEditor instanceof TLAEditorAndPDFViewer) - { - TLAEditor editor = ((TLAEditorAndPDFViewer) activeEditor).getTLAEditor(); - if (editor != null && editor.getViewer().getTextWidget().isFocusControl()) - { - return editor; - } - } - + IEditorPart activeEditor = UIHelper.getActiveEditor(); + if (activeEditor instanceof TLAEditorAndPDFViewer) { + TLAEditor editor = ((TLAEditorAndPDFViewer) activeEditor).getTLAEditor(); + if (editor != null && editor.getViewer().getTextWidget().isFocusControl()) { + return editor; + } + } else if (activeEditor != null && activeEditor.getAdapter(TLAEditor.class) != null) { + TLAEditor editor = activeEditor.getAdapter(TLAEditor.class); + if (editor != null && editor.getViewer().getTextWidget().isFocusControl()) { + return editor; + } + } return null; } @@ -114,9 +115,9 @@ public class EditorUtil if (activeEditor instanceof TLAEditorAndPDFViewer) { return ((TLAEditorAndPDFViewer) activeEditor).getTLAEditor(); - } + } - return null; + return activeEditor.getAdapter(TLAEditor.class); } /** @@ -644,14 +645,15 @@ public class EditorUtil * @param moduleFileName name of the module with .tla extension. * @return */ - public static TLAEditor openTLAEditor(String moduleFileName) + public static TLAEditor openTLAEditor(final String moduleFileName) { - IResource module = ResourceHelper.getResourceByName(moduleFileName); - if (module != null && module instanceof IFile) - { - IEditorPart editor = UIHelper.openEditor(TLAEditor.ID, (IFile) module); - if (editor instanceof TLAEditorAndPDFViewer) - { + final IResource module = ResourceHelper.getResourceByName(moduleFileName); + if ((module != null) && (module instanceof IFile)) { + final IEditorPart editor = UIHelper.openEditor(TLAEditor.ID, (IFile) module); + + if (editor instanceof TLAEditor) { + return (TLAEditor)editor; + } else if (editor instanceof TLAEditorAndPDFViewer) { return ((TLAEditorAndPDFViewer) editor).getTLAEditor(); } } @@ -708,12 +710,16 @@ public class EditorUtil IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput()); // check if editor's file is currently parsed. - IFile file = ((FileEditorInput) editor.getEditorInput()).getFile(); - String moduleName = ResourceHelper.getModuleName(file); - - ParseResult parseResult = ResourceHelper.getValidParseResult(file); - - return ResourceHelper.getTheoremNodeWithCaret(parseResult, moduleName, textSelection, document); + + if (editor.getEditorInput() instanceof FileEditorInput) { + IFile file = ((FileEditorInput) editor.getEditorInput()).getFile(); + String moduleName = ResourceHelper.getModuleName(file); + + ParseResult parseResult = ResourceHelper.getValidParseResult(file); + + return ResourceHelper.getTheoremNodeWithCaret(parseResult, moduleName, textSelection, document); + } + return null; } /** @@ -802,8 +808,7 @@ public class EditorUtil if (srcEditor != null) { Spec spec = ToolboxHandle.getCurrentSpec(); - spec.setOpenDeclModuleName(srcEditor.getEditorInput().getName()); - spec.setOpenDeclSelection((ITextSelection) srcEditor.getSelectionProvider().getSelection()); + spec.setOpenDeclModuleName(srcEditor); } } diff --git a/org.lamport.tla.toolbox.feature.standalone/build.properties b/org.lamport.tla.toolbox.feature.standalone/build.properties index 325133113f9e301bbf18a0e8100355462e7e0bdb..8c396f81c4a9616e23ce948021f0846ae7dbdd18 100644 --- a/org.lamport.tla.toolbox.feature.standalone/build.properties +++ b/org.lamport.tla.toolbox.feature.standalone/build.properties @@ -1,2 +1,5 @@ bin.includes = feature.xml,\ build.properties +root=file:../tlatools/dist/tla2tools.jar +root.permissions.755=tla2tools.jar + diff --git a/org.lamport.tla.toolbox.feature.standalone/feature.xml b/org.lamport.tla.toolbox.feature.standalone/feature.xml index c47aa9a2b731d5c3fd6a55cf2c1e73e9dfe7bd43..39cdc9dc04fef723c0b0dc61f5f3f72c349e9a1e 100644 --- a/org.lamport.tla.toolbox.feature.standalone/feature.xml +++ b/org.lamport.tla.toolbox.feature.standalone/feature.xml @@ -46,10 +46,6 @@ id="org.lamport.tla.toolbox.feature.jnlp" version="0.0.0"/> - <includes - id="org.lamport.tlatools.feature" - version="0.0.0"/> - <includes id="org.lamport.tla.toolbox.feature.branding" version="0.0.0"/> @@ -70,6 +66,10 @@ id="de.vonloesch.pdf4eclipse.feature" version="0.0.0"/> + <includes + id="org.lamport.openjdk.feature" + version="0.0.0"/> + <includes id="org.eclipse.ecf.core.feature" version="0.0.0"/> @@ -296,6 +296,13 @@ version="15.0.0.v201403281430" unpack="false"/> + <plugin + id="com.google.guava" + download-size="0" + install-size="0" + version="21.0.0.v20170206-1425" + unpack="false"/> + <plugin id="org.eclipse.mylyn.commons.ui" download-size="0" @@ -321,7 +328,15 @@ id="org.eclipse.jdt.annotation" download-size="0" install-size="0" - version="1.1.150.v20180322-1206" + version="1.1.300.v20180905-0314" + unpack="false"/> + + <plugin + id="org.lamport.tla.toolbox.rss" + download-size="0" + install-size="0" + version="0.0.0" + fragment="true" unpack="false"/> </feature> diff --git a/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF index 06936e2a86f5845f5fc12d5b442efce877066d23..d6af11099d3a6836ac22959182bfc2c2f58c7bf0 100644 --- a/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF @@ -11,12 +11,14 @@ Require-Bundle: org.eclipse.core.runtime, jclouds-scriptbuilder;bundle-version="1.7.3", jclouds-slf4j;bundle-version="1.7.3", jclouds-sshj;bundle-version="1.7.3", - com.google.guava;bundle-version="[15.0.0,21.0.0)", + com.google.guava;bundle-version="21.0.0", com.google.inject;bundle-version="3.0.0", org.apache.commons.io;bundle-version="2.0.1", org.lamport.tlatools;bundle-version="1.0.0" DynamicImport-Package: * Bundle-Activator: org.lamport.tla.toolbox.jcloud.JCloudActivator -Import-Package: org.jclouds.aws.ec2.reference;version="1.7.3", +Import-Package: org.jclouds.aws.ec2.compute;version="2.1.0", + org.jclouds.aws.ec2.reference;version="1.7.3", org.jclouds.ec2.reference;version="1.7.3", org.lamport.tla.toolbox.tool.tlc.job;resolution:=optional +Automatic-Module-Name: org.lamport.tla.toolbox.jclouds diff --git a/org.lamport.tla.toolbox.jclouds/cleanazure.sh b/org.lamport.tla.toolbox.jclouds/cleanazure.sh deleted file mode 100755 index 590b003ebe77d2d2ff8ac9104e6f5a6bcf6a3df9..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.jclouds/cleanazure.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -## Get the output of `azure vm list`, extract the vm ids and loop over the result -## Terminate/delete each VM including its disk image (-d) -IMAGES=`azure vm list --json | grep 'VMName'| cut -d '"' -f 4` -for i in $IMAGES; do - azure vm delete --quiet --blob-delete $i -done - -## Get the output of `azure storage account list` -## Quietly (no confirmation prompt) delete all accounts -ACCOUNTS=`azure storage account list --json | grep '"name"' | cut -d '"' -f 4` -for a in $ACCOUNTS; do - azure storage account delete --quiet $a -done diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java index 939751b67cadb60c21549cecf87bdf782392707a..c3e3ae70fc01b9c3cf702fe9135abe4ba69b5be0 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java @@ -25,10 +25,13 @@ ******************************************************************************/ package org.lamport.tla.toolbox.jcloud; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -38,9 +41,11 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; +import org.lamport.tla.toolbox.tool.tlc.job.ITLCJobStatus; import org.lamport.tla.toolbox.tool.tlc.job.TLCJobFactory; import tlc2.TLCGlobals; +import util.ExecutionStatisticsCollector; public class Application implements IApplication { @@ -59,7 +64,18 @@ public class Application implements IApplication { final String modelDirectory = args[0]; final Properties props = initializeFromFile(modelDirectory); + // By default send mail to the root account (might be overwritten below). + // Without specifying any email address, MailSender will not set up + // /mnt/tlc/MC.out and most of CloudDistributedTLCJob's functionality will not + // work (no TLC process output will be received). Do not add if cloud.properties + // file has defined it already. + props.putIfAbsent(TLCJobFactory.MAIL_ADDRESS, "root@localhost"); props.put(TLCJobFactory.MAIN_CLASS, tlc2.TLC.class.getName()); + + final ExecutionStatisticsCollector udc = new ExecutionStatisticsCollector(); + if (udc.isEnabled()) { + props.put(ExecutionStatisticsCollector.PROP, udc.getIdentifier()); + } // Optional parameters final String cloud = args.length >= 2 ? args[1] : "aws-ec2"; @@ -106,10 +122,10 @@ public class Application implements IApplication { final TLCJobFactory factory = new CloudTLCJobFactory(); final CloudDistributedTLCJob job = (CloudDistributedTLCJob) factory.getTLCJob(cloud, new File(modelDirectory), 1, props, tlcParams.toString()); job.setIsCLI(true); - job.setDoJfr(true); +// job.setDoJfr(true); //Todo Reactivate once CloudTLC copies the JFR dump file to the local machine. final IStatus status = job.run(new MyProgressMonitor(9)); // Show error message if any such as invalid credentials. - if (status.getSeverity() == IStatus.ERROR) { + if (status.getSeverity() == IStatus.ERROR || !(status instanceof ITLCJobStatus)) { System.err.println(status.getMessage()); final Throwable exception = status.getException(); if (exception instanceof CloudDistributedTLCJob.ScriptException) { @@ -120,6 +136,22 @@ public class Application implements IApplication { return new Integer(1); } + // If no error above, read the (remote) TLC process output (stdout, no stderr) + // and print it on the local stdout. + final InputStream output = ((ITLCJobStatus) status).getOutput(); + try { + final BufferedReader in = new BufferedReader( + new InputStreamReader(output)); + String line; + while ((line = in.readLine()) != null) { + System.out.println(line); + } + } catch (IOException e) { + System.err.println(status.getMessage()); + // Signal unsuccessful execution. + return new Integer(1); + } + return IApplication.EXIT_OK; } @@ -136,9 +168,10 @@ public class Application implements IApplication { * @see org.eclipse.equinox.app.IApplication#stop() */ public void stop() { + // cannot be stopped! } - private static class MyProgressMonitor implements IProgressMonitor { + static class MyProgressMonitor implements IProgressMonitor { private final DateFormat formatter = new SimpleDateFormat( "YYYY-MM-dd HH:mm:ss.SSS" ); private final int totalSteps; private int steps = 1; @@ -168,5 +201,9 @@ public class Application implements IApplication { public void setTaskName(String name) {} public void worked(int work) {} + + public void incSteps(int steps) { + this.steps += steps; + } } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java index a5b1e835e7790815c16f12f6c1e823109d5ab243..f460bdc095d6fc6f33b5f74704c6926d477139df 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java @@ -36,6 +36,11 @@ import org.jclouds.location.reference.LocationConstants; public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstanceParameters { + private static final String AZURE_COMPUTE_SUBSCRIPTION = "AZURE_COMPUTE_SUBSCRIPTION"; + private static final String AZURE_COMPUTE_SERVICE_PRINCIPAL = "AZURE_COMPUTE_SERVICE_PRINCIPAL"; + private static final String AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD = "AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"; + private static final String AZURE_COMPUTE_TENANT = "AZURE_COMPUTE_TENANT"; + public AzureARMCloudTLCInstanceParameters(final String tlcParams, int numberOfWorkers) { super(tlcParams.trim(), numberOfWorkers); } @@ -78,7 +83,7 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar */ @Override public String getIdentity() { - final String identity = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL"); + final String identity = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL); Assert.isNotNull(identity); return identity; } @@ -88,13 +93,13 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar */ @Override public String getCredentials() { - final String credential = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"); + final String credential = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD); Assert.isNotNull(credential); return credential; } private String getSubscriptionId() { - final String subscription = System.getenv("AZURE_COMPUTE_SUBSCRIPTION"); + final String subscription = System.getenv(AZURE_COMPUTE_SUBSCRIPTION); Assert.isNotNull(subscription); return subscription; } @@ -104,15 +109,15 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar */ @Override public IStatus validateCredentials() { - final String credential = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"); - final String identity = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL"); - final String subscription = System.getenv("AZURE_COMPUTE_SUBSCRIPTION"); - final String tenantId = System.getenv("AZURE_COMPUTE_TENANT"); + final String credential = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD); + final String identity = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL); + final String subscription = System.getenv(AZURE_COMPUTE_SUBSCRIPTION); + final String tenantId = System.getenv(AZURE_COMPUTE_TENANT); if (credential == null || identity == null || subscription == null || tenantId == null) { return new Status(Status.ERROR, "org.lamport.tla.toolbox.jcloud", "Invalid credentials, please check the environment variables " - + "(AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD & AZURE_COMPUTE_SERVICE_PRINCIPAL " - + "& AZURE_COMPUTE_TENANT and AZURE_COMPUTE_SUBSCRIPTION) are correctly " + + "(" + AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD + " & " + AZURE_COMPUTE_SERVICE_PRINCIPAL + " " + + "& " + AZURE_COMPUTE_TENANT + " and " + AZURE_COMPUTE_SUBSCRIPTION + ") are correctly " + "set up and picked up by the Toolbox." + "\n\nPlease visit the Toolbox help and read section 4 " + "of \"Cloud based distributed TLC\" on how to setup authentication."); @@ -125,7 +130,7 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar */ @Override public void mungeProperties(final Properties properties) { - properties.setProperty("azurecompute-arm.tenantId", System.getenv("AZURE_COMPUTE_TENANT")); + properties.setProperty("azurecompute-arm.tenantId", System.getenv(AZURE_COMPUTE_TENANT)); // Minimize back and forth with Azure API by limiting images to those provided // by Canoncial. Also only talk to Azure in US east. Both properties reduce // startup time. @@ -158,4 +163,74 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar // (similar to EC2CloudTLCInstanceParameters#getHostnameSetup. return "hostname \"$(hostname).cloudapp.net\" && echo \"$(curl -s ifconfig.co) $(hostname)\" >> /etc/hosts"; } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getExtraRepositories() + */ + @Override + public String getExtraRepositories() { + // https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest + return "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list" + + " && " + + "apt-key adv --keyserver packages.microsoft.com --recv-keys BC528686B50D79E339D3721CEB3E94ADBE1229CF"; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getExtraPackages() + */ + @Override + public String getExtraPackages() { + // https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest#install-on-debianubuntu-with-apt-get + // see getExtraRepositories too. + return "azure-cli"; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCloudAPIShutdown(java.lang.String, java.lang.String) + */ + @Override + public String getCloudAPIShutdown(final String credentials, final String groupName) { + final String servicePrincipal = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL); + final String password = System.getenv(AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD); + final String tenant = System.getenv(AZURE_COMPUTE_TENANT); + if (servicePrincipal == null || password == null || tenant == null) { + // Missing credentials. + return super.getCloudAPIShutdown(credentials, groupName); + } + // What we try to accomplish is to purge the complete Azure Resource Group (a RG + // combines all Azure resources associated with the VM (storage, networking, + // ips, ...). + // + // Unfortunately, the azure CLI needs credentials to talk to the Azure API. The + // switch to jclouds's azurecompute-arm provider means we can simply reuse the + // service-principal credentials here. + // + // An alternative to calling the az login process would be to use an + // auth.properties file, but this doesn't seem supported by azure CLI yet. Read + // "File based authentication" at + // https://docs.microsoft.com/en-us/java/azure/java-sdk-azure-authenticate#mgmt-file + return String.format( + // Sign into azure during instance provisioning to catch auth error early and not only during instance termination. + // Nest in "sudo -i" to make sure azure credentials are created for root account which runs + // "az group delete ..." during instance shutdown. + "/usr/bin/sudo -i /usr/bin/az login --service-principal -u %s -p %s --tenant %s" + + " && " + // @see PacketNetCloudTLCInstanceParameters#getCloudAPIShutdown + + "printf \"[Unit]\\nDescription=Delete Azure resource group via azure-cli on instance shutdown\\n" + + "Requires=network.target\\n" + + "After=network.target\\n" + + "DefaultDependencies=no\\n" + + "Before=shutdown.target\\n" + + "[Service]\\n" + + "Type=oneshot\\n" + + "RemainAfterExit=true\\n" + + "ExecStart=/bin/true\\n" + // Great, this is much simpler compared to 589e6fc82ce182b0c49c4c1fb63bc0aae711cf5f + + "ExecStop=/usr/bin/az group delete --name %s -y\\n" + + "[Install]\\n" + + "WantedBy=multi-user.target\\n\" | sudo tee /lib/systemd/system/delete-on-shutdown.service" + + " && systemctl enable delete-on-shutdown" // restart delete-on-shutdown service after a reboot. + + " && service delete-on-shutdown start", + servicePrincipal, password, tenant, groupName); + } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java index a90a821ab5a0da23d1ab7c383d0942409941846e..bd4f13d4a09940a3f6ea0c839549c04b5dad977f 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java @@ -87,9 +87,20 @@ public class AzureCloudTLCInstanceParameters extends CloudTLCInstanceParameters */ @Override public String getImageId() { - // 'azure vm image list eastus canonical' (manually lookup image release date from output) + // 'azure vm image list eastus canonical' (manually lookup image release date + // from output, note the extra digit after the date YYYYMMDD (below separated by + // a dot) which appears to be a sequence number for the images on the given + // date). // With azure-cli v2 (based on Python) extract date from 'az vm image list --all --publisher Canonical'. - return System.getProperty("azure.image", "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-18_04-LTS-amd64-server-20180426.2-en-us-30GB"); + // ... { + // "offer": "UbuntuServer", + // "publisher": "Canonical", + // "sku": "18.04-LTS", + // "urn": "Canonical:UbuntuServer:18.04-LTS:18.04.201902121", + // "version": "18.04.201902121" + // }, ... + // + return System.getProperty("azure.image", "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-18_04-LTS-amd64-server-20190212.1-en-us-30GB"); } /* (non-Javadoc) diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java index 6c23c9d0ea168cc98adfd26d5c63a23e5d25a926..110755aa6072964b59482b950d43b963e4238362 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java @@ -32,12 +32,10 @@ import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.jclouds.scriptbuilder.domain.Statements.exec; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.HashSet; import java.util.Map; @@ -49,6 +47,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.stream.Collectors; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -83,7 +82,6 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.io.ByteStreams; import com.google.common.io.Files; import com.google.inject.AbstractModule; @@ -128,6 +126,22 @@ public class CloudDistributedTLCJob extends Job { @Override protected IStatus run(final IProgressMonitor monitor) { + final String sshAuthSock = System.getenv("SSH_AUTH_SOCK"); + if (sshAuthSock != null && !(new File(sshAuthSock).exists())) { + //TODO Wire this up to the IProgressMonitor such that the warning is shown in the Toolbox. + System.err.printf( + "--------------------------------------------------------------------------------\n" + + "WARNING: SSH_AUTH_SOCK environment variable is set to %s\n" + + "but the socket file does not exist. Please make sure SSH_AUTH_SOCK points to a\n" + + "valid socket file.\n" + + "An invalid socket will result in a bogus ArrayIndexOutOfBoundsException related\n" + + "to reading past the end of a 1024 element buffer during ssh-agent setup (for\n" + + "technical details please see: \n" + + "https://github.com/ymnk/jsch-agent-proxy/issues/29#issuecomment-475787685)" + ".\n" + + "--------------------------------------------------------------------------------\n", + sshAuthSock); + } + monitor.beginTask("Starting TLC model checker in the cloud", 90 + (nodes > 1 ? 20 : 0)); // Validate credentials and fail fast if null or syntactically incorrect if (!params.validateCredentials().equals(Status.OK_STATUS)) { @@ -136,6 +150,10 @@ public class CloudDistributedTLCJob extends Job { ComputeServiceContext context = null; try { + // Fail fast if files/tla2tools.jar is missing. This happens frequently for me + // when I forget to run the maven build in my dev environment. + PayloadHelper.checkToolsJar(); // Throws RuntimeException on failure. + // Tweak tla2tools in a background thread. It takes a couple of seconds to run // pack200 to shrink the files size but we can lookup or launch a cloud instance // in the meantime. @@ -179,7 +197,10 @@ public class CloudDistributedTLCJob extends Job { } //TODO Support instance reuse with Cloud distributed TLC. - monitor.subTask("Looking for resusable nodes to quick-start model checking"); + monitor.subTask(String.format( + "Looking for %sresusable node%s to quick-start model checking (output might show failed connection attempts)", + nodes > 1 ? "" : "a ", nodes > 1 ? "s" : "")); + boolean isReconnect = false; final Set<NodeMetadata> createNodesInGroup = nodes > 1 ? new HashSet<>() : findReusableNodes(compute, monitor); monitor.worked(5); @@ -191,14 +212,21 @@ public class CloudDistributedTLCJob extends Job { return Status.CANCEL_STATUS; } } else { + isReconnect = true; + monitor.subTask(String.format( + "Lookup succeeded thus skipping provisioning steps 5 to 7", + nodes > 1 ? "" : "a ", nodes > 1 ? "s" : "")); // skipped provisionNodes(...) which takes 35 steps. + monitor.subTask("--- skipped ---"); + monitor.subTask("--- skipped ---"); monitor.worked(35); } // Choose one of the nodes to be the master and create an // identifying predicate. final NodeMetadata master = Iterables.getLast(createNodesInGroup); - final String hostname = Iterables.getOnlyElement(master.getPublicAddresses()); // master.getHostname() only returns internal name + // Get first one assuming it is the best (e.g. IPv4 vs. IPv6). + final String hostname = Iterables.getFirst(master.getPublicAddresses(), null); // master.getHostname() only returns internal name // Copy tlatools.jar to _one_ remote host (do not exhaust upload of // the machine running the toolbox). @@ -209,12 +237,13 @@ public class CloudDistributedTLCJob extends Job { monitor.subTask("Copying tla2tools.jar to master node at " + hostname); SshClient sshClient = context.utils().sshForNode().apply(master); sshClient.put("/tmp/tla2tools.pack.gz", future.get()); + sshClient.disconnect(); monitor.worked(10); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } - final String tlcMasterCommand = " shutdown -c && rm -rf /mnt/tlc/* && " // Cancel and remove any pending shutdown and leftovers from previous runs. + final String tlcMasterCommand = " sudo shutdown -c && rm -rf /mnt/tlc/* && " // Cancel and remove any pending shutdown and leftovers from previous runs. + "cd /mnt/tlc/ && " // Decompress tla2tools.pack.gz + "unpack200 /tmp/tla2tools.pack.gz /tmp/tla2tools.jar" @@ -224,7 +253,7 @@ public class CloudDistributedTLCJob extends Job { // detach from screen directly. Name screen // session "tlc". // (see http://stackoverflow.com/a/10126799) - + (isCLI ? "" : "screen -dm -S tlc bash -c \" ") + + "screen -dm -S tlc bash -c \" " // This requires a modified version where all parameters and // all spec modules are stored in files in a model/ folder // inside of the jar. @@ -251,15 +280,8 @@ public class CloudDistributedTLCJob extends Job { // TLC tuning options + params.getJavaSystemProperties() + " " + "-jar /tmp/tla2tools.jar " - + params.getTLCParameters() + " " - + (isCLI ? "|& tee /mnt/tlc/MC.out " : "") - + "&& " - // Run any cloud specific cleanup tasks. - // When CloudDistributedTLCJob runs in synchronous CLI mode (isCLI), it will destroy - // the VMs (nodes) via the jclouds API. No need to deallocate nodes - // via special logic. - + (isCLI ? "/bin/true" : params.getCloudAPIShutdown()) - + " && " + + params.getTLCParameters() + + " && " // Let the machine power down immediately after // finishing model checking to cut costs. However, // do not shut down (hence "&&") when TLC finished @@ -268,141 +290,121 @@ public class CloudDistributedTLCJob extends Job { // run as a user. No need to run the TLC process as // root. + "sudo shutdown -h +" + SHUTDOWN_AFTER - + (isCLI ? "" : "\""); // closing opening '"' of screen/bash -c - if (isCLI) { - monitor.subTask("Starting TLC model checker process"); - // Execute command via ssh instead of as a script to get access to the TLC - // processes' stdout and stderr. - //TODO Better handle error case. - ExecChannel channel = sshClient.execChannel(tlcMasterCommand); - // Send remote TLC's stdout to local stdout (this throws a TransportException - // unless shutdown is postponed by a few minutes above). - ByteStreams.copy(channel.getOutput(), System.out); - if (doJfr) { - // Get Java Flight Recording from remote machine and save if to a local file in - // the current working directory. We call "cat" because sftclient#get fails with - // the old net.schmizz.sshj and an update to the newer com.hierynomus seems - // awful lot of work. - channel = sshClient.execChannel("cat /mnt/tlc/tlc.jfr"); - final InputStream output = channel.getOutput(); - final String cwd = Paths.get(".").toAbsolutePath().normalize().toString() + File.separator; - final File jfr = new File(cwd + "tlc.jfr"); - ByteStreams.copy(output, new FileOutputStream(jfr)); - if (jfr.length() == 0) { - System.err.println("Received empty Java Flight recording. Not creating tlc.jfr file"); - jfr.delete(); - } + + "\""; // closing opening '"' of screen/bash -c + + // Run model checker master on master + monitor.subTask("Starting TLC model checker process on the master node (in background)"); + final ExecResponse response = compute.runScriptOnNode(master.getId(), exec(tlcMasterCommand), + new TemplateOptions().overrideLoginCredentials(master.getCredentials()).runAsRoot(false) + .wrapInInitScript(true).blockOnComplete(false).blockUntilRunning(false)); + throwExceptionOnErrorResponse(master, response, "Starting TLC model checker process on the master node"); + monitor.worked(5); + + if (nodes > 1) { + // The predicate will be applied to ALL instances owned by the + // cloud account (ie AWS), even the ones in different regions + // completely unrelated to TLC. + final Predicate<NodeMetadata> isMaster = new Predicate<NodeMetadata>() { + private final String masterHostname = master.getHostname(); + public boolean apply(NodeMetadata nodeMetadata) { + // hostname can be null if instance is terminated. + final String hostname = nodeMetadata.getHostname(); + return masterHostname.equals(hostname); + }; + }; + // copy the tla2tools.jar to the root of the master's webserver + // to make it available to workers. However, strip the spec + // (*.tla/*.cfg/...) from the jar file to not share the spec + // with the world. + monitor.subTask("Make TLC code available to all worker node(s)"); + Map<? extends NodeMetadata, ExecResponse> execResponse = compute.runScriptOnNodesMatching( + isMaster, + exec("cp /tmp/tla2tools.jar /var/www/html/tla2tools.jar && " + + "zip -d /var/www/html/tla2tools.jar model/*.tla model/*.cfg model/generated.properties"), + new TemplateOptions().runAsRoot(true).wrapInInitScript( + false)); + throwExceptionOnErrorResponse(execResponse, "Make TLC code available to all worker node"); + monitor.worked(10); + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; } - // Finally close the ssh connection. - sshClient.disconnect(); - monitor.subTask("TLC model checker process finished"); - // Eagerly destroy the instance after we pulled the tlc.jfr file from it. No - // point in waiting for shutdown -h +10 to shutdown the instance. - destroyNodes(context, groupNameUUID); - } else { - sshClient.disconnect(); - - // Run model checker master on master - monitor.subTask("Starting TLC model checker process on the master node (in background)"); - final ExecResponse response = compute.runScriptOnNode(master.getId(), exec(tlcMasterCommand), - new TemplateOptions().overrideLoginCredentials(master.getCredentials()).runAsRoot(false) - .wrapInInitScript(true).blockOnComplete(false).blockUntilRunning(false)); - throwExceptionOnErrorResponse(master, response, "Starting TLC model checker process on the master node"); - monitor.worked(5); - - if (nodes > 1) { - // The predicate will be applied to ALL instances owned by the - // cloud account (ie AWS), even the ones in different regions - // completely unrelated to TLC. - final Predicate<NodeMetadata> isMaster = new Predicate<NodeMetadata>() { + + // The predicate will be applied to ALL instances owned by the + // AWS account, even the ones in different regions completely + // unrelated to TLC. + final Predicate<NodeMetadata> onWorkers = new Predicate<NodeMetadata>() { + // Remove the master from the set of our nodes. + private final Iterable<? extends NodeMetadata> workers = Iterables.filter(createNodesInGroup, new Predicate<NodeMetadata>() { private final String masterHostname = master.getHostname(); public boolean apply(NodeMetadata nodeMetadata) { - // hostname can be null if instance is terminated. - final String hostname = nodeMetadata.getHostname(); - return masterHostname.equals(hostname); - }; - }; - // copy the tla2tools.jar to the root of the master's webserver - // to make it available to workers. However, strip the spec - // (*.tla/*.cfg/...) from the jar file to not share the spec - // with the world. - monitor.subTask("Make TLC code available to all worker node(s)"); - Map<? extends NodeMetadata, ExecResponse> execResponse = compute.runScriptOnNodesMatching( - isMaster, - exec("cp /tmp/tla2tools.jar /var/www/html/tla2tools.jar && " - + "zip -d /var/www/html/tla2tools.jar model/*.tla model/*.cfg model/generated.properties"), - new TemplateOptions().runAsRoot(true).wrapInInitScript( - false)); - throwExceptionOnErrorResponse(execResponse, "Make TLC code available to all worker node"); - monitor.worked(10); - if (monitor.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // The predicate will be applied to ALL instances owned by the - // AWS account, even the ones in different regions completely - // unrelated to TLC. - final Predicate<NodeMetadata> onWorkers = new Predicate<NodeMetadata>() { - // Remove the master from the set of our nodes. - private final Iterable<? extends NodeMetadata> workers = Iterables.filter(createNodesInGroup, new Predicate<NodeMetadata>() { - private final String masterHostname = master.getHostname(); - public boolean apply(NodeMetadata nodeMetadata) { - // nodeMetadata.getHostname is null for terminated hosts. - return !masterHostname.equals(nodeMetadata.getHostname()); - }; - }); - public boolean apply(NodeMetadata nodeMetadata) { - return Iterables.contains(workers, nodeMetadata); + // nodeMetadata.getHostname is null for terminated hosts. + return !masterHostname.equals(nodeMetadata.getHostname()); }; + }); + public boolean apply(NodeMetadata nodeMetadata) { + return Iterables.contains(workers, nodeMetadata); }; - - // see master startup for comments - monitor.subTask("Starting TLC workers on the remaining node(s) (in background)"); - final String privateHostname = Iterables.getOnlyElement(master.getPrivateAddresses()); - execResponse = compute.runScriptOnNodesMatching( - onWorkers, - exec("cd /mnt/tlc/ && " - + "wget http://" + privateHostname + "/tla2tools.jar && " - + "screen -dm -S tlc bash -c \" " - + "java " - + params.getJavaWorkerVMArgs() + " " - + "-Djava.io.tmpdir=/mnt/tlc/ " - + "-Dcom.sun.management.jmxremote " - + "-Dcom.sun.management.jmxremote.port=5400 " - + "-Dcom.sun.management.jmxremote.ssl=false " - + "-Dcom.sun.management.jmxremote.authenticate=false " - + params.getJavaWorkerSystemProperties() + " " - + "-cp /mnt/tlc/tla2tools.jar " - + params.getTLCWorkerParameters() + " " - + privateHostname + " " // Use host's internal ip due to firewall reasons. - + "&& " - // Terminate regardless of TLCWorker process - // exit value. E.g. TLCWorker can terminate due - // to a NoRouteToHostException when the master - // shut down caused by a violation among the - // init states. - // Run any cloud specific cleanup tasks. - + params.getCloudAPIShutdown() - + " && " - + "sudo shutdown -h now" - + "\""), - new TemplateOptions().runAsRoot(false).wrapInInitScript( - true).blockOnComplete(false).blockUntilRunning(false)); - throwExceptionOnErrorResponse(execResponse, "Starting TLC workers"); - monitor.worked(10); - } - + }; + + // see master startup for comments + monitor.subTask("Starting TLC workers on the remaining node(s) (in background)"); + final String privateHostname = Iterables.getOnlyElement(master.getPrivateAddresses()); + execResponse = compute.runScriptOnNodesMatching( + onWorkers, + exec("cd /mnt/tlc/ && " + + "wget http://" + privateHostname + "/tla2tools.jar && " + + "screen -dm -S tlc bash -c \" " + + "java " + + params.getJavaWorkerVMArgs() + " " + + "-Djava.io.tmpdir=/mnt/tlc/ " + + "-Dcom.sun.management.jmxremote " + + "-Dcom.sun.management.jmxremote.port=5400 " + + "-Dcom.sun.management.jmxremote.ssl=false " + + "-Dcom.sun.management.jmxremote.authenticate=false " + + params.getJavaWorkerSystemProperties() + " " + + "-cp /mnt/tlc/tla2tools.jar " + + params.getTLCWorkerParameters() + " " + + privateHostname + " " // Use host's internal ip due to firewall reasons. + + "&& " + // Terminate regardless of TLCWorker process + // exit value. E.g. TLCWorker can terminate due + // to a NoRouteToHostException when the master + // shut down caused by a violation among the + // init states. + // Run any cloud specific cleanup tasks. + + "sudo shutdown -h now" + + "\""), + new TemplateOptions().runAsRoot(false).wrapInInitScript( + true).blockOnComplete(false).blockUntilRunning(false)); + throwExceptionOnErrorResponse(execResponse, "Starting TLC workers"); + monitor.worked(10); } - + // Get the output from the remote instance and attach the corresponding // InputStream to the CloudStatus. A UI can then read the InputStream and show // the output of the TLC process to a user. The SSH connection automatically // terminates when the TLC process finishes. - // https://askubuntu.com/questions/509881/tail-reading-an-entire-file-and-then-following - ExecChannel execChannel = null; - if (!isCLI) { - execChannel = sshClient.execChannel("tail -q -f -n +1 /mnt/tlc/MC.out --pid $(pgrep -f tla2tools.jar)"); - } + // https://askubuntu.com/questions/509881/tail-reading-an-entire-file-and-then-following + // + // For tail... to succeed, the TLC process has to be started with a + // MailSender.MAIL_ADDRESS so that MailSender creates /mnt/tlc/MC.out. This is + // something which should eventually be refactored out of MailSender and be made + // independent of it (e.g. the command-line variant of CloudDistributedTLC does + // not necessarily require an email to be sent). + final ExecChannel execChannel = sshClient.execChannel( + // Wait for the java process to start before tail'ing its MC.out file below. + // This obviously open the door to blocking indefinitely if the java/TLC process + // terminates before until starts. + "until pids=$(pgrep -f \"^java .* -jar /tmp/tla2tools.jar\"); do sleep 1; done" + + " && " + // Guarantee the MC.out file exists in case the java process has not written to + // it yet. Otherwise tail might terminate immediately. touch is idempotent and + // thus does not fail when MC.out already exists. + + "touch /mnt/tlc/MC.out" + + " && " + // Read the MC.out file and remain attached for as long as there is a TLC/java + // process. + + "tail -q -f -n +1 /mnt/tlc/MC.out --pid $(pgrep -f \"^java .* -jar /tmp/tla2tools.jar\")"); // Communicate result to user monitor.done(); @@ -415,7 +417,7 @@ public class CloudDistributedTLCJob extends Job { + "Expect to receive an email at %s with the model checking result eventually.", hostname, props.get("result.mail.address")), null, new URL( - "http://" + hostname + "/munin/"), execChannel.getOutput(), sshClient); + "http://" + hostname + "/munin/"), execChannel == null ? null : execChannel.getOutput(), sshClient, isReconnect); } catch (ExecutionException|InterruptedException|RunNodesException|IOException|RunScriptOnNodesException|NoSuchElementException|AuthorizationException|SshException e) { e.printStackTrace(); if (context != null) { @@ -445,17 +447,20 @@ public class CloudDistributedTLCJob extends Job { private Set<NodeMetadata> findReusableNodes(final ComputeService compute, final IProgressMonitor monitor) throws IOException { // Filter out those nodes which haven't been created by the Toolbox. We can't be - // sure if they are reusable or that we are allowed to reuse them. Also, skip - // nodes which are CLI nodes. CLI nodes get destroyed by the Toolbox. Lastly, we - // are only interested in RUNNING instances. - final Set<? extends ComputeMetadata> runningNodes = compute.listNodesDetailsMatching( + // sure if they are reusable or that we are allowed to reuse them. Lastly, we + // are only interested in RUNNING and SUSPENDED instances. + final Set<? extends ComputeMetadata> potentialNodes = compute.listNodesDetailsMatching( node -> node.getName() != null && node.getName().startsWith(providerName.toLowerCase()) - && !node.getTags().contains("CLI") && node.getStatus() == NodeMetadata.Status.RUNNING); + && (node.getStatus() == NodeMetadata.Status.RUNNING + || node.getStatus() == NodeMetadata.Status.SUSPENDED)); // TODO what happens if a node terminates before we tried to runScriptOnNode // below? Does runScriptOnNode throw an exception or does the response indicate // it? + final Set<ComputeMetadata> runningNodes = potentialNodes.stream().filter(cii -> cii instanceof NodeMetadata) + .map(NodeMetadata.class::cast).filter(nm -> nm.getStatus() == NodeMetadata.Status.RUNNING) + .collect(Collectors.toSet()); for (final ComputeMetadata node : runningNodes) { final String id = node.getId(); @@ -469,7 +474,7 @@ public class CloudDistributedTLCJob extends Job { // https://askubuntu.com/questions/994339/check-if-shutdown-schedule-is-active-and-when-it-is try { final ExecResponse response = compute.runScriptOnNode(id, - "busctl call --system org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CancelScheduledShutdown", + "sudo busctl call --system org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CancelScheduledShutdown", TemplateOptions.Builder.overrideLoginCredentials(getLoginForCommandExecution()).runAsRoot(true) .wrapInInitScript(false)); if (response.getExitStatus() == 0 @@ -486,6 +491,18 @@ public class CloudDistributedTLCJob extends Job { } } + // Fall back to suspended nodes. + potentialNodes.removeAll(runningNodes); + for (final ComputeMetadata node : potentialNodes) { + try { + final String id = node.getId(); + compute.resumeNode(id); + return new HashSet<>(Arrays.asList(new WrapperNodeMetadata(compute.getNodeMetadata(id), getLoginForCommandExecution()))); + } catch (RuntimeException e) { + continue; + } + } + return new HashSet<>(); } @@ -507,15 +524,17 @@ public class CloudDistributedTLCJob extends Job { if (isCLI) { templateOptions.tags(Arrays.asList("CLI")); } - + params.mungeTemplateOptions(templateOptions); + final TemplateBuilder templateBuilder = compute.templateBuilder(); templateBuilder.options(templateOptions); templateBuilder.imageId(params.getImageId()); templateBuilder.hardwareId(params.getHardwareId()); + params.mungeTemplateBuilder(templateBuilder); // Everything configured, now launch node - monitor.subTask(String.format("Starting %s %s instance%s in region %s.", nodes > 1 ? nodes : "a", - params.getHardwareId(), nodes > 1 ? "s" : "", params.getRegion())); + monitor.subTask(String.format("Starting %s new %s instance%s in region %s.", (nodes > 1 ? nodes : "a"), + params.getHardwareId(), (nodes > 1 ? "s" : ""), params.getRegion())); final Set<? extends NodeMetadata> createNodesInGroup = compute.createNodesInGroup(groupNameUUID, nodes, templateBuilder.build()); monitor.worked(20); @@ -547,12 +566,9 @@ public class CloudDistributedTLCJob extends Job { + " && " + params.getHostnameSetup() + " && " - // Oracle Java 8 - + (doJfr ? "add-apt-repository ppa:webupd8team/java -y && " : "/bin/true && ") - // Accept license before apt (dpkg) tries to present it to us (which fails due to 'noninteractive' mode below) - // see http://stackoverflow.com/a/19391042 - + "echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections && " - + "echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections && " + // http://repos.azulsystems.com/ + + "apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0x219BD9C9 && " + + "apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main' && " + params.getExtraRepositories() + " && " // Update Ubuntu's package index. The public/remote @@ -596,19 +612,23 @@ public class CloudDistributedTLCJob extends Job { + "apt-get install --no-install-recommends mdadm e2fsprogs screen zip unattended-upgrades " + params.getExtraPackages() + " -y" + " && " - + (doJfr ? "apt-get install --no-install-recommends oracle-java8-installer oracle-java8-set-default -y " : "/bin/true") + // Azul goes the extra mile and provides Zulu - its build of OpenJDK - as a + // debian repo. This unfortunately adds a dependency to Azul's systems. + + "apt-get install --no-install-recommends zulu-11 -y" + " && " // Delegate file system tuning to cloud specific code. + params.getOSFilesystemTuning() - // Install Oracle Java8. It supports Java Mission - // Control, an honest profiler. But first, - // automatically accept the Oracle license because - // installation will fail otherwise. -// + " && " -// + "echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && " -// + "add-apt-repository ppa:webupd8team/java -y && " -// + "apt-get update && " -// + "apt-get --no-install-recommends install oracle-java8-installer oracle-java8-set-default -y" + + " && " + // Run any cloud specific cleanup tasks after additional packages have been + // installed (cloud shutdown might rely on those pkgs). + + params.getCloudAPIShutdown(params.getCredentials(), groupNameUUID) + + " && " + // Tell sshd not to use PAM user session modules. pam_nologin restricts + // subsequent logins to the instance five minutes prior to system halt and + // systemd apparently has no way to configure five minutes to e.g. 15 seconds. + + "sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config" + + " && " + + "service ssh restart" // Create /mnt/tlc and change permission to be world writable // Requires package 'apache2' to be already installed. apache2 // creates /var/www/html. @@ -701,13 +721,15 @@ public class CloudDistributedTLCJob extends Job { private final URL url; private final InputStream output; private final SshClient sshClient; + private final boolean isReconnect; public CloudStatus(int severity, String pluginId, int code, - String message, Throwable exception, URL url, InputStream output, SshClient sshClient) { + String message, Throwable exception, URL url, InputStream output, SshClient sshClient, boolean isReconnect) { super(severity, pluginId, code, message, exception); this.url = url; this.output = output; this.sshClient = sshClient; + this.isReconnect = isReconnect; } @Override @@ -725,6 +747,11 @@ public class CloudDistributedTLCJob extends Job { sshClient.execChannel( String.format("sudo shutdown -h +%s && kill $(pgrep -f tla2tools.jar)", SHUTDOWN_AFTER)); } + + @Override + public boolean isReconnect() { + return isReconnect; + } } /* @@ -741,6 +768,7 @@ public class CloudDistributedTLCJob extends Job { //TODO Does this work on Mac and Windows? private static LoginCredentials getLoginForCommandExecution() throws IOException { + //TODO Lookup user in ~/.ssh/config in case there exists a user-defined mapping for this host. final String user = System.getProperty("user.name"); final String privateKey = Files.toString(new File(System.getProperty("user.home") + "/.ssh/id_rsa"), Charsets.UTF_8); diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java index da8f3b5f2c6ea27f3855bd5dad8d11bc900a7f8d..2e87b7b594c2b4aad088f37bd425b0864cead43d 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java @@ -30,6 +30,8 @@ import java.util.Properties; import org.eclipse.core.runtime.IStatus; import org.jclouds.ContextBuilder; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.options.TemplateOptions; import tlc2.tool.distributed.fp.TLCWorkerAndFPSet; @@ -81,14 +83,18 @@ public abstract class CloudTLCInstanceParameters { return getJavaWorkerVMArgs(); } // See org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob.getAdditionalVMArgs() - return ("--add-modules=java.activation -XX:+IgnoreUnrecognizedVMOptions " + extraVMArgs).trim(); + return ("-XX:+IgnoreUnrecognizedVMOptions " + + "-XX:+UseParallelGC " // Java > 1.8 has switched to a low-latency GC which isn't optimized for + // throughput anymore. Obviously, we are not interested in latency but primarily + // in throughput. + + extraVMArgs).trim(); } public abstract String getJavaWorkerVMArgs(); protected String getJavaWorkerVMArgs(final String extraWorkerVMArgs) { // See org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob.getAdditionalVMArgs() - return ("--add-modules=java.activation -XX:+IgnoreUnrecognizedVMOptions " + return ("-XX:+IgnoreUnrecognizedVMOptions -XX:+UseParallelGC " + extraWorkerVMArgs).trim(); } @@ -134,23 +140,25 @@ public abstract class CloudTLCInstanceParameters { // Nothing to be done here } + public void mungeTemplateOptions(TemplateOptions templateOptions) { + // no-op, subclass may override + } + public String getOSFilesystemTuning() { return "/bin/true"; // no-op, because concat with && ... && in CDTJ. } public String getFlightRecording() { - return "-XX:+UnlockCommercialFeatures " - + "-XX:+FlightRecorder " + return "-XX:StartFlightRecording=settings=default,disk=true,dumponexit=true,maxage=12h,filename=/mnt/tlc/tlc.jfr " + "-XX:+UnlockDiagnosticVMOptions " - + "-XX:+DebugNonSafepoints " - + "-XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/mnt/tlc,dumponexit=true,dumponexitpath=/mnt/tlc/tlc.jfr,maxage=12h"; + + "-XX:+DebugNonSafepoints"; } public String getHostnameSetup() { return "/bin/true"; // no-op, because concat with && ... && in CDTJ. } - public String getCloudAPIShutdown() { + public String getCloudAPIShutdown(final String credentials, final String groupName) { return "/bin/true"; // no-op, because concat with && ... && in CDTJ. } @@ -161,4 +169,8 @@ public abstract class CloudTLCInstanceParameters { public String getExtraPackages() { return ""; // no-op, because concat with && ... && in CDTJ. } + + public void mungeTemplateBuilder(final TemplateBuilder templateBuilder) { + // no-op, subclass may override + } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java index 70edcc21562e3cc2fd5f3c52a53103942fdc0195..b75633f8f46c3438aac09124147762083dc4f2b2 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java @@ -37,6 +37,7 @@ public class CloudTLCJobFactory implements TLCJobFactory { private static final String AZURECOMPUTE = "Azure"; private static final String AWS_EC2 = "aws-ec2"; + private static final String PACKET_NET = "PacketNet"; @Override public Job getTLCJob(String aName, File aModelFolder, int numberOfWorkers, final Properties props, String tlcparams) { @@ -47,7 +48,10 @@ public class CloudTLCJobFactory implements TLCJobFactory { new EC2CloudTLCInstanceParameters(tlcparams, numberOfWorkers)); } else if (AZURECOMPUTE.equalsIgnoreCase(aName)) { return new CloudDistributedTLCJob(aName, aModelFolder, numberOfWorkers, props, - new AzureCloudTLCInstanceParameters(tlcparams, numberOfWorkers)); + new AzureARMCloudTLCInstanceParameters(tlcparams, numberOfWorkers)); + } else if (PACKET_NET.equalsIgnoreCase(aName)) { + return new CloudDistributedTLCJob(aName, aModelFolder, numberOfWorkers, props, + new PacketNetCloudTLCInstanceParameters(tlcparams, numberOfWorkers)); } throw new IllegalArgumentException(aName + " is an unknown cloud"); } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java index 566b30456ca77a4b8a346e803e0659694ad6fab4..65d7cbe5ebd7813f49f2da8cb050c1dbbc2407da 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java @@ -30,7 +30,9 @@ import java.util.Properties; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.aws.ec2.reference.AWSEC2Constants; +import org.jclouds.compute.options.TemplateOptions; import org.jclouds.location.reference.LocationConstants; public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { @@ -92,6 +94,29 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { // (i.e. South America). properties.setProperty(LocationConstants.PROPERTY_REGIONS, getRegion()); } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#mungeTemplateOptions(org.jclouds.compute.options.TemplateOptions) + */ + @Override + public void mungeTemplateOptions(TemplateOptions templateOptions) { + //TODO Create (and the reuse) subnet automatically for instance types that require it. + final String subnetId = System.getProperty("aws-ec2.subnetid"); + if (subnetId != null) { + // Manually create a subnet first: + // 1) Log into https://console.aws.amazon.com/vpc/ and select the correct region (match getRegion()) + // 1a) Optionally choose tenancy "dedicated" for more predictable performance + // 2) Create a VPC (defaults are fine) + // 3) Create a subnet (accept defaults) associated with VPC + // 3a) "Modify auto-assign IP settings" of newly created subnet to automatically assign a public ip + // 4) Create an Internet Gateway associated with the VPC + // 4a) Associate with VPC + // 5) Create a Route Table for the VPC + // 5a) Create a route with CIDR 0.0.0.0/0 via the gateway created in 4) + // 6) Modify inbound rules of (automatically) created security group to include ssh/22,http/80,https/443 with source "0.0.0.0/0" + templateOptions.as(AWSEC2TemplateOptions.class).subnetId(subnetId); + } + } @Override public String getHostnameSetup() { @@ -113,7 +138,7 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { // for paravirtual vs. hvm (if instance startup fails with funny errors // such as symlinks failing to be created, you accidentally picked paravirtual. // "us-east-1,bionic,amd64,hvm:instance-store" - final String imageId = System.getProperty("aws-ec2.image", "ami-9fedbbe0"); + final String imageId = System.getProperty("aws-ec2.image", "ami-053295bb822a154ba"); return getRegion() + "/" + imageId; } @@ -142,7 +167,7 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { // Create a raid0 out of the two instance store // disks and optimize its fs towards performance // by sacrificing data durability. - return "umount /mnt && " + return "umount /mnt ; " + "/usr/bin/yes|/sbin/mdadm --create --force --auto=yes /dev/md0 --level=0 --raid-devices=2 --assume-clean --name=tlaplus /dev/xvdb /dev/xvdc && " + "/sbin/mdadm --detail --scan >> /etc/mdadm/mdadm.conf && " + "sed -i '\\?^/dev/xvdb?d' /etc/fstab && " @@ -156,7 +181,8 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { */ @Override public String getJavaVMArgs() { - return System.getProperty("aws-ec2.vmargs", super.getJavaVMArgs("-Xmx56G -Xms56G")); + return System.getProperty("aws-ec2.vmargs", + super.getJavaVMArgs(System.getProperty("aws-ec2.vmargs.memory", "-Xmx56G -Xms56G"))); } /* (non-Javadoc) @@ -164,7 +190,7 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { */ @Override public String getTLCParameters() { - return System.getProperty("aws-ec2.tlcparams", super.getTLCParameters(32)); + return System.getProperty("aws-ec2.tlcparams", super.getTLCParameters(Integer.getInteger("aws-ec2.tlcparams.workers", 32))); } /* (non-Javadoc) @@ -172,6 +198,7 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { */ @Override public String getJavaWorkerVMArgs() { - return System.getProperty("aws-ec2.vmworkerargs", super.getJavaWorkerVMArgs("-Xmx24G -Xms24G -XX:MaxDirectMemorySize=32g")); + return System.getProperty("aws-ec2.vmworkerargs", super.getJavaWorkerVMArgs( + System.getProperty("aws-ec2.vmworkerargs.memory", "-Xmx24G -Xms24G -XX:MaxDirectMemorySize=32g"))); } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PacketNetCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PacketNetCloudTLCInstanceParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..3ed922c98f16667ca62f33b49d46e93d3e73aaf0 --- /dev/null +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PacketNetCloudTLCInstanceParameters.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.jcloud; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.jclouds.compute.domain.TemplateBuilder; + +public class PacketNetCloudTLCInstanceParameters extends CloudTLCInstanceParameters { + + public PacketNetCloudTLCInstanceParameters(final String tlcParams, int numberOfWorkers) { + super(tlcParams.trim(), numberOfWorkers); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getJavaVMArgs() + */ + @Override + public String getJavaVMArgs() { + return System.getProperty("packetnet.vmargs", super.getJavaVMArgs("-Xmx6G -Xms6G")); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getJavaWorkerVMArgs() + */ + @Override + public String getJavaWorkerVMArgs() { + return System.getProperty("packetnet.vmworkerargs", + super.getJavaWorkerVMArgs("-Xmx4G -Xms4G -XX:MaxDirectMemorySize=2g")); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getTLCParameters() + */ + @Override + public String getTLCParameters() { + return System.getProperty("packetnet.tlcparams", super.getTLCParameters(4)); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCloudProvier() + */ + @Override + public String getCloudProvider() { + return "packet"; // as defined by jclouds. + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getRegion() + */ + @Override + public String getRegion() { + return System.getProperty("packetnet.region", "sjc1"); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getImageId() + */ + @Override + public String getImageId() { + return System.getProperty("packetnet.image", "ubuntu_18_04"); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getHardwareId() + */ + @Override + public String getHardwareId() { + return System.getProperty("packetnet.instanceType", "baremetal_0"); // t1.small.x86 whose "slug" is baremetal_0. + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getIdentity() + */ + @Override + public String getIdentity() { + final String identity = System.getenv("PACKET_NET_PROJECT_ID"); + Assert.isNotNull(identity); + return identity; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCredentials() + */ + @Override + public String getCredentials() { + final String credential = System.getenv("PACKET_NET_APIKEY"); + Assert.isNotNull(credential); + return credential; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#validateCredentials() + */ + @Override + public IStatus validateCredentials() { + final String credential = System.getenv("PACKET_NET_PROJECT_ID"); + final String identity = System.getenv("PACKET_NET_APIKEY"); + if (credential == null || identity == null) { + return new Status(Status.ERROR, "org.lamport.tla.toolbox.jcloud", + "Invalid credentials, please check the environment variables " + + "(PACKET_NET_PROJECT_ID " + + "and PACKET_NET_APIKEY) are correctly " + + "set up and picked up by the Toolbox." + + "\n\nPlease visit the Toolbox help and read section 4 " + + "of \"Cloud based distributed TLC\" on how to setup authentication."); + } + return Status.OK_STATUS; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#mungeTemplateBuilder(org.jclouds.compute.domain.TemplateBuilder) + */ + @Override + public void mungeTemplateBuilder(TemplateBuilder templateBuilder) { + templateBuilder.locationId(getRegion()); + } + + @Override + public String getCloudAPIShutdown(final String credentials, String groupName) { + // One might think we could simply invoke curl and terminate the instance right + // away. That doesn't work because we want the instance to idle until the + // scheduled shutdown call executes in case the Toolbox reuses the instance to + // run another model. +// return String.format("/usr/bin/curl -X DELETE -H X-Auth-Token:%s https://api.packet.net/devices/%s", credentials, nodeId); + return String.format( + "printf \"#!/bin/bash\\n" + + "if /usr/bin/curl https://metadata.packet.net/metadata 2>/dev/null | jq -e -r '.tags | index(\\\"power_off\\\")' > /dev/null; then\\n" + + " /usr/bin/curl -X POST -H X-Auth-Token:%s https://api.packet.net/devices/$(curl https://metadata.packet.net/metadata 2>/dev/null | jq -r '.id')/actions?type=power_off\\n" + + "else\\n" + + " /usr/bin/curl -X DELETE -H X-Auth-Token:%s https://api.packet.net/devices/$(curl https://metadata.packet.net/metadata 2>/dev/null | jq -r '.id')\\n" + + "fi\\n\" | sudo tee /usr/local/bin/packetnet.sh" + + " && sudo chmod +x /usr/local/bin/packetnet.sh" + + " && " + + "printf \"[Unit]\\nDescription=Delete instance via packetnet api on shutdown\\n" + + "Requires=network.target\\n" + + "After=network.target\\n" + + "DefaultDependencies=no\\n" + + "Before=shutdown.target\\n" + + "[Service]\\n" + + "Type=oneshot\\n" + + "RemainAfterExit=true\\n" + + "ExecStart=/bin/true\\n" + + "ExecStop=/usr/local/bin/packetnet.sh\\n" + + "[Install]\\n" + + "WantedBy=multi-user.target\\n\" | sudo tee /lib/systemd/system/delete-on-shutdown.service" + + " && systemctl enable delete-on-shutdown" // restart delete-on-shutdown service after a reboot. + + " && service delete-on-shutdown start", + credentials, credentials); + + /* + @packethost Can I somehow set (upon creation) servers to be automatically be deleted on an OS shutdown? + @lemmster Not at the moment - you can control that from your automation / etc but we're not in the habit (in our API or otherwise) of deleting things on the behalf of clients. Make sense? + @packethost Others (Azure & AWS) do support automatic deletion. Why not make it a flag on instance creation? + @lemmster Actually I lied, we do revoke in our spot market. We actually have the ability but always found that the risk (why did you delete my database) was more than the benefit. Sorry! + @packethost Me: Why did you delete my database? You: Because you told us to (by setting the delete-upon-shutdown flag during instance creation)! + @lemmster For Ubuntu pass this userdata to create the delete-on-shutdown service for Packet's API. Not quite a flag but works! gist.github.com/nathangoulding… + @NathanGoulding Thanks! Just slightly worried about the security implications of having API token on the instance. + @lemmster For sure, best to pull from an envvar or something like Vault vs. embedding (and certainly not passing via https userdata). + @NathanGoulding I don't understand how an envvar or a vault - for which I need another secret to unlock, no? - solves the fundamental problem of having the API token on the instance? + @lemmster You can limit the blast radius significantly with certs/keys that are single-use, tied to that specific instance, and/or revocable. If you can't trust the instance at all then yes you're stuck. + @NathanGoulding Can I generate a single-use API subkey which is possibly even restricted to a specific instance? + @NathanGoulding Could even be part of the response to the instance creation API call. + @NathanGoulding Generally though, an instance creation flag is both simple and secure. + @lemmster Agreed, unfortunately we don't have a hypervisor present to intercept the system shutdown call. + @lemmster 'Unfortunately' in this one case at least ;) + @NathanGoulding I assume that the same reason why servers show up as running in the admin frontend when shutdown locally? + @lemmster Exactly, and I think our API calls them "active" to avoid "on/off" verbiage, but that green circle does look a lot like "on" + + https://twitter.com/NathanGoulding/status/1089990444287696897 + + https://gist.github.com/nathangoulding/6a69b3fd7023bf3f558acfc7bb9ba645 + */ + } +} diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java index b35098915118c6b26b445808a680256751b11bd1..1670f7048e56570fccc02e000a93ea9da97eec76 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java @@ -71,11 +71,7 @@ public class PayloadHelper { * The copy of the blueprint will contain the spec & model and * additional metadata (properties, amended manifest). */ - final Bundle bundle = FrameworkUtil.getBundle(PayloadHelper.class); - final URL toolsURL = bundle.getEntry("files/tla2tools.jar"); - if (toolsURL == null) { - throw new RuntimeException("No tlatools.jar and/or spec to deploy"); - } + final URL toolsURL = getToolsURL(); /* * Copy the tla2tools.jar blueprint to a temporary location on @@ -190,4 +186,17 @@ public class PayloadHelper { return jarPayLoad; } + + private static URL getToolsURL() { + final Bundle bundle = FrameworkUtil.getBundle(PayloadHelper.class); + final URL toolsURL = bundle.getEntry("files/tla2tools.jar"); + if (toolsURL == null) { + throw new RuntimeException("No tlatools.jar and/or spec to deploy"); + } + return toolsURL; + } + + public static void checkToolsJar() { + getToolsURL(); + } } diff --git a/org.lamport.tla.toolbox.jnlp/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.jnlp/META-INF/MANIFEST.MF index 6f376932d18adb8b6d14fc2944db989d705a8802..3ec47bbde3e4ebc1d6e40ff76c7620f42570a4fd 100644 --- a/org.lamport.tla.toolbox.jnlp/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.jnlp/META-INF/MANIFEST.MF @@ -8,3 +8,4 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: org.osgi.framework;version="1.3.0" Require-Bundle: javax.servlet;bundle-version="2.5.0", org.eclipse.equinox.http.registry;bundle-version="1.0.0" +Automatic-Module-Name: org.lamport.tla.toolbox.jnlp diff --git a/org.lamport.tla.toolbox.product.product/TLAToolbox.target b/org.lamport.tla.toolbox.product.product/TLAToolbox.target index 2f0af13360adceea3f6ecab3e2990f3a7ec5ca17..973e5aff713fcaacdab5890eb1a5cb476124afb6 100644 --- a/org.lamport.tla.toolbox.product.product/TLAToolbox.target +++ b/org.lamport.tla.toolbox.product.product/TLAToolbox.target @@ -1,73 +1,73 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde version="3.8"?><target name="TLA+ Toolbox" sequenceNumber="82"> +<?xml version="1.0" encoding="UTF-8" standalone="no"?><?pde version="3.8"?><target name="TLA+ Toolbox" sequenceNumber="86"> <locations> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.contribution.weaving.feature.group" version="2.2.4.201704242114"/> -<unit id="org.eclipse.ajdt.feature.group" version="2.2.4.201704242114"/> -<repository location="http://download.eclipse.org/tools/ajdt/47/dev/update/ajdt-e47-2.2.4.201704242114/" id="eclipse-ajdt"/> +<unit id="org.eclipse.contribution.weaving.feature.group" version="2.2.4.201805281636"/> +<unit id="org.eclipse.ajdt.feature.group" version="2.2.4.201805281636"/> +<repository id="eclipse-ajdt" location="http://download.eclipse.org/tools/ajdt/48/dev/update/ajdt-e48-2.2.4.201805281636/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> <unit id="org.apache.log4j" version="1.2.15.v201012070815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> -<unit id="com.jcraft.jsch.source" version="0.1.46.v201205102330"/> -<unit id="com.jcraft.jsch" version="0.1.46.v201205102330"/> -<unit id="org.apache.commons.io.source" version="2.0.1.v201105210651"/> -<unit id="org.apache.commons.io" version="2.0.1.v201105210651"/> +<unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/> +<unit id="org.apache.commons.io" version="2.2.0.v201405211200"/> +<unit id="org.apache.commons.collections" version="3.2.2.v201511171945"/> <unit id="javax.activation" version="1.1.0.v201211130549"/> <unit id="javax.mail" version="1.4.0.v201005080615"/> <unit id="org.easymock" version="2.4.0.v20090202-0900"/> -<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20140114142710/repository/" id="eclipse-orbit"/> +<repository id="eclipse-orbit" location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180905201904/repository/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.swtbot.ide.feature.group" version="2.6.0.201706141832"/> -<unit id="org.eclipse.swtbot.eclipse.test.junit.feature.group" version="2.6.0.201706141832"/> -<unit id="org.eclipse.swtbot.feature.group" version="2.6.0.201706141832"/> -<unit id="org.eclipse.swtbot.eclipse.feature.group" version="2.6.0.201706141832"/> -<repository location="http://download.eclipse.org/technology/swtbot/releases/2.6.0/" id="eclipse-swtbot"/> +<unit id="org.eclipse.swtbot.ide.feature.group" version="2.7.0.201806111355"/> +<unit id="org.eclipse.swtbot.eclipse.test.junit.feature.group" version="2.7.0.201806111355"/> +<unit id="org.eclipse.swtbot.feature.group" version="2.7.0.201806111355"/> +<unit id="org.eclipse.swtbot.eclipse.feature.group" version="2.7.0.201806111355"/> +<repository id="eclipse-swtbot" location="http://download.eclipse.org/technology/swtbot/releases/2.7.0/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> <unit id="org.apache.jclouds.feature.feature.group" version="0.0.0"/> <repository location="http://lemmy.github.com/jclouds2p2/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.rcp.id" version="4.7.3.M20180330-0640"/> -<unit id="org.eclipse.help.feature.group" version="2.2.104.v20180330-0640"/> -<unit id="org.eclipse.equinox.core.sdk.feature.group" version="3.13.2.v20180210-1608"/> -<unit id="org.eclipse.rcp.sdk.id" version="4.7.3.M20180330-0640"/> -<unit id="org.eclipse.platform.ide" version="4.7.3.M20180330-0640"/> -<unit id="org.eclipse.rcp.configuration.feature.group" version="1.1.4.v20180330-0640"/> -<unit id="org.eclipse.emf.ecore.feature.group" version="2.13.0.v20170609-0707"/> -<unit id="org.eclipse.equinox.executable" version="3.7.2.v20171108-1834"/> -<unit id="org.eclipse.ecf.core.feature.feature.group" version="1.4.0.v20170516-2248"/> -<unit id="org.eclipse.e4.rcp.feature.group" version="1.6.3.v20180329-0507"/> -<unit id="org.eclipse.platform.sdk" version="4.7.3.M20180330-0640"/> -<unit id="org.eclipse.emf.common.feature.group" version="2.13.0.v20170609-0707"/> -<unit id="org.eclipse.equinox.sdk.feature.group" version="3.13.4.v20180322-2228"/> -<unit id="org.eclipse.core.runtime.feature.feature.group" version="1.2.2.v20180210-1608"/> -<unit id="org.eclipse.sdk.ide" version="4.7.3.M20180330-0640"/> -<repository location="http://download.eclipse.org/eclipse/updates/4.7/" id="eclipse"/> +<unit id="org.eclipse.help.feature.group" version="2.2.300.v20180906-0745"/> +<unit id="org.eclipse.equinox.core.sdk.feature.group" version="3.15.0.v20180827-1536"/> +<unit id="org.eclipse.platform.feature.group" version="4.9.0.v20180906-1121"/> +<unit id="org.eclipse.rcp.configuration.feature.group" version="1.1.200.v20180906-0745"/> +<unit id="org.eclipse.emf.ecore.feature.group" version="2.15.0.v20180722-1159"/> +<unit id="org.eclipse.equinox.executable" version="3.8.100.v20180827-1352"/> +<unit id="org.eclipse.ecf.core.feature.feature.group" version="1.5.1.v20180810-0833"/> +<unit id="org.eclipse.e4.rcp.feature.group" version="1.6.200.v20180906-1121"/> +<unit id="org.eclipse.emf.common.feature.group" version="2.15.0.v20180723-1316"/> +<unit id="org.eclipse.equinox.sdk.feature.group" version="3.15.0.v20180904-1442"/> +<unit id="org.eclipse.core.runtime.feature.feature.group" version="1.2.200.v20180903-1343"/> +<unit id="org.eclipse.jdt.feature.group" version="3.15.0.v20180906-0745"/> +<unit id="org.eclipse.pde.source.feature.group" version="3.13.200.v20180906-0745"/> +<repository id="eclipse" location="http://download.eclipse.org/eclipse/updates/4.9/R-4.9-201809060745"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> <unit id="de.vonloesch.pdf4eclipse.feature.feature.group" version="0.0.0"/> <repository location="http://lemmy.github.com/Pdf4Eclipse/"/> </location> +<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="false" type="InstallableUnit"> +<unit id="org.lamport.openjdk.feature.feature.group" version="0.0.0"/> +<repository location="http://lemmy.github.com/eclipse-jdk-bundles/"/> +</location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="com.abstratt.eclipsegraphviz.feature.feature.group" version="2.1.201501.201606262232"/> -<repository location="jar:http://repository-textuml.forge.cloudbees.com/snapshot/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.1.201501/com.abstratt.eclipsegraphviz.repository-2.1.201501.zip!/"/> +<unit id="com.abstratt.eclipsegraphviz.feature.feature.group" version="2.5.201812"/> +<repository location="jar:https://dl.bintray.com/abstratt-oss/abstratt-oss/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.5.201812/com.abstratt.eclipsegraphviz.repository-2.5.201812.zip!/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.recommenders.news.rcp.feature.feature.group" version="2.5.0.v20171201-1623"/> -<repository location="http://download.eclipse.org/releases/oxygen"/> +<unit id="org.eclipse.recommenders.news.rcp.feature.feature.group" version="2.5.4.v20180909-1132"/> +<repository location="http://download.eclipse.org/releases/2018-09/201809191000"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.apache.commons.collections" version="3.2.2.v201511171945"/> -<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository"/> +<unit id="org.eclipse.mylyn.commons.feature.group" version="3.24.2.v20180904-2231"/> +<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="1.16.0.v20180904-2231"/> +<repository location="http://download.eclipse.org/mylyn/releases/3.24"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.mylyn.commons.feature.group" version="3.21.0.v20160707-1856"/> -<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="1.13.0.v20160721-2347"/> -<repository location="http://download.eclipse.org/mylyn/releases/3.21"/> +<unit id="org.eclipse.e4.tools.spies.feature.feature.group" version="0.0.0"/> +<repository location="http://download.eclipse.org/e4/snapshots/org.eclipse.e4.tools/latest/"/> </location> </locations> -<targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> -</target> +<targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/> +</target> \ No newline at end of file diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_32bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_32bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..069041c179d9420c94a2fa16c160af26d533f020 Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_32bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_8bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_8bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c849fec901d3a1899202f6b0de468fa5a648c3d3 Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-16_8bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256.xpm b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256.xpm new file mode 100644 index 0000000000000000000000000000000000000000..2ec61ca7209fca135a8e085331468203396c878c --- /dev/null +++ b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256.xpm @@ -0,0 +1,486 @@ +/* XPM */ +static char *_549347558310[] = { +/* columns rows colors chars-per-pixel */ +"256 256 224 2 ", +" c #000000", +". c #0F0F0F", +"X c #151616", +"o c #173A00", +"O c #296500", +"+ c #2F7500", +"@ c #215200", +"# c #586654", +"$ c #A27D18", +"% c #897F5F", +"& c #877E60", +"* c #887F60", +"= c #378B00", +"- c #338000", +"; c #3A9100", +": c #44AA00", +"> c #43A501", +", c #53A81D", +"< c #5FB727", +"1 c #6FBE3F", +"2 c #64A63B", +"3 c #579530", +"4 c #66974A", +"5 c #A5801D", +"6 c #A88629", +"7 c #B69538", +"8 c #AD8D34", +"9 c #8D815E", +"0 c #9E8A57", +"q c #94845B", +"w c #998759", +"e c #9C8959", +"r c #B5964E", +"t c #B8974D", +"y c #BB994C", +"u c #B79948", +"i c #A48D55", +"p c #A98F53", +"a c #A28D5A", +"s c #AD9152", +"d c #A6905C", +"f c #AA935D", +"g c #B19350", +"h c #B0975E", +"j c #AE9346", +"k c #AB9662", +"l c #AD9865", +"z c #B29B64", +"x c #B39E6A", +"c c #B9A26C", +"v c #BBA675", +"b c #A49565", +"n c #C4A54D", +"m c #C0A047", +"M c #C7A852", +"N c #C9AB55", +"B c #CCAE59", +"V c #C3A654", +"C c #CEB15C", +"Z c #D0B35F", +"A c #D3B562", +"S c #D5B966", +"D c #D7BA68", +"F c #D9BC6B", +"G c #D8B766", +"H c #C2AC7A", +"J c #D0B776", +"K c #84C85C", +"L c #8BCB67", +"P c #91CE6F", +"I c #9AD27A", +"U c #E1C67D", +"Y c #DEC376", +"T c #4476AA", +"R c #467AAD", +"E c #4A7CAE", +"W c #4F79A1", +"Q c #497EB1", +"! c #507FAF", +"~ c #7C7F81", +"^ c #67808F", +"/ c #6D8B98", +"( c #4B82B5", +") c #4D86B8", +"_ c #4E88BA", +"` c #5382B2", +"' c #5D89B6", +"] c #528BBC", +"[ c #5989B7", +"{ c #5D91BE", +"} c #638EB9", +"| c #618BB7", +" . c #6B93BC", +".. c #6591BC", +"X. c #7197BF", +"o. c #7497A3", +"O. c #518FC1", +"+. c #5593C4", +"@. c #599ACA", +"#. c #5C96C4", +"$. c #6998C3", +"%. c #749BC2", +"&. c #7A9EC3", +"*. c #57A7D9", +"=. c #7BA3C8", +"-. c #77A8CF", +";. c #57B2E4", +":. c #58B6E8", +">. c #5EB9E9", +",. c #5AB3E4", +"<. c #63BBEA", +"1. c #6BBEEB", +"2. c #65B9E6", +"3. c #71BEE8", +"4. c #73C2EC", +"5. c #7BC5ED", +"6. c #6FC0EB", +"7. c #989D9F", +"8. c #93989A", +"9. c #A49E87", +"0. c #ABA284", +"q. c #B0AD9B", +"w. c #B6AA86", +"e. c #B7BDBF", +"r. c #B9BDB4", +"t. c #B8B8AB", +"y. c #9BA0A2", +"u. c #C9B689", +"i. c #CBBB94", +"p. c #D1BE94", +"a. c #CBB683", +"s. c #DAC384", +"d. c #D4C39B", +"f. c #D4C297", +"g. c #CCC09E", +"h. c #FDDE9E", +"j. c #F5DA9B", +"k. c #EBCD88", +"l. c #D9CAA7", +"z. c #DED1B4", +"x. c #DBCDAD", +"c. c #FADEA3", +"v. c #E3D6B9", +"b. c #F1DEB4", +"n. c #FDE0A4", +"m. c #FCE2AB", +"M. c #F5E0AE", +"N. c #FCE5B4", +"B. c #F7E4BB", +"V. c #FAE6BB", +"C. c #FAE7BD", +"Z. c #C6E7BD", +"A. c #8BABCB", +"S. c #84A6C9", +"D. c #99B7D3", +"F. c #90B0CF", +"G. c #A3BDD6", +"H. c #B9BFC1", +"J. c #ABC3DB", +"K. c #A6C2DC", +"L. c #B4C8DD", +"P. c #87CAEE", +"I. c #99D2F1", +"U. c #92CFF0", +"Y. c #B8CDE1", +"T. c #BDD1E3", +"R. c #A8D9F3", +"E. c #B3DEF4", +"W. c #ACC9E1", +"Q. c #BBE1F6", +"!. c #9CC0DC", +"~. c #CCD9DC", +"^. c #C7D6DE", +"/. c #D5D8D7", +"(. c #D5D6CC", +"). c #E6DDC4", +"_. c #E1DED0", +"`. c #EBE3CC", +"'. c #FAEAC5", +"]. c #FAEBCC", +"[. c #F1E4C5", +"{. c #EBE6D5", +"}. c #FAEED3", +"|. c #F8EFD9", +" X c #F9F0DC", +".X c #C3D4E5", +"XX c #CDDBE9", +"oX c #C8D8E7", +"OX c #D2DEEA", +"+X c #D5E1ED", +"@X c #DAE4EE", +"#X c #DEE1E0", +"$X c #C6E2F5", +"%X c #CCE3F6", +"&X c #CDE9F8", +"*X c #D1E6F6", +"=X c #DDE6F0", +"-X c #D3E8F7", +";X c #D6E9F8", +":X c #DCECF9", +">X c #DDE8F3", +",X c #DDF0FA", +"<X c #CFE0EE", +"1X c #E5E8E7", +"2X c #F9F2E4", +"3X c #F8F5EB", +"4X c #F5F1E7", +"5X c #E4EBF3", +"6X c #E0EFFA", +"7X c #E8EFF5", +"8X c #ECF3F7", +"9X c #E4F2FB", +"0X c #EBF5FC", +"qX c #EEF7FC", +"wX c #F8F6F1", +"eX c #F7F8F7", +"rX c #F1F6FB", +"tX c #F4FCFF", +"yX c #FBFEFF", +"uX c #F7F7F4", +"iX c #EFEEE7", +"pX c #DBE2D5", +"aX c #B4DEA2", +"sX c None", +/* pixels */ +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXyX3X8 $ $ $ $ $ $ $ $ $ $ $ $ 8 u.u.u.u.u.u.u.u.u.u.u.p.u.u.u.H $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX2X8 5 $ $ $ $ $ $ $ $ $ $ $ $ u yXyXyXyXyXyXyXeXyXyXyXeXeXyXyX`.$ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX X8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ u eXrXeXeXyXeXeXyXyXeXeXeXyXtXeX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ t rXeXyXrXeXeXeXeXeXtXeXtXeXeXyX{.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ u eXeXeXeXeXeXeXeXrXeXeXeXeXtXeX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ u eXeXeXeXeXeXeXeXeXeXeXeXeXuXeX_.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ u eXeXeXeXeXeXeXeXeXeXeXeXeXeXeX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ r eXeXeXwXeXwXeXeXeXeXeXuXuXuXuX_.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ u wXuXuXuXuXuXuXuXuXuXuXuXuXuXuX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ r wXuXwXwXwXwXwXwXuXwXwXwXwXwXwX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ V wXwXwXwXwXwXwXwXwXwXwXwXwXwXwX).$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 7 J 3X3XwXwXwXwXwX3XwXwXwXwXwX3XwX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 m J 3X3XwX3XwX3X3XwX3XwXwX3XwXwX3X{.7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 7 n n J wX3X3X3X3XwX3X3XwX3X3X3X3X3X3X`.n 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 m n n J 4X3X3X3X3X3X3X3X3X3X3X3X3X3X3X{.n n 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX(.(./._.OXOX/.#X1X1X#X1X1X{.1X#X1X1X#X1X1X#X1X{.1X/.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 5 6 n n n n J 4X3X3X3X3X3X3X3X3X3X3X3X3X3X3X`.n n n 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T E T R T T R T T ! T ! E E E ! ! ! ! ! ! ' | ! | | } } . .X.X. .S.S.%.S.S.A.F.D.D.G.G.H.Y.Y.Y..XoXoXOXOX@X@X@X=X=X=X=X=X5X5X5X5X5X7X7X5X5X1Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 8 n n n n n J 4X3X3X3X3X3X3X3X2X3X2X3X3X3X3X`.M M n n 7 5 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 (.+X/.`.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R R R Q T T ! T T ! E ! ! ! ! ! | ! ' | | } } . .X.X.X. .S.S.8.S.A.A.D.G.H.G.G.L.L..X.XoXoXOXOX@X@X=X=X5X5X5X5X5X7X7X7X7X7X7X7X8X1Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 n n n M M n S 4X3X4X2X3X2X3X2X3X3X3X3X3X3X2X[.n n M n M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 (.OX`.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T E T T T T ! T ! ! E ! ! ! ! ! | ! | | | } .} .X.X.X.S.S.S.S.S.S.A.D.D.G.G.L.L.L..X.X.XoXOXOXOX@X@X=X=X5X5X7X7X7X7X7X7X7X7XwX7XiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 n n n M n M n D 2X3X2X2X3X2X3X3X3X2X2X2X3X2X3X`.M M M M n n 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 (.`.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX~ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T E T R T T T E T E T ! T E ! ! ! ! ! ! | ' | | } } . .X.X.X.X.S.S.S.S.A.A.F.D.D.G.G.G..XL..X.XoXoXOXOX@X@X@X5X5X5X7X7X7X7X7X8X8X7X7X7XiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 8 n n N M M M M M J 3X2X4X2X3X2X2X2X2X2X3X3X2X2X2X`.M n M n M M n 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 l.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ E T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T E T T T T T T E E T ! E T ! ! ! ! ! | | ! } ' | | } . . .%.X.X.X.S.S.S.A.A.A.D.G.G.H.J.L.Y..X.X.XoXOXOX+X@X@X5X5X7X5X7X7XuX7X8X8X8X8X7XiXj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 8 n M n N n M M M M J 2X2X2X2X2X2X2X2X3X2X2X2X2X2X2X[.N M M M n M M M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R T R T E T T T E ! E ! ! | ! ! ! ! | | | | } . . .%.X.S.S.S.y.S.A.F.D.D.G.G.L.Y.Y.Y..X.X.XXXOXOX@X=X=X=X5X7X7X7XrX7XrXuXrXrXuXiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 8 M n n M N M M M N N J 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X`.M M M M M M M M M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXW T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T W T T T T R T E E T ! E E E ! ! ! ! ! ! ! | | | } } . . .%.&.S.S.S.S.S.A.F.F.D.D.G.G.G..XY..X.XoXoXOXOX@X@X=X5X5X7X7X7XrX7XuXrXrXrXuXiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 M M M n N M M N M N N F 2X2X2X2X2X2X2X X2X2X2X2X2X2X2X[.N N M M M M M M M M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX~ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R T T T T T T T ! E W ! ! ! ! ! | | ! | | | . .X.X.%.&.S.S.S.S.A.A.F.D.F.H.G.G..XG.Y..XoXoXXXOX+X@X=X=X5X5X7X7X7X7XuX7X7X7X7X1Xg $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 7 n M M M N M N N N N N N J 2X X2X2X2X X2X X2X2X X2X X2X X[.N M N N N M M N M M M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ E T E T T T R T T T T T R R T T R T T T T T T T R T T T T T T T T R T R R R T T T R T T T T T T R T T T T T R T T R T R T T T T T T T T T T T T R T R R R R T E E E ! ! ! ! ! ! ! ! } ! .! } . . .%.%.&.&.S.S.A.F.F.F.D.D.G.G.G.L.Y.Y..X.XoXXXOXOX+X=X=X=X5X5X7X7X7XrXrXrXOX+XOXj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 6 M M M N M N N N N N N N N Y 2X2X2X2X2X2X X2X X2X X2X2X X2X[.N N N N N N N M M M M N 7 5 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXW E E T E R R R R R R R R R R T T R R R R R R R R R R R R T T R R R R R R R R T T R R R R R R R R R R R R R R R R R R R R R T T T T T Q T T Q R R R R R E E R E E Q ! Q ! ) ! ! ! } ! ! $.} %.} . .%.%.%.&.S.S.A.A.F.F.D.D.G.G.G.L.L.Y.Y..X.XXXOXOX@X+X=X5X5X5X7X7X7XrX8XwXrX@X/.j $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 8 M M M N N N M N N N B N N B J X X X X X X X X2X X2X X X2X X[.N N N N N N N N N M M N M 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ R Q E R R Q R R R ( R R R R T R R R R R ( R R R Q R Q Q T Q R Q Q R R R R R T R R R R R R Q R R R R R R R R R R R R R Q R Q R E E Q T Q Q Q Q Q Q Q ! Q Q Q Q Q ! ) Q ! ) ! O.! O.! ! } $.} $.%.$.%.&.&.=.S.S.A.F.F.D.G.G.G.G.L.L.Y..X.XoXXXXXOX@X@X=X5X5X5X7X7X7XuX8XrXrXuX#Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 7 M M M N N N N N N N N B N B B Y X X X X X X X X X X X X X X X[.B B N B N N N N N N M N M M 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ Q Q R Q Q Q ( ( R ( R ( Q R R ( ( R ( ( R ( Q Q Q R Q Q Q Q Q Q R Q Q Q R Q R R ( Q Q Q Q Q Q Q ( Q ( Q ( Q Q Q Q Q Q Q Q Q E Q Q Q Q Q Q Q Q Q Q Q Q Q Q ! ! ! ! ) ! ) ` ! | [ | #.$.} } $.$.$.&.&.&.S.S.A.A.F.F.D.D.G.J.G.J.L.L.Y..X.XoXXX<X+X@X@X=X5X5X7X7X7XrX7XrX8XrXiXg $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 8 M N M N N N N N N B N B N B B B J |. X X X X X X X X X X X X X X[.N B B B N B N N N N N N M M M j $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ) Q R ( R ( ( ( R ( Q ( ( ( ( Q Q ( ( Q ( Q ( ( Q ( ( ( ( ( ( Q ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Q ( ( ( ( ( ( Q ( Q Q ( Q Q Q Q ) Q Q Q Q O.Q ( Q Q Q ) ! ) ) ) ! ] ` [ ] [ ! $.O.#.$.| $.$.$.-.&.&.-.-.-.F.F.F.D.G.D.K.K.J.L.L.Y.T.oXoXXXOX+X@X@X=X5X5X7X7X7X7X7XuXrXuXiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 M M M N N N N B N B B B B B B B B Y X X X X X X X X X X X X X X X[.C B B B B B N N N N N N N M M M u 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ) ( _ ( _ ( ( ( ( _ ( ( ( ( ( ( ) ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ) ( ) ( ( O.Q O.Q ) Q ) Q Q Q ( ) ) ) ) ) ) ) ) ) ` ) ) [ [ O.#.! $.#.$.$.$.$.$.%.-.=.S.A.F.F.F.D.D.G.G.K.W.W.L.Y.T.T..X$XXX+X+X@X=X=X5X6X9X7X7XrX7XrXrX7Xt $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 8 M M M N N N N N N B B N B B B B C C J X|. X}. X X}. X}. X X X X X XB.B B B B B B B B N C N N M N N M N 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ _ ( _ _ ( _ _ ( _ _ ( ) ) ) _ ) ) ) _ ( _ _ ) ) ) ) ) ) _ ( _ _ _ ( ( ( O.( ( ) ) ) ) ) ) ) ) ) _ ( ( ) ) ) ) ) ) ) Q ( O.( ) ) ) ) Q O.O.Q ) ) ) ) ) ) ) ` ) ] O.[ [ O.[ #.#.| #.$.$.$.$.%.%.-.-.-.A.A.-.F.D.D.D.G.K.K.W.W.L.Y..X.XoXXX<X%X+X@X=X5X5X5X7X7X7X7XuXrXiXr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 V V M N N N N B N B B B B B C C C C Z Y |.|.|. X X X|.}.|. X}. X}.}.}.[.C C C B B B B B C N N N N M M N M V 7 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX( _ _ _ _ _ _ _ _ _ _ _ _ _ _ ) O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.] +.O.O.O.+.+.O.+.+.+.+.+.#.#.#.#.$.@.$.$.$.-.=.-.-.A.A.3.F.F.!.!.!.!.W.K.W.Y.R.T.T.$X.X%X<X<X@X>X:X6X5X5X5X7X7XrXrXrX7Xg $ $ $ $ $ $ $ $ $ $ $ $ V V c V V c V V V V H Y Y s.s.U U U s.s.s.s.s.s.s.s.s.s.s.s.s.k.|.}.|.}.|.}.}. X}.}. X}. X}. X'.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.U s.Y J V c V V V V c V V V c 7 $ $ $ $ $ $ $ $ $ $ $ sXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ O.] _ _ ] _ ] _ _ ] _ ] _ ] O.*.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.<.<.1.1.1.1.1.4.5.5.5.5.5.P.P.U.U.U.I.I.R.R.R.E.E.E.Q.Q.Q.$X&X&X&X,X&X,X,X,X0X0X0X0X0X8XrX7Xr $ $ $ $ $ $ $ $ $ $ $ $ $ |.|.}.}.|.|.}.|.}.}.|.|.}.}.|.}.|.|.}.}.|.|.}.|.}.}.|.|.}.}.|. X|.|.|.|.}. X}.|.}.}.}.|.}. X}.}.|.}.|.}.|.}.|.}.}.|.}.}. X}. X}.}.}. X}. X}.}.|.}.}.}.|.}. X}.s.5 5 5 $ $ $ $ $ $ $ $ $ sXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ] O.+._ O.] O.O.] ] O.O.] O.O.*.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.<.>.<.<.<.1.1.1.1.5.4.5.5.P.P.P.U.U.I.I.I.R.R.R.R.Q.E.Q.Q.Q.&X&X&X,X&X,X,X9X,X9X,X0X0XqXrX8Xu $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.}.}.|.}.}.}.}.|.}.}.}.|.}.}.|.}.}.}.}.}.}.}.}.|.}.}.}.|.}.}.|.|.|.}.}.}.}.}.}.|.}.}.}.|.}.|.}.}.|.}.}.}.|.}.}.|.}.|.}.}.}.}. X}.}.}.}.}.}.|.}.|.|.}.}.|.}.}.s.5 $ 5 $ $ $ $ $ $ $ $ $ $ sXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.+.] O.] +.] O.] O.] O.] O.O.O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.2.<.<.1.1.1.3.5.1.5.5.5.5.P.U.U.U.I.I.I.R.R.R.E.E.Q.Q.Q.&X&X&X&X,X,X,X,X9X,X0X0X0X0XqX8Xr $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.|.}.}.}.}.}.}.}.}.}.}.}.}.}.}. X}.}.}.}.}.}. X}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.J $ $ $ $ $ $ $ $ $ $ $ $ $ $ sX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ +.+.] +.+.+.+.+.+.+.+.+.O.+.O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.<.<.<.<.1.1.1.1.1.1.5.5.P.P.P.P.U.U.I.I.R.R.R.R.E.Q.Q.Q.Q.&X&X&X&X,X,X,X,X9X,X0X0X0X8X7Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.].}.].}.}.].}.}.}.].}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.].}.}.}.}.}.}.}.s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.+.+.+.+.+.+.+.+.+.+.+.+.+.+.O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.<.<.<.1.1.1.1.3.5.5.5.5.5.P.P.U.U.U.I.I.R.R.R.E.R.Q.Q.$XQ.&X&X&X&X,X,X,X,X9X0X9X0X0X7Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.}.].}.}.].}.}.}.}.}.}.}.}.].}.}.}.].}.].}.}.}.}.}.}.}.}.].].}.}.}.}.}.].}.}.}.}.}.}.].}.}.].}.}.}.}.}.}.}.}.].}.].}.}.}.}.}.}.}.}.].}.}.}.].}.}.}.}.}.].}.}.s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.+.@.+.@.@.+.@.+.+.@.+.@.+.+.+.*.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.<.<.<.1.1.1.3.1.1.5.5.P.5.P.P.U.U.I.I.I.R.R.E.Q.Q.Q.Q.Q.&X&X&X,X&X&X,X,X9X9X0X0X5Xu 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.].}.}.].}.].}.].}.].].}.].}.].}.].}.}.].}.].}.].}.].].}.}.}.}.].].}.].}.].}.].].}.}.}.].}.}.}.].}.].].}.].].}.].}.}.}.].].}.].].}.}.].}.].}.].}.].}.}.}.].}.s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.>.>.>.<.<.<.<.<.1.1.1.1.5.5.5.5.5.P.P.U.U.U.I.R.R.R.R.R.E.Q.Q.Q.Q.&X&X&X,X,X,X,X,X0X9X0X5Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ }.}.].].}.].}.].}.].}.}.].}.}.}.}.}.].}.}.].}.}.].].].].}.}.].].}.].}.}.}.].}.}.].}.].}.].].].}.}.].}.].}.].}.].}.}.].].}.].}.}.].].}.}.}.}.].}.].}.].].].}.].f.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.<.<.1.1.1.1.1.5.1.5.5.5.P.P.U.U.I.I.I.I.R.E.R.E.E.Q.Q.&XQ.&X&X&X&X,X,X,X,X0X,Xj $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ].].].}.].].].].].].].].].].].].].].].].].].].].].}.].].].].].].].].].].].].].].].].].].}.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].}.].].].].J 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.:.>.>.>.>.>.<.<.<.1.1.1.1.5.1.3.P.5.5.U.P.U.I.I.I.R.R.R.E.E.Q.Q.Q.Q.&X&X&X&X,X,X,X9X9X,Xj 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].a.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.>.<.<.1.1.1.1.5.1.5.5.3.P.P.P.U.U.U.I.I.I.R.R.E.E.E.Q.Q.Q.Q.&X&X&X,X,X,X,X9XV 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ].'.].].].].].].].].].].].].].].].'.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].C.].].].].].].].].].'.].].].].].].].].].].].].].].].].].].s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.@.@.@.+.@.+.+.@.+.@.+.@.@.+.+.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.:.>.>.>.>.<.<.<.<.1.1.4.1.1.5.3.P.5.P.P.P.U.U.I.I.I.R.R.E.E.E.Q.Q.&X&X&X&X&X,X&X,X,X9XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ].].].].].].].].].].].'.'.].].].].].].].].].].].].].].'.].].].].'.'.].].'.].].].].'.].].].].].].].].].].].].].'.].].].].].].].].].].].].'.].].].].].].].'.].].s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.+.+.+.+.+.#.+.+.+.+.+.+.+.+.O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.2.>.<.<.<.1.1.1.1.1.5.P.3.5.5.P.U.U.I.I.I.R.R.R.R.E.E.Q.$XQ.Q.&X&X&X&X,X,X,X,X9XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ].'.].'.'.].'.'.].'.].].].].'.'.].'.].'.'.].'.].].'.].].'.].'.].].].].'.].'.].'.].].'.'.'.].'.].].].C.].].C.].'.].].'.].'.].].'.].'.].].].'.'.'.'.].].].].'.].J $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXo.+.+.+.O.+.O.+.+.O.+.+.+.+.O.O.*.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.>.>.>.>.>.<.<.1.1.<.1.1.3.3.P.P.5.P.P.P.U.U.I.I.I.R.R.R.E.E.$XE.Q.&XQ.&X&X&X,X,X,X,X9X9XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ '.'.'.'.'.'.].'.'.].'.'.].'.'.'.'.'.].'.'.'.].'.'.'.'.'.'.'.'.'.'.'.].'.'.'.'.'.'.'.'.'.].'.'.C.].].].].].C.].'.].'.'.'.].'.'.'.'.'.'.'.'.'.].'.].'.'.'.].'.'.s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ O.O.O.+.O.O.O.] O.+.+.] O.O.O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.:.>.>.>.>.<.>.<.<.1.1.1.1.3.3.3.3.5.P.P.P.U.U.U.I.I.I.R.R.R.E.E.E.Q.Q.&X&X&X,X&X,X,X,X9X9X0XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ '.'.'.'.].'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.].'.'.'.'.'.].'.'.'.'.'.'.'.'.'.'.'.].'.].'.'.'.'.].'.].].C.].C.C.].].'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.s.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ] O.+._ ] O.] ] O.] O.] ] ] O.*.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.>.>.>.>.2.>.<.<.<.<.1.1.1.3.3.3.P.5.P.P.P.P.U.U.I.R.R.R.R.R.E.E.E.Q.Q.&X&X&X&X,X,X,X,X,X9X0X0XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ '.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.].C.].].].C.].C.].'.'.'.'.'.'.C.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.J $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ] ] _ ] _ ] _ ] ] _ ] ] ] ] ) *.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.:.:.:.:.:.:.:.:.:.,.,.,.,.>.>.2.<.<.1.1.1.1.3.3.3.5.5.5.P.P.U.U.I.I.I.R.R.E.R.E.E.Q.Q.Q.&X&X&X,X&X,X,X9X9X9X9X0XpX6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b.b.B.M.b.b.B.B.B.B.B.B.B.B.B.B.C.B.B.B.B.B.V.B.B.C.B.B.'.C.C.C.'.'.'.'.'.'.'.'.'.C.'.'.'.'.'.C.B.B.B.C.C.B.B.B.B.B.B.B.C.C.B.C.C.V.B.C.B.B.B.B.B.B.b.B.b.b.b.J $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ O.] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ) O.) ) ) O.Q O.O.Q O.Q O.Q O.Q ) ) ) O._ _ _ _ _ _ _ _ _ _ _ _ _ ) _ ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] ] ] [ [ O.{ +.{ { { #.$.$.$.$.-.-.-.-.S.-.F.F.F.F.!.G.!.K.K.J.L.Y.T.T.T.oX$X<X<X@X>X>X>X5X9X8X5X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m B B B B B C Z Z Z Z Z A A A S A S S S D D D D U '.'.'.C.'.'.C.'.'.C.'.'.C.C.'.N.F F F S S S S A S A A A A Z Z C Z C B B B B B B B m $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ _ _ ) ) ) ) ) ) ) ) ) ) _ ) _ _ _ ( _ _ _ _ ( _ ( _ ) ) ( ) Q Q O.) Q O.Q O.Q O.Q O.) O.Q ) _ ( _ ) _ ( _ ( ) ) ) _ _ ) _ ( ) ) ) ) ) ) ) ) ) ) ) ) _ _ _ _ ) ] ] ] [ ] [ [ { { ..#.$.$.$.$.$.%.=.-.A.-.A.F.F.D.D.!.!.K.J.L.W.Y.T.T.oXXXXX+X+X*X>X>X>X5X5X8X7X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 u N B B C C C Z Z Z A Z A A A S S S S D D D F U C.C.'.'.C.C.'.C.'.'.C.C.'.'.'.N.F F F F S S S S A A A A Z A Z Z C C C B B B B N m 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ) ) ( ) ) Q O.Q Q O.O.Q Q O.) ) Q ) ) ) ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ) ) ) ( ) ) ) ) Q ) ) ) ( ) ) ) ) ) ` ] ] [ ] [ { { { { { $.$.$.$.%.=.=.-.S.S.F.F.F.D.D.G.!.G.J.W.W.T.T..XoXXX<X+X@X@X>X>X5X5X5X7X7X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m B B C C C Z Z Z A A A A S S S S D D D F F U C.C.C.C.'.C.'.'.C.C.C.C.C.'.C.M.F F F F D S S S S S A A A Z Z Z C C C C B B B m $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ ( ( ( ( ( ( ( ( ( ( ( ( ( ( Q ( ( Q Q ( ( ( ( ( ( ( Q ( ( Q Q ) Q Q Q Q Q Q Q Q Q ) Q Q Q Q ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Q ( Q Q ( Q Q ( ( Q ( ( ( ( ( ( ` ) ) ) ) [ ] ] ] [ [ | ......$.$.%.%.-.-.-.S.S.F.F.F.D.D.G.G.G.W.W.Y.T.T..XoXXXOX+X+X@X=X5X5X7X7X7XrX_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m C B C C Z Z Z A A A S A S S S D D D F F U '.'.C.C.C.C.C.C.C.C.C.C.'.C.C.M.F F F S S F D S S A A A A Z Z Z Z C C C B B m 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX/ Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q ( ( Q Q R ( ( ( ( ( R ( ( R ( ( Q Q Q Q Q Q Q Q ( ( E ( ( ( ( Q ! ` ( ( ` ) ` [ [ [ [ [ { } ....$.$.%.%.&.&.S.S.A.F.F.F.D.G.G.G.K.J.L.L.Y.^.oXoXXX+X+X@X=X=X5X5X7X7X7X7X_.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m Z C C Z Z Z Z A A A S S S D D D F F F U C.C.C.C.C.'.C.C.C.C.C.C.C.C.C.M.F F F F F S S S S S A A A A Z Z Z C C C B m 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ Q E Q R R Q R Q Q R R Q R Q Q R R Q Q R Q T R Q R Q Q Q R Q Q Q Q R R Q Q R Q Q Q Q E E E E R R Q R ( R R R R R R R R ( R R Q R Q R R R R R R E E E Q Q E E Q E Q ` Q ! ` ` ` ` [ [ [ | { } $.$.$.%.%.&.=.S.-.A.A.F.F.D.D.G.K.K.J.L.L.T.T..XoXXXOX+X@X=X>X5X5X7X7X7XrX_.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m C Z Z Z A A A A S A S S D D D F F F U C.C.V.C.C.C.C.C.C.C.C.C.C.V.V.M.F F F F D F S S S A S A A A A Z Z C C Z m 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ E R R R R R R R R R R R R R R R R R R R T E R R R Q T R R Q R R R R Q R R R R Q T T R R R R R R R R R R R R R R R R R R T T R R R R R R R R R R R R R R E E E E E E ! Q ! ! ` ` ` [ [ | | | ! .$. .%.%.%.=.S.S.S.F.F.F.D.D.D.K.J.J.L.T.^.^.oXXXOX+X@X@X=X5X5X5X7X7X7XrX`.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m Z Z Z A Z A A S S S S S D D F F Y U C.V.V.V.V.C.V.V.C.V.V.V.V.V.V.M.F F F F F D S S S S A A A Z Z Z Z Z C n 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ R T T T T R R T T R T T T R R T T R T T T T T T T T T T T T R T T T T T T T T T T T T T T T T R T T R T T T R T T T T T T T T T R T R R T R R R R R R R R E E E E E E Q E ! Q ` ` ` [ ` [ | $.%.! .$.%.%.%.=.=.S.S.A.A.F.F.D.K.G.J.L.L.Y.^.oXoXXXXX+X@X@X@X5X7X7X7X7X7X8X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 m Z A Z A A A A S S S D D D F F F U C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.M.F F F F F F S S S S A A A A Z Z Z Z n 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R R E T ! T ! ! ! E ! ! ! ! ! ! ! S.! .! S. .X.S.! S.X.S.S.S.S.A.F.F.D.G.G.G..XG..X.X.XoXOXOXOX@X1X@X5X5X5X7XrX8X8X_.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m A A A A A A S S S S D F F F F U V.V.V.V.N.V.V.V.V.V.V.V.V.V.V.M.F F F F D D D S S S S A A A A Z Z M 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXW T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T E ! ! ! ! X.! ! ! ! ! ! %.! ! S.X.S.X.S.S.S.S.S.S.S.A.D.G.G.G.G..XL..X.XoXXXOXOXOX@X5X5X5X5X7X7X7X8X8X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m A A A A A S S S D D F F F F U V.N.N.V.V.N.V.N.N.N.N.N.V.N.V.M.F Y F F F F S S S S S S A A A Z M $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R T T T T ! ! ! T ! ! ! ! ! ! ! ! .! X. .S.! ! S.X.X.S.X.S.S.S.y.A.D.D.G.G.G..X.XL..X.XoXOXOXOX=X@X1X5X5X7X5X8X8X8X8X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n A A A S S S S D F F F F Y U V.N.V.N.N.N.N.N.V.V.N.N.N.N.N.n.F F F D F D D S S S S A A A C M 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX~ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R T T ! T T ! T T T ! ! ! ! ! ! ! ! ! ! .! .! S.! X.X.X.X.S.S.S.S.S.A.A.G.G.G.G.G.G.L..X.X.XoXOXOXOX@X@X5X5X5X5X7X7X8X8X8X/.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n A A A S S D S D D F F F U N.N.N.V.N.N.N.N.N.N.N.V.N.N.N.M.Y F F F F D D S S S A A Z A n $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T R T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T R T T T T T T T ! T ! T ! ! ! ! ! ! ! ! ! S.! ! S.! ! ! S.! .X.X.X.&.&.&.S.y.A.F.D.D.G.H.Y.L.L..X.XoXXXOXOX@X5X@X@X5X5X5X5X7X5X7X7X(.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n A A S S S D D D F F F U N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.c.F F F F F D D S S S A A A 7 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T W R T R T T T T T E T ! ! E ! E ! ! ! ! ! ! ! ! ! S.! S. . .X.X.%.&.&.S.S.S.A.D.D.G.G.G.L.L.L..X.XoXOXOXOX5XOX5X@X5X5X5X5X5X7X5XiX_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n S S S S S D F F F F U N.N.m.N.N.N.N.N.N.N.N.N.N.N.N.M.F F F F D D D S S S A A M 5 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ T T T T T T T T T T T T T T T T T E T T T T T R T T T T T T T T T T T T T T E R T E T T R T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T ! T ! ! T E ! ! ! ! ! ! ! ! ! ! X.! ! ! ! ! ! S. . . .X.%.X.%.&.S.S.A.A.D.G.G.G.G..XY..X.XoXoXOXOXOX@X@X@X@X5X5X5X=X5X5X5X5X(.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n A S S D D D D F F U N.N.N.N.N.m.N.N.N.N.m.N.m.N.N.c.F F F F F D D S S S S M 5 5 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX^ W W W W W W W W W W W W W T W ! ! ` ! ! ` ! ! ! ! Q ` ` ` ` ` ! ` ` ! ! ! Q ! ! ! ! ! ! ! ! ` ` ! ` ` ( ( Q ` W ` ` ` ` ` ` ` ` ` W ` ` ` ` ` ` ` ` ` ` ` ` ! ! ! ! ! ! ! ! ! ! ! ! ! ! X.! ! S.S.! S.S.! X.X.X.%.X.&.S.S.S.S.A.A.D.G.G.G.G.L.L.Y..X.XoXoXOXOXOXOX@X@X@XOX5XOX5X5X1X5X5X5X_.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n S S S D D D D F U m.m.N.m.N.N.m.N.m.m.N.m.N.N.m.c.D F F D D D S S S S M 5 5 5 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXn y y y n m y m y m y y y y y n /.@X%X$X$X$X$X$X$X$X%X$X$X$X$X$X$X$X$X$X$X$X%X$X$X$X$X$X$X$X$XXX$X$X$X$X%X$X$X$X$X$X$X%X$X$X$X$X$X$X$X$X$X$X$X$X%X$X$X%X$X$X$X$X$X%X$X%X$X$X$X%X%X%X%X%X$X%X%X%X%X%X%X%X%X%X*X*X*X-X%X-X-X>X-X@X=X:X:X6X6X5X5X6X9X0X0X0X0XrX0XrXrXrXrXrXtXrXrXtXrXyXrXrXtXeXtX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n S S S D D D F U N.N.m.N.m.m.N.m.N.N.m.m.N.N.m.c.F F F D D S G S S N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ sXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y y y y y y y y y y y y y y /.%X*X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X$X$X%X%X%X%X%X%X%X%X%X%X%X%X%X%X$X%X%X%X%X%X%X%X%X%X$X%X%X%X%X$X%X%X$X%X%X%X%X%X%X%X%X%X%X%X%X%X%X&X%X%X*X&X-X*X-X-X*X-X-X-X;X-X-X;X>X;X:X:X6X9X5X0X0X9X0X0X0X0XrXrXrXrXrXqXtXrXtXrXtXrXtXyXrXyXrXrX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ M S D D D D D U m.m.N.m.N.m.m.N.m.m.N.m.m.m.m.c.F F D D S D D S N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 5 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y y y y y y y y m y y y y y ~.<X%X*X*X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X$X%X%X%X%X%X&X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X*X*X%X%X%X*X%X*X*X*X*X*X-X-X-X*X-X*X-X-X-X-X-X;X;X;X-X;X:X:X:X9X6X9X9X9X7X0X0XrX0X0XrXqXrXrXrXrXrXrXqXrXrXrXrXyXrXrXyXyXeX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n D S D D D Y m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.j.D D D D D D A N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 J sXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y y y y y y y y y y y y y y ~.%X%X*X;X*X*X%X*X*X*X*X*X*X%X*X-X-X&X%X*X*X*X*X*X*X*X*X*X-X*X*X*X*X*X*X*X*X&X%X*X*X*X*X*X*X*X*X&X-X-X*X*X*X*X*X*X*X*X*X*X-X*X*X*X*X*X*X*X*X*X%X*X*X;X*X*X*X*X-X-X-X-X-X-X>X-X>X;X-X:X;X;X:X:X>X:X5X6X9X6X5X9X9X0X7X0XrX7XrX0X0XrXrXrXrXqXrXtXrXtXyXrXrXtXrXrXrXtXrX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ M S S D D Y m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.c.D D D D D D B 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 d.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y y y y y y m y y y y y y y /.XX%X%X*X;X*X;X*X*X;X*X*X;X*X-X-X-X-X-X-X-X-X*X*X-X-X*X-X-X-X*X-X*X-X-X-X*X-X-X-X-X-X-X-X-X*X-X-X-X-X-X-X-X-X*X*X-X-X-X*X-X*X*X*X*X*X*X;X*X*X-X-X-X-X*X;X*X;X-X-X-X-X;X-X:X-X;X:X:X;X:X;X:X:X6X;X;X6X9X9X9X9X9X0X0X7X0X0X0X0XrXqX0XrXrXrXrXrXtXrXrXtXrXrXtXrXtXeXtXrX#X6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n S D D U m.n.m.m.m.m.m.m.m.m.m.m.m.n.m.j.D D D D S N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 f.b.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y y y y t y y y y y y y y y OX%X%X%X*X;X6X;X;X;X*X;X;X;X;X-X-X-X-X-X-X-X-X-X;X;X-X-X-X-X-X-X-X-X;X-X-X;X-X-X-X-X-X-X-X-X-X;X-X;X-X-X-X-X-X;X*X-X-X-X-X;X-X;X;X;X;X;X;X;X;X;X;X;X;X;X;X-X>X:X-X:X-X:X:X-X:X:X;X:X:X:X:X:X:X;X6X9X9X6X9X9X5X0X0X0X0X0X0XrXrX0X0XrX0X0XqXqXrXrXrXrXrXrXyXrXtXtXrXrXyXrX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ n S D Y n.n.m.n.m.m.n.m.n.n.m.m.m.m.m.j.D D D D N 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ d.v.v.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy t y y y y y y y y y y y y y y ~.%X%X*X*X*X;X;X;X;X:X;X;X;X;X-X:X:X:X:X-X:X:X:X;X:X;X;X:X;X:X:X>X;X;X:X;X:X;X;X:X;X:X:X;X:X;X:X-X-X:X:X-X:X:X;X:X;X:X:X;X;X:X;X;X6X;X;X;X;X6X;X:X:X;X:X;X:X;X:X:X:X:X:X:X>X:X:X:X:X:X:X:X6X:X9X6X9X9X9X9X9X7X0X7X0X0X0X0X0X0XrXrXrXrXrX0XrXrXrXrXrXtXrXyXtXrXrXyXtXrXyXrX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ V D Y m.m.n.n.m.m.n.n.m.m.n.m.n.n.m.j.S S S N 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 d.v.v.v.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt y y y y y y y y y y y y y y y /.$X%X*X*X*X;X6X6X:X;X6X6X;X6X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X6X;X;X6X;X6X6X;X:X:X:X:X:X6X:X:X:X:X:X:X:X:X:X6X:X:X6X6X:X6X6X6X6X6X9X5X9X9X0X0X7XrX0X0X0X0XrX0X0X0X0XrXrXrXrXrXqXtXrXrXrXrXrXtXrXyXrXyXrXyXtX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ V Y n.m.n.m.n.n.m.n.n.m.n.n.m.n.n.j.S S N 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 f.).v.v.b.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy t t y t t y t y y t y y y y t ~.$X%X%X*X;X;X;X6X6X:X6X:X:X6X,X:X,X:X:X:X:X:X:X:X:X:X:X:X,X,X:X:X:X:X:X:X,X,X:X:X6X6X:X:X6X:X,X:X,X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X,X,X:X6X6X:X6X:X6X6X:X:X,X:X:X6X6X:X6X6X:X9X:X,X9X,X9X9X5X9X9X0X0X8X0X0X0X8X0X0XrX0X0X0X0X0XqXrX0XqX0XrXqXrXrXrXtXrXrXrXtXrXyXrXrXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ C n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.j.S N 5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 f.b.v.v.v.z.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy y y t y y y y t y y t t t t t ^.<X%X*X*X;X;X;X6X6X6X6X6X6X6X,X9X9X:X9X9X:X9X9X:X9X6X9X:X,X9X9X6X6X6X9X,X9X,X6X6X6X6X6X6X6X6X9X,X,X6X6X9X:X9X6X6X9X,X9X6X9X,X9X6X9X:X9X:X9X,X6X6X6X6X6X6X5X6X,X9X9X9X6X9X6X6X6X9X6X6X9X9X9X9X9X9X9X5X6X0X0X9X0X0X0X0X0XrX0X0XrXqXrXrXqXrXrXrXrXrXtXrXrXtXrXtXyXrXrXyXrXyXyXrXtX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 c.n.n.n.n.n.n.n.n.n.n.n.n.n.n.j.N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 f.).v.b.z.x.z.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXy t y y y h y y t y t t t r t t /.%X%X*X*X*X;X;X:X6X6X9X6X6X6X,X,X9X,X,X6X6X:X9X6X:X9X9X9X,X,X9X6X9X,X6X9X9X,X6X6X6X6X6X6X6X6X9X,X9X,X9X:X9X:X9X6X:X9X9X:X9X,X6X9X,X9X9X:X9X,X6X6X6X6X6X6X6X6X,X9X9X,X9X9X,X9X9X9X9X9X9X9X9X9X9X9X0X9X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqXqXqXqXqXrXtXqXrXrXrXrXtXrXtXtXrXyXtXeXyXyXrX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 c.n.n.n.n.n.n.n.n.n.n.n.n.n.n.j.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 f.v.v.v.v.z.b.l.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt t t t t y y t t t t t t t t y oX%X%X%X*X*X>X:X:X6X6X9X5X9X5X9X9X9X,X9X9X9X9X9X9X9X,X9X9X9X9X9X9X9X:X9X9X9X,X6X0X6X6X9X6X0X6X9X,X9X9X9X9X9X9X9X9X9X9X9X9X9X,X9X9X9X9X9X9X9X,X6X6X0X6X0X6X6X6X9X9X9X9X9X9X9X9X9X9X9X9X9X9X9X,X9X9X9X0X9X0X0X0X0X0X0X0X0X0X0X0XrX0XqXrX0X0XqXqXqXrXqXrXtXtXrXrXtXrXeXtXrXtXyXrXeXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 c.n.h.h.n.n.n.n.h.h.n.n.n.h.n.k.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 d.v.v.v.v.z.x.l.l.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt t t r t t t t t t t t t t t t ~.%X%X*X*X*X;X;X:X6X6X6X0X9X0X9X0X,X9X0X9X9X9X9X9X9X0X9X0X9X9X9X9X9X0X9X9X0X9X0X9X9X9X0X9X9X0X9X0X9X,X9X0X9X9X9X9X0X9X9X9X0X9X9X9X9X9X9X9X0X9X0X9X0X9X0X9X9X0X9X9X9X0X9X9X9X0X9X9X9X0X9X0X0X0X0X0X0X0X0X0X0X0X0X0XqX0XqXqXqX0XqXqXqX0XqXrXqXqXqXrXrXqXrXrXtXrXyXtXrXtXtXtXyXeXyXyXrXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 n.h.h.h.h.h.n.h.h.c.c.h.h.h.h.k.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 d.v.v.v.b.x.x.l.l.l.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt t t t t t t r t t t t t t t t /.%X%X*X*X;X;X:X:X:X6X6X9X9X0X0X9X0X0X9X9X0X0X0X9X0X0X9X0X0X9X9X0X0X0X0X9X9X0X9X9X0X0X9X0X0X9X9X9X0X0X9X9X0X0X0X9X0X0X0X9X9X0X9X0X0X0X0X9X9X0X9X9X0X9X9X0X0X9X0X9X0X9X0X0X0X0X8X0X9X0X0X0X9X0X0X0X0X0X0X0X0XqX0X0X0X0X0X0X0XqXqXqXqXrXqXqXqXtXqXqXtXtXtXqXrXtXrXrXtXrXrXyXrXtXtXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 h.h.h.h.n.h.h.h.h.h.h.h.h.h.h.k.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 f.).v.v.v.z.z.z.l.l.l.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt r t t r r t t t r y t t t t g /.%X%X%X*X;X;X;X6X6X6X6X9X9X0X0X0X9X0X0X0X0X0X0X0X0X9X0X0X0X0X0X0X0X9X0X0X0X0X0X0X0X0X0X0X0X0X0X0X9X0X0X0X0X0X0X0X0X9X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X9X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XrX0X0X0X0X0X0X0X0XqXqXqXqXqXqXqXqXqXqXrXqXrXtXqXqXrXtXrXtXqXtXtXtXrXyXtXtXyXyXyXeXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.k.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 f.).v.v.v.v.x.x.l.l.k.d.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt t r r r t t t t y h g t t t r ^.$X%X%X*X;X;X;X6X6X6X9X6X9X0X0X0XqXqX0XqX0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqX0X0X0X0X0X0XqXqXqX0XqX0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqX0X0X0XqXqX0X0X0X0X0X0X0X0X0XqXqXqX0XqX0XqX0X0X0XrXqXqXqXqXrXrXrXrXqXqXqXqXrXqXrXrXqXqXtXqXtXrXrXtXrXtXrXtXrXtXeXyXrXyXyXyXrXeXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 7 h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.k.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ d.v.v.v.v.v.x.x.l.l.d.l.d.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr t r r r t r t r t t h y t g r /.%X%X%X*X*X>X;X6X5X6X6X6X0X0X0X0XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXtXyXtXyXtXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 Z G G G G G G U U U G G G G G N $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ f.).).z.v.v.l.b.l.l.l.d.f.f.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr r t t r t r r t r r t t t r r ~.%X%X%X*X*X>X;X6X6X6X9X6X6X0X0XrXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXtXtXtXtXyXtXtXtXyXyXtXyXtXyXtXyXtXyXyXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyX|.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ m $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ f.).).z.b.z.z.l.l.l.d.d.f.f.p.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXt r t t t r r t r r r t r t r r ~.%X%X*X*X-X-X;X6X6X6X6X9X0X0X0XrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXaXP P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P I yXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 v.).v.v.v.z.z.x.l.l.l.l.f.f.f.p.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg t g g g t t r r r r t r r r r ~.%X%X%X-X-X;X;X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXqXqX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 8XiXyXyXyXyXyXyXyX}.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ [.|.).).v.v.z.z.x.l.l.d.d.f.f.f.a.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr r r t g t g g r r r r r r r r ~.%X%X*X*X*X;X:X6X6X6X6X6X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : > /.yXyXyXyXyXyXyX{.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXiXv.v.v.z.z.l.l.l.l.f.f.p.p.u.p.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg r g g t g t r r r g r r r r r ~.$X%X*X*X-X;X;X:X:X6X0X6X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : > /.yXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyX|.v.v.z.z.x.l.l.l.d.d.f.p.p.a.u.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr g t r g g t r r r g r g r r g /.$X%X*X*X-X;X:X:X6X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : > /.yXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyX1Xv.v.z.x.x.l.l.d.f.f.p.p.u.u.a.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr h r r t g g g r g r g r r r r oX$X%X*X-X-X;X;X6X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : > /.yXyXyXyXyXyXyXyXyXyX}.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyXyX|.v.z.z.x.l.l.d.d.f.p.p.u.u.a.a.sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr g r g r g g r g r g r g g g g ~.%X$X*X*X-X;X:X;X6X9X9X9X0X0X0XqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtX1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyX{.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyX{.v.z.x.l.l.d.d.p.p.p.p.u.a.a.H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg r g r g r r g r g r g r r g r /.%X%X%X*X-X;X;X6X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : > + + + + + + + + + + + + + + + + + + + + + + + + + + + ; : : : : : : : : : : : > + + + + + + + + + + + + + + + + + + + + + + + + + + + ; : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ [.yXyXyXyXyXyX1Xz.x.x.l.l.d.d.p.p.p.u.u.a.a.H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g g g g g g g r g r g g g g s /.%X%X*X*X-X:X;X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; O : : : : : : : : : : : = + : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyX{.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyXyXyX{.z.x.l.l.l.d.d.p.i.u.u.a.a.v H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXr g g g g g g g g g g g g g g g ^.$X%X*X*X-X;X:X:X:X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; 7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.2 : : : : : : : : : : : = 8.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.2 : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyX{.z.x.l.d.d.d.p.p.u.u.u.a.a.H H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g g g g g g g g g g g g g g g /.oX%X%X*X-X;X;X6X:X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; . tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP > : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXtXtXtXyXtXyXtXtXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyX|.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyXyXyXyXyX#Xx.l.l.l.d.g.i.i.a.u.a.H H H H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g g g g g g g g g g g g g g g oX%X%X%X*X-X;X;X6X6X6X6X9X9X9XqXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXyXtXtXyXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ [.yXyXyXyXyXyXyXyXyXyX{.l.l.d.g.p.i.i.i.u.a.a.H H H H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g g g g g g g g g g g g p g g ~.%X%X*X*X-X;X;X6X6X6X9X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; . tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX}.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyXyXyXeXyXeXuX{.l.l.d.d.p.p.i.u.u.a.H H H H V sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g g g g s g g g g g g g g g g ~.%X%X%X*X-X;X5X;X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXyXtXtXtXtXL : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX}.6 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyXeXeXeXrX{.l.l.d.p.p.i.u.u.a.H H H H H H sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs g s s g g s g s r s s s s s s ~.%X%X*X*X-X;X:X:X:X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : > /.tXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.8 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyXyXyXyXyXyX{.l.g.p.p.i.i.u.a.a.w.H H v H c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg s g g g s g s s s s r s r r s ~.$X%X%X-X-X;X:X:X6X6X6X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; . tXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyX`.d.l.p.i.i.i.u.a.a.H v H v c c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXg g s s g s s g s s r s s s s s XX$X%X*X*X*X;X:X:X6X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXyXtXyXtXL : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.8 $ $ $ $ $ $ $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyX_.l.i.i.i.u.u.u.a.H H H c c c c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs g s s s r s s g s s r s s r s /.$X%X*X*X>X;X:X:X:X6X6X9X9X0XqXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; . tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXtXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX`.6 $ $ $ $ $ $ $ $ $ 6 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX).d.p.i.i.u.u.a.H H v H v c C c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs g s s s g s s r s s s s r s s ~.%X%X%X*X-X;X:X:X:X:X9X9X0X9X0XqXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX(.g.i.i.u.u.u.w.H H H v v c c c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s s s s s s s s s s s s p s s /.%X%X*X*X-X;X>X:X:X6X6X6X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; yXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXK : : : : : : > /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ $ $ $ $ 5 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX).i.i.i.u.u.u.a.H v v c c c V z sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s s s s s s s s s s s s s p s ~.$X%X&X*X*X:X:X:X6X6X9X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : > /.yXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.8 $ $ $ 6 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX).i.u.u.u.u.v w.H v v c c c z c sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s s s s s s s s s s s s s s s ^.$X%X%X-X-X;X:X:X:X6X6X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX1 : : : : : : ; . tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXL : : : : > : > ~.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.6 $ 5 ).yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX(.i.u.u.u.u.H H H H c c c c c z sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s s s s s s s s s s s s s s s ^.$X%X%X*X;X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXZ.aX# o o o o o tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXZ.aX4 o o o o o /.yXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyX{.8 v.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXz.i.u.u.w.a.H H v v c c c z z z sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s s s i s s s s i p s s s s p /.%X%X%X%X=X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqX# . . . . . . X tXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXyX~ . . . . . . . /.yXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXz.u.u.u.a.H v v v c c c z c z z sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs p s p s s s s s s s s s p s p ^.%X%X*X*X*X;X:X:X:X6X9X9X0X9X0XqXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXP : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXyXrXeXyXyXyXtXyXtXtXtXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXx.u.u.w.w.H v v v c c c z z z h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXs s p s s s i s i s s s i s p p /.%X%X*X*X*X;X:X:X6X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXyXtXeXyXtXtXtXyXtXyXtXyXtXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXyXyXx.u.u.w.a.w.v v c c c x x z z z sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p s p s s s s i s i s s s s p ~.%X%X*X*X*X;X:X:X:X6X,X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXyXtXyXtXyXtXyXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXyXyXyXyXyXtXyXx.w.w.a.v v v v c c x x z h h h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp s s s i s i s s s s i i s p p ~.$X%X*X*X-X;X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXyXyXtXyXtXyXyXyXtXyXtXyXtXyXyXrXyXyXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXtXyXtXyXtXg.u.a.w.w.v v v c c x x z z h h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p p p p p p s i i s s i p p p ~.$X%X*X*X-X;X:X:X:X9X,X0X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXyXyXyXtXtXyXyXtXx.w.w.v v v c c x x x z z z h h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p p p p p p i s s i s s p p p ~.$X%X*X*X;X;X:X:X:X,X,X9X9X0XqXqXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXyXtXyXtXtXtXtXyXtXyXyXtXyXtXtXyXtXyXtXyXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXyXyXyXtXyXtXyXyXyXtXyXyXg.w.a.v v v c c x x x z h h h h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p i s i p p p p p p p p p p p ~.%X%X%X*X;X;X:X:X6X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXyXtXtXtXtXyXtXtXtXyXtXtXtXyXtXtXtXyXtXtXyXtXtXyXtXyXtXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXtXyXtXtXyXtXyXtXg.w.w.v v x c x x x z z h h f h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p p i s p p p p p p p p p p p ~.%X%X*X*X*X;X:X:X:X6X5X5X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXrXtXyXtXyXtXyXyXtXyXyXtXyXyXtXyXyXyXyXyXyXyXyXyXyXyXtXyXyXyXyXyXyXtXyXyXyXtXyXyXyXyXtXtXyXyXyXyXyXyXyXtXyXtXtXg.v v v v v x x z z z h h f h f sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p p s s p s i p i p s i p i p ~.XX%X%X@X;X;X:X:X6X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXyXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXyXtXyXyXtXyXyXtXtXyXyXyXyXyXyXyXyXyXtXyXyXyXtXyXyXtXyXyXtXyXtXyXtXyXtXyXyXtXtXyXyXyXtXyXg.v 0.c x x x x l z z k h h f f sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp i i i i i i p p i p i i s p p .X$X%X%X*X;X;X;X:X6X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXyXtXyXtXtXtXyXtXyXtXyXtXyXtXyXyXyXtXyXyXtXyXyXyXyXtXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXtXyXyXtXyXtXtXtXyXtXg.v v v v x x x x l k k h f f f sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p p p p p p p d i s i s p i i ~.$X%X%X*X;X;X:X:X6X6X9X9X6X7X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXyXtXyXtXyXyXtXyXyXyXyXyXyXtXtXyXyXyXyXyXyXyXyXyXyXtXyXtXtXyXyXyXyXtXyXyXyXtXtXyXtXtXyXtXi.v x x x x x x l z k h f f f p sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i p i i i p i i i s i i i p i ~.<X%X%X*X*X;X:X:X:X6X6X9X0X0X0XqXtXtXtXtXtXqXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXyXyXtXtXtXyXtXyXtXtXyXtXyXtXyXtXyXyXtXtXyXtXyXyXyXyXyXyXtXyXyXyXyXtXyXyXyXyXyXyXyXtXyXtXyXyXtXyXtXyXtXyXyXtXyXi.v 0.x x x l l k k k f f f f f sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXp p i p i p i i s i i i i p i p ~.%X%X%X*X*X;X;X:X6X6X6X6X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXyXtXtXtXtXtXyXyXtXtXyXtXyXtXyXyXtXtXyXyXtXtXyXyXyXtXyXyXtXyXyXyXtXyXyXyXtXyXtXyXyXtXyXtXyXyXtXtXyXtXtXt.v x x x l l z k k h f f f f p sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i p i i i i i i i i p i p i ~.%X%X*X*X;X;X;X6X6X6X6X0X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXrXtXtXtXyXtXyXtXtXtXtXyXtXyXtXtXyXyXtXyXtXtXyXyXyXtXyXtXyXyXtXyXtXyXyXtXyXtXyXtXyXtXtXyXtXtXyXtXyXtXtXtXyXi.x x x l z l k k k f f f p d f sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i p i i p i i i i i p i i p i ^.%X%X*X*X;X;X:X:X5X:X6X0X0X6X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXyXtXtXyXtXyXtXyXyXtXyXyXtXyXyXyXyXyXtXyXyXtXyXyXtXyXyXtXtXyXyXtXyXyXtXyXtXyXtXtXyXtXtXyXtXtXyXtXu.x x b x l l b f k f f f d f i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i i i i i i i i i i i i i i ^.%X%X*X*X;X;X;X:X6X6X6X6X0X0X0XtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXyXtXtXtXtXtXyXtXtXyXtXtXyXtXtXyXtXyXyXtXtXyXyXtXyXtXtXyXyXtXtXyXyXtXyXtXyXtXtXyXtXyXtXtXyXtXtXtXq.x x x l l l b k f d d d d d d sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i i i i i i i p p i i p i i /.$X%X%X*X;X;X:X6X6X6X6X0X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXrXtXtXtXtXtXtXyXyXyXtXtXtXyXtXtXtXtXtXyXtXtXyXtXyXyXtXtXyXtXyXyXtXtXyXtXyXyXtXtXyXtXyXyXtXtXtXyXtXtXtXtXyXi.l l l b k l k f d f d f f d d sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i i i i i i i p s % i s s i ^.$X%X*X*X*X;X;X6X;X9X6X6X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXyXyXtXtXyXyXtXyXtXtXyXyXtXyXtXyXyXyXtXyXtXtXyXtXtXyXtXtXyXyXyXtXtXyXtXtXtXu.b l l k k k d f d d d i i i i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i p p i i p s p % p p i % i ^.%X%X%X*X*X:X:X:X:X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXyXtXtXtXyXtXtXtXyXyXtXtXyXtXyXtXyXtXtXyXtXtXyXyXtXtXyXtXyXtXtXtXtXtXyXtXtXtXtXi.l k k k k d k d d d d d d i d sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i i s % i % s p s s % i i i ^.XX%X*X*X*X;X;X:X6X6X6X0X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXyXtXtXtXtXtXtXyXtXyXtXtXtXyXtXtXyXyXtXtXtXyXyXtXyXtXtXtXyXtXtXyXyXtXyXtXyXtXtXtXtXyXyXtXtXyXyXtXtXyXw.l k k k d d d d d d p i i d i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i i i i i p s p i i a a i i ^.$X%X*X*X*X;X:X:X6X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXyXtXtXtXyXyXtXtXtXtXyXyXyXtXyXyXyXyXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXq.k k b d k d d d d d a i d d i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i i s % i i i % i i i i i i a ^.%X%X*X*X;X;X:X:X:X6X0X6X0X6X0XqXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXtXtXtXyXyXtXtXyXtXtXtXtXyXtXyXtXtXtXyXtXtXtXtXtXtXtXyXyXtXyXtXyXtXtXyXtXtXtXtXtXtXu.d k b d d d d a d d d i a f t sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi i 0 0 i 0 i 0 i 0 i 0 i 0 i i ^.%X%X%X*X*X;X>X:X6X6X6X0X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXyXtXtXtXtXtXyXyXtXtXtXtXtXtXtXtXyXyXtXtXtXtXtXtXyXyXtXtXyXyXtXrXyXtXyXtXtXtXtXtXtXtXtXw.b d d d % h f t % t h % t % h sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXa 0 i i i i 0 i 0 i 0 i 0 i 0 i ^.%X%X%X*X;X;X>X:X:X6X6X9X0X9X9XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXyXyXyXtXyXtXtXtXtXyXyXtXyXtXtXtXtXtXtXtXtXyXtXtXtXtXtXyXtXtXyXtXtXw.d f d d b h % % h h % t % h t sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi 0 0 0 0 0 i 0 i 0 i 0 i 0 0 e ^.$X%X*X*X-X;X:X:X6X6X6X9X9X9X0XtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXyXyXtXtXtXtXtXtXyXyXtXtXyXyXtXtXtXtXtXtXtXtXtXtXtXtXtXw.d b f % f f d % g g % h % t % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 0 i 0 i 0 0 0 0 0 0 0 0 0 i i ^.%X%X%X*X-X;X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXyXtXtXrXyXtXtXtXtXyXtXtXtXtXtXyXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXtXw.k % h h s h % h h % h % g % t sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe 0 i e 0 0 0 0 0 0 0 0 0 a 0 e ^.%X%X*X*X-X>X:X:X6X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXyXtXtXtXtXtXtXtXtXw.d % d f f % g % h % t % h % t sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXi 0 0 i 0 0 0 0 0 0 0 0 0 0 0 i ~.XX%X*X*X-X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXrXtXtXtXtXyXtXtXtXtXtXtXyXtXtXyXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXw.f h f % g % f t % t % t % t % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 0 0 e 0 0 0 0 0 0 0 0 0 0 0 e ^.%X%X%X*X-X;X>X:X:X6X6X6X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXyXtXyXtXtXtXtXyXtXtXyXtXtXtXtXtXtXtXyXtXtXrXyXtXtXtXyXtXtXtXtXtXtXtXtXtXtXw.% % g d f g % % t % h % t % g sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe 0 0 0 0 0 0 0 0 0 0 0 0 0 0 e ^.%X%X*X*X;X;X:X:X:X6X9X9X0X0X0XqXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXrXyXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXw.h f g % % f g h % t % t % g % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ^.%X%X%X*X-X;X:X:X6X6X6X9X9X0X0XqXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXyXtXtXtXtXyXyXtXtXtXtXyXtXtXtXyXyXtXtXtXtXtXtXtXtXtXtXtXtXtXw.s % g % s % g % g s % % t % g sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe e 0 0 0 w e e 0 e e 0 0 0 0 e ~.%X%X%X*X-X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.% h % f g h % g % % h g % g % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 0 0 e 0 0 0 e 0 e 0 0 e 0 w e ~.%X%X%X*X-X;X:X:X:X6X9X9X0X9X0XtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXyXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.h % g s % f % % g % t % g h % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe w 0 w e w e e e e e w 0 w 0 0 .XoX%X*X*X-X;X:X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.% g % % s % f h % g % y % % g sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe 0 e e e e e w 0 w 0 0 w 0 w e ^.%X%X*X*X-X;X:X:X:X:X9X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXv % % g % g % g % g % % t % g % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe 0 w e e e e 0 w 0 w w 0 w 0 e ^.%X%X*X*X-X-X>X:X6X6X6X6X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXw.s g % g % s % g % h % % g % t sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 w w e e 0 e w w w 0 w 0 w 0 e ^.%X%X%X*X-X:X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : ; 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.% g t % s % s % % g t g t % % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX0 q 0 w w w w e w w 0 w w w w w .X%X%X*X*X-X-X:X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.% % % f % s % % t % % % % g % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXe w e w e e w 0 q w 0 w w 0 w w ^.%X%X%X*X-X;X>X:X6X6X6X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.w w w e w w w w w w w w i w w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w w w 0 w w w 0 w w w w w w e ^.%X%X*X*X-X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.w w a w w w w w w w i w % i w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w w 0 q 0 q w w w w w w w w w ^.%X%X%X*X-X;X:X:X6X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtX0.w w w w w w w w w w w w w w w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w w q 0 q 0 w w w w w w w w w .XoX%X*X*X-X;X:X:X:X6X6X9X9X0XqXqXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.w w w w w w w w w w w w w w w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw e w q e 0 q w 0 w w w w w w w ^.%X%X%X*X=X;X>X:X:X6X9X9X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.w w w w w w w w w w w w w w w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw q w e q q e q q w w w w q w w ^.%X%X*X*X-X;X;X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.w w w w i w w w w w w w i w w sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w w q w q q w q q w w q w w w ^.%X%X%X*X-X;X:X:X:X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.i % a i % % i % w w % i % i % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q w e q w w q w w w q w w q q ^.%X%X*X*X;X;X>X:X:X6X6X0X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtX0.% i % % w i % i i % i % i % i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq w q w q w q 0 q q w w q w q w ^.%X%X%X*X;X;X:X:X:X6X,X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtX0.i % i % i w % i % i % i % i % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw q w q w q q w q w q q w q w q ~.%X%X*X*X-X;X:X:X:X,X9X9X9X0XqXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.% w i i % % i % i % i % i % i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w q w q w w q w w w w q w q q ^.%X%X%X*X-X;X:X:X:X9X9X9X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXw.% a % % i i % i % i % i % i % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q w q q q q q q q q w q q q .XoX%X*X*X-X-X:X:X:X9X:X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXv % % w i % w w % i % % % w % i sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q q q w w q q w q w q q w ^.%X%X&X*X*X>X:X:X:X6X,X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.q % w % i % i % i % i % % a % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXw w q q q q q q q q q q q q q q ^.%X%X*X*X-X-X:X:X6X:X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.w w w w % w % w % a % i i % a sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q q q q q q q q q q q q w ^.%X%X%X*X-X:X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.w w w w w w % % i i % % i a % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q q q q q q q q q q q q % .X%X%X*X*X-X-X:X:X6X6X,X9X9X0XqXqXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqX0XK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXyX9.w % w % w % w i % % i % % % a sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q q q q q q q q q q q q q .X%X%X%X*X-X;X:X:X6X6X6X6X0X0X6XrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtX0.q q q q q 9 q q q q q q q q q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q 9 q q 9 q 9 q q 9 q q q ^.$X%X%X*X-X;X:X:X:X6X6X0X6X0X0XrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.q q 9 q q q q q q 9 q 9 q q 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q q q q q q q q q q q q q q ^.%X%X*X*X-X;X;X:X:X6X6X9X0X0X0XtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.q 9 q 9 q q q 9 q 9 q q 9 q q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 q q q 9 q 9 q q 9 q q 9 q q 9 ^.%X%X*X*X;X;X:X:X6X6X6X9X0X9X9XrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtX0.9 q q q q q 9 q q q q q q q q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq 9 9 q q q 9 9 q q 9 q q q 9 % ^.$X%X<X*X-X-X:X:X:X6X6X0X6X0X0XtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.q q q q 9 q q q q 9 9 9 q q 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q q 9 9 q q q 9 9 q q 9 q 9 % ^.$X%X*X*X-X>X:X:X6X6X6X6X0X6X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtX0.q 9 9 9 q q 9 q 9 q q q q 9 q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq q 9 q 9 q 9 9 q 9 q 9 q 9 q w oX$X%X*X*X-X-X:X:X6X6X6X0X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 q 9 q 9 q 9 q 9 q 9 q 9 q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 q 9 q 9 q q 9 q 9 q 9 q 9 % ~.%X%X*X*X-X;X;X:X6X6X6X6X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 q 9 q 9 q 9 q 9 q 9 q 9 q 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 q q 9 9 q 9 9 q q 9 q 9 9 9 % ~.%X%X%X*X-X;X:X:X6X6X6X0X0X0X0XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXK : : : : : : : : : : : = 8XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 9 q 9 9 9 q q 9 9 9 9 q q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq 9 9 9 q 9 q 9 9 9 9 9 9 q q % /.%X%X*X*X-X;X:X:X:X6X6X6X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXI < < < < < < < < < < < : : : : : : : : : : : : > - - 1 1 1 1 1 1 1 1 1 L tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 9 9 q q 9 9 9 9 q q 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 q 9 9 q 9 9 q 9 9 9 9 % ^.%X%X%X*X-X;X:X:X6X6X6X0X6X0X0X0XtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : , 7.y.tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 9 9 9 9 9 9 9 9 9 q 9 9 q sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXq 9 9 9 9 9 9 9 9 9 9 9 q 9 q % ^.%X%X*X-X-X;X:X:X:X6X6X6X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : = tXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtX0.9 9 q 9 9 q 9 9 9 q 9 9 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 q 9 q 9 9 9 q 9 9 9 9 9 9 % ^.oX%X%X*X>X-X;X:X:X6X6X6X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : = . tXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 9 9 9 9 9 q 9 9 9 q 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 % ^.%X%X%X*X-X;X:X:X6X6X6X9X6X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : = tXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX0.9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 % ^.%X%X*X*X-X;X:X:X6X6X9X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXL : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : = tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 % /.%X%X%X-X-X-X;X6X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXaXL 3 O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O @ . tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 & 9 9 9 9 * 9 * 9 9 % 9 % 9 * ^.%X%X*X*X;X;X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX~ tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtX9.9 9 * % 9 9 9 % 9 % 9 % 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 & % 9 9 & 9 * 9 % 9 * % ^.$X%X*X*X*X;X:X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtX~.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.L.tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.% 9 9 9 9 & & 9 % 9 9 9 9 * * sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 & 9 9 9 * 9 9 & 9 % * 9 9 % ^.$X%X*X*X-X;X:X:X6X6X6X9X9X0X0XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXwXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtX9.9 & 9 * 9 9 9 % 9 9 * % 9 9 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 & & 9 9 & 9 9 9 9 9 * 9 % ^.$X%X*X*X-X;X:X:X6X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXeXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 9 9 & 9 & 9 9 % 9 * 9 * & 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX9 9 9 9 9 9 9 9 & 9 9 9 9 9 9 % ^.%X%X*X*X-X;X>X:X:X6X6X0X9X0X0X0XtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 & 9 9 9 & 9 * 9 9 * 9 9 * 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX* & % & * & & % % & * * * * % % ^.%X%X%X*X-X;X;X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 & & % % 9 & * % % * % % * % sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX* % % & 9 * 9 % % % % * % % % % ^.%X%X*X*X-X-X:X:X6X6X6X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& 9 & % % % % % % % % & * * 9 sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX* % % * * * & % % % % % % * * % .X%X%X%X-X-X:X:X:X:X6X6X9X0X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& 9 & % % % % % % % % 9 * * * sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX* * 9 * * * * * * * * * * * * % ^.$X%X%X*X;X;X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.9 & & & & & & * * 9 & & 9 & * sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX* & & * * * * * * * * * * * * % ^.$X%X*X*X;X;X:X:X:X6X6X9X9X0X0XqXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtX9.& & & & & * & * * & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % ^.oX%X%X*X*X>X:X:X:X6X6X9X0X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXqXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & .X%X$X*X*X*X;X:X:X:X6X9X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % .X$X%X%X*X;X;X:X:X:X6X,X9X9X9X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & .X%X%X*X*X;X;X:X:X:X9X9X9X0X0X0XqXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & .X<X%X*X*X*X;X:X:X:X6X,X0X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % ^.%X%X%X*X;X;X:X:X:X,X,X9X9X0X0XqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXqXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX9.& & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % 7.r.r.r.r.r.r.r.r.r.r.t.t.r.t.t.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.t.9 9 & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % % & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & 9 9 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % % % & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & % % % % & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & * & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX& & & & & & & & & & & & & * * & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX", +"sXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsX" +}; diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256_32bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256_32bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0103ad7c88e74e25af5335e7de370e08817711e6 Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-256_32bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_32bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_32bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..99b9888f78e750b9b3a874786de706216b67071d Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_32bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_8bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_8bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5babf0d8344e896d01cfad28a1478d9fe4d2c47e Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-32_8bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_32bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_32bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3324f8f73d1dc1a14cfd313e362f93d22ceca561 Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_32bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_8bit.bmp b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_8bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..84e76b97aa1654e32e810e04e77be34c22275f1f Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application-48_8bit.bmp differ diff --git a/org.lamport.tla.toolbox.product.product/icons/toolbox_application.icns b/org.lamport.tla.toolbox.product.product/icons/toolbox_application.icns new file mode 100644 index 0000000000000000000000000000000000000000..47c0969eb58eb25c956981de3b72f319040aea4e Binary files /dev/null and b/org.lamport.tla.toolbox.product.product/icons/toolbox_application.icns differ diff --git a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product index 5efc5d875353a521cbb4b495385c04ee657468e6..aeaafcf998dd0151dc6967f92a35652e17b3130f 100644 --- a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product +++ b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product @@ -1,22 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> <?pde version="3.5"?> -<product name="TLA+ Toolbox" uid="org.lamport.tla.toolbox.product.product" id="org.lamport.tla.toolbox.product.standalone.product" application="org.lamport.tla.toolbox.application" version="1.5.7.qualifier" useFeatures="true" includeLaunchers="true"> +<product name="TLA+ Toolbox" uid="org.lamport.tla.toolbox.product.product" id="org.lamport.tla.toolbox.product.standalone.product" application="org.lamport.tla.toolbox.application" version="1.6.0.qualifier" useFeatures="true" includeLaunchers="true"> <aboutInfo> <image path="/org.lamport.tla.toolbox.product.standalone/images/splash_small.png"/> <text> TLA+ Toolbox provides a user interface for TLA+ Tools. -This is Version 1.5.7 of 18 July 2018 and includes: +This is Version 1.6.0 of Day Month 20?? and includes: - SANY Version 2.1 of 23 July 2017 - - TLC Version 2.13 of 18 July 2018 - - PlusCal Version 1.8 of 16 May 2018 + - TLC Version 2.14 of 10 July 2019 + - PlusCal Version 1.9 of 10 July 2019 - TLATeX Version 1.0 of 20 September 2017 Don't forget to click on help. You can learn about features that you never knew about or have forgotten. Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus . + +Some icons used in the Toolbox were provided by www.flaticon.com . </text> </aboutInfo> @@ -29,15 +31,16 @@ openFile -name "TLA+ Toolbox" </programArgs> - <programArgsLin>--launcher.GTK_version 2 + <programArgsLin>--launcher.GTK_version 3 </programArgsLin> - <vmArgs>--add-modules=java.se.ee --XX:+IgnoreUnrecognizedVMOptions --Xmx1000m + <vmArgs>-XX:+IgnoreUnrecognizedVMOptions +-Xmx1024m +-XX:+UseParallelGC -Dorg.eclipse.equinox.http.jetty.http.port=10996 -Dosgi.splashPath=platform:/base/ --Dosgi.requiredJavaVersion=1.8 +-Dosgi.requiredJavaVersion=11.0 -Dosgi.instance.area.default=@user.home/.tlaplus/ +-Dosgi.clean=true </vmArgs> <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts </vmArgsMac> @@ -45,19 +48,27 @@ openFile <windowImages i16="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_16.png" i32="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_32.png" i48="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_48.png" i64="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_64.png" i128="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_128.png" i256="/org.lamport.tla.toolbox/icons/full/etool16/tla_launch_check_wiz_256.png"/> - <launcher name="toolbox"> + <linux icon="/icons/toolbox_application-256.xpm"/> + <macosx icon="/icons/toolbox_application.icns"/> <win useIco="false"> - <bmp/> + <bmp + winSmallHigh="/icons/toolbox_application-16_32bit.bmp" + winSmallLow="/icons/toolbox_application-16_8bit.bmp" + winMediumHigh="/icons/toolbox_application-32_32bit.bmp" + winMediumLow="/icons/toolbox_application-32_8bit.bmp" + winLargeHigh="/icons/toolbox_application-48_32bit.bmp" + winLargeLow="/icons/toolbox_application-48_8bit.bmp" + winExtraLargeHigh="/icons/toolbox_application-256_32bit.bmp"/> </win> </launcher> <intro introId="org.lamport.tla.toolbox.product.standalone.intro"/> <vm> - <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8</linux> - <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8</macos> - <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8</windows> + <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</linux> + <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</macos> + <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</windows> </vm> <plugins> @@ -69,25 +80,26 @@ openFile <configurations> <plugin id="aws-ec2" autoStart="true" startLevel="4" /> - <plugin id="azurecompute" autoStart="true" startLevel="4" /> + <plugin id="azurecompute-arm" autoStart="true" startLevel="4" /> <plugin id="com.jcraft.jsch" autoStart="true" startLevel="4" /> <plugin id="ec2" autoStart="true" startLevel="4" /> <plugin id="jclouds-core" autoStart="true" startLevel="4" /> <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="4" /> <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" /> <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="2" /> + <plugin id="org.eclipse.equinox.event" autoStart="true" startLevel="2" /> <plugin id="org.eclipse.equinox.http.jetty" autoStart="true" startLevel="3" /> <plugin id="org.eclipse.equinox.http.registry" autoStart="true" startLevel="3" /> - <plugin id="org.eclipse.equinox.event" autoStart="true" startLevel="2" /> <plugin id="org.eclipse.equinox.simpleconfigurator" autoStart="true" startLevel="1" /> - <plugin id="org.eclipse.update.configurator"/> + <plugin id="org.eclipse.update.configurator" autoStart="false" startLevel="10" /> <plugin id="org.lamport.tla.toolbox.jclouds" autoStart="true" startLevel="4" /> + <plugin id="packet" autoStart="true" startLevel="4" /> <plugin id="sts" autoStart="true" startLevel="4" /> - <property name="eclipse.buildId" value="1.5.7" /> + <property name="eclipse.buildId" value="1.6.0" /> </configurations> <repositories> - <repository location="http://lamport.org/tlatoolbox/toolboxUpdate/" enabled="true" /> + <repository location="http://lamport.org/tlatoolbox/branches/1.6.0/toolboxUpdate/" enabled="true" /> <repository location="http://lamport.org/tlatoolbox/ci/toolboxUpdate/" enabled="false" /> </repositories> diff --git a/org.lamport.tla.toolbox.product.product/pom.xml b/org.lamport.tla.toolbox.product.product/pom.xml index 7ee073515578f30521855389520febb1ed136360..e4c70bc38bf5fa0f4fae4d220ba546c4c456995b 100644 --- a/org.lamport.tla.toolbox.product.product/pom.xml +++ b/org.lamport.tla.toolbox.product.product/pom.xml @@ -16,10 +16,7 @@ <packaging>eclipse-repository</packaging> <properties> - <!-- Align product.version with the version in - org.lamport.tla.toolbox.product.product.product - product.version. --> - <product.version>1.5.7</product.version> + <product.version>${toolbox.version}</product.version> <!-- Format build timestamp to adhere to the Debian package guidelines --> <maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format> <product.build>${maven.build.timestamp}</product.build> diff --git a/org.lamport.tla.toolbox.product.product/src/deb/control/control b/org.lamport.tla.toolbox.product.product/src/deb/control/control index e16ba509dda940811dec24343d74bc38040f23e5..9a43bac6206620b6633e408092d1718971ffa06c 100644 --- a/org.lamport.tla.toolbox.product.product/src/deb/control/control +++ b/org.lamport.tla.toolbox.product.product/src/deb/control/control @@ -3,6 +3,9 @@ Version: [[product.version]]~[[product.build]] Section: misc Distribution: development Priority: optional +## default-jre points to openjdk-11-re on Ubuntu for Bionic and up. We are not going to support Xenial/2016. +## default-jre installs Java 8 on Debian stretch (The successor buster already has Java 11). Users of stretch +## have to manually instal openjdk-11-jre from stretch backports (https://packages.debian.org/stretch-backports/openjdk-11-dbg) Depends: default-jre (>= 1.7) Recommends: texlive-latex-recommended, libwebkitgtk-1.0-0 Architecture: amd64 diff --git a/org.lamport.tla.toolbox.product.product/src/deb/control/postinst b/org.lamport.tla.toolbox.product.product/src/deb/control/postinst index d39accb3f3b04d9b755e4f8c3985eb48a4710977..3fea71ebf4ec17f7543efb5091fac4e184cbf72b 100644 --- a/org.lamport.tla.toolbox.product.product/src/deb/control/postinst +++ b/org.lamport.tla.toolbox.product.product/src/deb/control/postinst @@ -1,7 +1,9 @@ #!/bin/sh -## Fix permissions of executable +## Fix permissions of executables chmod 755 /opt/TLA+Toolbox/toolbox +chmod 755 /opt/TLA+Toolbox/tla2tools.jar +chmod 755 /opt/TLA+Toolbox/plugins/org.lamport.openjdk.linux.x86_64_*/jre/bin/* ## Update mime database for x-tla type. /usr/bin/update-mime-database /usr/share/mime diff --git a/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF index 7e966e7a4e3774e2ec852f7e6e49dbb537cd7e49..9579ae4ec2f514977d544768d662dd1cf144dddc 100644 --- a/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF @@ -22,5 +22,7 @@ Require-Bundle: org.eclipse.ui, Bundle-ActivationPolicy: lazy Bundle-Activator: org.lamport.tla.toolbox.StandaloneActivator Export-Package: org.lamport.tla.toolbox.lifecycle, - org.lamport.tla.toolbox.ui.intro + org.lamport.tla.toolbox.ui.intro, + org.lamport.tla.toolbox.util Import-Package: org.eclipse.equinox.p2.core +Automatic-Module-Name: org.lamport.tla.toolbox.product.standalone diff --git a/org.lamport.tla.toolbox.product.standalone/build.properties b/org.lamport.tla.toolbox.product.standalone/build.properties index 1424dc117ca9418f06ca898a8036d799d022f57d..27911bcb3184f14eda05cc89a6c83c7d24649c22 100644 --- a/org.lamport.tla.toolbox.product.standalone/build.properties +++ b/org.lamport.tla.toolbox.product.standalone/build.properties @@ -6,5 +6,6 @@ bin.includes = plugin.xml,\ icons/,\ icons/full/product_lg.gif,\ plugin_customization.ini,\ - images/ + images/,\ + examples/ diff --git a/org.lamport.tla.toolbox.product.standalone/examples/DijkstraMutex.zip b/org.lamport.tla.toolbox.product.standalone/examples/DijkstraMutex.zip new file mode 100644 index 0000000000000000000000000000000000000000..91f9dd2a1aed936ff9d749f19692dc940a199ad4 Binary files /dev/null and b/org.lamport.tla.toolbox.product.standalone/examples/DijkstraMutex.zip differ diff --git a/org.lamport.tla.toolbox.product.standalone/examples/EWD840.zip b/org.lamport.tla.toolbox.product.standalone/examples/EWD840.zip new file mode 100644 index 0000000000000000000000000000000000000000..6184351835a2e61ede7b7afaaaf9d1de2505376b Binary files /dev/null and b/org.lamport.tla.toolbox.product.standalone/examples/EWD840.zip differ diff --git a/org.lamport.tla.toolbox.product.standalone/examples/MissionariesAndCannibals.zip b/org.lamport.tla.toolbox.product.standalone/examples/MissionariesAndCannibals.zip new file mode 100644 index 0000000000000000000000000000000000000000..03254f37f4e7cd9025edcc82ca1f87dffbfa10d1 Binary files /dev/null and b/org.lamport.tla.toolbox.product.standalone/examples/MissionariesAndCannibals.zip differ diff --git a/org.lamport.tla.toolbox.product.standalone/examples/Queens.zip b/org.lamport.tla.toolbox.product.standalone/examples/Queens.zip new file mode 100644 index 0000000000000000000000000000000000000000..1bea480ba277b9726e8391aee7eeba833b819baa Binary files /dev/null and b/org.lamport.tla.toolbox.product.standalone/examples/Queens.zip differ diff --git a/org.lamport.tla.toolbox.product.standalone/plugin.xml b/org.lamport.tla.toolbox.product.standalone/plugin.xml index 76d7299e36ff4bf97d6c4c58f9d62be810653caf..f711ae8773c3b89b4c4076ed4626e773a75fb86d 100644 --- a/org.lamport.tla.toolbox.product.standalone/plugin.xml +++ b/org.lamport.tla.toolbox.product.standalone/plugin.xml @@ -30,7 +30,7 @@ </property> <property name="aboutText" - value="TLA+ Toolbox provides a user interface for TLA+ Tools. 

This is Version 1.5.7 of 18 July 2018 and includes:
 - SANY Version 2.1 of 23 July 2017
 - TLC Version 2.13 of 18 July 2018
 - PlusCal Version 1.8 of 16 May 2018
 - TLATeX Version 1.0 of 20 September 2017

Don't forget to click on help. You can learn about features that you never knew about or have forgotten.

Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus ."> + value="TLA+ Toolbox provides a user interface for TLA+ Tools. 

This is Version 1.6.0 of 10 July 2019 and includes:
 - SANY Version 2.1 of 23 July 2017
 - TLC Version 2.14 of 10 July 2019
 - PlusCal Version 1.9 of 10 July 2019
 - TLATeX Version 1.0 of 20 September 2017

Don't forget to click on help. You can learn about features that you never knew about or have forgotten.

Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus .

Some icons used in the Toolbox were provided by www.flaticon.com"> </property> <property name="aboutImage" diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/WindowUtils.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/WindowUtils.java index 9d48dfde9a465b1324662ffad4bee3a73e05dc98..a1fb814b76b653d20c550a5a0bf01d6eb713df15 100644 --- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/WindowUtils.java +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/WindowUtils.java @@ -1,8 +1,5 @@ package org.lamport.tla.toolbox; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.internal.WorkbenchWindow; - /** * Window toolkit * @author Simon Zambrovski diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/preferences/AutomaticUpdatesPreferencePage.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/preferences/AutomaticUpdatesPreferencePage.java index 53774ab236c1fbd9252bbaf85f7ca2c82f8f6eb7..642c96c9640b6c058a5cf33f15183575f7d41c93 100644 --- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/preferences/AutomaticUpdatesPreferencePage.java +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/preferences/AutomaticUpdatesPreferencePage.java @@ -59,6 +59,7 @@ import org.eclipse.ui.PlatformUI; * @since 3.4 * */ +@SuppressWarnings("restriction") public class AutomaticUpdatesPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { private Button enabledCheck; diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java index e8f4c6e1529f457d6eb328f2b36bab31a631d282..2d6c6cd3b2bd2e82e6f816f8f9714d1684a62299 100644 --- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java @@ -25,31 +25,56 @@ ******************************************************************************/ package org.lamport.tla.toolbox.ui.intro; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.NotEnabledException; +import org.eclipse.core.commands.NotHandledException; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.common.NotDefinedException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ColorDescriptor; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.help.IWorkbenchHelpSystem; import org.eclipse.ui.intro.IIntroPart; import org.eclipse.ui.part.IntroPart; +import org.lamport.tla.toolbox.StandaloneActivator; +import org.lamport.tla.toolbox.util.ZipUtil; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; @@ -75,15 +100,12 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { // the outerContainer Composite is disposed. final LocalResourceManager localResourceManager = new LocalResourceManager(JFaceResources.getResources(), outerContainer); - - final GridLayout gridLayout = new GridLayout(); - gridLayout.numColumns = 2; - outerContainer.setLayout(gridLayout); - final Color backgroundColor = localResourceManager + Color backgroundColor = localResourceManager .createColor(ColorDescriptor.createFrom(new RGB(255, 255, 228))); outerContainer.setBackground(backgroundColor); /* Logo */ + outerContainer.setLayout(new GridLayout(2, false)); final Label lblImage = new Label(outerContainer, SWT.NONE); lblImage.setText("Invisible text"); final Bundle bundle = FrameworkUtil.getBundle(ToolboxIntroPart.class); @@ -93,6 +115,7 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { /* Welcome header */ final Label lblHeader = new Label(outerContainer, SWT.WRAP); + lblHeader.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, true, false, 1, 1)); // Double its font size final FontDescriptor headerFontDescriptor = JFaceResources.getHeaderFontDescriptor(); @@ -101,8 +124,6 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { // Color value (taken from old style.css) lblHeader.setForeground(localResourceManager.createColor(new RGB(0, 0, 192))); - - lblHeader.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, true, false, 1, 1)); lblHeader.setText("Welcome to the TLA\u207A Toolbox"); lblHeader.setBackground(backgroundColor); @@ -112,70 +133,305 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { lblSeparator.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); final StyledText styledWhatIsNext = new StyledText(outerContainer, SWT.WRAP | SWT.CENTER); + styledWhatIsNext.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); styledWhatIsNext.setBackground(backgroundColor); final String whatIsnext = "There is no specification open. Click on Help if you're not sure what you should do next."; + final int indexOfHelp = whatIsnext.indexOf("Help"); + final int lengthOfHelp = "Help".length(); styledWhatIsNext.setText(whatIsnext); - GridData gd_styledWhatIsNext = new GridData(GridData.FILL_HORIZONTAL); - gd_styledWhatIsNext.horizontalAlignment = SWT.LEFT; - gd_styledWhatIsNext.horizontalSpan = 2; - styledWhatIsNext.setLayoutData(gd_styledWhatIsNext); StyleRange winStyle = new StyleRange(); winStyle.underline = true; winStyle.underlineStyle = SWT.UNDERLINE_LINK; - int[] winRange = { whatIsnext.indexOf("Help"), "Help".length() }; + int[] winRange = { indexOfHelp, lengthOfHelp }; StyleRange[] winStyles = { winStyle }; styledWhatIsNext.setStyleRanges(winRange, winStyles); // link styled text to getting started guide styledWhatIsNext.addListener(SWT.MouseDown, new Listener() { public void handleEvent(Event event) { - IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem(); - helpSystem.displayHelpResource("/org.lamport.tla.toolbox.doc/html/contents.html"); + // Only open help if user clicked on "Help" substring of whatIsNext. + final int oap = styledWhatIsNext.getOffsetAtPoint(new Point (event.x, event.y)); + if (indexOfHelp <= oap && oap <= indexOfHelp + lengthOfHelp) { + IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem(); + helpSystem.displayHelpResource("/org.lamport.tla.toolbox.doc/html/contents.html"); + } } }); /* Getting started text */ final StyledText styledGettingStarted = new StyledText(outerContainer, SWT.WRAP | SWT.CENTER); + styledGettingStarted.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); styledGettingStarted.setBackground(backgroundColor); final String lblString = "If this is the first time you have used the Toolbox, please read the Getting Started guide."; + final int indexOfGettingStarted = lblString.indexOf("Getting Started"); + final int lengthGettingStarted = "Getting Started".length(); styledGettingStarted.setText(lblString); - GridData gd_styledGettingStarted = new GridData(GridData.FILL_HORIZONTAL); - gd_styledGettingStarted.horizontalAlignment = SWT.LEFT; - gd_styledGettingStarted.horizontalSpan = 2; - styledGettingStarted.setLayoutData(gd_styledGettingStarted); - new Label(outerContainer, SWT.NONE); - new Label(outerContainer, SWT.NONE); StyleRange style = new StyleRange(); style.underline = true; style.underlineStyle = SWT.UNDERLINE_LINK; - int[] range = { lblString.indexOf("Getting Started"), "Getting Started".length() }; + int[] range = { indexOfGettingStarted, lengthGettingStarted }; StyleRange[] styles = { style }; styledGettingStarted.setStyleRanges(range, styles); // link styled text to getting started guide styledGettingStarted.addListener(SWT.MouseDown, new Listener() { public void handleEvent(Event event) { - IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem(); - helpSystem.displayHelpResource("/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html"); + final int oap = styledGettingStarted.getOffsetAtPoint(new Point(event.x, event.y)); + if (indexOfGettingStarted <= oap && oap <= indexOfGettingStarted + lengthGettingStarted) { + IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem(); + helpSystem.displayHelpResource( + "/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html"); + } } }); - - /* Toolbox version */ + final Label verticalFillUp = new Label(outerContainer, SWT.NONE); verticalFillUp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true, 2, 1)); verticalFillUp.setBackground(backgroundColor); + + /* Examples */ + + final StyledText styledExamples = new StyledText(outerContainer, SWT.WRAP | SWT.CENTER); + styledExamples.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 2, 1)); + styledExamples.setBackground(backgroundColor); + String exampleText = "Clicking on one of the buttons below imports an introductory example into the " + + "Toolbox. More examples can be found in the TLA+ examples repository.\nTo run the TLC model " + + "checker on an example spec, open one of its models by double-clicking on it in the Spec " + + "Explorer on the left."; + final int indexOfExamples = exampleText.indexOf("TLA+ examples repository"); + final int lengthOfExamples = "TLA+ examples repository".length(); + styledExamples.setText(exampleText); + + int[] exampleRange = { indexOfExamples, lengthOfExamples }; + styledExamples.setStyleRanges(exampleRange, styles); + styledExamples.addListener(SWT.MouseDown, new Listener() { + public void handleEvent(Event event) { + final int oap = styledExamples.getOffsetAtPoint(new Point(event.x, event.y)); + if (indexOfExamples <= oap && oap <= indexOfExamples + lengthOfExamples) { + try { + PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser() + .openURL(new URL("https://github.com/tlaplus/Examples")); + } catch (PartInitException | MalformedURLException e) { + StandaloneActivator.getDefault().getLog() + .log(new Status(Status.ERROR, StandaloneActivator.PLUGIN_ID, e.getMessage(), e)); + } + } + } + }); + + new Label(outerContainer, SWT.NONE); + + Composite examples = new Composite(outerContainer, SWT.NONE); + examples.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); + examples.setLayout(new GridLayout(7, true)); + examples.setBackground(backgroundColor); + + Label lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + backgroundColor = localResourceManager.createColor(ColorDescriptor.createFrom(new RGB(255, 255, 245))); + + // https://github.com/tlaplus/Examples/tree/master/specifications/MissionariesAndCannibals + Button btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setText("Missionaries and Cannibals\n(TLA+)"); + btnNewButton.setData(specKey, "MissionariesAndCannibals.tla"); + btnNewButton.setData(zipKey, "examples/MissionariesAndCannibals.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + // From https://en.wikipedia.org/wiki/Missionaries_and_cannibals_problem + btnNewButton.setToolTipText( + "Three missionaries and three cannibals must cross a river using a boat which can carry at most two people," + + " under the constraint that, for both banks, if there are missionaries present on the bank, they " + + "cannot be outnumbered by cannibals (if they were, the cannibals would eat the missionaries). " + + "The boat cannot cross the river by itself with no people on board."); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // https://github.com/tlaplus/Examples/tree/master/specifications/N-Queens + btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setText("N Queens\n(TLA+)"); + btnNewButton.setData(specKey, "Queens.tla"); + btnNewButton.setData(zipKey, "examples/Queens.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + // Wording adopted from https://en.wikipedia.org/wiki/Eight_queens_puzzle + btnNewButton.setToolTipText( + "The N queens puzzle is the problem of placing N chess queens on an N×N chessboard so that no two " + + "queens threaten each other."); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // https://github.com/tlaplus/Examples/tree/master/specifications/N-Queens + btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setData(specKey, "QueensPluscal.tla"); + btnNewButton.setData(zipKey, "examples/Queens.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + btnNewButton.setText("N Queens\n(PlusCal)"); + // Wording adopted from https://en.wikipedia.org/wiki/Eight_queens_puzzle + btnNewButton.setToolTipText( + "The N queens puzzle is the problem of placing N chess queens on an N×N chessboard so that no two " + + "queens threaten each other."); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // second row + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 7, 1)); +// +// // third row +// +// lbl = new Label(examples, SWT.NONE); +// lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// +// // https://github.com/tlaplus/Examples/tree/master/specifications/Prisoners +// btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); +// btnNewButton.setBackground(backgroundColor); +// btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// btnNewButton.setAlignment(SWT.CENTER); +// btnNewButton.setText("Prisoners\n(TLA+, Liveness)"); +// btnNewButton.setData(specKey, "Prisoners.tla"); +// btnNewButton.setData(zipKey, "examples/Prisoners.zip"); +// btnNewButton.addSelectionListener(selectionAdapter); +// btnNewButton.setToolTipText( +// "The warden of a prison gives his prisoners the following problem. There is a room in the prison with two switches, labeled A and B. Each switch can be either up or down. Every so often, the warden will select a prisoner at random and take him into the room, where he must flip (change the position of) exactly one of the switches. The only guarantee he makes is that every prisoner will eventually be brought into the room multiple times. (More precisely, there will never be a time after which some prisoner is never again brought into the room.) \n" +// + " \n" +// + "At any time, any prisoner may declare that all the prisoners have been in the room at least once. If that prisoner is right, then all the prisoners go free. If he is wrong, all the prisoners are immediately executed. \n" +// + " \n" +// + "The prisoners are allowed to decide upon a strategy, after which they will not be allowed to communicate with one another. And, of course, they cannot see the room or who is being brought into it. What do they do?"); +// +// lbl = new Label(examples, SWT.NONE); +// lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// +// // https://github.com/tlaplus/Examples/tree/master/specifications/tower_of_hanoi +// // Download archive via: https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/tower_of_hanoi&fileName=Hanoi&rootDirectory=false +// btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); +// btnNewButton.setBackground(backgroundColor); +// btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// btnNewButton.setAlignment(SWT.CENTER); +// btnNewButton.setData(specKey, "Hanoi.tla"); +// btnNewButton.setData(zipKey, "examples/Hanoi.zip"); +// btnNewButton.addSelectionListener(selectionAdapter); +// btnNewButton.setText("Towers of Hanoi\n(TLA+)"); +// // From https://en.wikipedia.org/wiki/Tower_of_Hanoi +// btnNewButton.setToolTipText( +// "The Tower of Hanoi is a mathematical game or puzzle. It consists of three rods and a number of disks of different sizes, which can slide onto any rod. The puzzle starts with the disks in a neat stack in ascending order of size on one rod, the smallest at the top, thus making a conical shape.\n" + +// "\n" + +// "The objective of the puzzle is to move the entire stack to another rod, obeying the following simple rules:\n" + +// "\n" + +// " - Only one disk can be moved at a time.\n" + +// " - Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty rod.\n" + +// " - No larger disk may be placed on top of a smaller disk.\n" + +// "\n" + +// "With 3 disks, the puzzle can be solved in 7 moves. The minimal number of moves required to solve a Tower of Hanoi puzzle is 2n − 1, where n is the number of disks. "); +// +// lbl = new Label(examples, SWT.NONE); +// lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// +// // https://github.com/tlaplus/Examples/tree/master/specifications/allocator +// btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); +// btnNewButton.setBackground(backgroundColor); +// btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// btnNewButton.setAlignment(SWT.CENTER); +// btnNewButton.setText("Simple Allocator\n(PlusCal)"); +// btnNewButton.setData(specKey, "SimpleAllocator.tla"); +// btnNewButton.setData(zipKey, "examples/SimpleAllocator.zip"); +// btnNewButton.addSelectionListener(selectionAdapter); +// btnNewButton.setToolTipText( +// "Specification of an allocator managing a set of resources:\n" +// + "- Clients can request sets of resources whenever all their previous requests have been satisfied.\n" +// + "- Requests can be partly fulfilled, and resources can be returned even before the full request has been satisfied. However, clients only have an obligation to return resources after they have obtained all resources they requested."); +// +// lbl = new Label(examples, SWT.NONE); +// lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// +// // fourth row +// +// lbl = new Label(examples, SWT.NONE); +// lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 7, 1)); + + // fifth row + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // https://github.com/tlaplus/Examples/tree/master/specifications/ewd840 + btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setText("Termination Detection\n(TLA+)"); + btnNewButton.setData(specKey, "EWD840.tla"); + btnNewButton.setData(zipKey, "examples/EWD840.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + btnNewButton.setToolTipText( + "A specification of Dijkstra's algorithm for termination detection in a ring. The algorithm was published as Edsger W. Dijkstra: Derivation of a termination detection algorithm for distributed computations. Inf. Proc. Letters 16:217-219 (1983)."); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // https://github.com/tlaplus/Examples/tree/master/specifications/ewd840 + btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setText("Termination Detection\n(TLAPS)"); + btnNewButton.setData(specKey, "EWD840_proof.tla"); + btnNewButton.setData(zipKey, "examples/EWD840.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + btnNewButton.setToolTipText( + "A specification of Dijkstra's algorithm for termination detection in a ring. The algorithm was published as Edsger W. Dijkstra: Derivation of a termination detection algorithm for distributed computations. Inf. Proc. Letters 16:217-219 (1983)."); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // https://github.com/tlaplus/Examples/tree/master/specifications/dijkstra-mutex + btnNewButton = new Button(examples, SWT.WRAP | SWT.FLAT); + btnNewButton.setBackground(backgroundColor); + btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + btnNewButton.setAlignment(SWT.CENTER); + btnNewButton.setText("Dijkstra Mutex\n(PlusCal)"); + btnNewButton.setData(specKey, "DijkstraMutex.tla"); + btnNewButton.setData(zipKey, "examples/DijkstraMutex.zip"); + btnNewButton.addSelectionListener(selectionAdapter); + btnNewButton.setToolTipText( + "This is a PlusCal version of the first published mutual exclusion algorithm, which appeared in\n" + + "\n" + + "E. W. Dijkstra\n" + + "\"Solution of a Problem in Concurrent Programming Control\" \n" + + "Communications of the ACM 8, 9 (September 1965) page 569"); + + lbl = new Label(examples, SWT.NONE); + lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // a little bit of space. + new Label(outerContainer, SWT.NONE); + new Label(outerContainer, SWT.NONE); + + /* Toolbox version */ + final Label horizontalLine = new Label(outerContainer, SWT.SEPARATOR | SWT.HORIZONTAL); horizontalLine.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1)); final Label lblVersion = new Label(outerContainer, SWT.WRAP); lblVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1)); - lblVersion.setText("Version 1.5.7 of 18 July 2018"); + lblVersion.setText("Version 1.6.0 of 10 July 2019"); lblVersion.setBackground(backgroundColor); } @@ -187,4 +443,98 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { public void setFocus() { container.setFocus(); } + + private static final String specKey = "tla-spec"; + private static final String zipKey = "tla-zip"; + + private static SelectionAdapter selectionAdapter = new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent se) { + + final String spec = (String) se.widget.getData(specKey); + final String zip = (String) se.widget.getData(zipKey); + + final URL resource = StandaloneActivator.getDefault().getBundle().getResource(zip); + final Location instanceLocation = Platform.getInstanceLocation(); + + try { + // Force-open the getting started guide that new users should read. + final Map<String, String> params = new HashMap<>(); + params.put("org.lamport.tla.toolbox.doc.contents.param", + "/org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html"); + runCommand("org.lamport.tla.toolbox.doc.contents", params); + + // TODO If the zip is large, this will block the main/UI thread. + final File destDir = ZipUtil.unzip(resource.openStream(), + new File(instanceLocation.getURL().getFile() + File.separator + spec.replaceFirst(".tla$", "")), + true); + + params.clear(); + params.put("toolbox.command.spec.new.param", destDir.getAbsolutePath() + File.separator + spec); + runCommand("toolbox.command.spec.new", params); + + } catch (IOException ex) { + StandaloneActivator.getDefault().logError(ex.getMessage(), ex); + } + } + + private Object runCommand(String commandId, Map<String, String> parameters) { + // Do not rely on the UI to be up and running when trying to execute a + // command + IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); + ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + + // Guard against NPEs anyway (e.g. some asynchronous jobs might try to + // run a + // command after shutdown has been called on the workbench in which case + // either service might be null + if (handlerService == null || commandService == null) { + StandaloneActivator.getDefault().logInfo( + "No IHandlerService|ICommandService available while trying to execute a command"); + return null; + } + + try { + Command command = commandService.getCommand(commandId); + ParameterizedCommand pCommand = ParameterizedCommand.generateCommand(command, parameters); + return handlerService.executeCommand(pCommand, null); + } catch (NotDefinedException e) { + StandaloneActivator.getDefault().logError(e.getMessage(), e); + } catch (NotEnabledException e) { + StandaloneActivator.getDefault().logError(e.getMessage(), e); + } catch (NotHandledException e) { + StandaloneActivator.getDefault().logError(e.getMessage(), e); + } catch (ExecutionException e) { + MessageDialog.openError(Display.getCurrent().getActiveShell(), "Failed to execute.", e.getMessage()); + StandaloneActivator.getDefault().logError(e.getMessage(), e); + } + + return null; + } + }; + + /* +## tower_of_hanoi Hanoi +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/tower_of_hanoi&fileName=Hanoi&rootDirectory=false + +## Prisoners Prisoners.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/Prisoners&fileName=Prisoners&rootDirectory=false + +## MissionariesAndCannibals MissionariesAndCannibals.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/MissionariesAndCannibals&fileName=MissionariesAndCannibals&rootDirectory=false + +## N-Queens Queens.tla +## N-Queens QueensPluscal.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/N-Queens&fileName=Queens&rootDirectory=false + +## dijkstra-mutex DijkstraMutex.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/dijkstra-mutex&fileName=DijkstraMutex&rootDirectory=false + +## allocator SimpleAllocator.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/allocator&fileName=SimpleAllocator&rootDirectory=false + +## ewd840 EWD840.tla EWD840_proof.tla +https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/tlaplus/Examples/tree/master/specifications/ewd840&fileName=EWD840&rootDirectory=false + */ } diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/util/ZipUtil.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/util/ZipUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..b6b662329d8f7ada4197b9a91049504ea7455e0e --- /dev/null +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/util/ZipUtil.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.util; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class ZipUtil { + + public static boolean isArchive(final String filePath) { + final File file = new File(filePath); + try { + final String probeContentType = Files.probeContentType(file.toPath()); + if (probeContentType != null && probeContentType.equals("application/zip")) { + return true; + } + } catch (final IOException intentionallyIgnored) { + } + return false; + } + + public static File unzip(final File zipFilePath, File destDir, boolean unique) throws IOException { + return unzip(new FileInputStream(zipFilePath), destDir, unique); + } + + public static File unzip(final InputStream zip, File destDir, boolean unique) throws IOException { + if (unique) { + while (destDir.exists()) { + // append suffix if another spec in the same directory already exists. This might append it multiple times. + destDir = new File(destDir + "_" + System.currentTimeMillis()); + } + destDir.mkdirs(); + } + final ZipInputStream zipIn = new ZipInputStream(zip); + + ZipEntry entry = zipIn.getNextEntry(); + while (entry != null) { + final String filePath = destDir + File.separator + entry.getName(); + final File file = new File(filePath); + if (entry.isDirectory()) { + file.mkdir(); + } else { + if (file.getParentFile() != null && !file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + // Better use Apache Commons IOUtils similar to PayloadHelper + final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); + final byte[] bytesIn = new byte[4096]; + int read = 0; + while ((read = zipIn.read(bytesIn)) != -1) { + bos.write(bytesIn, 0, read); + } + bos.close(); + } + zipIn.closeEntry(); + entry = zipIn.getNextEntry(); + } + + zipIn.close(); + + return destDir; + } +} diff --git a/org.lamport.tla.toolbox.product.uitest/.project b/org.lamport.tla.toolbox.product.uitest/.project new file mode 100644 index 0000000000000000000000000000000000000000..8c64df2960df631487e1489e14ad7212d497f0d8 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.lamport.tla.toolbox.product.uitest</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.rcptt.core.builder.q7Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.rcptt.core.rcpttnature</nature> + </natures> + <filteredResources> + <filter> + <id>1550702016861</id> + <name></name> + <type>10</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-true-false-target</arguments> + </matcher> + </filter> + </filteredResources> +</projectDescription> diff --git a/org.lamport.tla.toolbox.product.uitest/ECL-SMOKE-PROCS.ctx b/org.lamport.tla.toolbox.product.uitest/ECL-SMOKE-PROCS.ctx new file mode 100644 index 0000000000000000000000000000000000000000..b242a893f90767f17353c4542a58a83901ce0235 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/ECL-SMOKE-PROCS.ctx @@ -0,0 +1,185 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Context-Type: org.eclipse.rcptt.ctx.ecl +Element-Name: ECL-SMOKE-PROCS +Element-Type: context +Element-Version: 2.0 +Id: _DSUP8P5YEeilFekyyVb9lA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/27/19, 1:36 PM + +------=_.ecl.context-718f04b4-ed39-33e3-af62-0995e4561998 +Content-Type: text/ecl +Entry-Name: .ecl.context + +// For future people trying to figure out what is going on with temp directory names; "${rnd.tmp.dir}" is looked-for +// and substituted, in NewSpecWizardPage. + +// Set up the app window; remove all existing specs from the Spec Explorer; create a new spec with the default name +proc "OpenTLACreateNew" +{ + try -command { + SetUpAppWindow + DeleteSpecNew + } + -finally { + CreateNewSpec $TLA-File + } +} + +// Create a spec with a given name +proc "CreateNewSpec" [val fileName -input] +{ + get-menu -path "File/Open Spec/Add New Spec..." | click + get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] + | set-text [concat "${rnd.tmp.dir}" [get-java-property "file.separator"] $fileName] + with [get-window -class WizardDialog] { + get-label "New TLA+ Specification" | get-property caption | equals "New TLA+ Specification" | verify-true + with [get-button "Finish"] { + get-property enablement | equals true | verify-true + get-property caption | equals "&Finish" | verify-true + } + } + get-window -class WizardDialog | get-button Finish | click +} + +// set up main window +proc "SetUpAppWindow" +{ + get-eclipse-window | get-object | invoke setSize 1400 1024 + try { + get-view "Spec Explorer" + } -catch { + // couldn't get the view because it was in a minimzed couplet - close the errant open second welcome view + try { + get-view "Welcome View" | close + } -catch { } + } +} + +// Adds a new, additional, module in an already open specification +proc "AddModule" +{ + // "tla.rcptt.spec.dir" is set in NewSpecWizardPage when a spec with "${rnd.tmp.dir}" is made + set-dialog-result File [concat [get-java-property "tla.rcptt.spec.dir"] [get-java-property "file.separator"] $TLA-ADDITIONAL-MODULE-NAME-FILE] + get-menu -path "File/Open Module/Add TLA+ Module..." | click + with [get-window -text "TLA+ Module is not found"] { + get-button "Yes" | click + } +} + +// Do not call this unless the model editor is the active editor part +proc "wait-run" +{ + //verify that after you run the model that it waits until it completes + try -times 50 -delay 1200 -command { + with [get-button "Runs TLC on the model."] { + get-property enablement | equals true | verify-true + get-property tooltip | equals "Runs TLC on the model." | verify-true + } + } +} + +proc "wait-te" +{ + try -times 50 -delay 1200 -command { + with [get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button Restore] { + get-property enablement | equals true | verify-true + } + } +} + +// Delete all specs in the spec explorer - TODO name this proc more appropriately +proc "DeleteSpecNew" +{ + //MAK 04/25/2019: Removed seemingly bogus calls to parse spec & module during deletion. + //get-menu -path "File/Parse Spec" | click + //get-menu -path "File/Parse Module" | click + + with [get-view "Spec Explorer" | get-tree] { + collapse-all + get-items | foreach { + let [val item -input] { + format "project %s" [$item | get-property "caption" -raw] | log + get-view "Spec Explorer" | get-tree | select $item | get-menu -path "Delete" | click + get-window "Delete specification?" | get-button "Yes" | get-property caption | equals "&Yes" | verify-true + get-window "Delete specification?" | get-button "Yes" | click + } + } + } +} + + +// Create an invalid Spec +proc "CreateInvalidSpec" +{ + try -command { + SetUpAppWindow + get-menu -path "File/Open Spec/Add New Spec..." | click + get-window -class WizardDialog | get-editbox -after [get-label "New TLA+ Specification"] | get-property text + | equals "Creates a new TLA+ specification\n" + + "Enter a complete file name like c:\\jones\\specs\\foo.tla or click on Browse." | verify-true + get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text $TLA-BAD-DIR + with [get-window -class WizardDialog] { + get-editbox -after [get-label "New TLA+ Specification"] | get-property text + | equals "Root file name should have a file-system path and extension .tla" | verify-true + get-button Finish | get-property enablement | equals false | verify-true + } + } + -finally { + get-window -class WizardDialog | get-button Cancel | click + } +} + + +// Create a new spec with a long name +proc "OpenTLACreateNewLongName" +{ + SetUpAppWindow + get-menu -path "File/Open Spec/Add New Spec..." | click + //get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text [concat "${rnd.tmp.dir}" "\\" $TLA-File-Long] + get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text [concat "${rnd.tmp.dir}" [get-java-property "file.separator"] $TLA-File-Long] + //get-by-os + get-window -class WizardDialog | get-button Finish | get-property grayed | equals false | verify-true + get-window -class WizardDialog | get-button Finish | click + get-view "Spec Explorer" | get-tree | get-property itemCount | equals 1 | verify-true +} + + +// Create ten new models +proc "CreateTenNewModels" +{ + repeat -times 10 -command { + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + wait -ms 1000 + } +} + + +// Given a tree, does is there an item with the given path that exists? +proc "has-item" [val tree -input] [val item] +{ + try { + $tree | get-item $item + bool true + } -catch { + bool false + } +} + + +// Given the name of an editor, does is it exist in the workbench? +proc "editor-exists" [val editorName] +{ + try { + get-editor $editorName + bool true + } -catch { + bool false + } +} + +------=_.ecl.context-718f04b4-ed39-33e3-af62-0995e4561998-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test new file mode 100644 index 0000000000000000000000000000000000000000..4a5a000f74faf0042dc349716c9d16d40ad1219b --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test @@ -0,0 +1,66 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Example +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _0133MAldEem_kewt0eDFQIQ +Runtime-Version: 2.4.2.201905122359 +Save-Time: 5/29/19, 9:02 PM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +try -command { + // Create new spec from build-in example. + get-view "Welcome View" | get-button "Missionaries and Cannibals(TLA+)" | click + get-window -class WizardDialog | get-button Finish | click + get-view "Spec Explorer" | get-tree | select "MissionariesAndCannibals \\[ MissionariesAndCannibals.tla \\]/model" + + "s/Model_1" | double-click + + // Run model checking. + get-editor Model_1 | get-button "Runs TLC on the model." | click + + // wait for model checking to finish. + wait-run + + // validate the error trace. + get-view "TLC Errors" | get-section "Error-Trace" | get-button "Toggle between expand and collapse all (Shift+Cli" + + "ck to restore the default two-level expansion)" | click + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-property itemCount | equals 12 | verify-true + + // Expand the Error-Trace Exploration section if collapsed. + if [get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-property "isExpanded()" -raw | not ]{ + get-view "TLC Errors" | get-section "Error-Trace Exploration" | click + } + + // Insert new trace explorer expression. + get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button Add | click + try -command { + with [get-window -class WizardDialog] { + with [get-text-viewer] { + type-text "selfRef == _TETrace[_TEPosition]" + } + get-button Finish | click + } + } -catch { + // This probably means that the section is collapsed instead of expanded. + log -message "Error" -severity error -plugin "org.lamport.tla.toolbox.product.uitests" + echo "Failed to open the Error-Trace Exploration expression input dialog" | log -severity warning + } + + // Run trace exploration. + get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button Explore | click + + wait-te + + // Validate error trace exploration + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 6 0 | click + get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | contains "[bank_of_boat |" + + "-> \"W\", who_is_on_bank |-> [E |-> {" | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test new file mode 100644 index 0000000000000000000000000000000000000000..21bf35c7b2bb7aa8ac888ba9967f8075dfdad884 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test @@ -0,0 +1,156 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Test1 +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _1OLRMAlXEem_pLt0eVfQIQ +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 8:58 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +End to End Test + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type Enter -times 1 + type-text "Spec == Init /\ [][Next]_x" + +Invariant: x<10 +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals, Sequences" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type Enter -times 1 + type-text "Spec == Init /\ [][Next]_x" + key-type Enter -times 1 + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + with [get-editor "Model_1" | get-section "What to check?"] { + get-button "Deadlock" | uncheck + with [get-section Invariants] { + click + get-button "Add" | click + } + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x<10" + get-button Finish | click + } + get-editor "Model_1" | get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + get-editor "Model_1" | get-section General | get-link "1 Error" | get-property caption | equals "1 Error" | verify-true + with [get-view "TLC Errors"] { + get-text-viewer | get-property text | equals "Invariant x<10 is violated." | verify-true + get-section "Error-Trace" | get-property "getText()" | equals "Error-Trace" | verify-true + } + + with [get-view "TLC Errors" | get-section "Error-Trace" | get-tree] { + get-item -path " <Initial predicate>" | expand + get-cell 2 0 | click + } + + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 2 0 | click + get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ x = 1" + | verify-true + with [get-view "TLC Errors" | get-section "Error-Trace" | get-tree] { + get-item -path " <Next line 6, col 9 to line 6, col 18 of module new>" | expand + get-cell 3 0 | click + } + get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals 1 | verify-true + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 4 0 | click + get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ x = 2" + | verify-true + + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "foo == x \in Nat" + get-button Finish | click + } + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "42 # 23" + get-button Finish | click + } + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "stateNum == _TEPosition" + get-button Finish | click + } + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "sum == LET s[i \in DOMAIN _TETrace] == IF i = 1 THEN 1 ELSE s[i-1] + 1 IN s[stateNum]" + get-button Finish | click + } + + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Explore" | click + } + + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 6 0 | click + get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ 42 # 23 = TRUE\n/\\ foo = TRUE\n/\\ stateNum = 2\n/\\ sum = 2\n/\\ x = 1" + | verify-true + + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Restore" | click + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "bar(n) == x \in Nat" + get-button Finish | click + } + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Explore" | click + } + with [get-window "Parsing error when running trace explorer"] { + with [get-editbox] { + get-property text | equals "***Parse Error***\nWas expecting \"Expression or Instance\"\nEncountered \"Beginning of definition\" in Error-Trace Exploration expression at line 5 and token \"==\" \n\nResidual stack trace follows:\nDefinition starting at line 51, column 1.\nModule body starting at line 5, column 1.\nModule definition starting at line 1, column 1.\n" + | verify-true + } + get-button OK | click +} + +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test new file mode 100644 index 0000000000000000000000000000000000000000..d55e4d418457ebc36cbe2515deb85b95d8a53488 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test @@ -0,0 +1,133 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Test2 +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _0133MAldEem_pLt0eVfQIQ +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 8:59 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +End to End Test + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type Enter -times 1 + type-text "Spec == Init /\ [][Next]_x" + +Invariant: x<10 +Trace Error Eval: x \\in Nat +get-view "TLC Errors" | get-text-viewer | get-property text | equals "TLC threw an unexpected exception.\n" + + "This was probably caused by an error in the spec or model.\n" + + "See the User Output or TLC Console for clues to what happened.\n" + + "The exception was a java.lang.RuntimeException\n" + + ": \n" + + "A state predicate was evaluated to a non-boolean value.\n\n" + + "The error occurred when TLC was evaluating the nested\n" + + "expressions at the following positions:\n" + + " The error call stack is empty." | verify-true +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type Enter -times 1 + type-text "Spec == Init /\ [][Next]_x" + key-type Enter -times 1 + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + with [get-editor "Model_1" | get-section "What to check?"] { + get-button "Deadlock" | uncheck + with [get-section "Invariants"] { + click + get-button "Add" | click + } + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x<10" + get-button "Finish" | click + } + get-editor "Model_1" | get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + get-view "TLC Errors" | get-section "Error-Trace" + | get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" + | click + get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-property itemCount | equals 11 | verify-true + with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] { + get-button "Add" | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x \\in Nat" + wait -ms 1000 + get-button "Finish" | click + } + get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button "Explore" | click + + wait-run +//wait -ms 30000 +//get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-item -path " <Initial predicate>/x \\in Nat" + // | get-property caption | equals "x \\in Nat" | verify-true + with [get-editor "Model_1"] { + get-section "User Output" | click + with [get-tab-folder] { + get-tab-item "Model Overview" | click + get-tab-item "Model Checking Results" | click + get-tab-item "Model Overview" | click + } + with [get-section "What to check?" | get-section Properties] { + click + get-button "Add" | click + } + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "<>[](x - 10)" + get-button "Finish" | click + } + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + with [get-view "TLC Errors" | get-text-viewer] { + get-property enablement | equals true | verify-true + get-property "getBlockSelectionBounds().isEmpty()" | equals false | verify-true + } + + get-view "TLC Errors" | get-section "Error-Trace" + | get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" + | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test new file mode 100644 index 0000000000000000000000000000000000000000..810b9a472e12ee7f8eccd90038daf6c183cb5abe --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test @@ -0,0 +1,77 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Multiple.Model.Run +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _MHpE0ASNEemfpvVZm6oeFA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 8:58 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Execute Multiple Model run (4) Verify success and the count in the tree +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 1000 + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + with [get-editor $TLA-MODEL-ONE] { + get-section "What to check?" | get-button Deadlock | uncheck + get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-button "Runs TLC on the model." | click + } + wait-run + + // The error link should not be visible because there are no errors. + verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" } + get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click + + wait-run + + // The error link should not be visible because there are no errors. + verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" } + get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click + + wait-run + + // The error link should not be visible because there are no errors. + verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" } + get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click + + wait-run + + // The error link should not be visible because there are no errors. + verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" } + get-view "Spec Explorer" | get-tree | get-item -path $TLA-MODEL-ONE-TREE | get-property childCount + | equals 4 | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Suite.suite b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Suite.suite new file mode 100644 index 0000000000000000000000000000000000000000..107c065f14b38f6c4c997b712cddaa0ea5b50a81 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Suite.suite @@ -0,0 +1,20 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Suite +Element-Type: testsuite +Element-Version: 2.0 +Id: _dBfhABB5EemUS_ZdBJsvQg +Manually-Ordered: true +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/8/19 12:43 PM + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8 +Content-Type: text/testcase +Entry-Name: testcase-items + +_1OLRMAlXEem_pLt0eVfQIQ // kind: 'test' name: 'TLA.End.To.End.Test1' path: 'TLA.End.To.End.Test1.test' +_0133MAldEem_pLt0eVfQIQ // kind: 'test' name: 'TLA.End.To.End.Test2' path: 'TLA.End.To.End.Test2.test' +_Jm-wcBB2EemUS_ZdBJsvQg // kind: 'test' name: 'TLA.End.To.End.Test3' path: 'TLA_End_To_End_Test3.test' +_MHpE0ASNEemfpvVZm6oeFA // kind: 'test' name: 'TLA.End.To.End.Multiple.Model.Run' path: 'TLA_End_To_End_Multiple_Model_Run.test' + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8-- diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test new file mode 100644 index 0000000000000000000000000000000000000000..b66cf8144b16b1db72f4af0cdce8200a9038fc8c --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test @@ -0,0 +1,108 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.End.To.End.Test3 +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _Jm-wcBB2EemUS_ZdBJsvQg +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 8:58 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +End to End +type-text "EXTENDS Naturals" + type-text "VARIABLE x" + type-text "Init == x = 11" + type-text "Next == x' = x + 1" + type-text "Spec == Init /\ [][Next]_x" + +No Deadlock +Run, Interrup, verify then delete +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 11" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type Enter -times 1 + type-text "Spec == Init /\ [][Next]_x" + key-type Enter -times 1 + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + with [get-editor "Model_1" | get-section "What to check?"] { + get-button Deadlock | uncheck + with [get-section Invariants] { + click + get-button "Add" | click + } + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x<9" + get-button "Finish" | click + } + + with [get-editor "Model_1"] { + get-section "Model description" | get-text-viewer | type-text "This is a text of end to end" + get-section "What is the model?" | click + get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-button "Recover from checkpoint" | check + } + get-editor "Model_1" | get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true + with [get-editor "Model_1"] { + get-button "Recover from checkpoint" | uncheck + get-button "Checks the model for errors but does not run TLC on it." | click + } + + wait -ms 500 + + get-editor "Model_1" | get-button "Recover from checkpoint" | get-property selected + | equals false | verify-true + with [get-editor "Model_1"] { + with [get-tab-folder] { + get-tab-item "Model Checking Results" | click + } + //get-button "Runs TLC on the model." | click + get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click + } + + wait -ms 500 + + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + with [get-section "What to check?" | get-section Invariants] { + get-table | select "x<9" + get-button Remove | click + } + get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click + } + + wait -ms 500 + + get-editor "Model_1" | get-tab-folder | get-tab-item "Model Overview" | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Long_Name_Spec.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Long_Name_Spec.test new file mode 100644 index 0000000000000000000000000000000000000000..1df7d46d4861753885057eced1c24646a55f8288 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Long_Name_Spec.test @@ -0,0 +1,29 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA-Functional.Long.Name.Spec +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _QZqp4AL8EemtrbArmQOOJA +Runtime-Version: 2.4.0.201902270059 +Save-Time: 5/31/19, 2:50 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Long Name - Boundary Case +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +try -command { + //Create Spec with Long name + OpenTLACreateNewLongName +} -finally { + DeleteSpecNew +} + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test new file mode 100644 index 0000000000000000000000000000000000000000..d963c3b506e0750a2e9be0b99d2d6bf89e76634d --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test @@ -0,0 +1,51 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA-Functional.Tree.Collapse +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _7jq7EAOuEemtrbArmQOOJA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Close +Count Tree items +Double Click to Reopen +Count Items on the tree +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +try -command { +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 2 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type "M1+s" +} +get-view "Spec Explorer" | get-tree | select $TLA-MODEL-NEW | get-menu -path Close | click +get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property childCount | equals 0 + | verify-true +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | double-click +get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property childCount | equals 2 + | verify-true + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test new file mode 100644 index 0000000000000000000000000000000000000000..d91d5b0ab4b8a9cd155c42ef7bb035fa0c30ed36 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test @@ -0,0 +1,100 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Delete.Additional.Module +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _b7FWkFSpEemyiKKvW3h83Q +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 11:55 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +New Spec +Default module specified as + type-text "EXTENDS Naturals" + "VARIABLE x" + "Init == x = 0" + "Next == x' = x + 1" + +Create additional module "Bla" +Add content: + type-text "EXTENDS Naturals" + "VARIABLE x" + "Init == x = 0" + "Next == x' = x + 1" +Don't save +Attempt to delete additional module +Cancel out of dirty save modal +Verify that the module still exists in the tree and the editor is still open +Save module +Attempt to delete additional module +Verify that the module no longer exists in the tree and that no editor exists +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 2 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type "M1+s" + } + + AddModule + + with [get-editor $TLA-ADDITIONAL-MODULE-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE w" + key-type Enter -times 2 + type-text "Init == w = 8" + key-type Enter -times 2 + type-text "Next == w' = (w + 3) % 11" + } + + let [val treePath [concat $TLA-TREE-NAME "/modules/" $TLA-ADDITIONAL-MODULE-NAME]] { + get-view "Spec Explorer" | get-tree | get-item $treePath | select-item | get-menu -path "Delete" | click + get-window "Save Resource" | get-button "Cancel" | click + + if [editor-exists $TLA-ADDITIONAL-MODULE-NAME] { + } -else { + throw-error "Additional module's editor pane is prematurely gone." + } + + with [get-editor $TLA-ADDITIONAL-MODULE-NAME | get-text-viewer] { + key-type "M1+s" + } + + with [get-view "Spec Explorer"] { + get-tree | get-item $treePath | select-item | get-menu -path "Delete" | click + } + + if [get-tree | has-item $treePath] { + throw-error "Additional module still exists in the tree." + } + + if [editor-exists $TLA-ADDITIONAL-MODULE-NAME-FILE] { + throw-error "Additional module's editor pane is still displayed." + } + } +} -finally { + DeleteSpecNew +} + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test new file mode 100644 index 0000000000000000000000000000000000000000..71833b468e53905aa39d5c11fc1cc5553ad3b053 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test @@ -0,0 +1,45 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.File.Property +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _cCrygP25EeiCTvrXzYZPCg +Runtime-Version: 2.4.0.201902010011 +Save-Time: 3/29/19, 3:57 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create TLA +on New -File Select Properties + +Note: Error on dialog as file name does not display +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property caption + | equals $TLA-TREE-NAME | verify-true + get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/modules"] | get-menu -path "New Specification" | click + get-window -class WizardDialog | get-label "New TLA+ Specification" | get-property caption + | equals "New TLA+ Specification" | verify-true + get-window -class WizardDialog | get-button Cancel | click + get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/modules/new"] | get-menu -path Properties + | get-property enablement | equals false | verify-true + get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Properties | click + with [get-window [concat "Properties for " $TLA-SPEC-NAME]] { + get-editbox -after [get-label "Specification root module"] | get-text | length | not-eq 0 | verify-true + get-button "Cancel" | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test new file mode 100644 index 0000000000000000000000000000000000000000..afe38721b0fb227f7d52771855a212456628f0b6 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test @@ -0,0 +1,89 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Help.Menu +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _y2T94AL0EemtrbArmQOOJA +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/10/19, 3:33 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Simple Help Menu Test +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +let [val checkView [get-by-os -macosx "yes" -default "no"]] { + try -command { + get-menu -path "Help/Table of Contents" | click + get-view Help | get-link Contents | get-property caption | equals Contents | verify-true + + get-menu -path "Help/Dynamic Help" | click + get-view Help | get-section "About Help" | get-canvas | get-property text + | equals "Click on any workbench part to show related help topics.\r\n" | verify-true + +// Since commit b3d9edd9760ea9dbcfd4f4f774a0877c4aecdddb these two PDFs are loaded externally. If one knows how to test this, please re-add. +// get-menu -path "Help/Specifying Systems" | click +// if [$checkView | equals "yes"] { +// get-view "Specifying Systems" | click +// } +// -else { +// get-editor "Specifying Systems" | get-canvas | get-property className | equals "de.vonloesch.pdf4eclipse.PDFPageViewer" +// | verify-true +// } +// +// get-menu -path "Help/PlusCal User Manual" | click +// if [$checkView | equals "yes"] { +// get-view "PlusCal Manual" | click +// } +// -else { +// get-editor "PlusCal Manual" | get-canvas | get-property className | equals "de.vonloesch.pdf4eclipse.PDFPageViewer" +// | verify-true +// } + + get-menu -path "Help/The TLA+ Cheat Sheet" | click + if [$checkView | equals "yes"] { + get-view "TLA+ Cheat Sheet" | click + } + -else { + get-editor "TLA+ Cheat Sheet" | get-canvas | get-property className | equals "de.vonloesch.pdf4eclipse.PDFPageViewer" + | verify-true + } + + wait -ms 500 + + if [$checkView | equals "yes"] { +// get-view "Specifying Systems" | close +// get-view "PlusCal Manual" | close + get-view "TLA+ Cheat Sheet" | close + } + -else { +// get-editor "Specifying Systems" | close +// get-editor "PlusCal Manual" | close + get-editor "TLA+ Cheat Sheet" | close + } + + get-view Help | click + with [get-editor $TLA-SPEC-NAME] { + click + click + } + + get-editor $TLA-SPEC-NAME | click + + get-view Help | close + } + -finally { + DeleteSpecNew + } +} + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test new file mode 100644 index 0000000000000000000000000000000000000000..da953c9cb02f8bb411c246a9675ebc144ec2d816 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test @@ -0,0 +1,81 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.New.Model +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _LxG3gAJFEemDc-4PKyNT9w +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:05 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +New Spec +Create Model wit Following Info + type-text "EXTENDS Naturals" + "VARIABLE x" + "Init == x = 0" + "Next == x' = x + 1" + +Run Model +Verify +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 2 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-button "Runs TLC on the model." | click + wait -ms 1000 + + get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click + + + wait-run + + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + get-section "Additional Definitions" | click + get-section "State Constraint" | click + get-section "Model Values" | click + get-section "Definition Override" | click + get-section "Action Constraint" | click + get-button "Checks the model for errors but does not run TLC on it." | click + get-tab-folder | get-tab-item "Model Overview" | click + get-section "What is the model?" | click + get-section "How to run?" | click + } + with [get-editor "Model_1" | get-section "What is the behavior spec?"] { + get-text-viewer | get-property text | equals Init | verify-true + get-text-viewer -after [get-label "Next:"] | get-property text | equals Next | verify-true + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test new file mode 100644 index 0000000000000000000000000000000000000000..e6bd7898cff8c642c9c80ed7e6998a879bc9e723 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test @@ -0,0 +1,28 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Parse.Pref +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _eblOcP23EeiCTvrXzYZPCg +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/9/19 2:14 PM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//New Spec +OpenTLACreateNew +try -command { +get-menu -path "File/Parse Module" | click +get-preferences-menu | click +get-window Preferences | get-label "Automatic Update" | get-property caption | equals "Automatic Update" | verify-true +get-window Preferences | get-button Cancel | click + + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test new file mode 100644 index 0000000000000000000000000000000000000000..efe0dd806c1611402143778ad38e7aa43d04c634 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test @@ -0,0 +1,82 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Temporal.Formula +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _g-dKoAPoEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:02 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +New Spec +Model with Long Name +Deadlock Unchecked +Temopral Formula x=2 +Result: Incomplete +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 1000 + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + with [get-window "New model..."] { + get-editbox -after [get-label "Please input the name of the model to create"] + | set-text $TLA-Long-Model-Name + get-button OK | click + } + with [get-editor $TLA-Long-Model-Name] { + get-section "Model description" | get-text-viewer | type-text tlatlatla + with [get-section "What to check?"] { + get-button "Deadlock" | uncheck + get-section "Invariants" | click + get-section "Properties" | click + } + } + + with [get-editor $TLA-Long-Model-Name] { + with [get-section "What is the behavior spec?"] { + get-combo | select "Temporal formula" + get-text-viewer | type-text "x=2" + } + get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-button "Checks the model for errors but does not run TLC on it." | click + get-button "Runs TLC on the model." | click + } + + wait-run + + with [get-editor $TLA-Long-Model-Name] { + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true + get-link "State space exploration incomplete" | get-property caption | equals "State space exploration incomplete" + | verify-true + } + get-editor $TLA-Long-Model-Name | get-tab-folder | get-tab-item "Model Overview" | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite new file mode 100644 index 0000000000000000000000000000000000000000..c5d744ef5912419c2b79095dc1f89646a28846f5 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite @@ -0,0 +1,50 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Test.Suite +Element-Type: testsuite +Element-Version: 2.0 +Id: _XtCd4APNEemtrbArmQOOJA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 4:39 PM + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8 +Content-Type: text/testcase +Entry-Name: testcase-items + +_QZqp4AL8EemtrbArmQOOJA // kind: 'test' name: 'TLA-Functional.Long.Name.Spec' path: 'TLA-Functional_Long_Name_Spec.test' +_7jq7EAOuEemtrbArmQOOJA // kind: 'test' name: 'TLA-Functional.Tree.Collapse' path: 'TLA-Functional_Tree_Collapse.test' +_44K9cAJWEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Functional.Basic.Model' path: 'TLA_Functional_Basic_Model.test' +_I-Xj0APqEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Clear.Console' path: 'TLA_Functional_Clear_Console.test' +_ARWUAAJjEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Functional.Clone.Model' path: 'TLA_Functional_Clone_Model.test' +_qD9ogAPmEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Deadlock.Unchecked' path: 'TLA_Functional_Deadlock_Unchecked.test' +_dOXZwAJfEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Functional.Exp' path: 'TLA_Functional_Exp.test' +_cCrygP25EeiCTvrXzYZPCg // kind: 'test' name: 'TLA.Functional.File.Property' path: 'TLA.Functional.File.Property.test' +_uAilEAPhEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Find.Replace' path: 'TLA_Functional_Find_Replace.test' +_orbhsAJZEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Functional.Fingerprint' path: 'TLA_Functional_Fingerprint.test' +_y2T94AL0EemtrbArmQOOJA // kind: 'test' name: 'TLA.Functional.Help.Menu' path: 'TLA.Functional.Help.Menu.test' +_myVagAP4EemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Model.Defaults' path: 'TLA_Functional_Model_Defaults.test' +_3CVCoAMFEemtrbArmQOOJA // kind: 'test' name: 'TLA.Functional.Multiple.Models' path: 'TLA_Functional_Multiple_Models.test' +_DliAUAMNEemtrbArmQOOJA // kind: 'test' name: 'TLA.Functional.Multiple.Models.Description' path: 'TLA_Functional_Multiple_Models_Description.test' +_LxG3gAJFEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Functional.New.Model' path: 'TLA.Functional.New.Model.test' +_ntQ8oBB4EemUS_ZdBJsvQg // kind: 'test' name: 'TLA.Functional.NoFormula.Defaults' path: 'TLA_Functional_NoFormula_Defaults.test' +_5O_HkgPuEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Open.More.Editors' path: 'TLA_Functional_Open_More_Editors.test' +_gPS3MAPrEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Open.Saved.Model' path: 'TLA_Functional_Open_Saved_Model.test' +_eblOcP23EeiCTvrXzYZPCg // kind: 'test' name: 'TLA.Functional.Parse.Pref' path: 'TLA.Functional.Parse.Pref.test' +_8o7w0APsEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Run.Details' path: 'TLA_Functional_Run_Details.test' +_Lbbs8AMKEemtrbArmQOOJA // kind: 'test' name: 'TLA.Functional.Spec.Properties' path: 'TLA_Functional_Spec_Properties.test' +_6Vm88APkEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Spec.Properties.Valid' path: 'TLA_Functional_Spec_Properties_Valid.test' +_g-dKoAPoEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Functional.Temporal.Formula' path: 'TLA.Functional.Temporal.Formula.test' +_TZC_4BU2EemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Action.Constraint' path: 'TLA_Functional_Action_Constraint.test' +_ax464BUkEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Check.Model.OnError' path: 'TLA_Functional_Check_Model_OnError.test' +_gOLvABUlEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Clear.Error.Temporal' path: 'TLA_Functional_Clear_Error_Temporal.test' +_1MkFEBUzEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Definition.Override' path: 'TLA_Functional_Definition_Override.test' +_Gvi30BUtEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Distributed.Mode.Options' path: 'TLA_Functional_Distributed_Mode_Options.test' +_7RvKABUnEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Invariant .Formula' path: 'TLA_Functional_Invariant _Formula.test' +_CTEKoBUbEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Links' path: 'TLA_Functional_Links.test' +_EdNeQBUsEemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.Property.Formula' path: 'TLA_Functional_Property_Formula.test' +_HJaIUBU4EemG79v6PBILBA // kind: 'test' name: 'TLA.Functional.TLA.Options.Defaults' path: 'TLA_Functional_TLA_Options_Defaults.test' +_s4DEYBXnEemrGZBXFuwIoA // kind: 'test' name: 'TLA.Functional.Model.Results.Defaults' path: 'TLA_Functional_Model_Results_Defaults.test' +_b7FWkFSpEemyiKKvW3h83Q // kind: 'test' name: 'TLA.Functional.Delete.Additional.Module' path: 'TLA.Functional.Delete.Additional.Module.test' +_JObaIIvTEemXYtOZX2zpng // kind: 'test' name: 'TLA_Functional_ECE_Placement' path: 'TLA_Functional_ECE_Placement.test' + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test new file mode 100644 index 0000000000000000000000000000000000000000..54940b05b30f365a18333885c8d2e9d5d50ad87e --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test @@ -0,0 +1,71 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Action.Constraint +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _TZC_4BU2EemG79v6PBILBA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:03 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Action Constraint +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + wait -ms 1000 + + with [get-editor "Model_1"] { + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + with [get-section "Action Constraint"] { + get-text-viewer | type-text "x=1+5" + } + get-button "Checks the model for errors but does not run TLC on it." | click + } + get-editor "Model_1" | get-section "Action Constraint" | get-text-viewer | get-property text | equals "x=1+5" + | verify-true + with [get-editor "Model_1"] { + with [get-section "Action Constraint" | get-text-viewer] { + set-caret-pos 1 6 + key-type BackSpace -times 5 + type-text badformula + } + get-button "Checks the model for errors but does not run TLC on it." | click + } + with [get-editor "Model_1"] { + get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true + get-section "Action Constraint" | get-text-viewer | get-property text | equals badformula | verify-true + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test new file mode 100644 index 0000000000000000000000000000000000000000..ba6f1be6af104e02adaf5b5808c7eab29bc09ac5 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test @@ -0,0 +1,91 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Basic.Model +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _44K9cAJWEemDc-4PKyNT9w +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:47 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + with [get-editor "Model_1"] { + get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + get-tab-folder | get-tab-item "Model Overview" | click + get-section "How to run?" | click + get-link "Additional TLC Options" | click + get-tab-folder | get-tab-item "Model Overview" | click + get-button "Runs TLC on the model." | click + } + + wait-run + + // The error link should not be visible because there are no errors. + verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" } + with [get-editor "Model_1" | get-tab-folder] { + get-tab-item "Model Overview" | click + get-tab-item "Spec Options" | click + get-tab-item "TLC Options" | click + get-tab-item "Model Checking Results" | click + } + get-editor "Model_1" | close + + // Test the state-saving of open close-able tabs in the model editor: + + get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click + with [get-editor "Model_1" | get-tab-folder] { + get-tab-item "Model Overview" | click + get-tab-item "Spec Options" | click + get-tab-item "TLC Options" | click + get-tab-item "Spec Options" | close + } + get-editor "Model_1" | close + + get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click + with [get-editor "Model_1" | get-tab-folder] { + get-tab-item "Model Overview" | click + get-tab-item "TLC Options" | click + verify-error { get-tab-item "Spec Options" } + get-tab-item "TLC Options" | close + get-tab-item "Model Checking Results" | click + } + get-editor "Model_1" | close + + get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click + with [get-editor "Model_1" | get-tab-folder] { + get-tab-item "Model Overview" | click + verify-error { get-tab-item "TLC Options" } + get-tab-item "Model Checking Results" | click + } + get-editor "Model_1" | close +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test new file mode 100644 index 0000000000000000000000000000000000000000..ccdacc51c9e44f959d9d8a962689c0b58634bdc9 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test @@ -0,0 +1,76 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Check.Model.OnError +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _ax464BUkEemG79v6PBILBA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:12 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Generate Error on Initial Predicate +Verify Error +Click No Behavior +Check Model +Verify No Errors +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + with [get-editor "Model_1"] { + with [get-section "What is the behavior spec?"] { + with [get-text-viewer] { + set-caret-pos 1 5 + key-type BackSpace -times 4 + type-text foo + } + with [get-text-viewer -after [get-label "Next:"]] { + set-caret-pos 1 4 + select-range 1 5 1 1 + type-text no + } + } + get-button "Checks the model for errors but does not run TLC on it." | click + } + get-editor "Model_1" | get-link "2 errors detected" | get-property caption | equals "2 errors detected" | verify-true + with [get-editor "Model_1"] { + get-link "2 errors detected" | click + get-section "What is the behavior spec?" | get-combo | select "No Behavior Spec" + get-button "Checks the model for errors but does not run TLC on it." | click + } + //Verify no error link + get-editor "Model_1" | get-link | get-property caption | equals "2 errors detected" | verify-false +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test new file mode 100644 index 0000000000000000000000000000000000000000..4b2eeb23a20f67273357c743a5324fb5e2b4e351 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test @@ -0,0 +1,68 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Clear.Console +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _I-Xj0APqEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec and Model +Show TLC-Console +Clear +Run Model +Clear Console +Verify that Console is Clear +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x - 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/TLC Console" | click + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait -ms 1000 + //TODO + get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click + + wait-run + + get-editor "Model_1" | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" + | verify-true + with [get-view Console | get-text-viewer] { + set-caret-pos 4 13 + get-menu -path Clear | click + set-caret-pos 1 1 + } + get-view Console | get-text-viewer | get-property text | equals "" | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test new file mode 100644 index 0000000000000000000000000000000000000000..105a0b02b5410fba1c2227bf2682741ce6c62fd3 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test @@ -0,0 +1,68 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Clear.Error.Temporal +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _gOLvABUlEemG79v6PBILBA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + + with [get-editor "Model_1"] { + with [get-section "What is the behavior spec?"] { + get-combo | select "Temporal formula" + get-text-viewer | type-text "x == 1" + } + get-button "Checks the model for errors but does not run TLC on it." | click + with [get-section "What is the behavior spec?" | get-text-viewer ] { + set-caret-pos 1 8 + key-type BackSpace -times 6 + type-text "=2" + } + get-button "Checks the model for errors but does not run TLC on it." | click + get-section "What is the behavior spec?" | get-text-viewer | type-text ";y=1" + get-button "Checks the model for errors but does not run TLC on it." | click + } + get-editor "Model_1" | get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true + with [get-editor "Model_1"] { + with [get-section "What is the behavior spec?" | get-text-viewer ] { + set-caret-pos 1 8 + key-type BackSpace -times 4 + } + get-button "Checks the model for errors but does not run TLC on it." | click + } + + get-editor "Model_1" | get-link | get-property caption | equals "1 error detected" | verify-false +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test new file mode 100644 index 0000000000000000000000000000000000000000..f532fa99b514feeb9bad32d5d9ab560a9478a596 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test @@ -0,0 +1,85 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Clone.Model +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _ARWUAAJjEemDc-4PKyNT9w +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/30/19, 8:38 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x - 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button "OK" | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-editor "Model_1" | get-button "Runs TLC on the model." | click + get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click + + wait-run + + get-editor "Model_1" | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" + | verify-true + get-menu -path "TLC Model Checker/Clone Model/Model_1" | click + get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption + | equals "Please input the new name of the model" | verify-true + get-window "Clone model..." | get-button "OK" | click + + let [val descriptionText "Some description text."] { + with [get-editor "Model_2"] { + with [get-section "Model description"] { + click + with [get-text-viewer] { + type-text $descriptionText + key-type "M1+s" + } + click + } + get-tab-folder | get-tab-item "Model Checking Results" | click + } + + CreateNewSpec "another.tla" + get-menu -path [concat "TLC Model Checker/Clone Model/Foreign Model..."] | click + with [get-window "Please choose a spec and a model"] { + get-list | select $TLA-SPEC-NAME + get-list -index 1 | select "Model_2" + get-button "OK" | click + } + get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption + | equals "Please input the new name of the model" | verify-true + get-window "Clone model..." | get-button "OK" | click + with [get-editor "Model_2"] { + get-tab-folder | get-tab-item "Model Overview" | click + with [get-section "Model description"] { + get-text-viewer | get-text | equals $descriptionText | verify-true + click + } + get-tab-folder | get-tab-item "Model Checking Results" | click + } + get-menu -path "File/Save" | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test new file mode 100644 index 0000000000000000000000000000000000000000..cf7e5a71e392965ffb229a7f3774122d9118e9ac --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test @@ -0,0 +1,77 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Deadlock.Unchecked +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _qD9ogAPmEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 8:59 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +New Spec +Model with Long Name +Deadlock Unchecked +Worker Thread =2 +Physical Memory 4% +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 1000 + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + with [get-window "New model..."] { + get-editbox -after [get-label "Please input the name of the model to create"] + | set-text $TLA-Long-Model-Name + get-button "OK" | click + } + with [get-editor $TLA-Long-Model-Name] { + get-section "Model description" | get-text-viewer | type-text tlatlatla + with [get-section "What to check?"] { + get-button "Deadlock" | uncheck + get-section "Invariants" | click + get-section "Properties" | click + } + get-section "What is the model?" | click + get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-button "Runs TLC on the model." | click + } + + wait-run + + with [get-editor $TLA-Long-Model-Name] { + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true + // The error link should not be visible because there are no errors. + verify-error {get-section General | get-link "No errors" } + } + with [get-editor $TLA-Long-Model-Name | get-tab-folder] { + get-tab-item "Model Overview" | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test new file mode 100644 index 0000000000000000000000000000000000000000..4ba7df263659cd5307d714fb87fc4059d7834b23 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test @@ -0,0 +1,111 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Definition.Override +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _1MkFEBUzEemG79v6PBILBA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:03 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Definition Override +Check several presets, count items, verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + with [get-section "Definition Override"] { + get-button Add | click + } + } + with [get-window "Select Definition to Override"] { + get-table | select [get-item -path "%" -index 0] + get-button OK | click + } + wait -ms 500 + + with [get-window -class WizardDialog] { + get-label "Definition Override" | get-property caption | equals "Definition Override" | verify-true + get-editbox -after [get-label "("] | get-property enablement | equals true | verify-true + } + wait -ms 500 + + with [get-window -class WizardDialog] { + get-editbox -after [get-label "("] | set-text 1 + get-editbox -after [get-label ","] | set-text 1 + get-text-viewer | type-text x + get-button Finish | click + } + wait -ms 500 + + get-editor "Model_1" | get-section "Definition Override" | get-table | get-item -path "%\\(1, 1\\) <- x" + | get-property caption | equals "%(1, 1) <- x" | verify-true + with [get-editor "Model_1" | get-section "Definition Override"] { + get-table | select "%(1, 1) <- x" + get-button Remove | click + } + + with [get-editor "Model_1"] { + get-button "Checks the model for errors but does not run TLC on it." | click + get-section "Definition Override" | get-button Add | click + } + get-window "Select Definition to Override" + | get-label "Type definition to override or select from the list below(?= any character, *= any string)" + | get-property caption | equals "Type definition to override or select from the list below\n" + + "(?= any character, *= any string)" | verify-true + with [get-window "Select Definition to Override"] { + get-table | select Next + get-button OK | click + } + get-window -class WizardDialog | get-label "Definition Override" | get-property caption | equals "Definition Override" + | verify-true + with [get-window -class WizardDialog] { + get-text-viewer | type-text 1 + get-button "Model value" | click + } + get-window -class WizardDialog | get-editbox -after [get-label "<-"] | get-property enablement | equals false + | verify-true + get-window -class WizardDialog | get-button "Ordinary assignment" | click + get-window -class WizardDialog | get-text-viewer | get-property enablement | equals true | verify-true + get-window -class WizardDialog | get-button Finish | click + get-editor "Model_1" | get-section "Definition Override" | get-table | get-property itemCount | equals 1 | verify-true + get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test new file mode 100644 index 0000000000000000000000000000000000000000..be3be856e7e0cbee6e06a38c17924132823ab3d9 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test @@ -0,0 +1,89 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Distributed.Mode.Options +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _Gvi30BUtEemG79v6PBILBA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Run In distributed Mode +Select from options and verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + get-editor "Model_1" | get-section "How to run?" | click + get-editor "Model_1" | get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] + | select "Ad Hoc" + with [get-editor "Model_1" | get-section "How to run?"] { + get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Ad Hoc" | verify-true + // TODO: unable to use ECL to get a spinner presently +// get-control -kind "Spinner" -after [get-label "Number of worker threads:"] | get-property enablement | equals false | verify-true + // TODO: unable to use ECL to get a scale presently +// get-control -kind "Scale" -after [get-label "Fraction of physical memory allocated to TLC:"] | get-property enablement | equals true | verify-true + get-combo -after [get-label "Master's network address:"] | get-property enablement | equals true | verify-true + } + get-editor "Model_1" | get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] + | select "Amazon" + with [get-editor "Model_1" | get-section "How to run?"] { + get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Amazon" | verify-true + with [get-editbox -after [get-label "Result mailto addresses:"]] { + get-property className | equals "org.eclipse.swt.widgets.Text" | verify-true + get-property enablement | equals true | verify-true + } + with [get-label "Result mailto addresses:"] { + get-property enablement | equals true | verify-true + get-property caption | equals "Result mailto addresses:" | verify-true + } + + get-combo -after [get-label "System resources dedicated to TLC:"] | select "Azure" + get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Azure" | verify-true + + get-combo -after [get-label "System resources dedicated to TLC:"] | select "\u2014\u2014 Local \u2014\u2014" + get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Azure" | verify-true + + get-combo -after [get-label "System resources dedicated to TLC:"] | select "\u2014\u2014 Remote \u2014\u2014" + get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Azure" | verify-true + } + + with [get-editor "Model_1"] { + get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] | select "Medium" + get-button "Checks the model for errors but does not run TLC on it." | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test new file mode 100644 index 0000000000000000000000000000000000000000..39bfe0ec8ce5ec48ad7d43a2a7fbdc7a36997e8f --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test @@ -0,0 +1,92 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA_Functional_ECE_Placement +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _JObaIIvTEemXYtOZX2zpng +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/14/19, 10:55 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-button OK | click + with [get-editor "Model_1"] { + get-tab-item "Model Checking Results" | click + with [get-section "Evaluate Constant Expression" | get-text-viewer -after [get-label "Expression:"]] { + type-text "CHOOSE w in {3, 5, 7} : w*w*w = 125" // yes, "in" is invalid but escaping backspaces in the comparison below is quirky + } + } + + get-preferences-menu | click + with [get-window Preferences ] { + get-tree | select "TLA+ Preferences/TLC Model Checker" + get-checkbox -text "Show Evaluate Constant Expression in its own tab" | check + + get-button "Apply and Close" | click + } + + let [val tabTitle [invoke-static + -pluginId "org.lamport.tla.toolbox.tool.tlc.ui" + -className "org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.EvaluateConstantExpressionPage" + -methodName "getTabTitle"]] { + with [get-editor "Model_1"] { + verify-error { get-section "Evaluate Constant Expression" } + get-tab-item $tabTitle | click + with [get-section "Evaluate Constant Expression"] { + get-text-viewer -after [get-label "Expression:"] | get-text | + equals "CHOOSE w in {3, 5, 7} : w*w*w = 125" | verify-true + } + } + + get-preferences-menu | click + with [get-window Preferences ] { + get-tree | select "TLA+ Preferences/TLC Model Checker" + get-checkbox -text "Show Evaluate Constant Expression in its own tab" | uncheck + + get-button "Apply and Close" | click + } + + with [get-editor "Model_1"] { + verify-error { get-tab-item $tabTitle } + get-tab-item "Model Checking Results" | click + with [get-section "Evaluate Constant Expression"] { + get-text-viewer -after [get-label "Expression:"] | get-text | + equals "CHOOSE w in {3, 5, 7} : w*w*w = 125" | verify-true + get-button "No Behavior Spec" | click + get-button "No Behavior Spec" | get-object | invoke getSelection | verify-true + } + get-tab-item "Model Overview" | click + with [get-section "What is the behavior spec?" | get-combo] { + get-text | equals "No behavior spec" | verify-true + select "Temporal formula" + } + get-tab-item "Model Checking Results" | click + get-section "Evaluate Constant Expression" | get-button | get-object | invoke getSelection | verify-false + key-type "M1+s" + } + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test new file mode 100644 index 0000000000000000000000000000000000000000..ef5d3bbd858f64bdf85b7db2415a9249700d18d5 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test @@ -0,0 +1,48 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Exp +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _dOXZwAJfEemDc-4PKyNT9w +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/17/19, 2:45 PM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 3" + key-type Enter -times 2 + type-text "Next == x' = x ^ 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + with [get-editor "Model_1" | get-section General] { + get-label "Fingerprint collision probability: calculated: 5.4E-20" + verify-error {get-link "No errors"} + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test new file mode 100644 index 0000000000000000000000000000000000000000..a904790bac1e395d580b5c27db3f24a324e08c0a --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test @@ -0,0 +1,65 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Find.Replace +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _uAilEAPhEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 11:52 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew +try -command { + + +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 1000 +get-menu -path "TLC Model Checker/TLC Console" | click +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + set-caret-pos 4 7 + hover-text 4 1 + set-caret-pos 4 1 +} +get-menu -path "Edit/Content Assist" | click +get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "\\n" + + "eg: \\n" + + "eg" +get-editor $TLA-SPEC-NAME | get-text-viewer | set-caret-pos 7 1 +get-menu -path "Edit/Content Assist" | click +get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "ACTION : ACTION " +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + set-caret-pos 4 10 + select-range 4 9 4 10 + hover-text 4 9 -with Left +} +get-menu -path "Edit/Find and Replace" | click +with [get-window "Find/Replace"] { + get-combo -after [get-label "Replace with:"] | set-text y + get-button "Replace All" | click + get-button Close | click + +} + + +get-menu -path "File/Parse Spec" | click +get-window "Modified resources" | get-button OK | click + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test new file mode 100644 index 0000000000000000000000000000000000000000..aef79f04f7cfe6001293f715bb330045f833be24 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test @@ -0,0 +1,47 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Fingerprint +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _orbhsAJZEemDc-4PKyNT9w +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/17/19, 2:45 PM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 5" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-editor "Model_1" | get-button "Runs TLC on the model." | click + wait-run + + with [get-editor "Model_1"] { + get-section General | get-label "Fingerprint collision probability: calculated: 5.4E-20" + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test new file mode 100644 index 0000000000000000000000000000000000000000..d14310f396c75a201bf8549ced5fa5ffda2cc5f1 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test @@ -0,0 +1,77 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Invariant .Formula +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _7RvKABUnEemG79v6PBILBA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +On Model enter a Formula on Invariant Section +Remove Formula +Verify formula is gone +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] { + click + get-button Add | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x=1+1" + get-button Finish | click + } + get-editor "Model_1" | get-section "What to check?" | get-section Invariants | get-table | get-item -path "x=1\\+1" + | get-property caption | equals "x=1+1" | verify-true + + with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] { + get-table | select "x=1+1" + get-button Edit | click + } + get-window -class WizardDialog | get-button Cancel | click + with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] { + get-table | select "x=1+1" + get-button Remove | click + } + + //get-editor "Model_1" | get-link | get-property caption | equals "1 error detected" | verify-false + + get-editor "Model_1" | get-section "What to check?" | get-section Invariants | get-table | get-property itemCount + | equals 0 | verify-true + get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test new file mode 100644 index 0000000000000000000000000000000000000000..823fbe789ad047d3e28552dc8fe7fb4d22e1d6bf --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test @@ -0,0 +1,85 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Links +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _CTEKoBUbEemG79v6PBILBA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:04 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Create Model +Verify Links and Activate +Verify that proper navigation takes place +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + with [get-editor "Model_1"] { + get-section "Model description" | get-text-viewer | type-text sample + get-section "What is the model?" | click + get-link "Additional TLC Options" | click + get-editbox -after [get-label "Number of worker threads:"] | set-text 2 + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional Spec Options" | click + } + get-editor "Model_1" | get-section "Additional Definitions" | get-label "Additional Definitions" | get-property caption + | equals "Additional Definitions" | verify-true + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-section "What is the model?" | get-button Edit | click + get-button "Checks the model for errors but does not run TLC on it." | click + get-section "What is the behavior spec?" | get-combo | select "No Behavior Spec" + get-button "Checks the model for errors but does not run TLC on it." | click + get-link "Additional Spec Options" | click + } + get-editor "Model_1" | get-section "State Constraint" | get-label "State Constraint" | get-property caption + | equals "State Constraint" | verify-true + get-editor $TLA-SPEC-NAME | click + with [get-editor "Model_1"] { + click + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional Spec Options" | click + } + get-editor "Model_1" | get-section "Model Values" | get-label "Model Values" | get-property caption + | equals "Model Values" | verify-true + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional TLC Options" | click + get-button "Select randomly" | uncheck + get-button "Checks the model for errors but does not run TLC on it." | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test new file mode 100644 index 0000000000000000000000000000000000000000..30d9e3fa5b420345fccecbedcf2fd9804ae97796 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test @@ -0,0 +1,101 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Model.Defaults +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _myVagAP4EemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:48 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Functional: Verify Model Defaults + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 999999999999999999999999999999999999999" + key-type Enter -times 2 + type-text "Next == x' = x * 999999999999999999999999999999" + key-type "M1+s" + } + wait -ms 1000 + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + with [get-editor "Model_1"] { + get-section "What is the model?" | click + get-section "How to run?" | click + } + with [get-editor "Model_1"] { + with [get-section "What is the behavior spec?"] { + get-text-viewer | get-property text | equals Init | verify-true + get-text-viewer -after [get-label "Next:"] | get-property text | equals Next | verify-true + get-combo | get-property selection | equals "Initial predicate and next-state" | verify-true + } + } + + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional Spec Options" | click + get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true + get-section "Additional Definitions" | click + get-section "State Constraint" | click + get-section "Model Values" | click + get-section "Definition Override" | click + get-section "Action Constraint" | click + get-section "Additional Definitions" | click + get-section "Definition Override" | click + get-section "Model Values" | click + get-section "State Constraint" | click + get-section "Action Constraint" | click | get-text-viewer | get-property text | equals "" | verify-true + } + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional TLC Options" | click + get-button "Model-checking mode" | get-property selected | equals true | verify-true + get-text-viewer | get-property text | equals "" | verify-true + get-button "Depth-first" | get-property selected | equals false | verify-true + get-editbox -after [get-label "Depth:"] | get-property text | equals 100 | verify-true + get-editbox -after [get-label "Maximum length of the trace:"] | get-property text | equals 100 | verify-true + get-button "Simulation mode" | get-property selected | equals false | verify-true + get-editbox -after [get-label "Seed:"] | get-property text | equals "" | verify-true + get-editbox -after [get-label "Aril:"] | get-property text | equals "" | verify-true + get-button "Recover from checkpoint" | get-property selected | equals false | verify-true + get-editbox -after [get-label "Checkpoint ID:"] | get-property text | equals "" | verify-true + get-button "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space." + | get-property selected | equals false | verify-true + get-button "Select randomly" | get-property selected | equals true | verify-true + get-editbox -after [get-label "Fingerprint seed index:"] | get-property text | equals "0.0" | verify-true + get-editbox -after [get-label "Log base 2 of number of disk storage files:"] | get-property text | equals "1.0" + | verify-true + get-editbox -after [get-label "Cardinality of largest enumerable set:"] | get-property text + | equals "1000000.0" | verify-true + get-button "Draw the state graph after completion of model checking provided the state graph is sufficiently small (cannot handle more than a few dozen states and slows down model checking)." + | get-property selected | equals false | verify-true + get-editbox -after [get-label "JVM arguments:"] | get-property text | equals "" | verify-true + get-editbox -after [get-label "TLC command line parameters:"] | get-property text | equals "" | verify-true + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test new file mode 100644 index 0000000000000000000000000000000000000000..937891e2f6d483e26878172257e2b55a6891e446 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test @@ -0,0 +1,74 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Model.Results.Defaults +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _s4DEYBXnEemrGZBXFuwIoA +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/19/19, 9:27 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Model Checking Results - Defaults +Everything should be empty +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + with [get-editor "Model_1"] { + get-section "Model description" | get-text-viewer | type-text "this is a test" + with [get-tab-folder] { + get-tab-item "Model Checking Results" | click + } + } + with [get-editor "Model_1"] { + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true + with [get-section General] { + get-label "Awaiting first run..." + verify-error {get-label "Not running"} + verify-error {get-link "No errors"} + } + get-section "Statistics" | get-editbox -after [get-label "Actions at"] | get-property text | equals "" | verify-true + get-section "Evaluate Constant Expression" | get-editbox -after [get-label "Expression:"] | get-property text + | equals "" | verify-true + get-section "User Output" | get-text-viewer | get-property text | equals "No output is available" | verify-true + get-section "Progress Output" | get-text-viewer | get-property text | equals "No output is available" | verify-true + get-section "Statistics" | click + get-section "Evaluate Constant Expression" | click + get-section "User Output" | click + get-section "General" | click + get-section "Progress Output" | click + get-button "Checks the model for errors but does not run TLC on it." | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test new file mode 100644 index 0000000000000000000000000000000000000000..30b00a496d7782a2c155fc8bcd5d5b35ddfdd004 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test @@ -0,0 +1,56 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Multiple.Models +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _3CVCoAMFEemtrbArmQOOJA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 3/25/19, 11:46 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create new spec +Add 10 Models +Verify +Delete eveything +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +//try -command { +//Create 10 Models +CreateTenNewModels +wait -ms 200 + + +get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true +get-menu -path "File/Parse Spec" | click +get-menu -path "File/Parse Module" | click + + + +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Delete | click +get-window "Delete specification?" + | get-label "Do you really want the Toolbox to forget the specification new and delete all its models?" + | get-property className | equals "org.eclipse.swt.widgets.Label" | verify-true +get-window "Delete specification?" | get-button Yes | click +with [get-window "Save Resources" | get-button "Select All"] { + get-property enablement | equals true | verify-true + get-property caption | equals "&Select All" | verify-true +} +get-window "Save Resources" | get-button [ get-by-os -default "Save Selected" -win "OK" ] | click + +wait -ms 2000 + + + + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test new file mode 100644 index 0000000000000000000000000000000000000000..18ee795c98dc853ac5fbce277f27c47faf9cdd3a --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test @@ -0,0 +1,77 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Multiple.Models.Description +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _DliAUAMNEemtrbArmQOOJA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Add Spec Data +Create 10 Models +Enter Description and Run Model +Delete + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 2 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type "M1+s" + } + + //Create 10 Models + CreateTenNewModels + wait -ms 1200 + //new \\[ new.tla \\]/models + + get-view "Spec Explorer" | get-tree | get-item -path $TLA-MODEL-TREE-NAME | get-property childCount | equals 10 + | verify-true + + with [get-editor "Model_10" | get-section "Model description" | get-text-viewer] { + type-text TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + key-type Enter + type-text LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL + key-type Enter + type-text AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + key-type Enter + type-text PLUS + } + get-view "Spec Explorer" | get-tree | select $TLA-MODEL-TEN | get-menu -path Clone | click + get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption + | equals "Please input the new name of the model" | verify-true + get-window "Clone model..." | get-button Cancel | click + get-menu -path "TLC Model Checker/Run model" | click + //get-window "TLC run for Model_10" | get-label "Running TLC model checker" | get-property caption + // | equals "Running TLC model checker" | verify-true + //TODO + + get-editor "Model_10" | get-button "Stops the current TLC model checker run." | click + + wait-run + + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test new file mode 100644 index 0000000000000000000000000000000000000000..415d0f26772a022cd8e8a0d198aeea640d2aa5aa --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test @@ -0,0 +1,96 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.NoFormula.Defaults +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _ntQ8oBB4EemUS_ZdBJsvQg +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/12/19, 10:56 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Functional Test that check for defaults when nothing has been defined +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + + wait -ms 500 + + with [get-editor "Model_1"] { + get-section "General (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" + | get-label "General (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" + | get-property enablement | equals false | verify-true + get-section "Statistics (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" + | get-label "Statistics (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" + | get-property enablement | equals false | verify-true + } + + wait -ms 1000 + + with [get-editor "Model_1"] { + get-tab-folder | get-tab-item "Model Overview" | click + get-section "Model description" | get-text-viewer | type-text "Model without any variables or formulas" + } + + with [get-editor "Model_1"] { + with [get-section "What is the behavior spec?"] { + get-combo | get-combo-items | to-list | length | equals 1 | verify-true + } + get-section "What to check? (\"What is the behavior spec?\" above has no behavior spec)" + | get-label "What to check? (\"What is the behavior spec?\" above has no behavior spec)" + | get-property enablement | equals false | verify-true + } + + with [get-editor "Model_1"] { + get-section "What is the model?" | click + get-section "How to run?" | click + get-link "Additional Spec Options" | click + get-section "Additional Definitions" | click + get-section "State Constraint" | click + get-section "Model Values" | click + get-section "Definition Override" | click + get-section "Action Constraint" | click + get-tab-folder | get-tab-item "Model Overview" | click + get-link "Additional TLC Options" | click + get-link "1 message detected" | click + } + + with [get-editor "Model_1"] { + with [get-link "1 message detected"] { + get-property caption | equals "1 message detected" | verify-true + get-property toltip + | equals "\"What is the behavior spec?\" automatically set to \"No Behavior Spec\" because spec has no declared variables." + | verify-true + } + get-button "Stops the current TLC model checker run." | get-property enablement | equals false + | verify-true + } + + get-menu -path "File/Parse Module" | click + get-view "Parsing Errors" | get-expand-bar | get-item -path "TLA\\+ Parser Error" | get-editbox | get-property text + | equals "Could not find module" | verify-true + + get-menu -path "File/Parse Spec" | click + get-menu -path "File/Parse Module" | click + //get-menu -path "Window/Reset Window Layout" | click + //get-window "Reset Perspective" | get-button Yes | click + +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test new file mode 100644 index 0000000000000000000000000000000000000000..ce1b6466b3e415d9bc7f6647490454638c9f7648 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test @@ -0,0 +1,70 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Open.More.Editors +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _5O_HkgPuEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Create Model +Open New Editor +Reset Window +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +try -command { +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x - 1" + key-type "M1+s" + } + + +get-menu -path "TLC Model Checker/New Model..." | click +get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true +with [get-window "New model..."] { + get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved + get-button OK | click +} + +wait -ms 1000 + +get-menu -path "Window/New Editor..." | click +get-menu -path "Window/Quick Access..." | click +get-window -class TLAFilteredItemsSelectionDialog | get-table | select saved +get-window -class TLAFilteredItemsSelectionDialog + | get-label "Select an item to open (? = any character, * = any string):" | get-property caption + | equals "&Select an item to open (? = any character, * = any string):" | verify-true +get-window -class TLAFilteredItemsSelectionDialog | get-button OK | click +get-menu -path "Window/Reset Window Layout" | click +get-window "Reset Perspective" + | get-label "Do you want to reset the current Specification perspective to its defaults?" | get-property caption + | equals "Do you want to reset the current Specification perspective to its defaults?" | verify-true + + +get-window "Reset Perspective" | get-button [ get-by-os -default "Reset Perspective" -win "Yes" ] | click + + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test new file mode 100644 index 0000000000000000000000000000000000000000..0564210393fccf85e0fa0ceb833895b47e162834 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test @@ -0,0 +1,60 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Open.Saved.Model +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _gPS3MAPrEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Create Model +Close Model +Open Saved Model +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x - 1" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + with [get-window "New model..."] { + get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved + get-button OK | click + } + get-editor $TLA-SPEC-NAME | click + get-editor saved | close + get-menu -path "TLC Model Checker/Open Model/saved" | click + + with [get-editor saved] { + get-section "What to check?" | get-button Deadlock | uncheck + get-button "Checks the model for errors but does not run TLC on it." | click + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test new file mode 100644 index 0000000000000000000000000000000000000000..2bdb98776661944f6287b6e3c192bed1e3d9eb4f --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test @@ -0,0 +1,84 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Property.Formula +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _EdNeQBUsEemG79v6PBILBA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Add Formula To Property +Edit the Formula +Remove the formula +verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + + with [get-editor "Model_1" | get-section "What to check?"] { + get-section Properties | click + with [get-section Invariants] { + click + click + } + get-section Properties | get-button Add | click + } + with [get-window -class WizardDialog] { + get-text-viewer | type-text "x=1+x" + get-button Finish | click + } + get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-item -path "x=1\\+x" + | get-property caption | equals "x=1+x" | verify-true + with [get-editor "Model_1" | get-section "What to check?" | get-section Properties] { + get-table | select "x=1+x" + get-button Edit | click + } + with [get-window -class WizardDialog] { + with [get-text-viewer] { + key-type Right -times 2 + type-text 3 + } + get-button Finish | click + } + get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-item -path "x=31\\+x" + | get-property caption | equals "x=31+x" | verify-true + get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-button Remove | click + get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-property itemCount + | equals 0 | verify-true + get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test new file mode 100644 index 0000000000000000000000000000000000000000..20dfc0ffd1dbacda3b58e9bef840cc60aec7553b --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test @@ -0,0 +1,75 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Run.Details +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _8o7w0APsEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +End-End +Create Spec +Create Model +Close Spec and Model Windows +Run Model: Should open Model Check +Verify +Delete +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x - 1" + key-type "M1+s" + } + wait -ms 500 + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + with [get-window "New model..."] { + get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved + get-button "OK" | click + } + + get-editor $TLA-SPEC-NAME | click + get-menu -path "TLC Model Checker/Run model" | click + wait -ms 1000 + + get-window "TLC run for saved" | get-button "Details >>" | click + wait -ms 1000 + + get-window "TLC run for saved" | get-label "TLC run for saved" | get-property caption | equals "TLC run for saved" + | verify-true + wait -ms 1000 + + get-window "TLC run for saved" | get-button Cancel | click + + // note wait-run must be on the model page to work + get-editor saved | click + wait-run + + get-editor saved | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" + | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test new file mode 100644 index 0000000000000000000000000000000000000000..4f5d471c83917de7cb58ccf9b3358363942caf26 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test @@ -0,0 +1,36 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Spec.Properties +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _Lbbs8AMKEemtrbArmQOOJA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/9/19 2:15 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +View Model Properties, Verify Display +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +try -command { +get-view "Spec Explorer" | get-tree | select $TLA-MODEL-NEW | get-menu -path "Show in History" | click + +get-view History | get-button Refresh | get-property kind | equals Tool | verify-true +get-view "Spec Explorer" | click +get-view History | close + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test new file mode 100644 index 0000000000000000000000000000000000000000..beacd9a886d69ddf8667a59bfbae48c5e088b664 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test @@ -0,0 +1,46 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.Spec.Properties.Valid +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _6Vm88APkEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create Spec +Select Spec Properties and Verify +Delete Spec +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew +try -command { +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 500 +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Properties | click +get-window "Properties for new" | get-label "Specification Properties" | get-property caption + | equals "Specification Properties" | verify-true +get-window "Properties for new" | get-button "Apply and Close" | click + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test new file mode 100644 index 0000000000000000000000000000000000000000..4cc287610eb431248b27e8f1c51f03db03cee20e --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test @@ -0,0 +1,103 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Functional.TLA.Options.Defaults +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _HJaIUBU4EemG79v6PBILBA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:48 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Advanced Options >>TLC Option +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 2" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + + + with [get-editor "Model_1"] { + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true + get-tab-folder | get-tab-item "Model Overview" | click + get-section "How to run?" | click + get-link "Additional TLC Options" | click + with [get-button "Model-checking mode"] { + get-property caption | equals "Model-checking mode" | verify-true + get-property selected | equals true | verify-true + } + get-label "View:" | get-property caption | equals "View:" | verify-true + get-button "Depth-first" | get-property caption | equals "Depth-first" | verify-true + get-label "Depth:" | get-property caption | equals "Depth:" | verify-true + with [get-button "Simulation mode"] { + get-property caption | equals "Simulation mode" | verify-true + get-property selected | equals false | verify-true + } + get-label "Maximum length of the trace:" | get-property caption | equals "Maximum length of the trace:" + | verify-true + get-label "Seed:" | get-property caption | equals "Seed:" | verify-true + get-label "Aril:" | get-property caption | equals "Aril:" | verify-true + get-label "Verify temporal properties upon termination only:" | get-property caption + | equals "Verify temporal properties upon termination only:" | verify-true + with [get-button "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space."] { + get-property tooltip + | equals "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space." + | verify-true + get-property selected | equals false | verify-true + } + get-label "Fingerprint seed index:" | get-property caption | equals "Fingerprint seed index:" | verify-true + with [get-button "Select randomly"] { + get-property caption | equals "Select randomly" | verify-true + get-property selected | equals true | verify-true + } + get-editbox -after [get-label "Fingerprint seed index:"] | get-property enablement | equals false | verify-true + get-editbox -after [get-label "Log base 2 of number of disk storage files:"] | get-property text | equals "1.0" + | verify-true + get-label "Log base 2 of number of disk storage files:" | get-property caption + | equals "Log base 2 of number of disk storage files:" | verify-true + get-label "Cardinality of largest enumerable set:" | get-property caption + | equals "Cardinality of largest enumerable set:" | verify-true + get-editbox -after [get-label "Cardinality of largest enumerable set:"] | get-property text | equals "1000000.0" + | verify-true + get-label "Visualize state graph after completion of model checking:" | get-property caption + | equals "Visualize state graph after completion of model checking:" | verify-true + get-button "Draw the state graph after completion of model checking provided the state graph is sufficiently small (cannot handle more than a few dozen states and slows down model checking)." + | get-property selected | equals false | verify-true + get-label "JVM arguments:" | get-property caption | equals "JVM arguments:" | verify-true + get-editbox -after [get-label "JVM arguments:"] | get-property text | equals "" | verify-true + get-label "TLC command line parameters:" | get-property caption | equals "TLC command line parameters:" + | verify-true + get-editbox -after [get-label "TLC command line parameters:"] | get-property text | equals "" | verify-true + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test new file mode 100644 index 0000000000000000000000000000000000000000..d6ba3b3195e1e0f7e40322fdafb055bf7468d84e --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test @@ -0,0 +1,38 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.File +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _RNcosP5FEeilFekyyVb9lA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/9/19 2:16 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +BVT Level Test that types an inalid formula into model, then error is verified +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +try -command { +get-menu -path "File/Open Spec/Add New Spec..." | click +get-window -class WizardDialog | get-editbox -after [get-label "New TLA+ Specification"] | get-property text + | equals "Creates a new TLA+ specification\n" + + "Enter a complete file name like c:\\jones\\specs\\foo.tla or click on Browse." | verify-true +get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text $TLA-BADFile +with [get-window -class WizardDialog] { + get-editbox -after [get-label "New TLA+ Specification"] | get-property text + | equals "Root file name should have a file-system path and extension .tla" | verify-true + get-button Finish | get-property enablement | equals false | verify-true +} + +} -finally +{ +get-window -class WizardDialog | get-button Cancel | click +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.Set.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.Set.test new file mode 100644 index 0000000000000000000000000000000000000000..70fa071bf556b48fdd193d74316a95baae0fa6d6 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.Set.test @@ -0,0 +1,25 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.Set +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _rVC6oPz7Eeidh8ibqA9n7A +Runtime-Version: 2.3.0.201806262310 +Save-Time: 12/17/18 2:42 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Enter Invalid Name into Spec and verify error +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Invalid Spec +CreateInvalidSpec + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test new file mode 100644 index 0000000000000000000000000000000000000000..1911415747313a993459e860da3a0553119002c1 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test @@ -0,0 +1,66 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.Model.Content +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _GbDfMAJNEemDc-4PKyNT9w +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Invalid Module Content +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x y" + key-type Enter -times 2 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Init == y = 5" + key-type Enter -times 2 + type-text "Next == x' = x * 1" + key-type "M1+s" + } + wait -ms 5000 + get-view "Parsing Errors" | get-expand-bar | get-item -path "TLA\\+ Parser Error" | get-property caption + | equals "TLA+ Parser Error" | verify-true + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + set-caret-pos 1 1 + key-type Down -times 2 + key-type End + set-caret-pos 3 13 + key-type BackSpace -times 2 + key-type Enter + } + // ldq: this never did anything (there was never a model made) - i have no idea why it's here + // but i commmented out instead of nuking it. +// get-menu -path "TLC Model Checker/Run model" | click +// wait -ms 1000 + get-label error | get-property caption | equals error | verify-true +} -finally { + get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Delete | click + get-window "Delete specification?" + | get-label "Do you really want the Toolbox to forget the specification new and delete all its models?" + | get-property caption + | equals "Do you really want the Toolbox to forget the specification new and delete all its models?" | verify-true + get-window "Delete specification?" | get-button Yes | click + get-window "Save Resource" | get-button "Don't Save" | get-property caption | equals "Do&n't Save" | verify-true + get-window "Save Resource" | get-button "Don't Save" | click + get-view "Spec Explorer" | get-tree | get-property itemCount | equals 0 | verify-true +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test new file mode 100644 index 0000000000000000000000000000000000000000..702ac74e3461f049f768e5dc31539e00c8d8e45c --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test @@ -0,0 +1,69 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.Model.Formula +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _N4SlcAJQEemDc-4PKyNT9w +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:13 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +New Spec +Model with Wrong Parameters + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "VARIABLE y" + key-type Enter -times 2 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1 + y" +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "VARIABLE y" + key-type Enter -times 2 + type-text "Init == x = 1" + key-type Enter -times 2 + type-text "Next == x' = x * 1 + y" + key-type "M1+s" + } + wait -ms 500 + get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + get-view "TLC Errors" | get-editbox -after [get-label "Model_1"] | get-property text + | equals "current state is not a legal state\n" + + "While working on the initial state:\n" + + "/\\ x = 1\n" + + "/\\ y = null" | verify-true + get-view "TLC Errors" | get-section "Error-Trace Exploration" | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test new file mode 100644 index 0000000000000000000000000000000000000000..9f9c8269af3dcfe333202b2bc5d9291d9a02b5df --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test @@ -0,0 +1,52 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.Non.Real.Number +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _8r57gAJbEemDc-4PKyNT9w +Runtime-Version: 2.4.2.201905122359 +Save-Time: 6/12/19, 9:35 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Invalid, Non Real Number +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 3" + key-type Enter -times 2 + type-text "Next == x' = x - 1.5" + key-type "M1+s" + } + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-editor "Model_1" | get-button "Runs TLC on the model." | click + + wait-run + + get-view "TLC Errors" | get-text-viewer | get-property text | equals "TLC can't handle real numbers.\n" + + "1.5" | verify-true +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Test_Suite.suite b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Test_Suite.suite new file mode 100644 index 0000000000000000000000000000000000000000..9275df53c82b568d796093e494b13d870b72c4d2 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Test_Suite.suite @@ -0,0 +1,20 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Invalid.Test.Suite +Element-Type: testsuite +Element-Version: 2.0 +Id: _iadp4APNEemtrbArmQOOJA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 12/19/18 12:35 PM + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8 +Content-Type: text/testcase +Entry-Name: testcase-items + +_RNcosP5FEeilFekyyVb9lA // kind: 'test' name: 'TLA.Invalid.File' path: 'TLA.Invalid.File.test' +_GbDfMAJNEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Invalid.Model.Content' path: 'TLA_Invalid_Model_Content.test' +_N4SlcAJQEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Invalid.Model.Formula' path: 'TLA_Invalid_Model_Formula.test' +_8r57gAJbEemDc-4PKyNT9w // kind: 'test' name: 'TLA.Invalid.Non.Real.Number' path: 'TLA_Invalid_Non_Real_Number.test' +_rVC6oPz7Eeidh8ibqA9n7A // kind: 'test' name: 'TLA.Invalid.Set' path: 'TLA.Invalid.Set.test' + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8-- diff --git a/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx b/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx new file mode 100644 index 0000000000000000000000000000000000000000..e00e56dfbb1ea32bb575d5b3ed311b677a0a8e10 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx @@ -0,0 +1,35 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Context-Type: org.eclipse.rcptt.ctx.parameters +Element-Name: TLA.Test.Parameters +Element-Type: context +Element-Version: 2.0 +Id: _zmZVMP5NEeilFekyyVb9lA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 5/7/19, 10:32 AM + +------=_.parameters.context-2e023de5-3294-36a9-ac1d-6701f05a40ee +Content-Type: text/properties +Entry-Name: .parameters.context + +#Tue May 07 10:32:12 PDT 2019 +TLA-Long-Model-Name=thisisaverylongnameforamodel +TLA-File=new.tla +TLA-TREE-NAME=new [ new.tla ] +TLA-TREE-NAME-LONG=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz [ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla ] +TLA-BAD-DIR=C\:\\foo +TLA-MODEL-TEN=new [ new.tla ]/models/Model_10 +TLA-File-Long=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla +TLA-ADDITIONAL-MODULE-NAME=other +TLA-MODEL-NEW=new [ new.tla ]/modules/new +TLA-TREE-NAME-RENAME=new_Copy [ new.tla ] +TLA-NEW-FILE-RENAME=new_Copy +TLA-MODEL-ONE=Model_1 +TLA-BADFile=QQQ +Model-TEST-Name=foo +TLA-MODEL-ONE-TREE=new [ new.tla ]/models/Model_1 +TLA-MODEL-TREE-NAME=new [ new.tla ]/models +TLA-ADDITIONAL-MODULE-NAME-FILE=other.tla +TLA-SPEC-NAME=new + +------=_.parameters.context-2e023de5-3294-36a9-ac1d-6701f05a40ee-- diff --git a/org.lamport.tla.toolbox.product.uitest/TLA_Global_Verification.verification b/org.lamport.tla.toolbox.product.uitest/TLA_Global_Verification.verification new file mode 100644 index 0000000000000000000000000000000000000000..5140e1f35a4a1baaa2b69238baf54898534aedbe --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/TLA_Global_Verification.verification @@ -0,0 +1,22 @@ +--- RCPTT verification --- +Format-Version: 1.0 +Element-Name: TLA.Global.Verification +Element-Type: verification +Element-Version: 2.0 +Id: _OR3AcBLBEemDf5eqf3kQng +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/17/19 2:53 PM +Verification-Type: org.eclipse.rcptt.verifications.time + +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf +Content-Type: q7/binary +Entry-Name: .q7.content + +UEsDBBQACAgIAAAAIQAAAAAAAAAAAAAAAAAIAAkALmNvbnRlbnRVVAUAAQAAAACNkEFLw0AQhe+C/2GZ +u7tqFCR0W1oVESqiFPEm6WYSB7OzMTsx+fluhJZ662UYHt97b3Zni9E36ge7SIEtXOhzUMgulMS1hV6q +sxtYzE9PZqGrNbqG2oi6c62ITiaqyBWSnFELecw3abwdyGr0lO/DL6fwVMcxT7qFT5E2N2YYBh18rVOD +eX963CHHFO4zduCU8Qebf7CZYFBcTJbNeqkfmrAtGn14KygqLXw8v2ZLt1qv7tHfVdf4XWVfL1yD8sS9 +YLRwBSqiC1ymPUsPInZNX+JtYMFRkihdj2DSn/0CUEsHCK4u7dbfAAAAXAEAAFBLAQIUABQACAgIAAAA +IQCuLu3W3wAAAFwBAAAIAAkAAAAAAAAAAAAAAAAAAAAuY29udGVudFVUBQABAAAAAFBLBQYAAAAAAQAB +AD8AAAAeAQAAAAA= +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf-- diff --git a/org.lamport.tla.toolbox.product.uitest/TLA_Test_Preferences.ctx b/org.lamport.tla.toolbox.product.uitest/TLA_Test_Preferences.ctx new file mode 100644 index 0000000000000000000000000000000000000000..6c26fbf557532313dc4b57165c35633bc9f8346e --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/TLA_Test_Preferences.ctx @@ -0,0 +1,123 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Context-Type: org.eclipse.rcptt.ctx.preferences +Element-Name: TLA.Test.Preferences +Element-Type: context +Element-Version: 2.0 +Id: _MMwoABN4EemG79v6PBILBA +Runtime-Version: 2.4.2.201905122359 +Save-Time: 5/29/19, 9:12 PM + +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf +Content-Type: q7/binary +Entry-Name: .q7.content + +UEsDBBQACAgIAAAAIQAAAAAAAAAAAAAAAAAIAAkALmNvbnRlbnRVVAUAAQAAAADlXelzm8i2/37/Cpdv +1XxysBbLSybJFJKwxRiBBpAd3zevKCzaEjcINIC83Mof/043u5Y4cTjNvLqV2JYE4tfL6bOf7g+/PS+9 +g0cSRm7gfzxsC63DA+LPAsf15x8P1/HDu/PD3z7940MQzgUy89xVRIRwtopjYRY/C6uQPJAQ7ifR+0nx +ehD4MXmOD56X7vv80R36aADzo/fw+cfDRRyv3h8fPz09CcFyLgDA8eexnN8SVW956rI7Oq1WG25TjNmC +LO13rh/FNiBm33q1lfkzs7voQ9mdx3DncenOwwPfXpKPh6YiCiaJYmFSvuY6Hw+t8fgpEPvqiUSWV2cX +j6eTvqz0xcODmUdsf1IGjcM1Ofz0j4ODDzM6NH6cPvx+7TsesRzyYK+9OGK30JsWrudE6T3lPq3d9Ba4 +ybFj+wCG6X38stq4bfcEGXEIk0rbNYSvHh58IS8fD42RdmuZ0mfT0lRrIunGRBqY8o1k9UX98ODR9tbw +7Afbi8jhcc3QN7IE0GLfmmiGbMqamuO1O+e1o00NyRpoiqZLQ0sR+5Ji5HBsdjDwbmV1CMN7q+nXsnpl +GZJp9e+soXQpThUTeXTZxF7KiinRHtMZRu6w67uxa3uXdhTfuOSpb4dKMLNjWPs57n0Qx8ESp6vGnWFK +Y+t3rW8gj+y1dAeUpF7KV1NdpHRrycMcsrpahXRli7MZ8Uhox0EIvPHBna/DZGRQhsLUxSFbUKJiGead +ItFVhjz7xki+BB4ykVRLhWVd4iQ5LrtYZjG6NFHEgVR7W3RpIKmmcmfBGhxmqw8Wn2EZ8r+K9vRqB5ZU +sQ+jLarymBEGNiWKdHWroin9TQaecfSxDN2fjq3BSNTFATSwGIU2Dr2z/n1DfKEQ/FAbXO9HDFYKeYjr +JzBY15rOT2imBN3tAB+RB9fA9xQN5FpfGok3soatIDhuZN97RCVPmVBBBkx6lwyyQSlK+ixzkdNj0Afk +iZJhc+DXiqxeWyrM4pXIALUUGrm3fw8+lXANcyTpllxFHEvqFHfg0xn+Bpd8Vz+bnOja79DDv4mYiBbB +k+zHYYA80gnzgpG2xuJnLlhDyRQHI1A6qCREXsEwp+OJad2OYNYM8UZiDQA2rShsmneCfzhOTMvX7MyQ +zILlkvgOGO+CT54i2rC6Tc9V4Hnw6ZB49guiUpbCAMGREEAQkR4IcQTPjWIhCsKYOBWjwLOXK/hUiD1b +iIPg3guehTCKBPql2ltCp0zyqfB0fooOwIIhjgtWS1T35FMeoBCbuplkhwTz0F4t3Jmxspl7BXPdADF8 +gXkiz24s+PajO2eWmOCEwcoJnnxkAUj7LfkzL4iIY9r3fPoaefYjER5JGLsz2wvXYIoid/OvtTv74rgP +DwJ7NYRXuD0V76M4tGexSZ5jiZGsMAg8+G2A4T2jM3wZhGQeBmvfEYyXKCbLYWKb47YLgFZGbMfriLas +J3JF6yOjrQhjrZucBoeknuzQZ3zccRO3EpvfHLRzcnLUabWOTurn68CuvXtg10s7/EIFYuzNhFkAy8me +E8FZL5cvxbS2juBfAy3oI4/+6y0Y4BJbSB5dGkgQfT+I2fwXlDBy5wsPfmL4GvI4ZM3QKRPVmYYEN40D +h+TA4hx7YZ8is5GK2JhVlln7vHXUafeOOr3619lGJ7G5V0kS89A7SBgG4V7u1esB48Bw4ZTVHbpeH13y +xEMDyIRD0WPZ11J8nQP+fRB8oczqdXyU2U6lFSVkI37xCu4AZhsYamNrqg4lXZFVHPPaCm1/Tiw36XyA +3Fk30re481VgBir0Xs1VbNMO5yTGJrsKDznjqm+dIXOs8lJeZCKvSbm/9tfAPHO2gk1kogOKfXOkVR5+ +nrbULk56k+Lz4KQlUx3fYt3Ftnd3lsOCPufKPs6R2YfrPwSN6MwVdZK/yyW2oy/bctj4YypfXSmSwWG9 +chzrKkldcCXgC2wCjvopd2hKucgdHnPXL0iJq61btRvOz4/gf6eDMNYStVfoQE9oc4J1tHewMRXohtT3 +grAz4dMWua3cHBLbqVOVCLgj6hCPVCmZ64S+7h/u27Mv/P3DVDjtmAJeJNbhT9UdbKrewTk4apB2aqTs +49ht4NdtxrPrZ9q71hhPS2GfH+BVCYIdhErTMCdh8Og6pWHYiHW6NEbs214W9BSKJyh2FBugv+oZZv4s +XKa8QTzd1lH7FH4u6o8xbK/ULn/m0OXOHDjq5m5kArdvSHd9Wrgxiaife7CwqSQkoeitFvYNBS30yfrp +KrX+HoLZOmoi4L5FYyf8yfoEm6xhkIm6Xt6TcINhdGhUgf0gkPPUny2on9lpiKaZ940WG4Xu/ZqiRng2 +2WwdwuVYKRt+SFauDBLg1RFFNnsYGZVsHhqgavfayHG/BLXPB3URPJmh7Xr8U5DcaMDWTYO6Ucm+509m +C/hySOXCNXkZB6BfuSQcg2gs5v200z45qR03iBckjLiZW25kpA6jxoNhmSDq8Zd9PWzZV0DmulyJcSHz +yQISO10hh8y8Ju0W9mQm0p3bennYkSfLgo+JOSbc25E7EyjfnsKDH2bRaHKNzahvE3uhaXFczDkHTbJQ +17kmjFS1gE5V9+i0Wzx0j06fC+p3E/rEhscwSc2F3re59yk2j9n2lzXs6D/FXmF7XdFNZyjnsqzDX3x2 ++OTOJGyNV/LMDv7NMYxUYPLTwBghl/yG7W73KP1BR+1zQa0QEtc0oJK9yrlyhG7mIkSV9AlVQ8pcFHN5 +QPUtah0PU0ehSYWkHYoz/GAl7fAwtOei71D0b5VSIUqiM368IofEZhW7xD3XZLZt0dPlL+26yNJuBZ/F +Y7BQ3M0A0tnpEU3hb59jqtK55OEYXi4wsUn4taAh45ZTXRllXq4hickMLlkRtJRUHF0Itd6UiW6HYb+X +nXJREEoRmMTDe0Z/0FE3/co4qNscjjsXP+cvOM4b8PKdIDPuTXdxlZXiVPptVAkhd/BtbghN5+eHKCab +Y3HFbGOiqcSsf6rXESn4c0QvTuw54cuJexuc+OKU/qCj9rmgbrqvN0ruWidH7dPuUadVvyqUElPMfMS7 +zKe+9pkDU77gLwcuGpADPWQ5UI3jTZoJ2O7qNzJLfApC5ym0VwLhUuC/1y9aZOZWnfM97DJkBl/ygLfP +Thgq/EVH7XNBzSPxERcfxzpLGOIYgx+mSbENrt3tvFweqiTddDSK3HvXc+MXYRoRA6grBAvUYehRU8u5 +CHMgD8AOlom9c8IuSG6JAUUuQot/N8uRabT9Gmj23SXh54llBFtyw3a6lBW3eQiAkicWE3XLz89fjeFX +pF9A8k/WacAT2kTiVROZV/xSr9jKLHnXMjW03btoQh1uJk0gGYQ+l0GoBjLWy0JdRKhUqFYzcxSiCRwy +Fe+gp0INFoylHcajYEkkn5t0zVcwv30WCkjuEqCBWBh6KGwXN24geaiNnT20wfxKfrX2SYuXI6LkWsNE +rVYkcyyP21UVkEMO4tDj4L7Ez6nehclvmTJJw09HS+Cw3ZSbJZ3c+Q+/bVYKSO7yi2M1cA7JrZP5Wmxi +mw90Q60ajmomqZ+xAn66QQKHTD8/XLBiYgfO1xH5I9twm17iGlHOli3HAuscEnmm35gpgT7fFHKYRxf+ +HileOV/Dt3i2dlrb3lW33Tk/OsX01hbdxWbjG7lBHFXzUvH7xgh3O0edE/jpIQwx5ZtFwLBJ4q4KUJ5Z +/9/cf5W9gHatwiAOKAxyVvx37AWbjU2Tw5I2hUYz8LNu9m1u6fOMpWRisMdf8mInoXxrL0Tkzv6wejco +ifv2efeo08Vx0ZRzFSsxu8aWPa+Kuj2H93BYbD9MDEaJGDAYzxtV0jKNMv3opEV/cOvkqgm1vdbRGc6W +RFU5vXFyxRkreznqIODuiK1Us29uXYcMYB44LdUKDeR+1awOhZILp1qULXGBXk++A5JHQdAbViI2g/iW +5ORaY/+9yhp6gn+6RRqPOsN80W1n+qEEbb5jiGdbtjFu0l1GYRzLWHNIvh7VkiaySjNMOepBO8oL5L4k +jhFyaUu74Uwa2RX82zyNayHxlu+JbzEa39OUSnk43BczfjUjiGZQzkIXmKVO4nXILYKYdxE9Alyc4cJj +g8NqDkHTG71vJcIP1lEcLJk+jjwQdNyNnFM0uKPFNs1xLA7LIXmQOZ34EVV9xAew2R0b7saf40Faatjk +DLNT1ene4Q02otgwfZbtMl05G5OrV4iTLsY21Y4ug7CyKw/eWUYNHWwQ8OPh5aM5OW/Nu33+GM8w20bB +MlfBubGd96v6PQ/DCt8rUD1TqqFO7yiL5KveV9nKpsuChtAxnBaVs5QNuvfXOl4EPPZRk5JIeoOCcnup +8zReY/v+1nXiRQ5Tf/R+m5FyrfRtYrdtqnyyhdQgXa19Jxi5YN6EL4b7n0Lx6rQQNjDZxbZ4kvE2jVVZ +V5fu8HFydFF/XRJLxWnicOeqX5lnAdi+c1x4JDrAyrrdPr+Gk5N1K7WDk12xJR6zXd3+bpFu/P2g6JlY +PI9wrdA6l9BUQWjbqRToZ5A0ICyLU26aCSQUjgo/oAUkwj0BuidC9OTGs0Ivsr0n+yXCzlPnmxWPnLC1 +oI4Cnaw8YNUV30/9CgidOMt9sFx/tY4th4TuI/beEHsDfxzE4Eb+b0P75FMa4lvHwXVveO6btSVnXpXq +DtNDJ7gctVUqPcSE3btqeB0CWNo7nYcXcXvDJ65uM17ZmNWjSvnyI2oSZIWfDdrbWzyZo0e+yiX5bWPO +0PhW3JfrMs+7YNVfcGGPJV0JExVouZ+7MhokZjfKTl9oPgKw5WfgFs1LovVNOHd2ONR4bBRYnEvc0JRn +frwGTPzE5uZZEr0pNBsTGNjbp2+gcRYYJROlfdE+6nS6XCRGyVbBhN2/uabrO8YsKJUC0pqH9NiPrBkf +jmcL13Oi9F3y5sC3lxsNWrvCUxB+uYeGLA5r7sGI2OnACesVPJLI9ByNx1LlYA8hZDGUDRGYuKVNJNWS +hrKp6ZasWhNFHEjI694QbyRLnJraWDTlgagod4BsSvqNqJSiNPUHGkF96NvhjRu59x5yJlQ6oKbYt27l +oTkqAjG1QyninTY1raGsSwNT1lREL5OkMpJRpVtrLKlTA3cMdWlqVOizwDuvHYzBaKplyCoIWWugyINr +7GUgKTBjFHSk3Ug6Mtqtpl/3JXUwstjy21pw9XPmZNIU2aDEaQBjubMup4piqeIYm8Ow2RQvoYvWUAJg +ZLhSTw1NN62BLgO0LGIuxQJyAoM61G6hw7D+b9CZd2mBABcwR9oQsZv6VKVSqS8Orq90DewNXJajKpb0 +2ZRUA/howW2w+OhA0xTomo7MR9limEi6MZEYgVhjbSghztmKhGA6gpH+SHiJ2/FUMWXrWrqzRMOga8KU +Szym3ULQn7aVGOSFR4WhTKcR+sfIZ1MoooysCethh26BPoPoPtO150zCYLmKL4MwOfFhSXzkUGtJ06ee +rrH9jEwz2yqU1QemI4kqMjB1I4SuQ+DGCIaVh+MfaMewJrp0Kemg5khWol5JQ6qE8xHECaJMtcgBjHnB +f9CMt6EsKtqVdampJrbYByZ3fWcN7gYKtoYBvEZSTetSps4uvLTMRAgPQUEcaLpY4aR4Al+9lK+mOnsz +0bXfqf5/K/9L1IfIY9qXh7JlTCcTUE+RoQaaQl0Jg7IGhcJNjZFG7dCxpt+BSqPSZbi7a9/r5JnRtBef +xIWDp3LrKgyeXxh+dn3zjpFpTozS1fpUqiAsRFN5d4oaMRZ2RLPO91HH5jBu997QBtf/vb2nc/9f0/mt +9/W0ww980MmeXeKMgqhUkOoFM9tbwEdf250zoQX/EDZoYfnDCXzE5Qiw1etYr3GuHbmpdXun7XUcTOww +IgbYdMgDMrA9+O8BnL0sZv+dH8we5vXnK7Bggeg4yQ7rWYkbKxjA7WdIlqAfD+Gb0FGKOo3IONmuRPPZ +WOPi51MKPV9jm+ZL1x+60cqzX4hTqcPotTDMcrjGdraxYHUFD1awqlgeG1eB1uonYjqw4SRYrVestgo5 +v2qjR5H9iDyfybLRaU7Vxi4YZ/WfIA7WI4ARxY7ivezne7U78tfa9QMA7dBoXuR8EaLZgjgs1lz3GHE5 +JZTVHbCA4a37HzvEhgOu5fqO5NnwPcd0lwWddVsHcGkdE4T08HSKcqzAfxfFdhivV/WnKgZPvhfYfMZR +843Nrr3dZoFlEqxDmstZ9/D7MNuLII6EYEUSWVXwszYC+3ZINAtdxrQFe7XyXh5cj7AN+laB587QBfMD +DOVCYBmjT4T+5nTib7nfjhtRSMX1v7johfZl4Ps1EFkQOqXkm/rFhz8LnHK3cEkINB3WqzIiUp5zgZrT +rBf4c/LoxgXZnrZOzlsoik+5AUv7OW9DVNa52gDfO6v/fHmHeLEtkOeVG1ZdvZ3eRaeF0+FssTawQJMi +0x3LBZ20KjNbUqWxQZNFFO+QAajImfxxNzOiuhWa+oEsLtchdQtJ5oek6RXGRMzjDjQKkHjnsZNkLnXJ +GJXwafjBFHVzOuGSxqUoVl+61HTJ6k9lBduPPVA0Q7Kmqi4pIo3tpE50A7urdIoBazgdmDQfwZTNUhgE +z7utaAORkVIlZwYH71Y2B6NKngDgZkGKgS6JlQDwisVOa29Fmllu0OiPCU2xxvKVDjPNY36zwUbGWkfE +ICvq+QlCYUG8lUCPsF2luZ/I7oK1b0dRMHMByUmyZeE2eDMvVJRthikkvtHkfnNB/CLXtv5AlaZdj0Xg +ZZwpYN+sLG0XudREHtOgXBLutER1aF1qypB1vJymg7TepM+ySRf5eMISERP2qogGDUuqQ+0WOW0HJlrS +LUUey6Zh3YjKVEK1LnPuwhBRoUzR4E7DrFdW1smGqPZGBtVDVNL3XIh4b1vMu1IWRv2+KftxR6o+ku5R +Estb+gdevlllgeIS1K2kDLSxxEVpZglRuvTHVNZ36ZBIZJopkQkLupGl2yz3hGab8tPbM52OjQLN5S8R +Vw69lTSqS0lpCLfFy1T8cpOwjoncKfdBTXIj5HTAW1FXLbFPqzcK801WYRlMoOd9WZHNu50tKNu78DoA +JuTH7E36OrV9XT+K2a6/rxnGMbGXoOzVbRnvgBAe3DCKrbgcP3iT4/vfTsyc35htzjDg13LleiQUEj97 +oTkI9VeifLsB9IXnVrZy5t8IYJA0X5YuEhLGsgMUVz2jnO0FwH1kHDInfrrzw8Sz44cgXDY6VUmDXJ8e +uPJ7FPZfYjIr7wOUuS6bmT0aOX5t7n7As5YEhmsPQVU2W7aW7nzDw5x8Qhyri5AU9F1nTnZOWsmJMtek +sKJpySsrey1KXr93LNP2IfA2kCxjELGGJX2WBtPER1kpj/phjyqlLs+m1fo0woJMxjmQQNO8rZux9Xlc +FLD94sW//va89A5gVujegB9/+WsdxL+2hVby4iALPaUXpublu/P0EhWTju0FPkkv+kHy97dPv/zzefgr +/BJ/pQCPS4PEdP/r6CCNAtyM06/0zo42G8zc1r7tCQ65X8/pIkm6AIvQYIihczM2YYja3aN27+T0otU7 +u+idnHeSJ25h01sPXCcFfDPanqcXT97RlmTuk9f/dr4ANxVaFhB4enVlx4v06uD9n5OQblS+PLikoYo/ +f7cf7T+3v3O80YDjpH/bn2YjXrry4+yp9sg4O2MgDoOf02Iw68r3187VlB1d/yrPMISFHY1Txv5TST+4 +6REpp9ku9HhD3ib7ywQMDrGOA2BwbGGSaLeT+XutCtAfaAwy+Vp+7YcaSWbrkNBGqkwdSp4bsU8NUCJA +um6YLD//9J1kxlL6aZbAYivn/+cRk3z44/ofzFLNkZ5rvE4NUSYBs2lL3r5qZO7mdZXbb7Prk7yxQxfk +8tyogtS4NtISqs+WpstXchH86ZZPgq0b7W4TrV1JyqhyjzeIErZ3Y6KQ7xnpjW8W97N9U9JNS5Oxr3/M +3Ugnc2lv8WN9fI94pLpZ2AsCysyOaJFj5NKKZ/Q+uf4sZKWq+0+Wrw3rKbRXe1xg9WEsAo8A4e5N4HkL +kuJG8QbOA5D1Is3uLx4ND2eo0afnD8fpqwL3mALX3I4wWVrfasrLa03ZKr9569K2HPanH6x9B4+3VnfA +6Zyf4DFWWglbTZZofzXIPCAHU/nrhdD62vqaBDaNr+2v79qdry3276TVSl+1v2avsq/hNXYkyVejIgzZ +vWjjYW3Jt95Jl6N867Yu3irfvlnjVLl7WCJmdIWhStSnLURt4f8zUfcwB2ZbaTvvcSTqTnev0lZfqHJK +NzG6ZYNq0P0xcvT/6bRaRwfnrdb/1h+ppOc4sjPnaNUN9j6jDC1goSrsQ0gNO1ro1H9sBoVic4aQPiur +6r5p69Fp62FNW7K9iOL6yGVgm4WSP+F93fSxpo8+/oQ3/f0gjoMiNtTp7XR8fzjObNtP//hw/DpmYbRG +A2ovP4O9/H9QSwcI/9apEbEYAABWAAEAUEsBAhQAFAAICAgAAAAhAP/WqRGxGAAAVgABAAgACQAAAAAA +AAAAAAAAAAAAAC5jb250ZW50VVQFAAEAAAAAUEsFBgAAAAABAAEAPwAAAPAYAAAAAA== +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf-- diff --git a/org.lamport.tla.toolbox.product.uitest/TLA_Test_Workbench.ctx b/org.lamport.tla.toolbox.product.uitest/TLA_Test_Workbench.ctx new file mode 100644 index 0000000000000000000000000000000000000000..cbda8dd60b0da0cddb707fc5d12fee500d98bc65 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/TLA_Test_Workbench.ctx @@ -0,0 +1,22 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Context-Type: org.eclipse.rcptt.ctx.workbench +Element-Name: TLA.Test.Workbench +Element-Type: context +Element-Version: 2.0 +Id: _KWU8wBN2EemG79v6PBILBA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/8/19 10:53 AM + +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf +Content-Type: q7/binary +Entry-Name: .q7.content + +UEsDBBQACAgIAAAAIQAAAAAAAAAAAAAAAAAIAAkALmNvbnRlbnRVVAUAAQAAAACVkUFPwzAMhe9I/Ico +dxzYAUbVbtrQhCoG4rAxbqjrTBeRxFHqtf35pEwdXBDiaPt7z092Ou2sEQ2GWpPL5BVcSoGupJ12VSYP +/H4xltPJ+VlKoQIsjfY1Qig9M9QluiJoSjYUPrZRtL8jx9ix6KxOTpaj3jIucXUS+5ncM/tEqbZtgWwF +0Ve9PuYD8vuak3IY98ovRFnaoVEDGPUUUApXWMzkajmDFdYMp5RS6F0m3x4263E7fxot0N7f3DbXz/N8 +OZ9J4WNwjyXrBvPI9YFMYT0FBjYFMJHZUgcHDT9I0E6zLoyMpxIibTS29WRA+wpWx2LReRPThVQdmT/w +DZqSLL7E1rciVf94RuQ/AVBLBwhQFDEKDQEAAOQBAABQSwECFAAUAAgICAAAACEAUBQxCg0BAADkAQAA +CAAJAAAAAAAAAAAAAAAAAAAALmNvbnRlbnRVVAUAAQAAAABQSwUGAAAAAAEAAQA/AAAATAEAAAAA +------=_.q7.content-3d2e0690-ce48-3609-83e0-c704d49f1eaf-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/ActivateExperimentalUpdates.test b/org.lamport.tla.toolbox.product.uitest/bvt/ActivateExperimentalUpdates.test new file mode 100644 index 0000000000000000000000000000000000000000..691698819d67dac36dccb35d75e4c9c02883b0a0 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/ActivateExperimentalUpdates.test @@ -0,0 +1,26 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: ActivateExperimentalUpdates +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _rtcgcP9UEeiWgvGqW2E8Fg +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 3:55 PM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +SetUpAppWindow + +get-preferences-menu | click +with [get-window Preferences ] { + get-tree | select "Automatic Update" + get-checkbox -text "Receive experimental features for the TLA Toolbox." | check + + get-button "Apply and Close" | click +} + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/SmokeSuite.suite b/org.lamport.tla.toolbox.product.uitest/bvt/SmokeSuite.suite new file mode 100644 index 0000000000000000000000000000000000000000..c208b40088e74e2af8adadc058b8ea7f034c4d68 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/SmokeSuite.suite @@ -0,0 +1,24 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: SmokeSuite +Element-Type: testsuite +Element-Version: 2.0 +Id: _3DuDsP8pEeimGdyWh_qiaA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/10/19 10:27 AM + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8 +Content-Type: text/testcase +Entry-Name: testcase-items + +_4M7XgP21EeiCTvrXzYZPCg // kind: 'test' name: 'TLA.Smoke.Create.Close.Open' path: 'TLA.Smoke.Create.Close.Open.test' +_c0C1QP19EeiqL7RHpA20Ww // kind: 'test' name: 'TLA.Smoke.Create.Delete' path: 'TLA.Smoke.Create.Delete.test' +_Nhf3gP9aEeiWgvGqW2E8Fg // kind: 'test' name: 'TLA.Smoke.Create.Test.Spec' path: 'TLA.Smoke.Create.Test.Spec.test' +__NXfoAPwEemwBd2liJ-qvA // kind: 'test' name: 'TLA.Smoke.Model.Tabs' path: 'TLA_Smoke_Model_Tabs.test' +_thReYP27EeiCTvrXzYZPCg // kind: 'test' name: 'TLA.Smoke.New.Model.Simple' path: 'TLA.Smoke.New.Model.Simple.test' +_LlgJkAL3EemtrbArmQOOJA // kind: 'test' name: 'TLA.Smoke.Quick.Access' path: 'TLA_Smoke_Quick_Access.test' +_HS58UP2vEeiCTvrXzYZPCg // kind: 'test' name: 'TLA.Smoke.Rename.Spec' path: 'TLA.Smoke.Rename.Spec.test' +_lPDvMP18EeiqL7RHpA20Ww // kind: 'test' name: 'TLA.Smoke.Valid.Path' path: 'TLA.Smoke.Valid.Path.test' +_CxeGQAP2EemwBd2liJ-qvA // kind: 'test' name: 'TLA.Smoke.Window.Reset' path: 'TLA_Smoke_Window_Reset.test' + +------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test new file mode 100644 index 0000000000000000000000000000000000000000..da8074277a5795a8c48dadcdcfb5a1a3be2faf24 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test @@ -0,0 +1,41 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Create.Close.Open +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _4M7XgP21EeiCTvrXzYZPCg +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/14/19 8:12 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create TLA +Close it +Reopen and Verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew +try -command { +//Reopen +get-menu -path "File/Close Spec" | click + + +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME +get-menu -path "File/Spec Explorer" | click +get-menu -path "File/Open Spec/new" | click +get-view "Spec Explorer" | get-tree | get-item -path [concat $TLA-TREE-NAME "/modules"] | get-property caption + | equals modules | verify-true + +} -finally +//Delete Spec +{DeleteSpecNew} + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test new file mode 100644 index 0000000000000000000000000000000000000000..78e695bd2d2792ab9dee345fceb973391970c5f5 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test @@ -0,0 +1,37 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Create.Delete +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _c0C1QP19EeiqL7RHpA20Ww +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/15/19 11:11 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create then Deletes TLA, Verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create new Spec +OpenTLACreateNew + +try -command { +get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property caption + | equals $TLA-TREE-NAME | verify-true +with [get-label parsed] { + get-property "getVisible()" | equals true | verify-true + get-property "toString()" | equals "Label { parsed }" | verify-true +} +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test new file mode 100644 index 0000000000000000000000000000000000000000..01a425c6254ce0bfa1919ce1685875a7cea1b0c7 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test @@ -0,0 +1,35 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Create.Test.Spec +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _Nhf3gP9aEeiWgvGqW2E8Fg +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:11 AM +Testcase-Type: ecl + +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew +try -command { + +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 2 + type-text "Init == x = 0" + key-type Enter -times 2 + type-text "Next == x' = x + 1" + key-type "M1+s" +} + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test new file mode 100644 index 0000000000000000000000000000000000000000..18ab13fd8a84556e5121d8f32993a377a8501e92 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test @@ -0,0 +1,43 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.New.Model.Simple +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _thReYP27EeiCTvrXzYZPCg +Runtime-Version: 2.4.0.201902010011 +Save-Time: 3/26/19, 11:18 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create TLA +Add new Model Foo +Delete TLA +Say no to saving foo + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create Spec +OpenTLACreateNew + +try -command { + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-editbox -after [get-label "Please input the name of the model to create"] | set-text $Model-TEST-Name + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + get-editor $Model-TEST-Name | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" + | verify-true + + + get-editor foo | get-button "Checks the model for errors but does not run TLC on it." | click +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test new file mode 100644 index 0000000000000000000000000000000000000000..3c8f1c996a7540ff05fd2944add72a0a15cf03c3 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test @@ -0,0 +1,35 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Rename.Spec +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _HS58UP2vEeiCTvrXzYZPCg +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/14/19 7:29 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Create TLA then Renames. +Delete and Verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//Create new spec +OpenTLACreateNew + +try -command { +get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Rename | click +get-window "New specification name" | get-label "Please input the new name of the specification" | get-property caption + | equals "Please input the new name of the specification" | verify-true +get-window "New specification name" | get-button OK | click + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test new file mode 100644 index 0000000000000000000000000000000000000000..aa2b6910d1e98aa4fd85ea1612588ae9cecf1603 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test @@ -0,0 +1,30 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Valid.Path +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _lPDvMP18EeiqL7RHpA20Ww +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/9/19 12:50 PM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Standard Create then Delete. Verify +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +//new Spec +try -command { +OpenTLACreateNew +} -finally +{ +//Delete Spec +DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test new file mode 100644 index 0000000000000000000000000000000000000000..04cdc2a3b40ef6d866d618d441988f4a7805c832 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test @@ -0,0 +1,69 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Model.Tabs +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: __NXfoAPwEemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902010011 +Save-Time: 6/10/19, 9:48 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Smoke +New Spec +New Model +Verify all 3 tabs +Verify that No run has taken place +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +try -command { + with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 999999999999999999999999999999999999999" + key-type Enter -times 2 + type-text "Next == x' = x * 999999999999999999999999999999" + key-type "M1+s" + } + wait -ms 1000 + + get-menu -path "TLC Model Checker/New Model..." | click + get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true + get-window "New model..." | get-button OK | click + with [get-editor "Model_1"] { + get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true + get-section "What is the model?" | click + get-link "Additional Spec Options" | click + get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true + get-section "Additional Definitions" | click + get-section "State Constraint" | click + get-section "Model Values" | click + get-section "Definition Override" | click + get-section "Action Constraint" | click + get-tab-folder | get-tab-item "Model Checking Results" | click + } + with [get-editor "Model_1"] { + get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true + with [get-section "General"] { + get-label "Awaiting first run..." + verify-error {get-label "Not running"} + verify-error {get-link "No errors"} + } + } +} -finally { + DeleteSpecNew +} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test new file mode 100644 index 0000000000000000000000000000000000000000..f204a45dd59dad445e287ed6bb9924138d7e0655 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test @@ -0,0 +1,28 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Quick.Access +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _LlgJkAL3EemtrbArmQOOJA +Runtime-Version: 2.3.0.201806262310 +Save-Time: 12/18/18 11:00 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Menu Item +Quick Access +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +get-menu -path "Window/Quick Access..." | click +get-window -class TLAFilteredItemsSelectionDialog + | get-label "Select an item to open (? = any character, * = any string):" | get-property caption + | equals "&Select an item to open (? = any character, * = any string):" | verify-true +get-window -class TLAFilteredItemsSelectionDialog | get-button Cancel | click +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test new file mode 100644 index 0000000000000000000000000000000000000000..b88581947ecf4f8eef02640037c37450a26e2a46 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test @@ -0,0 +1,57 @@ +--- RCPTT testcase --- +Format-Version: 1.0 +Element-Name: TLA.Smoke.Window.Reset +Element-Type: testcase +Element-Version: 3.0 +External-Reference: +Id: _CxeGQAP2EemwBd2liJ-qvA +Runtime-Version: 2.4.0.201902090011 +Save-Time: 4/3/19, 9:11 AM +Testcase-Type: ecl + +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa +Content-Type: text/plain +Entry-Name: .description + +Smoke +Spec Window Reset +------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa-- +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac +Content-Type: text/ecl +Entry-Name: .content + +OpenTLACreateNew + +try -command { +with [get-editor $TLA-SPEC-NAME | get-text-viewer] { + key-type Down + type-text "EXTENDS Naturals" + key-type Enter + type-text "VARIABLE x" + key-type Enter -times 1 + type-text "Init == x = 999999999999999999999999999999999999999" + key-type Enter -times 2 + type-text "Next == x' = x * 999999999999999999999999999999" + key-type "M1+s" + } + wait -ms 1000 +get-menu -path "TLC Model Checker/New Model..." | click +get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption + | equals "Please input the name of the model to create" | verify-true +get-window "New model..." | get-button OK | click + + +get-menu -path "Window/Spec Explorer" | click +get-view "Spec Explorer" | minimize +get-menu -path "Window/Spec Explorer" | click +//get-menu -path "Window/Reset Window Layout" | click +//get-window "Reset Perspective" +// | get-label "Do you want to reset the current Specification perspective to its defaults?" | get-property caption +// | equals "Do you want to reset the current Specification perspective to its defaults?" | verify-true +// get-window "Reset Perspective" | get-button Yes | click + + +} -finally +//Delete Spec +{DeleteSpecNew} +------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac-- diff --git a/org.lamport.tla.toolbox.product.uitest/pom.xml b/org.lamport.tla.toolbox.product.uitest/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ee48a8ced0ef632d26e87156f16f5d3841dd46a6 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/pom.xml @@ -0,0 +1,342 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>parent</artifactId> + <groupId>tlatoolbox</groupId> + <version>0.0.1-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <groupId>tlatoolbox</groupId> + <artifactId>org.lamport.tla.toolbox.product.uitest</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>rcpttTest</packaging> + + <!-- RCPTT Maven Plugin and RCPTT Runner are hosted in this repository --> + <pluginRepositories> + <pluginRepository> + <id>rcptt-releases</id> + <name>RCPTT Maven repository</name> + <url>https://repo.eclipse.org/content/repositories/rcptt-releases/</url> + </pluginRepository> + <!-- + <pluginRepository> + <id>rcptt-snapshots</id> + <name>RCPTT Maven Snapshots repository</name> + <snapshots> + <updatePolicy>always</updatePolicy> + </snapshots> + <url>https://repo.eclipse.org/content/repositories/rcptt-snapshots/</url> + </pluginRepository> + --> + </pluginRepositories> + + <!-- + If RCPTT tests are planned to be run on an update site, + RCPTT Maven Plugin can download Eclipse SDK of required version + for current platform from repository below (to see + an up-to-date list of available versions visit this link: + http://maven.xored.com/nexus/content/repositories/ci4rcptt-releases/org/eclipse/sdk/ + --> + <properties> + <rcptt-maven-version>2.4.2</rcptt-maven-version> + <rcptt-runner-version>2.4.2</rcptt-runner-version> + <aut-unpack-directory>target/unpack-for-aut/</aut-unpack-directory> +<!-- + <jdk-bundle-plugin-prefix>st.theori.openjdk.</jdk-bundle-plugin-prefix> + --> + <jdk-bundle-plugin-prefix>org.lamport.openjdk.</jdk-bundle-plugin-prefix> + </properties> + + <!-- ordering here is important since macos matches the family 'unix' --> + <profiles> + <profile> + <id>linux</id> + <activation> + <os> + <family>unix</family> + </os> + </activation> + <properties> + <os-ws-arch>linux.gtk.x86_64</os-ws-arch> + <product-path>linux/gtk/x86_64/</product-path> + </properties> + </profile> + <profile> + <id>macos</id> + <activation> + <os> + <name>mac os x</name> + </os> + </activation> + <properties> + <os-ws-arch>macosx.cocoa.x86_64</os-ws-arch> + <product-path>macosx/cocoa/x86_64</product-path> + </properties> + </profile> + <profile> + <id>win32</id> + <activation> + <os> + <family>windows</family> + </os> + </activation> + <properties> + <os-ws-arch>win32.win32.x86_64</os-ws-arch> + <product-path>win32/win32/x86_64</product-path> + </properties> + </profile> + </profiles> + + + <build> + <plugins> + <!-- + Something has a bug on macos where it does not preserve the executable + perms on unpacked files; this bites us as RCPTT attempts to run the java binary + that has been zipped up in our JDK wrapping feature. We will unpack the ZIP using a + different route which allows us to chmod too. + + https://github.com/mojohaus/truezip/issues/8 + + Would you believe that ant's unzip on macOS also doesn't preserve the execution bit? what in the world... + --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.8</version> + <executions> + <execution> + <phase>validate</phase> + <goals> + <goal>run</goal> + </goals> + <configuration> + <skip>${maven.test.skip}</skip> + <target> + <property name="toolbox_version" value="${toolbox.version}"/> + <property name="os_ws_arch" value="${os-ws-arch}"/> + <property name="unpack_dir" value="${aut-unpack-directory}"/> + <property name="plugin_prefix" value="${jdk-bundle-plugin-prefix}"/> + <property name="plugin_version" value="${jdk-bundle-plugin-version}"/> + + <mkdir dir="${unpack_dir}" /> + <unzip + src="../org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-${toolbox_version}-${os_ws_arch}.zip" + dest="${unpack_dir}" /> + <chmod dir="${unpack_dir}" perm="ugo+x" includes="**/bin/*,**/Contents/Home/lib/jspawnhelper"/> + + <ac:if xmlns:ac="antlib:net.sf.antcontrib"> + <ac:equals arg1="${os_ws_arch}" arg2="macosx.cocoa.x86_64"/> + <ac:then> + <echo message="Performing additional repairs to the macOS JDK bundle..."/> + <delete file="${unpack_dir}/TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/MacOS/libjli.dylib"/> + <symlink + link="${basedir}/${unpack_dir}/TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/MacOS/libjli.dylib" + resource="${basedir}/${unpack_dir}TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/Home/lib/jli/libjli.dylib"/> + <!-- Rename Toolbox directory to remove "+ " in path ".../TLA+ Toolbox/..." to make RCPTT not crash with + java.net.URISyntaxException: Illegal character in path at index 104: ... + (see https://bugs.eclipse.org/547632) --> + <move todir="${unpack_dir}/TLAToolbox.app"> + <fileset dir="${unpack_dir}/TLA+ Toolbox.app/"/> + </move> + </ac:then> + </ac:if> + </target> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>ant-contrib</groupId> + <artifactId>ant-contrib</artifactId> + <version>1.0b3</version> + <exclusions> + <exclusion> + <groupId>ant</groupId> + <artifactId>ant</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + </plugin> + + + <!-- The main part of RCPTT Maven plugin --> + <plugin> + <groupId>org.eclipse.rcptt</groupId> + <artifactId>rcptt-maven-plugin</artifactId> + <version>${rcptt-maven-version}</version> + <extensions>true</extensions> + <configuration> + + <!-- This element describes where to get an AUT to run tests --> + <aut> + <!-- There are several ways to specify AUT location, + Uncomment an element corresponding to a most suitable way + --> + + <!-- Use AUT from current build results. [classifier] will be + automatically replaced according to the current platform + + DO NOT USE - see above comment WRT truezip + + <explicit>../org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.0-[platform].zip</explicit> + --> + + <explicit>${aut-unpack-directory}</explicit> + + <!-- Or specify a path to AUT folder --> + <!-- + <explicit>/Users/RCPTTuser/path/to/aut</explicit> + --> + + <!-- As well AUT can be downloaded from HTTP --> + <!-- + <explicit>http://server/path/aut-archive.zip</explicit> + --> + + <!-- AUT can be downloaded automatically from Maven repository --> + <!-- + <groupId>com.company.product</groupId> + <artifactId>com.company.product.rcp</artifactId> + <version>3.7.2</version> + --> + + <!-- AUT Artifact classifier is based on a current platform: + Windows 32bit: win32.win32.x86 + Windows 64bit: win32.win32.x86_64 + Linux 32bit: linux.gtk.x86 + Linux 64bit: linux.gtk.x86_64 + Mac OS X 64bit: macosx.coca.x86_64 + --> + + <!-- Optionally it is possible to specify extra features to + be installed into AUT, this is useful when RCPTT tests + need to be executed using a repository assembled as + part of current Maven build. + + Inside an 'injection element it is possible to specify a list of + features/plugins to install, if nothing is set, all available + features will be installed. + feature.group suffix is required by p2, + otherwise it searches for a plugin with given id + + Currently RCPTT Runner does not install requirements automatically, + so the full list of features to install must be explicitly set + --> + + + + <injections> + <!-- features are optional - when omitted, all features from given site will be installed --> + <!-- + <injection> + <site></site> + <features> + <feature>com.comanyname.featureid</feature> + </features> + </injection> + --> + </injections> + + <!-- additional AUT args (besides taken in its ini-file) can be set + Use one argument per <arg> element --> + <!-- + <args> + <arg>-ws</arg> + <arg>$${target.ws}</arg> + </args> + --> + <!-- optional VM args can be set too --> + <!-- + <vmArgs> + <vmArg>-Xmx768m</vmArg> + <vmArg>-XX:MaxPermSize=256m</vmArg> + <vmArg>-Xdebug</vmArg> + <vmArg>-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8989</vmArg> + </vmArgs> + --> + </aut> + + <runner> + <!-- RCPTT Runner location can be set using the same methods + as AUT location: + --> + <!-- + <explicit>/path/to/rcptt/runner</explicit> + --> + + <!-- but the most convenient way is to just set its version, + RCPTT maven plugin will automatically set right groupId and + artifact ID and will download RCPTT Runner from Xored Maven Repo --> + <version>${rcptt-runner-version}</version> + + <vmArgs> + </vmArgs> + </runner> + + <!-- Test options for RCPTT Runner, most popular options listed here. + Full list of options is available at: + https://ci.xored.com/doc/runner/ + --> + <testOptions> + <!-- Timeout for all tests, in seconds --> + <execTimeout>1800</execTimeout> + <!-- Timeout for a single test case, in seconds --> + <testExecTimeout>300</testExecTimeout> + + <!-- When set to true, in case of test failure + AUT will be restarted. This significantly + slows down execution, but may be useful + for some test suites --> + <!-- + <restartAUTOnFailure>true</restartAUTOnFailure> + --> + </testOptions> + + <!-- By default RCPTT Runner runs tests from a project directory, + but in some cases it might be required to import additional + projects into runner's workspace --> + <!-- + <projects> + <project>${project.basedir}/../project</project> + </projects> + --> + + <!-- By default RCPTT Runner runs all tests from workspace, + but it is possible to pass test suite names, so it + will execute only test suites from given project. --> + + <!-- + <suites> + <suite>MyTestSuite</suite> + </suites> + --> + + <!-- Sometimes it might be useful to skip a test case + (for instance because of some unresolved bug). RCPTT + can skip tests based on its tags. By default RCPTT skips + tests with tag 'skipExecution' (this value has been + chosen because on one hand it is descriptive enough, + on another hand it is unlikely that this tag name + will collide with some user's tag) + --> + <!-- + <skipTags> + <skipTag>linuxOnly</skipTag> + </skipTags> + --> + + <!-- By default RCPTT generates a single HTML report file with + all tests, but it is possible to generate one file per + test --> + <!-- + <splitHtmlReport>true</splitHtmlReport> + --> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/org.lamport.tla.toolbox.product.uitest/rcptt.properties b/org.lamport.tla.toolbox.product.uitest/rcptt.properties new file mode 100644 index 0000000000000000000000000000000000000000..68b064d167bfc9b183da61f50405ebde63782aa7 --- /dev/null +++ b/org.lamport.tla.toolbox.product.uitest/rcptt.properties @@ -0,0 +1,11 @@ +--- RCPTT project settings --- +Format-Version: 1.0 +Contexts: _KWU8wBN2EemG79v6PBILBA,_MMwoABN4EemG79v6PBILBA,_zmZVMP5NEeilFekyyVb9lA,_DSUP8P5YEeilFekyyVb9lA +Element-Name: Project Settings +Element-Type: projectMetadata +Element-Version: 2.0 +Id: _i5aFsP9ZEeiWgvGqW2E8Fg +Runtime-Version: 2.3.0.201806262310 +Save-Time: 1/8/19 11:24 AM +Verifications: _OR3AcBLBEemDf5eqf3kQng + diff --git a/org.lamport.tla.toolbox.rss/.classpath b/org.lamport.tla.toolbox.rss/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..d486d9caf61f5f4c9a2433bd71463c8cf1d3996c --- /dev/null +++ b/org.lamport.tla.toolbox.rss/.classpath @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry exported="true" kind="lib" path="lib/istack-commons-runtime-3.0.7.jar"/> + <classpathentry exported="true" kind="lib" path="lib/jaxb-api-2.3.1.jar"/> + <classpathentry exported="true" kind="lib" path="lib/jaxb-runtime-2.3.1.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.lamport.tla.toolbox.rss/.project b/org.lamport.tla.toolbox.rss/.project new file mode 100644 index 0000000000000000000000000000000000000000..4a2b5a4662e79fd41b36b0cf28e2c126890fc397 --- /dev/null +++ b/org.lamport.tla.toolbox.rss/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.lamport.tla.toolbox.rss</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/org.lamport.tla.toolbox.rss/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.rss/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..fb1077bceaf46dda9c8481d0012527b903790b55 --- /dev/null +++ b/org.lamport.tla.toolbox.rss/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox.rss/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.rss/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..749168c167ec4021934583585185da3496ebb133 --- /dev/null +++ b/org.lamport.tla.toolbox.rss/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Extends Mylyn Notification Feed for Java11 +Bundle-SymbolicName: org.lamport.tla.toolbox.rss +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: Markus Alexander Kuppe +Fragment-Host: org.eclipse.mylyn.commons.notifications.feed;bundle-version="1.16.0" +Automatic-Module-Name: org.eclipse.mylyn.commons.notifications.feed.jaxb +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ClassPath: ., + lib/istack-commons-runtime-3.0.7.jar, + lib/jaxb-api-2.3.1.jar, + lib/jaxb-runtime-2.3.1.jar +Require-Bundle: javax.activation;bundle-version="1.1.0" diff --git a/org.lamport.tla.toolbox.rss/README.txt b/org.lamport.tla.toolbox.rss/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..1446b72a9dba3728ca10d3dd27370d14db45f4af --- /dev/null +++ b/org.lamport.tla.toolbox.rss/README.txt @@ -0,0 +1,18 @@ +This is a fragment bundle to Mylyn's notification feed bundle. The Mylyn +bundle is broken on Java 11 (https://bugs.eclipse.org/541569) because +Java 11 finally removes the (previously deprecated) java.se.ee module +(https://openjdk.java.net/jeps/320). + +This fragment causes the feed bundle to use the classes in the packages +javax.xml.bind and com.sun.xml provided by the nested libraries (plain +jars) in the lib/ directory instead of XML provided by the JVM itself. + +Once Mylyn bug #541569 has been addressed and a new Mylyn release +consumed by the Toolbox (via the .target file), this bundle can probably +be removed again. + +-- + +A similar change (include jaxb-api) was required to fix problems with +jclouds +(ttps://github.com/lemmy/jclouds2p2/commit/38296ac50042c18c17d0c91f3bbd2872d6c2e4ac). \ No newline at end of file diff --git a/org.lamport.tla.toolbox.rss/build.properties b/org.lamport.tla.toolbox.rss/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..704e6742e0c4b2022fad2ade96e354a6066da07d --- /dev/null +++ b/org.lamport.tla.toolbox.rss/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + lib/istack-commons-runtime-3.0.7.jar,\ + lib/jaxb-api-2.3.1.jar,\ + lib/jaxb-runtime-2.3.1.jar diff --git a/org.lamport.tla.toolbox.rss/lib/istack-commons-runtime-3.0.7.jar b/org.lamport.tla.toolbox.rss/lib/istack-commons-runtime-3.0.7.jar new file mode 100644 index 0000000000000000000000000000000000000000..2fe5b82620b5765e4a77dc3cca97d3424b6cbaed Binary files /dev/null and b/org.lamport.tla.toolbox.rss/lib/istack-commons-runtime-3.0.7.jar differ diff --git a/org.lamport.tla.toolbox.rss/lib/jaxb-api-2.3.1.jar b/org.lamport.tla.toolbox.rss/lib/jaxb-api-2.3.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..45658654712b88d45c9464286ffc2fcb07036bdf Binary files /dev/null and b/org.lamport.tla.toolbox.rss/lib/jaxb-api-2.3.1.jar differ diff --git a/org.lamport.tla.toolbox.rss/lib/jaxb-runtime-2.3.1.jar b/org.lamport.tla.toolbox.rss/lib/jaxb-runtime-2.3.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..0b9ef67c498bd731a34125f540dcc9621adea8d8 Binary files /dev/null and b/org.lamport.tla.toolbox.rss/lib/jaxb-runtime-2.3.1.jar differ diff --git a/org.lamport.tla.toolbox.rss/pom.xml b/org.lamport.tla.toolbox.rss/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f0ab03d6e7c7be6ff17b17d75351274b8545c50 --- /dev/null +++ b/org.lamport.tla.toolbox.rss/pom.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>parent</artifactId> + <groupId>tlatoolbox</groupId> + <version>0.0.1-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <groupId>tlatoolbox</groupId> + <artifactId>org.lamport.tla.toolbox.rss</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.lamport.tla.toolbox.rss/src/org/lamport/tla/toolbox/rss/Noop.java b/org.lamport.tla.toolbox.rss/src/org/lamport/tla/toolbox/rss/Noop.java new file mode 100644 index 0000000000000000000000000000000000000000..e6a55fafe9b0a28016cd2cd68738985990bd49ae --- /dev/null +++ b/org.lamport.tla.toolbox.rss/src/org/lamport/tla/toolbox/rss/Noop.java @@ -0,0 +1,5 @@ +package org.lamport.tla.toolbox.rss; + +public class Noop { + // Make Tycho (signing) happy. +} diff --git a/org.lamport.tla.toolbox.test/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.test/META-INF/MANIFEST.MF index 514d9a91a97905add6520ab952ee2d101c21eaca..835f8dc88b908a40803f82a2970859d02d27a283 100644 --- a/org.lamport.tla.toolbox.test/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.test/META-INF/MANIFEST.MF @@ -9,3 +9,4 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.osgi.framework;version="1.3.0" Require-Bundle: org.eclipse.swt;bundle-version="3.5.0", org.junit;bundle-version="3.8.2" +Automatic-Module-Name: org.lamport.tla.toolbox.test diff --git a/org.lamport.tla.toolbox.test/pom.xml b/org.lamport.tla.toolbox.test/pom.xml index 9b65c29fdc7b595c6ed9a7d95ae066495d03b5d3..8a3d429bbc54e5af6edbead808e12f49dcb31b06 100644 --- a/org.lamport.tla.toolbox.test/pom.xml +++ b/org.lamport.tla.toolbox.test/pom.xml @@ -23,7 +23,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> diff --git a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java index 1c03d01324fadde92891ec76d7bad183f92ec953..9f409a57a84756a92ea647fdae8caa09e7280b0b 100644 --- a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java +++ b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java @@ -37,6 +37,7 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; import org.eclipse.jface.preference.IPreferenceStore; import org.junit.Assert; import org.lamport.tla.toolbox.spec.manager.WorkspaceSpecManager; @@ -88,7 +89,17 @@ public class SpecTest extends TestCase { // Create... final Path tempDirectory = Files.createTempDirectory("ReadOnlyDirectory" + System.currentTimeMillis()); final File tempFile = Files.createTempFile(tempDirectory, "TestCreateSpecInReadOnlyDirectory", ".tla").toFile(); - tempDirectory.toFile().setReadOnly(); + +// Assume.assumeTrue(tempDirectory.toFile().setReadOnly()); + if (!tempDirectory.toFile().setReadOnly()) { + // Setting the test-file to read-only doesn't appear to work on Windows. + // Normally, this case can be handled with Assume.assumeTrue(tempDirectory...) + // but this test runs as an Eclipse Plug-in test whose Junit runner doesn't + // appear to correctly handle JUunit's AssumptionViolationException. + assertTrue(Platform.OS_WIN32.equals(Platform.getOS())); + return; + } + try { Spec.createNewSpec("TestCreateSpecInReadOnlyDirectory", tempFile.getAbsolutePath(), false, new NullProgressMonitor()); } catch (CoreException e) { diff --git a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java index 44e13899724e926fab617da84b170ecccbebb1d1..a1764aaa4ede1d6791ec528d07cef6b102db3a81 100644 --- a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java +++ b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java @@ -27,6 +27,7 @@ package org.lamport.tla.toolbox.util; import static org.junit.Assert.assertArrayEquals; + import junit.framework.TestCase; public class StringHelperTest extends TestCase { diff --git a/org.lamport.tla.toolbox.tool.prover/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.prover/META-INF/MANIFEST.MF index 1ac78412a71a2e4da3e73a8e8861aeb73d88c339..abdb28deefe6781dca9b1d4d6965f9f2058c0c01 100644 --- a/org.lamport.tla.toolbox.tool.prover/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.prover/META-INF/MANIFEST.MF @@ -23,3 +23,4 @@ Import-Package: org.eclipse.ui.forms, org.lamport.tla.toolbox.editor.basic.util Export-Package: org.lamport.tla.toolbox.tool.prover.ui.output.data, org.lamport.tla.toolbox.tool.prover.ui.output.source +Automatic-Module-Name: org.lamport.tla.toolbox.tool.prover diff --git a/org.lamport.tla.toolbox.tool.prover/plugin.xml b/org.lamport.tla.toolbox.tool.prover/plugin.xml index 4ff073cb3a2f5d0d0da7afcc5ca5b55eabad9324..ada4e6516e212c7a2398e4fd7afe671d907d14ad 100644 --- a/org.lamport.tla.toolbox.tool.prover/plugin.xml +++ b/org.lamport.tla.toolbox.tool.prover/plugin.xml @@ -33,9 +33,9 @@ <extension point="org.eclipse.ui.menus"> <menuContribution - locationURI="popup:#TextEditorContext?after=foldCommands"> + locationURI="popup:org.lamport.tla.toolbox.editor.basic.tlaps?after=additions"> <command - commandId="org.lamport.tla.toolbox.tool.prover.ui.checkStep.delegate" + commandId="org.lamport.tla.toolbox.tool.prover.ui.launchProver" style="push"> </command> <command @@ -43,7 +43,7 @@ style="push"> </command> <command - commandId="org.lamport.tla.toolbox.tool.prover.ui.launchProver" + commandId="org.lamport.tla.toolbox.tool.prover.ui.checkStep.delegate" style="push"> </command> </menuContribution> diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java index d676dce4943c651bbc5b65b8b30d57e7d4a34f0d..f98d8ed6d3983ee6474ea4ea2e3125f3dd98146d 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java @@ -17,7 +17,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; @@ -50,6 +49,7 @@ import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepStatusMessage; import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepTuple; import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage; import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; +import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator; import org.lamport.tla.toolbox.tool.prover.ui.view.ObligationsView; import org.lamport.tla.toolbox.util.ResourceHelper; @@ -63,10 +63,8 @@ import util.UniqueString; * and the run method for information about this job. * * @author Daniel Ricketts - * */ -public class ProverJob extends Job -{ +public class ProverJob extends Job { /** * The time that the run method was called. * This is the time in milliseconds returned @@ -239,59 +237,10 @@ public class ProverJob extends Job * The following sets the path to tlapm. */ Assert.isTrue(Platform.isRunning(), "Platform is not running when prover was launched. This makes no sense."); - // the default tlapm command on all systems if - // no complete tlapm path can be found. - this.tlapmPath = new Path("tlapm"); - - if (Platform.getOS().equals(Platform.OS_WIN32)) - { - /* - * Check if "C:/cygwin/usr/local/bin/tlapm.exe" exists. - * If it does exist, that is the path. Else, the path is "tlapm". Setting - * the path to "tlapm" assumes that it is in the system path. - */ - final IPath defaultPath = new Path("C:/cygwin/usr/local/bin/tlapm.exe"); - final IPath defaultPath64 = new Path("C:/cygwin64/usr/local/bin/tlapm.exe"); - - if (defaultPath.toFile().exists()) - { - this.tlapmPath = defaultPath; - - /* - * If cygwin path is specified, use that. If not - * use the default cygwin path : - * "C:\cygwin\bin" - */ - this.cygwinPath = new Path("C:\\cygwin\\bin"); - } - /* - * Nowadays 64bit systems are common, thus also check c:/cygwin64/... - */ - else if (defaultPath64.toFile().exists()) - { - this.tlapmPath = defaultPath64; - this.cygwinPath = new Path("C:\\cygwin64\\bin"); - } - - } else if (Platform.getOS().equals(Platform.OS_MACOSX) || Platform.getOS().equals(Platform.OS_LINUX)) - { - - /* - * Check if "/usr/local/bin/tlapm" exists. - * If it does exist, that is the path. Else, the path is tlapm. Setting - * the path to "tlapm" assumes that it is in the system path. - */ - IPath defaultPath = new Path("/usr/local/bin/tlapm"); - - if (defaultPath.toFile().exists()) - { - this.tlapmPath = defaultPath; - } - - } else - { - // TODO indicate that the operating system is unsupported - } + + final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE; + this.tlapmPath = locator.getTLAPMPath(); + this.cygwinPath = locator.getCygwinPath(); /* * We create a useless launch object. It is diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/dialog/LaunchProverDialog.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/dialog/LaunchProverDialog.java index 2464763f58da845a01dd8cf1e88d2b2ccac07c56..afc89a21239610d447363db07fbdf4ea33212955 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/dialog/LaunchProverDialog.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/dialog/LaunchProverDialog.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.window.IShellProvider; @@ -26,7 +25,6 @@ import org.lamport.tla.toolbox.tool.prover.ProverPreferenceInitializer; import org.lamport.tla.toolbox.tool.prover.job.ITLAPMOptions; import org.lamport.tla.toolbox.tool.prover.job.ProverJob; import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator; -import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverSecondPreferencePage; import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; /** diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java index 0a54411df23ba8a652302aa4f0f6e592b80980bb..68eb574177ea93177541d94a1791e2126d08d372 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java @@ -6,6 +6,7 @@ import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; +import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator; /** * Launches TLAPM on the proof step currently containing the caret or on the @@ -30,10 +31,12 @@ public class CheckProofHandler extends AbstractHandler implements IHandler } /** - * This handler is enabled if there is a TLA editor with focus. + * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists. */ public void setEnabled(Object context) { - setBaseEnabled(EditorUtil.getTLAEditorWithFocus() != null); + final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE; + + setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist()); } } diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java index 7631a3a3e6ecda3b614eb9744afd753ec9771f93..369621c5503d88831e008b09b0120fbb63e548d5 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java @@ -4,7 +4,9 @@ import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.tool.prover.ui.dialog.LaunchProverDialog; +import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator; import org.lamport.tla.toolbox.util.UIHelper; /** @@ -17,7 +19,6 @@ import org.lamport.tla.toolbox.util.UIHelper; */ public class GeneralLaunchProverHandler extends AbstractHandler implements IHandler { - public Object execute(ExecutionEvent event) throws ExecutionException { /* @@ -34,4 +35,13 @@ public class GeneralLaunchProverHandler extends AbstractHandler implements IHand return null; } + /** + * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists. + */ + public void setEnabled(Object context) + { + final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE; + + setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist()); + } } diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java index 253f37669889b75ef150a9c88aecbc41ed0c14ae..0f245e0aca6f4b660558a878403fec9910c01bfe 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java @@ -4,7 +4,9 @@ import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; +import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator; /** * Runs the prover to simply get the status of the step containing @@ -18,7 +20,6 @@ import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; */ public class StatusStepHandler extends AbstractHandler implements IHandler { - public Object execute(ExecutionEvent event) throws ExecutionException { ProverHelper.runProverForActiveSelection(true, false); @@ -26,4 +27,13 @@ public class StatusStepHandler extends AbstractHandler implements IHandler return null; } + /** + * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists. + */ + public void setEnabled(Object context) + { + final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE; + + setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist()); + } } diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ErrorMessage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ErrorMessage.java index a4d5929255c5070ff733f1c2494ab6a2c51fc2fb..79e7bb93a1dd39273c91765fa4eebf8e0d9cc20e 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ErrorMessage.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ErrorMessage.java @@ -2,8 +2,8 @@ package org.lamport.tla.toolbox.tool.prover.ui.output.data; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator; diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ObligationStatusMessage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ObligationStatusMessage.java index defc911475f0ebcfc4e2f683a7f9ca9e77b02217..5f26c52b8f5daa8fc14e654dbd6743a433b11dc5 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ObligationStatusMessage.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ObligationStatusMessage.java @@ -2,8 +2,8 @@ package org.lamport.tla.toolbox.tool.prover.ui.output.data; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator; import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper; diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepStatusMessage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepStatusMessage.java index eb8f7b9b26a50be8b098ba2b99d92cb5c591cf0e..683d12242d312c9886cc34dc83d33517009a35e5 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepStatusMessage.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepStatusMessage.java @@ -2,8 +2,8 @@ package org.lamport.tla.toolbox.tool.prover.ui.output.data; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import tla2sany.st.Location; diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/WarningMessage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/WarningMessage.java index be5419c9d800a988011cc2c4db112c9209ddaac8..74eb9f852b96f2e6626b6558dbedfdf8709da71d 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/WarningMessage.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/WarningMessage.java @@ -2,8 +2,8 @@ package org.lamport.tla.toolbox.tool.prover.ui.output.data; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator; diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java index 9f9f020fd7a3410194c107f6ef2349c9e82951c7..fe647ebca4d732b61f30b914e0667525bfa33bc4 100644 --- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java @@ -5,7 +5,6 @@ package org.lamport.tla.toolbox.tool.prover.ui.preference; import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; -import org.eclipse.jface.preference.RadioGroupFieldEditor; import org.eclipse.jface.preference.StringFieldEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; @@ -14,7 +13,6 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator; -import org.lamport.tla.toolbox.ui.preference.EditorPreferencePage; /** * @author lamport diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java new file mode 100644 index 0000000000000000000000000000000000000000..c5e60aad62a9a4773c2f1d75e2e8db48e65f2422 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java @@ -0,0 +1,89 @@ +package org.lamport.tla.toolbox.tool.prover.ui.util; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.lamport.tla.toolbox.Activator; + +/** + * A singleton which provides reference to the {@link IPath} instances for the TLAPM executable, should one exist, and + * the Cygwin path, should the platform be appropriate. + */ +public class TLAPMExecutableLocator { + public static final TLAPMExecutableLocator INSTANCE = new TLAPMExecutableLocator(); + + + private final IPath tlapmPath; + private final IPath cygwinPath; + + private TLAPMExecutableLocator() { + // the default tlapm command on all systems if no complete tlapm path can be found. + IPath tlapm = new Path("tlapm"); + IPath cygwin = null; + + if (Platform.getOS().equals(Platform.OS_WIN32)) { + /* + * Check if "C:/cygwin/usr/local/bin/tlapm.exe" exists. + * If it does exist, that is the path. Else, the path is "tlapm". Setting + * the path to "tlapm" assumes that it is in the system path. + */ + final IPath defaultPath = new Path("C:/cygwin/usr/local/bin/tlapm.exe"); + final IPath defaultPath64 = new Path("C:/cygwin64/usr/local/bin/tlapm.exe"); + + if (defaultPath.toFile().exists()) { + tlapm = defaultPath; + + /* + * If cygwin path is specified, use that. If not + * use the default cygwin path : + * "C:\cygwin\bin" + */ + cygwin = new Path("C:\\cygwin\\bin"); + } + /* + * Nowadays 64bit systems are common, thus also check c:/cygwin64/... preferring to use that + */ + else if (defaultPath64.toFile().exists()) { + tlapm = defaultPath64; + cygwin = new Path("C:\\cygwin64\\bin"); + } + } else if (Platform.getOS().equals(Platform.OS_MACOSX) || Platform.getOS().equals(Platform.OS_LINUX)) { + /* + * Check if "/usr/local/bin/tlapm" exists. + * If it does exist, that is the path. Else, the path is tlapm. Setting + * the path to "tlapm" assumes that it is in the system path. + */ + final IPath defaultPath = new Path("/usr/local/bin/tlapm"); + + if (defaultPath.toFile().exists()) { + tlapm = defaultPath; + } + } else { + Activator.getDefault().logError("Platform [" + Platform.getOS() + "] is not supported."); + } + + tlapmPath = tlapm; + cygwinPath = cygwin; + } + + /** + * @return true if the path to TLAPM exists and there is a file there which can be executed + */ + public boolean tlapmDoesExist() { + return ((tlapmPath != null) + && (tlapmPath.toFile() != null) + && tlapmPath.toFile().exists() + && tlapmPath.toFile().canExecute()); + } + + /** + * @return this will be null on non-Windows platforms + */ + public IPath getCygwinPath() { + return cygwinPath; + } + + public IPath getTLAPMPath() { + return tlapmPath; + } +} diff --git a/org.lamport.tla.toolbox.tool.tla2tex.uitest/.classpath b/org.lamport.tla.toolbox.tool.tla2tex.uitest/.classpath index 64c5e31b7a264082f4c1dfdabb8097de820e66ce..eca7bdba8f03f22510b7980a94dbfe10c16c0901 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex.uitest/.classpath +++ b/org.lamport.tla.toolbox.tool.tla2tex.uitest/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> diff --git a/org.lamport.tla.toolbox.tool.tla2tex.uitest/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.tool.tla2tex.uitest/.settings/org.eclipse.jdt.core.prefs index 5c4cd5620d080c92b74905208ea0bd5e54c38a56..0c68a61dca867ceb49e79d2402935261ec3e3809 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex.uitest/.settings/org.eclipse.jdt.core.prefs +++ b/org.lamport.tla.toolbox.tool.tla2tex.uitest/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,7 @@ -#Sat May 14 13:03:18 CEST 2011 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox.tool.tla2tex.uitest/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tla2tex.uitest/META-INF/MANIFEST.MF index 1bfb54c9f24127203d780aad5fc014b257fcb679..73302bcda600783ff29005bc9f850ecca8f9ee62 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex.uitest/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tla2tex.uitest/META-INF/MANIFEST.MF @@ -5,4 +5,5 @@ Bundle-SymbolicName: org.lamport.tla.toolbox.tool.tla2tex.uitest Bundle-Version: 1.0.0.qualifier Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe Require-Bundle: org.lamport.tla.toolbox.uitest;bundle-version="1.0.0" -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tla2tex.uitest diff --git a/org.lamport.tla.toolbox.tool.tla2tex.uitest/pom.xml b/org.lamport.tla.toolbox.tool.tla2tex.uitest/pom.xml index fcab171009279160ba1cbd4b6a8a93a6c58564aa..ae442e8864c2776906fe783c5a333d383b278d5e 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex.uitest/pom.xml +++ b/org.lamport.tla.toolbox.tool.tla2tex.uitest/pom.xml @@ -12,7 +12,7 @@ <groupId>tlatoolbox</groupId> <artifactId>org.lamport.tla.toolbox.tool.tla2tex.uitest</artifactId> <version>1.0.0-SNAPSHOT</version> - <packaging>eclipse-test-plugin</packaging> + <packaging>eclipse-plugin</packaging> <properties> <!-- Do not include test project in Sonar reporting. --> <sonar.skip>true</sonar.skip> @@ -23,7 +23,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> @@ -36,113 +36,6 @@ </execution> </executions> </plugin> - <!-- Run JUnit tests --> - <plugin> - <groupId>org.eclipse.tycho</groupId> - <artifactId>tycho-surefire-plugin</artifactId> - <version>${tycho-version}</version> - - <configuration> - <showEclipseLog>true</showEclipseLog> - <useUIHarness>true</useUIHarness> - <useUIThread>${tycho.test.vm.useUiThread}</useUIThread> - <argLine>${tycho.test.vm.argline} ${tycho.testArgLine}</argLine> - <!-- use our product and application to launch the tests --> - <product>org.lamport.tla.toolbox.product.standalone.product</product> - <application>org.lamport.tla.toolbox.application</application> - - <systemProperties combine.children="append"> - <!-- References used by tests to access spec files --> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/farsite/DistributedSystemModule.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/DieHard/DieHard.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB> - <!-- JDT weaving debug output --> - <aj.weaving.verbose>true</aj.weaving.verbose> - <org.aspectj.weaver.showWeaveInfo>false</org.aspectj.weaver.showWeaveInfo> - <org.aspectj.osgi.verbose>false</org.aspectj.osgi.verbose> - </systemProperties> - - <dependencies> - <!-- help system needs javax.servlet --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>javax.servlet</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency is only needed because SWTbot brings its own - hamcrest bundle which conflicts with the one from junit in the eclipse platform --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.hamcrest</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency is needed because product/app is provided - by this bundle --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.lamport.tla.toolbox.product.standalone</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency toward AspectJ --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.aspectj.runtime</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.aspectj.weaver</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.weaving.aspectj</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.weaving.hook</artifactId> - <version>1.2.0.v20160929-1449</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.event</artifactId> - <version>0.0.0</version> - </dependency> - </dependencies> - - <!-- Enable JDT weaving --> - <frameworkExtensions> - <frameworkExtension> - <groupId>p2.osgi.bundle</groupId> - <artifactId>org.eclipse.equinox.weaving.hook</artifactId> - <version>1.2.0.v20160929-1449</version> - </frameworkExtension> - </frameworkExtensions> - - <bundleStartLevel> - <bundle> - <id>org.eclipse.equinox.weaving.aspectj</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.aspectj.weaver</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.aspectj.runtime</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.eclipse.equinox.event</id> - <level>4</level> - <autoStart>true</autoStart> - </bundle> - </bundleStartLevel> - </configuration> - </plugin> </plugins> </build> </project> diff --git a/org.lamport.tla.toolbox.tool.tla2tex.uitest/src/org/lamport/tla/toolbox/tool/tla2tex/PDFHandlerThreadingTest.java b/org.lamport.tla.toolbox.tool.tla2tex.uitest/src/org/lamport/tla/toolbox/tool/tla2tex/PDFHandlerThreadingTest.java index c140079a03b8fb0a7177a618c3ca42db5809be6a..cc11c9ad9d23d538160c099755d8149f2b5e92fc 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex.uitest/src/org/lamport/tla/toolbox/tool/tla2tex/PDFHandlerThreadingTest.java +++ b/org.lamport.tla.toolbox.tool.tla2tex.uitest/src/org/lamport/tla/toolbox/tool/tla2tex/PDFHandlerThreadingTest.java @@ -6,6 +6,7 @@ import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; @@ -14,8 +15,6 @@ import org.lamport.tla.toolbox.test.RCPTestSetupHelper; import org.lamport.tla.toolbox.test.threading.MonitorAdaptor; import org.lamport.tla.toolbox.ui.handler.OpenSpecHandler; -import org.junit.Assert; - @RunWith(SWTBotJunit4ClassRunner.class) public class PDFHandlerThreadingTest { diff --git a/org.lamport.tla.toolbox.tool.tla2tex/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tla2tex/META-INF/MANIFEST.MF index f7b581382b7a7ece789c2be45bf96dbde134ac62..06c72cde4ed018bcceeac33779cf1baf4173d415 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tla2tex/META-INF/MANIFEST.MF @@ -18,3 +18,4 @@ Import-Package: com.abstratt.graphviz, org.eclipse.ui, org.eclipse.ui.forms.editor, org.osgi.service.event;version="1.3.1" +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tla2tex diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java index c0b52d207fdf0b8a23b0cb116fea9ed2f3c5a85e..ac224a1061d5bf5ee165a8f2472c5348e2b80502 100644 --- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java +++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java @@ -1,14 +1,14 @@ package org.lamport.tla.toolbox.tool.tla2tex; -import com.abstratt.graphviz.GraphVizActivator; -import com.abstratt.graphviz.GraphVizActivator.DotMethod; - import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.lamport.tla.toolbox.AbstractTLCActivator; import org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants; import org.osgi.framework.BundleContext; +import com.abstratt.graphviz.GraphVizActivator; +import com.abstratt.graphviz.GraphVizActivator.DotMethod; + /** * The activator class controls the plug-in life cycle */ diff --git a/org.lamport.tla.toolbox.tool.tlc.test/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.test/META-INF/MANIFEST.MF index 9633f416fa8d38911c8e5ea774ff53255b30e271..7bd1daccf00d8b616b1d3c1983a74bcf0da1bcec 100644 --- a/org.lamport.tla.toolbox.tool.tlc.test/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc.test/META-INF/MANIFEST.MF @@ -7,3 +7,4 @@ Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe Fragment-Host: org.lamport.tla.toolbox.tool.tlc;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: J2SE-1.5 Require-Bundle: org.junit;bundle-version="3.8.2" +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc.test diff --git a/org.lamport.tla.toolbox.tool.tlc.test/pom.xml b/org.lamport.tla.toolbox.tool.tlc.test/pom.xml index 8b99e93b2eada9ccfa4fcea92236b02fe24f3736..c5f080b762c598fe9e3cf2dfa6a2ef5f204470f2 100644 --- a/org.lamport.tla.toolbox.tool.tlc.test/pom.xml +++ b/org.lamport.tla.toolbox.tool.tlc.test/pom.xml @@ -23,7 +23,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java index 2e1fdf3864e80c5898c6b323c8aaf97a7424c466..b8979130fd2a58750a383f59677b2b537169451a 100644 --- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java @@ -26,7 +26,7 @@ package org.lamport.tla.toolbox.tool.tlc.model; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import org.junit.Test; diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f01628c3d71a5c91f0188f074cdb8da218496195 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java @@ -0,0 +1,50 @@ +package org.lamport.tla.toolbox.tool.tlc.model; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class FormulaTest { + + @Test + public void testUnnamed() { + Formula formula = new Formula("TRUE"); + assertFalse(formula.isNamed()); + assertEquals("TRUE", formula.getRightHandSide()); + + formula = new Formula("LET clock[i \\in 1..(__trace_var_state)] ==\n" + + " IF i = 1\n" + + " THEN [ p \\in DOMAIN pc |-> 0 ]\n" + + " ELSE clock[i - 1]\n" + + "IN clock[__trace_var_state]"); + assertFalse(formula.isNamed()); + assertEquals("LET clock[i \\in 1..(__trace_var_state)] ==\n" + + " IF i = 1\n" + + " THEN [ p \\in DOMAIN pc |-> 0 ]\n" + + " ELSE clock[i - 1]\n" + + "IN clock[__trace_var_state]", formula.getRightHandSide()); + } + + @Test + public void testNamed() { + Formula formula = new Formula("foo == TRUE"); + assertEquals("foo", formula.getLeftHandSide()); + assertEquals("TRUE", formula.getRightHandSide()); + + formula = new Formula("foo == LET bar == TRUE IN bar"); + assertEquals("foo", formula.getLeftHandSide()); + assertEquals("LET bar == TRUE IN bar", formula.getRightHandSide()); + + formula = new Formula("bar == LET clock[i \\in 1..(__trace_var_state)] ==\n" + + " IF i = 1\n" + + " THEN [ p \\in DOMAIN pc |-> 0 ]\n" + + " ELSE clock[i - 1]\n" + + "IN clock[__trace_var_state]"); + assertEquals("bar", formula.getLeftHandSide()); + assertEquals("LET clock[i \\in 1..(__trace_var_state)] ==\n" + + " IF i = 1\n" + + " THEN [ p \\in DOMAIN pc |-> 0 ]\n" + + " ELSE clock[i - 1]\n" + + "IN clock[__trace_var_state]", formula.getRightHandSide()); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java index ce4de309a7f6227dfeb8a9e9793d02260f208b63..b9027a0a54c6c3a86add3bc85458f75958bf774e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java @@ -1,7 +1,5 @@ package org.lamport.tla.toolbox.tool.tlc.model; -import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; - import junit.framework.TestCase; /** diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java index 3e04be4c0c8161109c93e289ff87e9890696838a..339c3bf6b9dd8b06a2a0f0d221f8ecb0d75ddbb3 100644 --- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java @@ -26,6 +26,7 @@ package org.lamport.tla.toolbox.tool.tlc.util; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -251,5 +252,35 @@ public class ModelHelperTest extends TestCase public boolean isReadOnly() { return false; } + + public void delete(int flag) throws CoreException { + } + + public ILaunchConfiguration getPrototype() throws CoreException { + return null; + } + + public boolean isAttributeModified(String attribute) throws CoreException { + return false; + } + + public Collection<ILaunchConfiguration> getPrototypeChildren() throws CoreException { + return new ArrayList<ILaunchConfiguration>(); + } + + public int getKind() throws CoreException { + return 0; + } + + public Set<String> getPrototypeVisibleAttributes() throws CoreException { + return null; + } + + public void setPrototypeAttributeVisibility(String attribute, boolean visible) throws CoreException { + } + + public boolean isPrototype() { + return false; + } } } diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java index e4f285c0dc0f826b40f9a7be82f9f2f09c60cda7..7713f8d49f90f76b2206baa2c7abc42b2b46961d 100755 --- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java @@ -7,9 +7,8 @@ import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IRegion; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; -import tla2sany.st.Location; - import junit.framework.TestCase; +import tla2sany.st.Location; /** * Tests the regex matcher for generated ids diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF index 19b581bb5bc24dd5a1449e7e8731bed4b0f4251f..021ac3a01b0e951c18ebc634bc0461e7feaa93b0 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF @@ -12,3 +12,4 @@ Import-Package: org.osgi.framework;version="1.3.0" Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe Bundle-ActivationPolicy: lazy +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc.ui.test diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/pom.xml b/org.lamport.tla.toolbox.tool.tlc.ui.test/pom.xml index 436633f9c14c350ff0d46185ab6cd7662509300a..63e936bf2de7b19f4a1ffa4947727768f535bace 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/pom.xml +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/pom.xml @@ -23,7 +23,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItemTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItemTest.java new file mode 100644 index 0000000000000000000000000000000000000000..072aab65bf46bffb63687aa06b993d80a0c3fe99 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItemTest.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ActionInformationItemTest { + + @Test + public void testParseInit() { + final ActionInformationItem item = ActionInformationItem + .parseInit("<Init line 13, col 1 to line 14, col 5 of module H>: 3:15", "Model"); + assertNotNull(item); + assertNull(item.getDefinition()); + + assertEquals("H", item.getModule()); + assertEquals("Model", item.getModelName()); + + assertEquals("Init", item.getName()); + + assertEquals(13, item.getModuleLocation().beginLine()); + assertEquals(1, item.getModuleLocation().beginColumn()); + assertEquals(14, item.getModuleLocation().endLine()); + assertEquals(5, item.getModuleLocation().endColumn()); + + assertEquals(3, item.getCost()); + assertEquals(15, item.getCount()); + } + + @Test + public void testParseInit2() { + final ActionInformationItem item = ActionInformationItem + .parseInit("<Init line 13, col 1 to line 17, col 5 of module H (14 16 15 28)>: 3:15", "Model"); + assertNotNull(item); + + assertEquals(14, item.getDefinition().beginLine()); + assertEquals(16, item.getDefinition().beginColumn()); + assertEquals(15, item.getDefinition().endLine()); + assertEquals(28, item.getDefinition().endColumn()); + + assertEquals("H", item.getModule()); + assertEquals("Model", item.getModelName()); + + assertEquals("Init", item.getName()); + + assertEquals(13, item.getModuleLocation().beginLine()); + assertEquals(1, item.getModuleLocation().beginColumn()); + assertEquals(17, item.getModuleLocation().endLine()); + assertEquals(5, item.getModuleLocation().endColumn()); + + assertEquals(3, item.getCost()); + assertEquals(15, item.getCount()); + } + + @Test + public void testParseNext() { + final ActionInformationItem item = ActionInformationItem + .parseNext("<BandC line 13, col 1 to line 14, col 5 of module H>: 2:15", "Model"); + assertNotNull(item); + assertNull(item.getDefinition()); + + assertEquals("H", item.getModule()); + assertEquals("Model", item.getModelName()); + + assertEquals("BandC", item.getName()); + + assertEquals(13, item.getModuleLocation().beginLine()); + assertEquals(1, item.getModuleLocation().beginColumn()); + assertEquals(14, item.getModuleLocation().endLine()); + assertEquals(5, item.getModuleLocation().endColumn()); + + assertEquals(2, item.getCost()); + assertEquals(15, item.getCount()); + } + + @Test + public void testParseNextWithDefinition() { + final ActionInformationItem item = ActionInformationItem + .parseNext("<BandC line 13, col 1 to line 17, col 5 of module H (14 16 15 28)>: 2:15", "Model"); + assertNotNull(item); + + assertEquals(14, item.getDefinition().beginLine()); + assertEquals(16, item.getDefinition().beginColumn()); + assertEquals(15, item.getDefinition().endLine()); + assertEquals(28, item.getDefinition().endColumn()); + + assertEquals("H", item.getModule()); + assertEquals("Model", item.getModelName()); + + assertEquals("BandC", item.getName()); + + assertEquals(13, item.getModuleLocation().beginLine()); + assertEquals(1, item.getModuleLocation().beginColumn()); + assertEquals(17, item.getModuleLocation().endLine()); + assertEquals(5, item.getModuleLocation().endColumn()); + + assertEquals(2, item.getCost()); + assertEquals(15, item.getCount()); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java index 16d09f54ff85a1f4c412824325b41bfff9314582..8d790a0265f4642eaf4c2b05df886d3ae5cdc64a 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java @@ -2,6 +2,9 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; +import java.text.ParseException; +import java.text.SimpleDateFormat; + import junit.framework.TestCase; /** @@ -84,4 +87,69 @@ public class StateSpaceInformationItemTest extends TestCase { assertEquals(0, parsed.getSpm()); assertEquals(0, parsed.getDistinctSPM()); } + + public void testParseInit5() throws ParseException { + StateSpaceInformationItem parsed = StateSpaceInformationItem + .parseInit("Finished computing initial states: 2 distinct states generated at 2018-07-03 16:10:44."); + + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-07-03 16:10:44"), parsed.getTime()); + assertEquals(0, parsed.getDiameter()); + assertEquals(2, parsed.getDistinctStates()); + assertEquals(2, parsed.getFoundStates()); + assertEquals(2, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseInit6() throws ParseException { + StateSpaceInformationItem parsed = StateSpaceInformationItem.parseInit( + "Finished computing initial states: 2 states generated, with 1 of them distinct at 2018-07-03 16:10:44."); + + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-07-03 16:10:44"), parsed.getTime()); + assertEquals(0, parsed.getDiameter()); + assertEquals(1, parsed.getDistinctStates()); + assertEquals(2, parsed.getFoundStates()); + assertEquals(1, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseOldComma() throws ParseException { + StateSpaceInformationItem parsed = StateSpaceInformationItem.parseOld( + "Progress(57) at 2019-03-21 10:20:20: 48,613 states generated, 25,188 distinct states found, 556,000 states left on queue."); + + assertEquals(57, parsed.getDiameter()); + assertEquals(48613, parsed.getFoundStates()); + assertEquals(25188, parsed.getDistinctStates()); + assertEquals(556000, parsed.getLeftStates()); + + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseOldDot() throws ParseException { + StateSpaceInformationItem parsed = StateSpaceInformationItem.parseOld( + "Progress(57) at 2019-03-21 10:20:20: 48.613 states generated, 25.188 distinct states found, 556.000 states left on queue."); + + assertEquals(57, parsed.getDiameter()); + assertEquals(48613, parsed.getFoundStates()); + assertEquals(25188, parsed.getDistinctStates()); + assertEquals(556000, parsed.getLeftStates()); + + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseOld() throws ParseException { + StateSpaceInformationItem parsed = StateSpaceInformationItem.parseOld( + "Progress(57) at 2019-03-21 10:20:20: 48613 states generated, 25188 distinct states found, 556000 states left on queue."); + + assertEquals(57, parsed.getDiameter()); + assertEquals(48613, parsed.getFoundStates()); + assertEquals(25188, parsed.getDistinctStates()); + assertEquals(556000, parsed.getLeftStates()); + + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d2574fe6aa789ce854126383b358e928e7dcb1d5 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; +import org.lamport.tla.toolbox.tool.tlc.model.Formula; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order; + +public class TLCErrorTest { + + @Test + public void testA() { + test(Order.OneToN, Order.NToOne, 0, 1); + } + @Test + public void testB() { + test(Order.NToOne, Order.OneToN, 1, 0); + } + @Test + public void testC() { + test(Order.OneToN, Order.OneToN, 0, 1); + } + @Test + public void testD() { + test(Order.NToOne, Order.NToOne, 1, 0); + } + + private static void test(final Order sortMC, final Order sortTE, final int init, final int next) { + final String modelName = "Model_1"; + final Map<String, Formula> traceExplorerExpressions = new HashMap<String, Formula>(); + final Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable = getTraceExpressionDataTable(); + + // error origination for a "regular" TLC run. + final TLCError mcError = new TLCError(sortMC); + final TLCState mcInitState = TLCState.parseState("1: <Initial predicate>\n" + + "/\\ store = <<>>\n" + + "/\\ waitC = {}\n" + + "/\\ waitP = {}", modelName); + mcError.addState(mcInitState); + final TLCState mcNextState = TLCState.parseState("2: <p2 line 63, col 13 to line 66, col 36 of module BlockingQueue>\n" + + "/\\ store = <<\"data\">>\n" + + "/\\ waitC = {}\n" + + "/\\ waitP = {}", modelName); + mcError.addState(mcNextState); + + // error originating from a trace expression evaluation. + final TLCError teError = new TLCError(sortTE); + teError.addState(TLCState.parseState("1: <Initial predicate>\n" + + "/\\ store = <<>>\n" + + "/\\ waitC = {}\n" + + "/\\ waitP = {}\n" + + "/\\ __trace_var_155717784845014000 = 1\n" + + "/\\ __trace_var_155717784845012000 = TRUE", modelName)); + teError.addState(TLCState.parseState("2: <next_155717784845016000 line 44, col 3 to line 67, col 2 of module TE>\n" + + "/\\ store = <<\"data\">>\n" + + "/\\ waitC = {}\n" + + "/\\ waitP = {}\n" + + "/\\ __trace_var_155717784845014000 = 2\n" + + "/\\ __trace_var_155717784845012000 = FALSE", modelName)); + + // Merge teError with mcError + teError.applyFrom(mcError, traceExplorerExpressions, traceExpressionDataTable, modelName); + + final List<TLCState> teStates = teError.getStates(); + assertEquals(2, teStates.size()); + + final TLCState teInitState = teStates.get(init); + assertTrue(teInitState.isInitialState()); + assertEquals(mcInitState.getLabel(), teInitState.getLabel()); + assertEquals(mcInitState.getStateNumber(), teInitState.getStateNumber()); + assertEquals(mcInitState.getVariableCount(1) + 2, teInitState.getVariableCount(1)); + final Map<String, TLCVariable> teInitDiff = teInitState.getDiff(mcInitState); + assertEquals(2, teInitDiff.size()); + assertEquals(teInitDiff.get("_TEPosition").toString(), "1"); + assertEquals(teInitDiff.get("store = <<>>").toString(), "TRUE"); + + final TLCState teNextState = teStates.get(next); + assertFalse(teNextState.isInitialState()); + assertEquals(mcNextState.getLabel(), teNextState.getLabel()); + assertEquals(mcNextState.getStateNumber(), teNextState.getStateNumber()); + assertEquals(mcNextState.getVariableCount(1) + 2, teNextState.getVariableCount(1)); + final Map<String, TLCVariable> teNextDiff = teNextState.getDiff(mcNextState); + assertEquals(2, teNextDiff.size()); + assertEquals(teNextDiff.get("_TEPosition").toString(), "2"); + assertEquals(teNextDiff.get("store = <<>>").toString(), "FALSE"); + } + + private static final Hashtable<String, TraceExpressionInformationHolder> getTraceExpressionDataTable() { + final Hashtable<String, TraceExpressionInformationHolder> hashtable = new Hashtable<String, TraceExpressionInformationHolder>(); + hashtable.put("__trace_var_155717784845014000", new TraceExpressionInformationHolder("_TEPosition", null, "__trace_var_155717784845014000")); + + final TraceExpressionInformationHolder value = new TraceExpressionInformationHolder("store = <<>>", null, "__trace_var_155717784845012000"); + value.setLevel(1); + hashtable.put(value.getVariableName(), value); + + return hashtable; + } + + //*********************************************// + + @Test + public void testXA() { + testX(Order.OneToN, Order.NToOne, 0, 1); + } + @Test + public void testXB() { + testX(Order.NToOne, Order.OneToN, 2, 1); + } + @Test + public void testXC() { + testX(Order.OneToN, Order.OneToN, 0, 1); + } + @Test + public void testXD() { + testX(Order.NToOne, Order.NToOne, 2, 1); + } + + private static void testX(final Order sortMC, final Order sortTE, final int init, final int next) { + final String modelName = "Model_1"; + final Map<String, Formula> traceExplorerExpressions = new HashMap<String, Formula>(); + final Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable = getTraceExpressionDataTableX(); + + // error origination for a "regular" TLC run. + final TLCError mcError = new TLCError(sortMC); + final TLCState mcInitState = TLCState.parseState("1: <Initial predicate>\n" + "x = 0", modelName); + mcError.addState(mcInitState); + final TLCState mcNextState = TLCState + .parseState("2: <Next line 6, col 9 to line 6, col 40 of module Counter>\n" + "x = 1", modelName); + mcError.addState(mcNextState); + final TLCState mcLoopState = TLCState + .parseState("1: Back to state: <Next line 6, col 9 to line 6, col 40 of module Counter>", modelName); + mcError.addState(mcLoopState); + + // error originating from a trace expression evaluation. + final TLCError teError = new TLCError(sortTE); + teError.addState(TLCState.parseState( + "1: <Initial predicate>\n/\\ __trace_var_15571917867925000 = \"--\"\n/\\ x = 0", modelName)); + teError.addState( + TLCState.parseState("2: <next_15571917867927000 line 34, col 2 to line 42, col 1 of module TE>\n" + + "/\\ __trace_var_15571917867925000 = TRUE\n/\\ x = 1", modelName)); + teError.addState( + TLCState.parseState("3: <next_15571917867927000 line 44, col 2 to line 52, col 1 of module TE>\n" + + "/\\ __trace_var_15571917867925000 = FALSE\n" + "/\\ x = 0", modelName)); + teError.addState(TLCState.parseState( + "2: Back to state: <next_15571917867927000 line 34, col 2 to line 42, col 1 of module TE>", modelName)); + + // Merge teError with mcError + teError.applyFrom(mcError, traceExplorerExpressions, traceExpressionDataTable, modelName); + + final List<TLCState> teStates = teError.getStates(); + assertEquals(3, teStates.size()); + + final TLCState teInitState = teStates.get(init); + assertTrue(teInitState.isInitialState()); + assertEquals(mcInitState.getLabel(), teInitState.getLabel()); + assertEquals(mcInitState.getStateNumber(), teInitState.getStateNumber()); + final Map<String, TLCVariable> teInitDiff = teInitState.getDiff(mcInitState); + assertEquals(2, teInitDiff.size()); + assertEquals(teInitDiff.get("x' > x").toString(), "\"--\""); + + final TLCState teNextState = teStates.get(next); + assertFalse(teNextState.isInitialState()); + assertEquals(mcNextState.getLabel(), teNextState.getLabel()); + assertEquals(mcNextState.getStateNumber(), teNextState.getStateNumber()); + final Map<String, TLCVariable> teNextDiff = teNextState.getDiff(mcNextState); + assertEquals(2, teNextDiff.size()); + assertEquals(teNextDiff.get("x' > x").toString(), "TRUE"); + } + + private static final Hashtable<String, TraceExpressionInformationHolder> getTraceExpressionDataTableX() { + final Hashtable<String, TraceExpressionInformationHolder> hashtable = new Hashtable<String, TraceExpressionInformationHolder>(); + + final TraceExpressionInformationHolder value = new TraceExpressionInformationHolder("x' > x", null, "__trace_var_15571917867925000"); + value.setLevel(1); + hashtable.put(value.getVariableName(), value); + + return hashtable; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProviderTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c89933d5963cb58ae503148ecd58911b3ccf1764 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProviderTest.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import tlc2.TLC; +import tlc2.TLCGlobals; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.tool.fp.FPSetConfiguration; + +public class TLCModelLaunchDataProviderTest { + + @Test + public void testDFSSingleWorker() { + TLCGlobals.setNumWorkers(1); + String startupMessage = MP.getMessage(MP.NONE, EC.TLC_MODE_MC_DFS, + TLC.getModelCheckingRuntime(23, new FPSetConfiguration()).values().toArray(new String[0])); + + assertEquals(23, TLCModelLaunchDataProvider.getFPIndex(startupMessage)); + } + + @Test + public void testDFSMultipleWorkers() { + TLCGlobals.setNumWorkers(3); + String startupMessage = MP.getMessage(MP.NONE, EC.TLC_MODE_MC_DFS, + TLC.getModelCheckingRuntime(4, new FPSetConfiguration()).values().toArray(new String[0])); + + assertEquals(4, TLCModelLaunchDataProvider.getFPIndex(startupMessage)); + } + + @Test + public void testBFSSingleWorker() { + TLCGlobals.setNumWorkers(1); + String startupMessage = MP.getMessage(MP.NONE, EC.TLC_MODE_MC, + TLC.getModelCheckingRuntime(4711, new FPSetConfiguration()).values().toArray(new String[0])); + + assertEquals(4711, TLCModelLaunchDataProvider.getFPIndex(startupMessage)); + } + + @Test + public void testBFSMultipleWorkers() { + TLCGlobals.setNumWorkers(2); + String startupMessage = MP.getMessage(MP.NONE, EC.TLC_MODE_MC, + TLC.getModelCheckingRuntime(42, new FPSetConfiguration()).values().toArray(new String[0])); + + assertEquals(42, TLCModelLaunchDataProvider.getFPIndex(startupMessage)); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCStateTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCStateTest.java index eddf77b693a9932ba48bf2aed4d8ca913f46c4da..67e9abacc184d3423ce4cefef4e0f53a7ca42a6e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCStateTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCStateTest.java @@ -25,7 +25,9 @@ ******************************************************************************/ package org.lamport.tla.toolbox.tool.tlc.output.data; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.util.List; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValueTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValueTest.java index ba459b93684cc0f5b989acdb77620e8ab1265c1b..376b79677a7a35becaf3be1dfe1dc75c758b5777 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValueTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValueTest.java @@ -1,11 +1,11 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; -import junit.framework.Assert; -import junit.framework.TestCase; - import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue.InputPair; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue.VariableValueParseException; +import junit.framework.Assert; +import junit.framework.TestCase; + public class TLCVariableValueTest extends TestCase { public void testGetNextChar() diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java index 3fc87259b6fd8bc1d01a5eb49d7c1837d3d05994..c97eee3202811c63ee7900c78f80b93de12d1789 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java @@ -1,12 +1,17 @@ // Copyright (c) Feb 6, 2012 Microsoft Corporation. All rights reserved. package org.lamport.tla.toolbox.tool.tlc.output.source; +import java.util.ArrayList; +import java.util.List; import java.util.Vector; +import org.easymock.EasyMock; +import org.eclipse.core.resources.IFile; +import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jface.text.Document; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.output.ITLCOutputListener; -import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformation; import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; @@ -15,7 +20,7 @@ public class Bug267Listener extends TLCModelLaunchDataProvider implements ITLCOutputListener { public Bug267Listener() { - super(null); + super(new DummyModel()); } /* (non-Javadoc) @@ -33,7 +38,7 @@ public class Bug267Listener extends TLCModelLaunchDataProvider implements isTLCStarted = false; errors = new Vector<TLCError>(); lastDetectedError = null; - coverageInfo = new Vector<CoverageInformationItem>(); + coverageInfo = new CoverageInformation(); progressInformation = new Vector<StateSpaceInformationItem>(); startTimestamp = Long.MIN_VALUE; finishTimestamp = Long.MIN_VALUE; @@ -67,4 +72,21 @@ public class Bug267Listener extends TLCModelLaunchDataProvider implements public void connectToSourceRegistry() { // intentionally noop } + + private static class DummyModel extends Model { + + DummyModel() { + super(EasyMock.createNiceMock(ILaunchConfiguration.class)); + } + + public String getName() { + // Stop super from delegating to ILC + return "Bug267Listener"; + } + + @Override + public List<IFile> getSavedTLAFiles() { + return new ArrayList<IFile>(); + } + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ParsingToolkitTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ParsingToolkitTest.java index 178b3fb81d289fa880a2a34fc071fec57263c6cb..b5b6057dd70648e33146c30ba78325b62562880d 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ParsingToolkitTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ParsingToolkitTest.java @@ -1,11 +1,11 @@ package org.lamport.tla.toolbox.tool.tlc.ui.util; -import junit.framework.TestCase; - import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.TypedRegion; import org.lamport.tla.toolbox.tool.tlc.output.PartitionToolkit; +import junit.framework.TestCase; + /** * Tests of parsing toolkit * @author Simon Zambrovski diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelperTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelperTest.java index 7819aca28ca141ede2fb938489c9dcc923f4b84d..fd1b8f2b384aa7f4ebba920a5addf37834945fa6 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelperTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelperTest.java @@ -3,11 +3,10 @@ package org.lamport.tla.toolbox.tool.tlc.ui.util; import java.util.List; -import junit.framework.Assert; - import org.eclipse.swt.custom.StyleRange; import org.junit.Test; +import junit.framework.Assert; import tla2sany.st.Location; /** diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java index 62e4abed7f9a02c8c3ad1d9e5ab214f1ffae4a77..3dace7264db35bbb2eb4316b5d62ecbd9313e72a 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java @@ -49,6 +49,7 @@ import org.junit.Ignore; import org.junit.Test; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; @@ -93,13 +94,13 @@ public class TLCErrorViewTest { final List<TLCError> errors = new ArrayList<TLCError>(); provider.setErrors(errors); - final TLCError error = new TLCError(); + final TLCError error = new TLCError(Order.NToOne); errors.add(error); for (int i = 1; i <= 10000; i++) { final TLCState state = TLCState.parseState( i + ": <Action line 1, col 1 to line 1, col 2 of module testLargeNumberOfStates>\nx = " + i, name); - error.addState(state, true); + error.addState(state); } // show all states @@ -148,7 +149,6 @@ public class TLCErrorViewTest { * Create dummy error trace */ final TLCError error = new TLCError(); - final boolean sortOrder = false; String str = "1: <Initial predicate>\n" + "/\\ sq = <<>>\n" + @@ -158,7 +158,7 @@ public class TLCErrorViewTest { "/\\ x = (a :> 0 @@ b :> 0 @@ c :> 0)\n" + "/\\ y = <<0, 0, 0>>\n" + "/\\ z = [a |-> 0, b |-> 0, c |-> 0]"; - error.addState(TLCState.parseState(str, "testColoring"), sortOrder); + error.addState(TLCState.parseState(str, "testColoring")); str = "2: <Action line 22, col 12 to line 29, col 33 of module TraceExplorerColoring>\n" + "/\\ sq = <<1>>\n" + @@ -168,7 +168,7 @@ public class TLCErrorViewTest { "/\\ x = (a :> 42 @@ b :> 0 @@ c :> 0)\n" + "/\\ y = <<42, 0, 0>>\n" + "/\\ z = [a |-> 42, b |-> 0, c |-> 0]"; - error.addState(TLCState.parseState(str, "testColoring"), sortOrder); + error.addState(TLCState.parseState(str, "testColoring")); str = "3: <Action line 22, col 12 to line 29, col 33 of module TraceExplorerColoring>\n" + "/\\ sq = <<1, 2>>\n" + @@ -178,7 +178,7 @@ public class TLCErrorViewTest { "/\\ x = (a :> 42 @@ b :> 42 @@ c :> 0)\n" + "/\\ y = <<42, 42, 0>>\n" + "/\\ z = [a |-> 42, b |-> 42, c |-> 0]"; - error.addState(TLCState.parseState(str, "testColoring"), sortOrder); + error.addState(TLCState.parseState(str, "testColoring")); str = "4: <Action line 22, col 12 to line 29, col 33 of module TraceExplorerColoring>\n" + "/\\ sq = <<1, 2, 3>>\n" + @@ -188,7 +188,7 @@ public class TLCErrorViewTest { "/\\ x = (a :> 42 @@ b :> 42 @@ c :> 42)\n" + "/\\ y = <<42, 42, 42>>\n" + "/\\ z = [a |-> 42, b |-> 42, c |-> 42]"; - error.addState(TLCState.parseState(str, "testColoring"), sortOrder); + error.addState(TLCState.parseState(str, "testColoring")); str = "5: <Action line 30, col 12 to line 37, col 29 of module TraceExplorerColoring>\n" + "/\\ sq = <<2, 3>>\n" + @@ -198,7 +198,7 @@ public class TLCErrorViewTest { "/\\ x = (a :> 42 @@ b :> 42 @@ c :> 42)\n" + "/\\ y = <<42, 42, 42>>\n" + "/\\ z = [a |-> 42, b |-> 42, c |-> 42]"; - error.addState(TLCState.parseState(str, "testColoring"), sortOrder); + error.addState(TLCState.parseState(str, "testColoring")); /* * Feed error trace to view. diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandlerTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandlerTest.java index 62183551c969faecc91ec260d46536a5a237d1c5..2189df2c5f8feb7a2b8aaba2dfe9ef6def50e929 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandlerTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandlerTest.java @@ -31,8 +31,6 @@ import java.io.IOException; import java.net.URI; import java.util.HashMap; -import junit.framework.TestCase; - import org.eclipse.core.internal.resources.LinkDescription; import org.eclipse.core.internal.resources.Project; import org.eclipse.core.internal.resources.ProjectDescription; @@ -44,6 +42,8 @@ import org.eclipse.core.runtime.Path; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.util.ResourceHelper; +import junit.framework.TestCase; + @SuppressWarnings("restriction") public class AddModuleHandlerTest extends TestCase { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.classpath b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.classpath index 64c5e31b7a264082f4c1dfdabb8097de820e66ce..eca7bdba8f03f22510b7980a94dbfe10c16c0901 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.classpath +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..0c68a61dca867ceb49e79d2402935261ec3e3809 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF index 7d12e074a3f589529d9271c8986f85e9a213a6ac..266ebb99d8573158452300869813c56377f92314 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF @@ -16,6 +16,7 @@ Require-Bundle: org.lamport.tla.toolbox;bundle-version="1.0.0", org.eclipse.jface.text;bundle-version="3.12.0", org.apache.commons.io;bundle-version="2.0.1" Import-Package: org.osgi.framework;version="1.3.0" -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe Bundle-ActivationPolicy: lazy +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc.ui.uitest diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/org.lamport.tla.toolbox.tool.tlc.ui.uitest.launch b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/org.lamport.tla.toolbox.tool.tlc.ui.uitest.launch index f8e723531aff2d2dce400183476b7d3af0f3dc5a..8cb71bb43a1f20c9f1bd9115931d93faa33ce84d 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/org.lamport.tla.toolbox.tool.tlc.ui.uitest.launch +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/org.lamport.tla.toolbox.tool.tlc.ui.uitest.launch @@ -27,7 +27,7 @@ <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.lamport.tla.toolbox.ui.handler.RenameSpecHandlerTest"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.lamport.tla.toolbox.tool.tlc.ui.uitest"/> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml index 663f6bad89fb71a7cf6ef99650e482417bb5d247..e0e87e06ff576239fc4bf1e27e4e8c3b47e937e2 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml @@ -12,7 +12,7 @@ <groupId>tlatoolbox</groupId> <artifactId>org.lamport.tla.toolbox.tool.tlc.ui.uitest</artifactId> <version>1.0.0-SNAPSHOT</version> - <packaging>eclipse-test-plugin</packaging> + <packaging>eclipse-plugin</packaging> <properties> <!-- Do not include test project in Sonar reporting. --> <sonar.skip>true</sonar.skip> @@ -24,7 +24,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> @@ -37,114 +37,6 @@ </execution> </executions> </plugin> - <!-- Run JUnit tests --> - <plugin> - <groupId>org.eclipse.tycho</groupId> - <artifactId>tycho-surefire-plugin</artifactId> - <version>${tycho-version}</version> - - <configuration> - <showEclipseLog>true</showEclipseLog> - <useUIHarness>true</useUIHarness> - <useUIThread>${tycho.test.vm.useUiThread}</useUIThread> - <argLine>${tycho.test.vm.argline} ${tycho.testArgLine}</argLine> - <!-- use our product and application to launch the tests --> - <product>org.lamport.tla.toolbox.product.standalone.product</product> - <application>org.lamport.tla.toolbox.application</application> - - <systemProperties combine.children="append"> - <!-- References used by tests to access spec files --> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecC>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/farsite/GotoDefinition.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecC> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/farsite/DistributedSystemModule.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/DieHard/DieHard.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA> - <!-- JDT weaving debug output --> - <aj.weaving.verbose>true</aj.weaving.verbose> - <org.aspectj.weaver.showWeaveInfo>false</org.aspectj.weaver.showWeaveInfo> - <org.aspectj.osgi.verbose>false</org.aspectj.osgi.verbose> - </systemProperties> - - <dependencies> - <!-- help system needs javax.servlet --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>javax.servlet</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency is only needed because SWTbot brings its own - hamcrest bundle which conflicts with the one from junit in the eclipse platform --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.hamcrest</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency is needed because product/app is provided - by this bundle --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.lamport.tla.toolbox.product.standalone</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency toward AspectJ --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.aspectj.runtime</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.aspectj.weaver</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.weaving.aspectj</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.weaving.hook</artifactId> - <version>1.2.0.v20160929-1449</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.event</artifactId> - <version>0.0.0</version> - </dependency> - </dependencies> - - <!-- Enable JDT weaving --> - <frameworkExtensions> - <frameworkExtension> - <groupId>p2.osgi.bundle</groupId> - <artifactId>org.eclipse.equinox.weaving.hook</artifactId> - <version>1.2.0.v20160929-1449</version> - </frameworkExtension> - </frameworkExtensions> - - <bundleStartLevel> - <bundle> - <id>org.eclipse.equinox.weaving.aspectj</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.aspectj.weaver</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.aspectj.runtime</id> - <level>3</level> - <autoStart>true</autoStart> - </bundle> - <bundle> - <id>org.eclipse.equinox.event</id> - <level>4</level> - <autoStart>true</autoStart> - </bundle> - </bundleStartLevel> - </configuration> - </plugin> </plugins> </build> </project> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/threading/HandlerThreadingTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/threading/HandlerThreadingTest.java index 82b8cb77ae04ca27c4622be4ab0c3055f3b612ea..d5eb1ca7db254f46fca21f87a7d72f121e49f34c 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/threading/HandlerThreadingTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/threading/HandlerThreadingTest.java @@ -13,6 +13,7 @@ import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.lamport.tla.toolbox.test.RCPTestSetupHelper; @@ -61,6 +62,7 @@ public class HandlerThreadingTest extends AbstractTest { * @see Bug #103 in general/bugzilla/index.html */ @Test + @Ignore public void parseSpecInNonUIThread() { // Open specA diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java index 4a22fd9753567153982e429c170b6c379307e083..1a463c1408aa2ae7527e33b71e06c1ccdd76466a 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java @@ -8,7 +8,6 @@ import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; import org.eclipse.swtbot.swt.finder.matchers.WithText; import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; - import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java index 22546e0c9a96a2d5b58e62f08c59019dccc23647..a6a7029f8a30d9d2277df0b5cca41cc445cb1d80 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java @@ -3,10 +3,11 @@ package org.lamport.tla.toolbox.ui.handler; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; import org.apache.commons.io.IOUtils; - import org.eclipse.jface.text.Region; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; @@ -15,7 +16,6 @@ import org.eclipse.swtbot.swt.finder.matchers.WithText; import org.eclipse.swtbot.swt.finder.utils.FileUtils; import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; - import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; @@ -85,50 +85,31 @@ public class GotoDefinitionTest extends AbstractTest { * * We don't need to test the hyperlink jump, we only need to test that the TokenSpec instance returned by * TokenSpec.findCurrentTokenSpec(IRegion) has a non-null resolvedSymbol attribute. + * @throws InterruptedException */ @Test - public void verifyTokenSpecSymbolResolution () { + public void verifyTokenSpecSymbolResolution () throws InterruptedException { + final BlockingQueue<TokenSpec> queue = new ArrayBlockingQueue<TokenSpec>(1); + final Region r = new Region(193, 0); // This region is expected to place the cursor just prior to the subscripted identifier, the 's' in "..._s" in: // Spec == s = "" /\ [][Next(s)]_s - final Region r = new Region(193, 0); - final ArrayList<TokenSpec> crossThreadSmuggler = new ArrayList<>(); - final Runnable uiRunnable = new Runnable () { - public void run () { - TokenSpec ts = TokenSpec.findCurrentTokenSpec(r); - - synchronized (crossThreadSmuggler) { - crossThreadSmuggler.add(ts); - } - } - }; - final TokenSpec ts; - int size = 0; - int waitCycles = 0; + UIHelper.runUIAsync(new Runnable() { + @Override + public void run() { + queue.add(TokenSpec.findCurrentTokenSpec(r)); + } + }); + + final TokenSpec ts = queue.poll(15, TimeUnit.SECONDS); - UIHelper.runUIAsync(uiRunnable); - while ((size == 0) && (waitCycles < 15)) { - try { - Thread.sleep(575); - } - catch (Exception e) { } // NOPMD - - waitCycles++; - synchronized (crossThreadSmuggler) { - size = crossThreadSmuggler.size(); - } - } + Assert.assertNotNull("TokenSpec was unable to find any token at " + r.toString(), ts); - Assert.assertNotEquals("We timed out waiting for the TokenSpec find.", 0, size); - - ts = crossThreadSmuggler.get(0); - - Assert.assertNotNull("TokenSpec was unable to find any token at " + r.toString(), ts); - - Assert.assertEquals("TokenSpec was not for the expected token, perhaps someone has changed GotoDefinition.tla?", "_s", - ts.token); + Assert.assertEquals("TokenSpec was not for the expected token, perhaps someone has changed GotoDefinition.tla?", + "_s", ts.token); - Assert.assertNotNull("TokenSpec was unable to resolve the symbol for the token [" + ts.token + "] at " + r.toString(), - ts.resolvedSymbol); + Assert.assertNotNull( + "TokenSpec was unable to resolve the symbol for the token [" + ts.token + "] at " + r.toString(), + ts.resolvedSymbol); // No real reason this need be done from a test functionality perspective SWTBotEditor activeEditor = bot.activeEditor(); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java index 28018399dc93019aeda0ba3fb52650db234fa61d..55b7276a1f85b68537049ed5abc3c1e4a7c51f08 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java @@ -16,7 +16,6 @@ import org.eclipse.swtbot.swt.finder.waits.ICondition; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; import org.eclipse.ui.IEditorPart; - import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.ui/META-INF/MANIFEST.MF index e59dad9f58775066800b7186ce1284666353fc3b..07b6155ad065dc235439a83dd6c59327da489321 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc.ui/META-INF/MANIFEST.MF @@ -19,7 +19,12 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.expressions;bundle-version="3.4.100", javax.mail;bundle-version="1.4.0", com.abstratt.graphviz;bundle-version="2.1.201501", - com.abstratt.graphviz.ui;bundle-version="2.1.201501" + com.abstratt.graphviz.ui;bundle-version="2.1.201501", + org.eclipse.mylyn.commons.notifications.core;bundle-version="1.16.0", + org.eclipse.mylyn.commons.notifications.ui;bundle-version="1.16.0", + org.eclipse.mylyn.commons.ui;bundle-version="3.24.2", + org.apache.commons.lang3;bundle-version="3.1.0", + org.lamport.tla.toolbox.editor.basic;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Import-Package: org.lamport.tla.toolbox.editor.basic @@ -28,3 +33,4 @@ Export-Package: org.lamport.tla.toolbox.tool.tlc.output;x-friends:="org.lamport. org.lamport.tla.toolbox.tool.tlc.ui.editor;x-friends:="org.lamport.tla.toolbox.tool.tlc.ui.uitest", org.lamport.tla.toolbox.tool.tlc.ui.util;x-friends:="org.lamport.tla.toolbox.tool.tlc.ui.test" Bundle-ClassPath: . +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc.ui diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/helpContexts.xml b/org.lamport.tla.toolbox.tool.tlc.ui/helpContexts.xml index 9ac27d1dd29bc3f8a245ce7f8f7d99d116f826cc..ea1bf42247fae5421dc9c4139e14de4a3cf1c0f8 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/helpContexts.xml +++ b/org.lamport.tla.toolbox.tool.tlc.ui/helpContexts.xml @@ -11,7 +11,7 @@ <context id="advancedModelPage"> <description>This is the advanced model page. You can use it to create the more esoteric aspects of a model.</description> <topic label="Advanced Options Page" - href="../org.lamport.tla.toolbox.doc/html/model/advanced-page.html" /> + href="../org.lamport.tla.toolbox.doc/html/model/spec-options-page.html" /> </context> <context id="resultModelPage"> <description>This is the model's result page. It shows the results of a TLC run.</description> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..6142a8c60842070b6bf5b6d6e764ef9a1fce9a75 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj@2x.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f939a4dd778f97c8f93fc40b3b38003e24b9949f Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/quickfix_obj@2x.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state.png new file mode 100644 index 0000000000000000000000000000000000000000..86aadacdb233ffb0d4bb3879160fa9e06731cd95 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state@2x.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d4ff85d4a6774a527bb8df9ea64374690ef9ab1c Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/toggle_expand_state@2x.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_128.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_128.png new file mode 100644 index 0000000000000000000000000000000000000000..611bba60ab399729df7a1fc8401e6e9af6bf71d2 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_128.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_16.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_16.png new file mode 100644 index 0000000000000000000000000000000000000000..6344d51097cd7a97d2b6a30bb9a22aa466772ed6 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_16.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_24.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_24.png new file mode 100644 index 0000000000000000000000000000000000000000..530b46bddfa04dd16b3a161e0ac1b35d808a87cf Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_24.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_32.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_32.png new file mode 100644 index 0000000000000000000000000000000000000000..ec277ace97248690ae11386bcc77cde124b296f1 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_32.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_512.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_512.png new file mode 100644 index 0000000000000000000000000000000000000000..68b21b005e25bf936f4c6a0c504e152c40d827d5 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_512.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_64.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_64.png new file mode 100644 index 0000000000000000000000000000000000000000..5bec770a54ab2999aca07564de65a0498208661d Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_model_options_64.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_128.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_128.png new file mode 100644 index 0000000000000000000000000000000000000000..9c6888d1f5c84a8fb21b13e0d66670dbb5157859 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_128.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_16.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_16.png new file mode 100644 index 0000000000000000000000000000000000000000..52be17c3bf0c5d4c065a69bd9860f3d8edbd06f1 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_16.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_24.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8bbae3ff6134fc6b0af85d4d0ddce2b2eabdec9d Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_24.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_32.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_32.png new file mode 100644 index 0000000000000000000000000000000000000000..08087ac037384aaa206816d3ac477dca1812ec9d Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_32.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_512.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_512.png new file mode 100644 index 0000000000000000000000000000000000000000..8cbd7f6b38af9e25634108a59b714f08a4f67c00 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_512.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_64.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_64.png new file mode 100644 index 0000000000000000000000000000000000000000..6e1e9bd17dbdda301cfd1fba772ffd1b461a9b83 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/advanced_tlc_options_64.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_128.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_128.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff69a1d0ad3762dc36e26642fbc7b0bd45ba148 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_128.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_16.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_16.png new file mode 100644 index 0000000000000000000000000000000000000000..048f9de8f6f79092609842a45c286eaa8576dfe8 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_16.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_24.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_24.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb535b84731af003d1997ba35b492e880316c38 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_24.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_32.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_32.png new file mode 100644 index 0000000000000000000000000000000000000000..0b176c3b8eeb3a259c088cb9234bd22472a03f6b Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_32.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_512.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_512.png new file mode 100644 index 0000000000000000000000000000000000000000..89ae7a1674c60dee416378093186fc2d9935fc6d Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_512.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_64.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_64.png new file mode 100644 index 0000000000000000000000000000000000000000..46ac55a7d111527d174d2aaffa1a09e2e535d8ee Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/ece_page_64.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_128.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_128.png new file mode 100644 index 0000000000000000000000000000000000000000..93fd9a7fac8a507ab6000ce1dd4925917ef054fd Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_128.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_16.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_16.png new file mode 100644 index 0000000000000000000000000000000000000000..affd54201323c9320025c59fab1abba5e713cac3 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_16.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_24.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ebaefc8b432f9bb947c7a912d5d0a5e31f9595c5 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_24.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_32.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_32.png new file mode 100644 index 0000000000000000000000000000000000000000..5303034bc8b65dd2a2d99d9eeb3f671b4aa3c47f Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_32.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_512.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_512.png new file mode 100644 index 0000000000000000000000000000000000000000..4a966ad79cc4b9e3a9b86760246598956cf68d75 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_512.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_64.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_64.png new file mode 100644 index 0000000000000000000000000000000000000000..bebe8ae3a80f9c0f7532ae8d86aa329f67833c97 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_options_64.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/report2_obj.gif b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/report2_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..16f8b684192fa6864ad3349abe602d6b1fc271b8 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/report2_obj.gif differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_128.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_128.png new file mode 100644 index 0000000000000000000000000000000000000000..d9bb0997c896bedc9de645e28c010e53553bc188 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_128.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_16.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_16.png new file mode 100644 index 0000000000000000000000000000000000000000..69e9b72343f959b346ec15019f74e9dce7af22be Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_16.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_24.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f5f1c7a50570152a34d19a8e762ca9b615bdf8b1 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_24.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_32.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_32.png new file mode 100644 index 0000000000000000000000000000000000000000..98a11b398bce77dfa87533362fd2588a31f93a2f Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_32.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_512.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_512.png new file mode 100644 index 0000000000000000000000000000000000000000..4c9d8c720d7327f039f38e4d347ec828d2c1219f Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_512.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_64.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_64.png new file mode 100644 index 0000000000000000000000000000000000000000..0829ee1af09f01682bd16ecbb6b06f8ad87b2741 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/results_page_64.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml b/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml index fcd694f4dc868de975dea1387897871856265d52..b12e5cd2c517db8897871899e4ecd4db9b4e7e35 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml +++ b/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml @@ -108,8 +108,7 @@ <commandParameter id="toolbox.tool.tlc.commands.model.clone.param.modelName" name="Model to be cloned" - optional="true"> - </commandParameter> + optional="true"/> </command> <!-- The difference between this command and the "...delegate" above is, that handlers associated to this command are *always* created. This @@ -124,15 +123,18 @@ <commandParameter id="toolbox.tool.tlc.commands.model.clone.param.modelName" name="Model to be cloned" - optional="true"> - </commandParameter> + optional="true"/> </command> + <command + categoryId="toolbox.tool.tlc.commands.category" + description="Starts the process of cloning a foreign model." + id="toolbox.tool.tlc.commands.model.cloneforeign" + name="Clone a foreign model"/> <command categoryId="toolbox.tool.tlc.commands.category" description="Runs the model checker." id="toolbox.tool.tlc.commands.model.run" - name="Run model checking"> - </command> + name="Run model checking"/> <command categoryId="toolbox.tool.tlc.commands.category" description="Stops the model checker execution." @@ -163,6 +165,13 @@ id="org.lamport.tla.toolbox.openElementSelection" name="Filtered open element selection dialog"> </command> + <command + categoryId="toolbox.tool.tlc.commands.category" + defaultHandler="org.lamport.tla.toolbox.tool.tlc.ui.util.ExecutionStatisticsHandler" + description="Opt-in or opt-out of TLA+ Execution Statistics collection" + id="org.lamport.tla.toolbox.tool.tlc.ui.executionstatistics" + name="&Opt In/Out Execution Statistics"> + </command> </extension> @@ -215,8 +224,7 @@ </menu> <menu id="toolbox.tool.tlc.modellaunch.clone" - label="Clone Model" - mnemonic="O"> + label="Clone Model"> <dynamic class="org.lamport.tla.toolbox.tool.tlc.ui.modelexplorer.CloneModelContributionItem" id="toolbox.tool.tlc.model.clone.dynamic"> @@ -369,6 +377,17 @@ </visibleWhen> </command --> </menuContribution> + <menuContribution + locationURI="menu:toolbox.menu.help?after=toolbox.command.about"> + <command + commandId="org.lamport.tla.toolbox.tool.tlc.ui.executionstatistics" + label="Opt In/Out Execution Statistics" + mnemonic="O" + mode="FORCE_TEXT" + style="push" + tooltip="Opt-in or opt-out of TLA+ Execution Statistics collection"> + </command> + </menuContribution> </extension> <!-- Spec explorer context menu --> @@ -637,6 +656,10 @@ Console Facory </with> </activeWhen> </handler> + <handler + class="org.lamport.tla.toolbox.tool.tlc.handlers.CloneForeignModelHandler" + commandId="toolbox.tool.tlc.commands.model.cloneforeign"> + </handler> <handler class="org.lamport.tla.toolbox.tool.tlc.handlers.CloneModelHandlerDelegate" commandId="toolbox.tool.tlc.commands.model.clone.delegate.always.enabled"> @@ -831,7 +854,7 @@ Console Facory <fontDefinition id="org.lamport.tla.toolbox.tool.tlc.ui.tlcOutputFont" isEditable="true" - label="TLC Output" + label="TLC User, Progress, and Error Output" value="Courier New-regular-8"> <fontValue os="win32" @@ -841,6 +864,23 @@ Console Facory os="macosx" value="Microsoft Sans Serif-regular-10"> </fontValue> + <description> + The font used on the User and Progress output text areas on the Results page of the Model Editor, as well as the Error Output in the TLC Error view. + </description> + </fontDefinition> + <fontDefinition + id="org.lamport.tla.toolbox.tool.tlc.ui.tlcErrorTraceFont" + isEditable="true" + label="Error Trace" + value="DejaVu Sans-regular-12"> + <fontValue + os="win32" + value="Arial-regular-12"> + </fontValue> + <fontValue + os="macosx" + value="Helvetica Neue-regular-12"> + </fontValue> </fontDefinition> </extension> <extension point="org.eclipse.ui.bindings"> @@ -869,4 +909,59 @@ Console Facory </adapter> </factory> </extension> + <extension + point="org.eclipse.mylyn.commons.notifications.ui.notifications"> + <category + id="org.lamport.tla.toolbox.tool.tlc.ui.notification.category" + label="CategoryLabel"> + </category> + <event + categoryId="org.lamport.tla.toolbox.tool.tlc.ui.notification.category" + id="org.lamport.tla.toolbox.tool.tlc.ui.notification.event" + label="EventLabel"> + <defaultHandler + sinkId="org.eclipse.mylyn.commons.notifications.sink.Popup"> + </defaultHandler> + </event> + </extension> + <extension + id="org.lamport.tla.toolbox.tlc.zerocoverage" + name="Zero Coverage Marker Name" + point="org.eclipse.core.resources.markers"> + <super + type="org.eclipse.core.resources.textmarker"> + </super> + <persistent + value="true"> + </persistent> + </extension> + <extension + point="org.eclipse.ui.editors.annotationTypes"> + <type + markerType="org.lamport.tla.toolbox.tlc.zerocoverage" + name="org.lamport.tla.toolbox.tlc.zerocoverage"> + </type> + </extension> + <extension + point="org.eclipse.ui.editors.markerAnnotationSpecification"> + <specification + annotationType="org.lamport.tla.toolbox.tlc.zerocoverage" + colorPreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.color" + colorPreferenceValue="250,218,92" + contributesToHeader="true" + highlightPreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.highlight" + highlightPreferenceValue="true" + includeOnPreferencePage="true" + label="Disabled Actions" + overviewRulerPreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.overruler" + overviewRulerPreferenceValue="true" + symbolicIcon="warning" + textPreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.text" + textPreferenceValue="true" + textStylePreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.textstyle" + textStylePreferenceValue="BOX" + verticalRulerPreferenceKey="org.lamport.tla.toolbox.tlc.zerocoverage.vertruler" + verticalRulerPreferenceValue="true"> + </specification> + </extension> </plugin> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneForeignModelHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneForeignModelHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..2b74d889b964275c0cb7b71b781c7e8cd0b4bf14 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneForeignModelHandler.java @@ -0,0 +1,256 @@ +package org.lamport.tla.toolbox.tool.tlc.handlers; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; +import org.lamport.tla.toolbox.spec.Spec; +import org.lamport.tla.toolbox.tool.ToolboxHandle; +import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; + +/** + * A handler which presents the user with a dialog through which to choose a spec and a model. + */ +public class CloneForeignModelHandler extends AbstractHandler implements IModelConfigurationConstants { + public static final String COMMAND_ID = "toolbox.tool.tlc.commands.model.cloneforeign"; + + private static final Comparator<Model> MODEL_SORTER = (m1, m2) -> { + return m1.getName().compareTo(m2.getName()); + }; + + + public Object execute(final ExecutionEvent event) throws ExecutionException { + final TreeMap<String, TreeSet<Model>> projectModelMap = buildMap(); + if (projectModelMap == null) { + return null; + } + + final Shell shell = PlatformUI.getWorkbench().getDisplay().getActiveShell(); + final ForeignModelPicker modelPicker = new ForeignModelPicker(shell, projectModelMap); + + if (modelPicker.open() == Dialog.OK) { + final Map<String, String> parameters = new HashMap<String, String>(); + parameters.put(CloneModelHandlerDelegate.PARAM_FOREIGN_FULLY_QUALIFIED_MODEL_NAME, + modelPicker.getFullyQualifiedNameOfSelection()); + + final ExecutionEvent cloneEvent = new ExecutionEvent(null, parameters, null, null); + final CloneModelHandlerDelegate cloner = new CloneModelHandlerDelegate(); + cloner.execute(cloneEvent); + } + + return null; + } + + private TreeMap<String, TreeSet<Model>> buildMap() { + final Spec currentSpec = ToolboxHandle.getCurrentSpec(); + if (currentSpec == null) { + return null; + } + + final IProject specProject = currentSpec.getProject(); + final TreeMap<String, TreeSet<Model>> projectModelMap = new TreeMap<>(); + + try { + final IWorkspace iws = ResourcesPlugin.getWorkspace(); + final IWorkspaceRoot root = iws.getRoot(); + final IProject[] projects = root.getProjects(); + + for (final IProject project : projects) { + if (!specProject.equals(project)) { + projectModelMap.put(project.getName(), new TreeSet<>(MODEL_SORTER)); + } + } + + final String currentProjectName = specProject.getName(); + final ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager(); + final ILaunchConfigurationType launchConfigurationType + = launchManager.getLaunchConfigurationType(TLCModelLaunchDelegate.LAUNCH_CONFIGURATION_TYPE); + final ILaunchConfiguration[] launchConfigurations + = launchManager.getLaunchConfigurations(launchConfigurationType); + for (final ILaunchConfiguration launchConfiguration : launchConfigurations) { + final String projectName = launchConfiguration.getAttribute(IConfigurationConstants.SPEC_NAME, "-l!D!q_-l!D!q_-l!D!q_"); + if (!projectName.equals(currentProjectName)) { + final TreeSet<Model> models = projectModelMap.get(projectName); + + if (models != null) { + final Model model = launchConfiguration.getAdapter(Model.class); + + if (!model.isSnapshot()) { + models.add(model); + } + } else { + TLCUIActivator.getDefault().logError("Could not generate model map for [" + projectName + "]!"); + } + } + } + } catch (final CoreException e) { + TLCUIActivator.getDefault().logError("Building foreign model map.", e); + + return null; + } + + return projectModelMap; + } + + + private static class ForeignModelPicker extends Dialog { + private final TreeMap<String, TreeSet<Model>> specNameModelMap; + + private List specList; + private List modelList; + + // oh SWT, you terrible terrible thing... after the dialog closes, all of the widgets are disposed - too bad, too late... + private String selectedFullyQualifiedName; + + private ForeignModelPicker(final Shell shell, final TreeMap<String, TreeSet<Model>> projectModelMap) { + super(shell); + + specNameModelMap = projectModelMap; + } + + private String getFullyQualifiedNameOfSelection() { + return selectedFullyQualifiedName; + } + + @Override + protected Control createDialogArea(final Composite parent) { + final Composite container = (Composite) super.createDialogArea(parent); + + GridLayout gl = new GridLayout(2, false); + container.setLayout(gl); + + + final Composite leftPane = new Composite(container, SWT.NONE); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + leftPane.setLayout(gl); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessVerticalSpace = true; + leftPane.setLayoutData(gd); + + final Composite rightPane = new Composite(container, SWT.NONE); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + rightPane.setLayout(gl); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessVerticalSpace = true; + rightPane.setLayoutData(gd); + + + Label l = new Label(leftPane, SWT.LEFT); + l.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + l.setText("Spec:"); + + specList = new List(leftPane, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL); + for (final String specName : specNameModelMap.keySet()) { + specList.add(specName); + } + specList.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent se) { + getButton(IDialogConstants.OK_ID).setEnabled(false); + selectedFullyQualifiedName = null; + + modelList.removeAll(); + + final TreeSet<Model> models = specNameModelMap.get(specList.getSelection()[0]); + for (final Model model : models) { + modelList.add(model.getName()); + } + } + }); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessVerticalSpace = true; + specList.setLayoutData(gd); + + + l = new Label(rightPane, SWT.LEFT); + l.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + l.setText("Model:"); + + modelList = new List(rightPane, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessVerticalSpace = true; + modelList.setLayoutData(gd); + modelList.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent se) { + getButton(IDialogConstants.OK_ID).setEnabled(true); + + selectedFullyQualifiedName + = Model.fullyQualifiedNameFromSpecNameAndModelName(specList.getSelection()[0], + modelList.getSelection()[0]); + } + }); + + return container; + } + + @Override + protected Control createButtonBar(final Composite parent) { + final Control buttonBar = super.createButtonBar(parent); + + getButton(IDialogConstants.OK_ID).setEnabled(false); + + return buttonBar; + } + + @Override + protected Point getInitialSize() { + return new Point(500, 330); + } + + @Override + protected void configureShell(final Shell shell) { + super.configureShell(shell); + shell.setText("Please choose a spec and a model"); + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneModelHandlerDelegate.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneModelHandlerDelegate.java index 99ef71c1fdfd357d3e19f60dbc40193881c23c68..b243f755d963064f7ca88f2156c7383cb928949d 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneModelHandlerDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/CloneModelHandlerDelegate.java @@ -39,6 +39,7 @@ import org.eclipse.jface.window.Window; import org.eclipse.ui.handlers.HandlerUtil; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.model.TLCModelFactory; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; import org.lamport.tla.toolbox.tool.tlc.util.ModelNameValidator; import org.lamport.tla.toolbox.util.UIHelper; @@ -65,6 +66,17 @@ public class CloneModelHandlerDelegate extends AbstractHandler implements IHandl */ public static final String PARAM_MODEL_NAME = "toolbox.tool.tlc.commands.model.clone.param.modelName"; + /** + * If the cloning is being done on a foreign spec, this value must be set. + * + * N.B The Eclipse codebase is such an exceedingly well written thing that if this parameter is not defined + * in the command XML, Eclipse will silently discard all contribution items containing parameters with + * this value. Kwality! + */ + public static final String PARAM_FOREIGN_FULLY_QUALIFIED_MODEL_NAME + = "toolbox.tool.tlc.commands.model.clone.param.foreignFullyQualifiedModelName"; + + /** * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) */ @@ -77,12 +89,16 @@ public class CloneModelHandlerDelegate extends AbstractHandler implements IHandl * parameter, so it may not have been set. */ final String paramModelName = (String) event.getParameter(PARAM_MODEL_NAME); + final String paramForeignModelName = (String) event.getParameter(PARAM_FOREIGN_FULLY_QUALIFIED_MODEL_NAME); + final boolean isForeignClone = (paramForeignModelName != null); if (paramModelName != null) { // The name is given which means the user clicked the main menu // instead of the spec explorer. Under the constraint that only ever // a single spec can be open, lookup the current spec to eventually // get the corresponding model. model = spec.getModel(paramModelName); + } else if (isForeignClone) { + model = TLCModelFactory.getByName(paramForeignModelName); } else { /* * No parameter try to get it from active navigator if any @@ -99,15 +115,22 @@ public class CloneModelHandlerDelegate extends AbstractHandler implements IHandl "Please input the new name of the model", spec.getModelNameSuggestion(model), new ModelNameValidator(spec)); dialog.setBlockOnOpen(true); if (dialog.open() == Window.OK) { - final String usersChosenName = dialog.getValue(); - if (model.copy(usersChosenName) == null) { - throw new ExecutionException( - "Failed to copy with name " + usersChosenName + " from model " + model.getName()); + final String chosenName = dialog.getValue(); + + if (isForeignClone) { + if (model.copyIntoForeignSpec(spec, chosenName) == null) { + throw new ExecutionException("Failed to copy with name " + chosenName + + " from model " + model.getName() + " in spec " + model.getSpec().getName()); + } + } else { + if (model.copy(chosenName) == null) { + throw new ExecutionException("Failed to copy with name " + chosenName + " from model " + model.getName()); + } } // Open the previously created model final Map<String, String> parameters = new HashMap<String, String>(); - parameters.put(OpenModelHandler.PARAM_MODEL_NAME, usersChosenName); + parameters.put(OpenModelHandler.PARAM_MODEL_NAME, chosenName); UIHelper.runCommand(OpenModelHandler.COMMAND_ID, parameters); } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/StartLaunchHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/StartLaunchHandler.java index 86f364186270df2ca8f3a22132add8259c50aed0..3928a042bbbb0c2cd4f2cc4efdb2eda5ace63259 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/StartLaunchHandler.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/StartLaunchHandler.java @@ -5,13 +5,16 @@ import java.util.Map; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.ISources; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.IWorkbenchWindow; @@ -33,7 +36,22 @@ public class StartLaunchHandler extends AbstractHandler { * The last launched model editor or null if no previous launch has happened */ private ModelEditor lastModelEditor; + + private boolean m_isEnabled = false; + @Override + public void setEnabled(Object evaluationContext) { + final ModelEditor modelEditor = getModelEditor((IEvaluationContext)evaluationContext); + + m_isEnabled = (modelEditor != null); + } + + @Override + public boolean isEnabled() { + return m_isEnabled; + } + + @Override public Object execute(ExecutionEvent event) throws ExecutionException { ModelEditor modelEditor = getModelEditor(event); @@ -116,12 +134,22 @@ public class StartLaunchHandler extends AbstractHandler { } return null; } - + private ModelEditor getModelEditor(final ExecutionEvent event) { + return getModelEditor((IEvaluationContext)event.getApplicationContext()); + } + + private ModelEditor getModelEditor(final IEvaluationContext context) { // is current editor a model editor? - final String activeEditorId = HandlerUtil.getActiveEditorId(event); - if (activeEditorId != null && activeEditorId.startsWith(ModelEditor.ID)) { - lastModelEditor = (ModelEditor) HandlerUtil.getActiveEditor(event); + Object variable = context.getVariable(ISources.ACTIVE_EDITOR_ID_NAME); + final String id = (variable != IEvaluationContext.UNDEFINED_VARIABLE) ? (String)variable : null; + + if ((id != null) && (id.startsWith(ModelEditor.ID))) { + variable = context.getVariable(ISources.ACTIVE_EDITOR_NAME); + + if (variable instanceof IEditorPart) { + lastModelEditor = (ModelEditor)variable; + } } // If lastModelEditor is still null, it means we haven't run the model // checker yet AND the model editor view is *not* active. Lets search @@ -139,11 +167,11 @@ public class StartLaunchHandler extends AbstractHandler { // editors are open ("Model_1" and "Model_2"). It would launch Model_1, // even though Model_2 might be what the user wants. if (lastModelEditor == null) { - final IWorkbenchWindow workbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event); - final IWorkbenchPage[] pages = workbenchWindow.getPages(); - for (final IWorkbenchPage page : pages) { - final IEditorReference[] editorReferences = page.getEditorReferences(); - for (final IEditorReference editorRefs: editorReferences) { + final IWorkbenchWindow workbenchWindow = (IWorkbenchWindow) context + .getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME); + + for (final IWorkbenchPage page : workbenchWindow.getPages()) { + for (final IEditorReference editorRefs : page.getEditorReferences()) { if (editorRefs.getId().equals(ModelEditor.ID)) { lastModelEditor = (ModelEditor) editorRefs.getEditor(true); break; @@ -155,7 +183,7 @@ public class StartLaunchHandler extends AbstractHandler { // open spec. E.g. lastModelEditor might still be around from when // the user ran a it on spec X, but has switched to spec Y in the // meantime. Closing the spec nulls the ModelEditor - if (lastModelEditor != null && lastModelEditor.isDisposed()) { + if ((lastModelEditor != null) && lastModelEditor.isDisposed()) { lastModelEditor = null; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java index d1907c70a01cf44ba6c575d9597a4a501a157846..abef46b86ac4a5df52571eece05879a3eb6a4d8e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java @@ -5,7 +5,6 @@ import java.io.IOException; import org.eclipse.ui.console.IOConsoleOutputStream; import org.eclipse.ui.console.MessageConsole; import org.lamport.tla.toolbox.tool.tlc.model.Model; -import org.lamport.tla.toolbox.tool.tlc.output.IProcessOutputSink; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; import org.lamport.tla.toolbox.tool.tlc.ui.console.ConsoleFactory; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java new file mode 100644 index 0000000000000000000000000000000000000000..0c345abb51e4b5fcd4faa244b5a18ce1f13b53c0 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; + +import tla2sany.st.Location; +import tlc2.tool.coverage.ActionWrapper.Relation; + +public class ActionInformationItem extends CoverageInformationItem { + + private static final Pattern pattern = Pattern.compile("^<(.*?) (line [^(]+)( \\(([0-9 ]+)\\))?>: ([0-9]+):([0-9]+)$"); + + public static final int actionLayer = RootCoverageInformationItem.rootLayer + 1; + + public static ActionInformationItem parseInit(String outputMessage, String modelName) { + return parseInitAndNext(Relation.INIT, outputMessage, modelName); + } + + public static ActionInformationItem parseNext(String outputMessage, String modelName) { + return parseInitAndNext(Relation.NEXT, outputMessage, modelName); + } + + private static ActionInformationItem parseInitAndNext(Relation rel, String outputMessage, String modelName) { + final Matcher matcher = pattern.matcher(outputMessage); + matcher.find(); + + final Location declaration = Location.parseLocation(matcher.group(2)); + + // Optional group with the definition. + final String group4 = matcher.group(4); + Location definition = null; + if (group4 != null) { + definition = Location.parseCoordinates(declaration.source(), group4); + } + + final long distinctStates = Long.parseLong(matcher.group(5)); + final long generatedStates = Long.parseLong(matcher.group(6)); + + return new ActionInformationItem(rel, matcher.group(1), declaration, definition, modelName, + generatedStates, distinctStates); + } + + + public static ActionInformationItem parseProp(String outputMessage, String modelName) { + final Pattern pattern = Pattern.compile("^<(.*?) (line .*)>$"); + final Matcher matcher = pattern.matcher(outputMessage); + matcher.find(); + + final Location location = Location.parseLocation(matcher.group(2)); + + return new ActionInformationItem(matcher.group(1), location, modelName); + } + + // ---- ---- // + + private final Relation relation; + private final String name; + private long sum; + private boolean isNotInFile = false; + + /** + * @see tlc2.tool.coverage.ActionWrapper.printLocation() + */ + private final Location definition; + + public ActionInformationItem(final String name, Location loc, final String modelName) { + super(loc, 0, modelName, actionLayer); + this.name = name; + this.relation = Relation.PROP; + this.definition = null; + } + + public ActionInformationItem(final Relation relation, final String name, Location loc, Location definition, + final String modelName, long generated, long unseen) { + super(loc, generated, unseen, modelName, actionLayer); + this.name = name; + this.relation = relation; + this.definition = definition; + } + + ActionInformationItem(ActionInformationItem item) { + super(item.location, item.count, item.cost, item.modelName, item.layer); + this.name = item.name; + this.relation = item.relation; + this.definition = item.definition; + } + + public String getName() { + return name; + } + + public Relation getRelation() { + return relation; + } + + /** + * @return a Location or null if the definition location is unknown + * @see tlc2.tool.coverage.ActionWrapper.printLocation() + */ + public Location getDefinition() { + return definition; + } + + public boolean hasDefinition() { + return definition != null; + } + + @Override + public boolean includeInCounts() { + if (relation == Relation.PROP && count == 0) { + // Count should always be zero but better be safe than sorry. The reason to + // exclude PROP from counts is to prevent bogus zero coverage reports for + // properties. Consider the spec below: + // ---- Foo ---- + // VARIABLE x + // Init == ... + // Next == ... + // TypeOK == x \in Nat + // ===== + // The ActionInformationItem instance for the expression "TypeOK" (just the + // left-hand side), has zero count. The right-hand side will however report + // its count. + return false; + } + return true; + } + + /** + * Number of *distinct* states. + */ + public long getUnseen() { + return getCost(); + } + + public CoverageInformationItem setIsNotInFile() { + this.isNotInFile = true; + return this; + } + + @Override + CoverageInformationItem addChild(CoverageInformationItem child) { + super.addChild(child); + + assert child.getRoot() == null; + child.setRoot(this); // overwrite root set by super.addChild + return this; + } + + @Override + protected StyleRange addStlye(final StyleRange sr) { + sr.borderStyle = SWT.BORDER_DOT; + return sr; + } + + @Override + public void style(TextPresentation textPresentation, final Representation rep) { + if (relation == Relation.PROP) { + return; + } else if (isNotInFile) { + // Skip styling this item but style its children. + for (CoverageInformationItem child : getChildren()) { + child.style(textPresentation, rep); + } + return; + } + super.style(textPresentation, rep); + } + + @Override + protected void style(final TextPresentation textPresentation, boolean merge, final Representation rep) { + if (relation == Relation.PROP) { + return; + } else if (isNotInFile) { + // Skip styling this item but style its children. + for (CoverageInformationItem child : getChildren()) { + child.style(textPresentation, merge, rep); + } + return; + } + super.style(textPresentation, merge, rep); + } + + @Override + public void style(final TextPresentation textPresentation, final Color c, final Representation rep) { + // Do not unstyle AII when specific CostModel tree gets selected. + for (CoverageInformationItem child : getChildren()) { + child.style(textPresentation, c, rep); + } + } + + @Override + Color colorItem(TreeSet<Long> counts, final Representation ignored) { + // This shouldn't be called because the second parameter is bogus. I don't think + // it is called but decided to better leave it in. + return colorItem(counts, counts); + } + + Color colorItem(final TreeSet<Long> distinctStateCounts, final TreeSet<Long> stateCounts) { + // Distinct states colors... + for (Representation rep : Representation.values()) { + // Always use the same representation (also for the unrelated representations + // Inv, Cost, InvCost to avoid NPEs). + representations.put(rep, createColors(distinctStateCounts, getUnseen())); + } + + // For non-distinct states calculate a dedicated color mapping and replace the + // incorrect color mapping from the previous for loop with the correct one. + representations.put(Representation.STATES, createColors(stateCounts, getCount())); + + // Return one of the colors (should be ignored anyway). + return representations.get(Representation.STATES)[0]; + } + + private Color[] createColors(final TreeSet<Long> counts, long count) { + final int hue = ModuleCoverageInformation.getHue(count, counts); + final String key = Integer.toString(hue); + if (!JFaceResources.getColorRegistry().hasValueFor(key)) { + JFaceResources.getColorRegistry().put(key, new RGB(hue, .25f, 1f)); + } + return new Color[] { JFaceResources.getColorRegistry().get(key), JFaceResources.getColorRegistry().get(key) }; + } + + public String getHover() { + final String definition = hasDefinition() ? " (" + getDefinition().linesAndColumns() + ")" : ""; + if (relation == Relation.PROP){ + return ""; + } else if (relation == Relation.NEXT) { + if (getCount() == 0) { + return String.format("Action %s%s:\n- No states found\n", name, definition); + } else if (getUnseen() == 0) { + return String.format("Action %s%s:\n- %,d state%s found but none distinct\n", name, definition, getCount(), + getCount() == 1 ? "" : "s"); + } else { + final double ratio = (getUnseen() * 1d / sum) * 100d; + final double overhead = (getUnseen() * 1d / getCount()) * 100d; + return String.format( + "Action %s%s:\n- %,d state%s found with %,d distinct (%.2f%%)\n- Contributes %.2f%% to total number of distinct states across all actions\n", + name, definition, getCount(), getCount() == 1 ? "" : "s", getUnseen(), overhead, ratio); + } + } else if (relation == Relation.INIT) { + return String.format("Action %s%s (Init):\n- %,d state%s found", name, definition, getCount(), + getCount() == 1 ? "" : "s"); + } + return ""; + } + + public void setSum(final long sum) { + this.sum = sum; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java new file mode 100644 index 0000000000000000000000000000000000000000..f48aa98e8054b94e237c862f6bc1e89c8501c752 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.ui.editors.text.FileDocumentProvider; +import org.eclipse.ui.part.FileEditorInput; +import org.lamport.tla.toolbox.util.AdapterFactory; + +import tlc2.tool.coverage.ActionWrapper.Relation; + +public class CoverageInformation { + + private final List<CoverageInformationItem> items = new ArrayList<>(); + + private final Map<String, IDocument> nameToDocument = new HashMap<>(); + + private final Map<IFile, ModuleCoverageInformation> fileToFCI = new HashMap<>(); + + public CoverageInformation() { + // Testing only! + } + + public CoverageInformation(final List<IFile> savedTLAFiles) { + for (final IFile iFile : savedTLAFiles) { + try { + final FileDocumentProvider fileDocumentProvider = new FileDocumentProvider(); + final FileEditorInput fei = new FileEditorInput(iFile); + fileDocumentProvider.connect(fei); + final IDocument document = fileDocumentProvider.getDocument(fei); + nameToDocument.put(iFile.getName(), document); + } catch (final CoreException notExpectedToHappen) { + notExpectedToHappen.printStackTrace(); + } + } + } + + public void add(final CoverageInformationItem item) { + try { + final String filename = item.getModuleLocation().source() + ".tla"; + if (nameToDocument.containsKey(filename)) { + final IDocument document = nameToDocument.get(filename); + final IRegion region = AdapterFactory.locationToRegion(document , item.getModuleLocation()); + item.setRegion(region); + } + } catch (BadLocationException notExpectedToHappen) { + notExpectedToHappen.printStackTrace(); + } + + synchronized (items) { + this.items.add(item); + } + } + + public boolean isEmpty() { + return this.items.isEmpty(); + } + + /** + * CIIs for zero-covered/disabled spec actions (init and next-state relation). + */ + public List<ActionInformationItem> getDisabledSpecActions() { + synchronized (items) { + return items.stream() + .filter(item -> ((item instanceof ActionInformationItem) + && ((ActionInformationItem) item).getRelation() != Relation.PROP + && (((ActionInformationItem) item).getCount() == 0))) + .map(item -> (ActionInformationItem) item).collect(Collectors.toList()); + } + } + + public boolean hasDisabledSpecActions() { + synchronized (items) { + return items.stream() + .filter(item -> ((item instanceof ActionInformationItem) + && ((ActionInformationItem) item).getRelation() != Relation.PROP + && (((ActionInformationItem) item).getCount() == 0))) + .findAny().isPresent(); + } + } + + public List<ActionInformationItem> getSpecActions() { + synchronized (items) { + return items.stream() + .filter(item -> ((item instanceof ActionInformationItem) + && ((ActionInformationItem) item).getRelation() != Relation.PROP)) + .map(item -> (ActionInformationItem) item).collect(Collectors.toList()); + } + } + + /** + * @return true if coverage information pre-dates TLC's new/hierarchical format introduced by the CostModel. + */ + public boolean isLegacy() { + // true if there are no ActionInformationItems. + synchronized (items) { + return !items.stream().filter(i -> i instanceof ActionInformationItem).findAny().isPresent(); + } + } + + public boolean has(final IFile iFile) { + synchronized (items) { + return items.stream().filter(i -> i.isInFile(iFile)).findAny().isPresent(); + } + } + + public ModuleCoverageInformation projectionFor(final IFile iFile) { + // The CoverageInformation keeps the CoverageInformationItems for the complete + // model whereas a FileCoverageInformation keeps the CII for a single module. + return fileToFCI.computeIfAbsent(iFile, f -> new ModuleCoverageInformation(f, items)); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java index 9ea63ed02f0d31a358f658e8d9ab54ae5aae130c..6f0c6f3ce463325c2e1aeabcc19996247b34c927 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java @@ -1,25 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Simon Zambrowski - initial API and implementation + ******************************************************************************/ package org.lamport.tla.toolbox.tool.tlc.output.data; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping; import org.lamport.tla.toolbox.tool.tlc.ui.util.IModuleLocatable; import tla2sany.st.Location; +import tlc2.TLCGlobals; -/** - * Coverage information item - * @author Simon Zambrovski - * @version $Id$ - */ public class CoverageInformationItem implements IModuleLocatable { - private final static String MOD = " of module "; private final static String COLON = ": "; private final static String AT = "at "; - private String locationString; - private Location location; - private String modelName; - private long count; + protected Location location; + protected String modelName; + protected long count; + protected long cost; + protected int layer; + + // Siblings are CII instances shown at the same editor region/location. + private final Set<CoverageInformationItem> siblings = new HashSet<>(); + // Children are CII instances corresponding to nested expressions (will only be + // populated after the TLACoverageEditor has been opened). + private final Set<CoverageInformationItem> childs = new HashSet<>(); + // The parent is the CII instance this CII is a nested expressions of. + private CoverageInformationItem parent; + private ActionInformationItem root; + + private boolean active = false; + protected final Map<Representation, Color[]> representations = new HashMap<>(); + /** * Creates an simple item storing information about a coverage at a certain location * @param location @@ -28,29 +81,62 @@ public class CoverageInformationItem implements IModuleLocatable * @param module */ - public CoverageInformationItem(Location location, long count, String modelName) + protected CoverageInformationItem(Location location, long count, String modelName, int layer) { this.location = location; - this.locationString = this.location.toString(); this.count = count; this.modelName = modelName; + assert layer >= ActionInformationItem.actionLayer; + this.layer = layer; } + + public CoverageInformationItem(Location location, long count, long cost, String modelName, int layer) { + this(location, count, modelName, layer); + this.cost = cost; + } + + public CoverageInformationItem() { + } - public final String getModule() + public final String getModule() { - return locationString.substring(locationString.indexOf(MOD) + MOD.length()); + return location.source(); } public final String getLocation() { - return locationString.substring(0, locationString.indexOf(MOD)); + return location.linesAndColumns(); + } + + public final boolean isInFile(IFile f) { + final String nameWithoutSuffix = f.getName().replace(".tla", ""); + return nameWithoutSuffix.equalsIgnoreCase(location.source()); } - public final long getCount() + public boolean includeInCounts() { + return true; + } + + public long getCount() { return count; } + public final long getCost() { + return cost; + } + + public long getCountAndCost() { + return count + cost; + } + /** + * If two CCI are co-located (overlapping, nested, ...), the layer indicates + * which one is considered more important. + */ + public int getLayer() { + return layer; + } + /** * Parses the coverage information item from a string * @param outputMessage @@ -62,9 +148,30 @@ public class CoverageInformationItem implements IModuleLocatable // " line 84, col 32 to line 85, col 73 of module AtomicBakery: 1012492" outputMessage = outputMessage.trim(); + + final int layer = outputMessage.lastIndexOf(TLCGlobals.coverageIndent) + 1; + int index = outputMessage.indexOf(COLON); - return new CoverageInformationItem(Location.parseLocation(outputMessage.substring(0, index)), Long - .parseLong(outputMessage.substring(index + COLON.length())), modelName); + return new CoverageInformationItem(Location.parseLocation(outputMessage.substring(layer, index)), Long + .parseLong(outputMessage.substring(index + COLON.length())), modelName, layer); + } + + public static CoverageInformationItem parseCost(String outputMessage, String modelName) + { + + // " line 84, col 32 to line 85, col 73 of module AtomicBakery: 1012492" + outputMessage = outputMessage.trim(); + + final Pattern pattern = Pattern.compile("^(\\|*?)(line .*): ([0-9]+):([0-9]+)$"); + final Matcher matcher = pattern.matcher(outputMessage); + matcher.find(); + + final int layer = matcher.group(1).length(); + final Location location = Location.parseLocation(matcher.group(2)); + final long count = Long.parseLong(matcher.group(3)); + final long cost= Long.parseLong(matcher.group(4)); + + return new CoverageInformationItem(location, count, cost, modelName, layer); } /** @@ -95,5 +202,209 @@ public class CoverageInformationItem implements IModuleLocatable { return modelName; } + + CoverageInformationItem setRoot(ActionInformationItem root) { + this.root = root; + return this; + } + + CoverageInformationItem setSiblings(List<CoverageInformationItem> siblings) { + this.siblings.clear(); + this.siblings.addAll(siblings); + this.siblings.remove(this); + return this; + } + + boolean hasSiblings() { + return !this.siblings.isEmpty(); + } + + public long getTotalCount() { + return siblings.stream().mapToLong(CoverageInformationItem::getCount).sum() + getCount(); + } + + public long getTotalCost() { + return siblings.stream().mapToLong(CoverageInformationItem::getCost).sum() + getCost(); + } + + public long getTotalCountAndCost() { + return getTotalCost() + getTotalCount(); + } + + Collection<CoverageInformationItem> getChildren() { + return childs; + } + + CoverageInformationItem addChild(CoverageInformationItem child) { + assert child != this; + this.childs.add(child); + + assert child.parent == null; + child.parent = this; + + child.root = this.root; + + return this; + } + + CoverageInformationItem setLayer(int i) { + assert layer > ActionInformationItem.actionLayer; + this.layer = i; + return this; + } + + private IRegion region; + + public IRegion getRegion() { + return this.region; + } + + CoverageInformationItem setRegion(IRegion locationToRegion) { + this.region = locationToRegion; + return this; + } + + protected boolean isRoot() { + return false; + } + + public boolean isActive() { + return active; + } + + protected StyleRange addStlye(StyleRange sr) { + // no-op + return sr; + } + + public void style(final TextPresentation textPresentation, final Representation rep) { + if (isRoot()) { + style(textPresentation, true, rep); + } else { + style(textPresentation, false, rep); + } + } + + protected void style(final TextPresentation textPresentation, final boolean merge, final Representation rep) { + if (!isRoot()) { + final StyleRange rs = new StyleRange(); + + // IRegion + rs.start = region.getOffset(); + rs.length = region.getLength(); + + // Background Color + rs.background = rep.getColor(this, merge ? Grouping.COMBINED : Grouping.INDIVIDUAL); + + // Zero Coverage + if ((rep == Representation.STATES_DISTINCT || rep == Representation.STATES) && !(this instanceof ActionInformationItem)) { + rs.background = JFaceResources.getColorRegistry().get(ModuleCoverageInformation.GRAY); + rs.borderStyle = SWT.NONE; + rs.borderColor = null; + } else if (rep != Representation.COST && rep.getValue(this, Grouping.INDIVIDUAL) == 0L) { + rs.background = null; + rs.borderStyle = SWT.BORDER_SOLID; + rs.borderColor = JFaceResources.getColorRegistry().get(ModuleCoverageInformation.RED); + } + + // Track active subtree + rs.data = this; //mergeStyleRange does not merge rs.data, thus track active instead. + active = true; + + textPresentation.mergeStyleRange(addStlye(rs)); + } + for (CoverageInformationItem child : childs) { + child.style(textPresentation, merge, rep); + } + } + + public void style(final TextPresentation textPresentation, final Color c, final Representation rep) { + if (!isRoot()) { + final StyleRange rs = new StyleRange(); + rs.start = region.getOffset(); + rs.length = region.getLength(); + rs.background = c; + if ((rep == Representation.STATES_DISTINCT || rep == Representation.STATES) && !(this instanceof ActionInformationItem)) { + rs.background = JFaceResources.getColorRegistry().get(ModuleCoverageInformation.GRAY); + rs.borderStyle = SWT.NONE; + rs.borderColor = null; + } else if (rep != Representation.COST && rep.getValue(this, Grouping.INDIVIDUAL) == 0L) { + rs.background = null; + rs.borderStyle = SWT.BORDER_SOLID; + rs.borderColor = JFaceResources.getColorRegistry().get(ModuleCoverageInformation.RED); + } + active = false; + textPresentation.replaceStyleRange(addStlye(rs)); + } + for (CoverageInformationItem child : childs) { + child.style(textPresentation, c, rep); + } + } + + Color colorItem(TreeSet<Long> counts, final Representation rep) { + int hue = ModuleCoverageInformation.getHue(rep.getValue(this, Grouping.INDIVIDUAL), counts); + String key = Integer.toString(hue); + if (!JFaceResources.getColorRegistry().hasValueFor(key)) { + JFaceResources.getColorRegistry().put(key, new RGB(hue, .25f, 1f)); + } + final Color color = JFaceResources.getColorRegistry().get(key); + + Color[] colors = new Color[2]; + colors[Grouping.INDIVIDUAL.ordinal()] = color; + colors[Grouping.COMBINED.ordinal()] = color; + representations.put(rep, colors); + + if (hasSiblings()) { + // Aggregated color (might be identical to color). + hue = ModuleCoverageInformation.getHue(rep.getValue(this, Grouping.COMBINED), counts); + key = Integer.toString(hue); + if (!JFaceResources.getColorRegistry().hasValueFor(key)) { + JFaceResources.getColorRegistry().put(key, new RGB(hue, .25f, 1f)); + } + Color aggregate = JFaceResources.getColorRegistry().get(key); + + colors = new Color[2]; + colors[Grouping.INDIVIDUAL.ordinal()] = color; + colors[Grouping.COMBINED.ordinal()] = aggregate; + representations.put(rep, colors); + return aggregate; + } + + return color; + } + + public CoverageInformationItem getParent() { + return parent; + } + + public ActionInformationItem getRoot() { + return root; + } + + public boolean hasLocation() { + return this.location != null; + } + public TreeSet<CoverageInformationItem> getLegend(final Representation rep) { + if (rep == Representation.STATES || rep == Representation.STATES_DISTINCT) { + // The active tree also contains CoverageInformationItem instances which - for + // states found and distinct states - are not relevant. The legend for the + // state based profiling (as opposed to invocation and cost) for a selected + // action just needs a single legend item, namely the selected action itself. + final TreeSet<CoverageInformationItem> s = new TreeSet<>(rep.getComparator(Grouping.INDIVIDUAL)); + s.add(this); + return s; + } + return collectActive(new TreeSet<CoverageInformationItem>(rep.getComparator(Grouping.INDIVIDUAL))); + } + + protected TreeSet<CoverageInformationItem> collectActive(final TreeSet<CoverageInformationItem> legend) { + legend.add(this); + for (CoverageInformationItem child : childs) { + if (child.isActive()) { + child.collectActive(legend); + } + } + return legend; + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java new file mode 100644 index 0000000000000000000000000000000000000000..f9e17e10ec6287d6e8621f6d3409448260426f11 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.Date; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.resource.ImageDescriptor; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.util.TLCUINotification; + +public class CoverageUINotification extends TLCUINotification { + + private static final ImageDescriptor id = TLCUIActivator.getImageDescriptor("/icons/elcl16/quickfix_obj.png"); + + private final ModelEditor editor; + + public CoverageUINotification(final ModelEditor editor) { + super("Performance Hint", + "TLC has for some time been\n" + + "running with profiling enabled\n" + + "Please be advised that profiling\n" + + "negatively impacts performance.\n" + + "For this reason, please consider\n" + + "turning profiling off on the\n" + + "advanced TLC options page and\n" + + "re-run model checking without it.", + new Date()); + this.editor = editor; + Assert.isNotNull(editor); + + setKindImage(id.createImage()); + } + + @Override + public void open() { + editor.addOrShowAdvancedTLCOptionsPage(); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ITLCModelLaunchDataPresenter.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ITLCModelLaunchDataPresenter.java index 46c311088edcd64cef7385615e569cd8e8c8ab02..853c1b5fafc46e497e989158a6051d46420f7bd6 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ITLCModelLaunchDataPresenter.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ITLCModelLaunchDataPresenter.java @@ -7,25 +7,29 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; public interface ITLCModelLaunchDataPresenter { /* constants for the fields */ - public final static int USER_OUTPUT = 1; - public final static int PROGRESS_OUTPUT = 2; - public final static int START_TIME = 4; - public final static int END_TIME = 8; - public final static int COVERAGE_TIME = 16; - public final static int COVERAGE = 32; - public final static int PROGRESS = 64; - public final static int ERRORS = 128; - public final static int LAST_CHECKPOINT_TIME = 256; - public final static int CURRENT_STATUS = 512; - public final static int CONST_EXPR_EVAL_OUTPUT = 1024; - public final static int FINGERPRINT_COLLISION_PROBABILITY = 2048; - public static final int DISTRIBUTED_SERVER_RUNNING = 4069; - public static final int DISTRIBUTED_WORKER_REGISTERED = 8192; - public static final int TLC_MODE = DISTRIBUTED_WORKER_REGISTERED << 1; + public final static int USER_OUTPUT = 1; + public final static int PROGRESS_OUTPUT = USER_OUTPUT << 1; + public final static int START_TIME = PROGRESS_OUTPUT << 1; + public final static int END_TIME = START_TIME << 1; + public final static int COVERAGE_TIME = END_TIME << 1; + public final static int COVERAGE = COVERAGE_TIME << 1; + public final static int COVERAGE_END = COVERAGE << 1; + public final static int COVERAGE_END_OVERHEAD = COVERAGE_END << 1; + public final static int PROGRESS = COVERAGE_END_OVERHEAD << 1; + public final static int ERRORS = PROGRESS << 1; + public final static int LAST_CHECKPOINT_TIME = ERRORS << 1; + public final static int CURRENT_STATUS = LAST_CHECKPOINT_TIME << 1; + public final static int CONST_EXPR_EVAL_OUTPUT = CURRENT_STATUS << 1; + public final static int FINGERPRINT_COLLISION_PROBABILITY = CONST_EXPR_EVAL_OUTPUT << 1; + public static final int DISTRIBUTED_SERVER_RUNNING = FINGERPRINT_COLLISION_PROBABILITY << 1; + public static final int DISTRIBUTED_WORKER_REGISTERED = DISTRIBUTED_SERVER_RUNNING << 1; + public static final int TLC_MODE = DISTRIBUTED_WORKER_REGISTERED << 1; + public static final int WARNINGS = TLC_MODE << 1; public final static int[] ALL_FIELDS = { USER_OUTPUT, PROGRESS_OUTPUT, START_TIME, END_TIME, LAST_CHECKPOINT_TIME, - COVERAGE_TIME, COVERAGE, PROGRESS, ERRORS, CONST_EXPR_EVAL_OUTPUT, FINGERPRINT_COLLISION_PROBABILITY, - DISTRIBUTED_SERVER_RUNNING, DISTRIBUTED_WORKER_REGISTERED, TLC_MODE }; + COVERAGE_TIME, COVERAGE, COVERAGE_END, PROGRESS, ERRORS, CONST_EXPR_EVAL_OUTPUT, + FINGERPRINT_COLLISION_PROBABILITY, DISTRIBUTED_SERVER_RUNNING, DISTRIBUTED_WORKER_REGISTERED, TLC_MODE, + WARNINGS }; /** * Inform the presenter about the data changes diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ModuleCoverageInformation.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ModuleCoverageInformation.java new file mode 100644 index 0000000000000000000000000000000000000000..9ec5a9304680480b5cbe49142d2153764a2cd1ee --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ModuleCoverageInformation.java @@ -0,0 +1,261 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.RGB; +import org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping; + +import tla2sany.st.Location; + +public class ModuleCoverageInformation { + + public static final String GRAY = "GRAY"; + + public static final String RED = "RED"; + + static { + JFaceResources.getColorRegistry().put(RED, new RGB(255,0,0)); + JFaceResources.getColorRegistry().put(GRAY, new RGB(211,211,211)); + } + + private static final int BLUE = 240; + + static int getHue(final long count, final TreeSet<Long> counts) { + final int size = counts.size(); + final float r = 240f / size; + final SortedSet<Long> headSet = counts.headSet(count); + return BLUE - Math.round(r * (headSet.size() + 1)); + } + + private static CoverageInformationItem getRoot(final List<CoverageInformationItem> items, final IFile file) { + // Root is the technical root acting as entry point for the editor. It doesn't + // have a location or counts. Its only children are ActionInformationItems. + final CoverageInformationItem root = new RootCoverageInformationItem(); + + final Deque<CoverageInformationItem> stack = new ArrayDeque<>(); + stack.push(root); + + // AII is the (logical) root of the current CostModel. It has a location and + // counts. + ActionInformationItem aiiRoot = null; + for (CoverageInformationItem item : items) { + if (item.isInFile(file)) { + if (item instanceof ActionInformationItem) { + aiiRoot = (ActionInformationItem) item; + } + int layer = item.getLayer(); + while (layer <= stack.peek().getLayer()) { + stack.pop(); + } + stack.peek().addChild(item); + stack.push(item); + } else if (aiiRoot == null && item instanceof ActionInformationItem) { + // aiiroot is in a different file, e.g. definition of Init or Next in MC.tla. + aiiRoot = new ActionInformationItem((ActionInformationItem) item); + aiiRoot.setIsNotInFile(); + root.addChild(aiiRoot); + stack.push(aiiRoot); + } + } + assert root.getChildren().stream().allMatch(c -> c instanceof ActionInformationItem); + + return root; + } + + //-------------------------// + + private final Map<Location, List<CoverageInformationItem>> loc2cci = new HashMap<>(); + + private final TreeMap<Integer, List<CoverageInformationItem>> offset2cii = new TreeMap<>(); + + private final Map<Representation, TreeSet<CoverageInformationItem>> rootLegends = new HashMap<>(); + + private final IFile file; + + private final List<CoverageInformationItem> allItems; + + private CoverageInformationItem root; + + public ModuleCoverageInformation(final IFile file, final List<CoverageInformationItem> allItems) { + this.file = file; + this.allItems = allItems; + + // The subset of items that belong to this file. + final List<CoverageInformationItem> subset = allItems.stream().filter(i -> i.isInFile(file)) + .collect(Collectors.toList()); + + // Group items belonging to the same location/region. + for (CoverageInformationItem item : subset) { + this.loc2cci.computeIfAbsent(item.getModuleLocation(), c -> new ArrayList<>()).add(item); + this.offset2cii.computeIfAbsent(item.getRegion().getOffset(), c -> new ArrayList<>()).add(item); + } + for (CoverageInformationItem item : subset) { + // Set siblings if any: + item.setSiblings(loc2cci.get(item.getModuleLocation())); + } + + // Initialize legends for each representation. + for (Representation rep : Representation.values()) { + this.rootLegends.put(rep, new TreeSet<CoverageInformationItem>(rep.getComparator(Grouping.COMBINED))); + } + + // Calculate the range of values for the ActionInformationItems. + final List<ActionInformationItem> actionSubset = subset.stream() + .filter(cii -> cii instanceof ActionInformationItem).map(ActionInformationItem.class::cast) + .collect(Collectors.toList()); + + // Sum of all distinct states. + final long sum = actionSubset.stream().mapToLong(ActionInformationItem::getUnseen).sum(); + + final TreeSet<Long> distinctStateCounts = new TreeSet<>(); + final TreeSet<Long> stateCounts = new TreeSet<>(); + actionSubset.forEach(a -> { + distinctStateCounts.add(a.getUnseen()); + stateCounts.add(a.getCount()); + a.setSum(sum); + }); + // With aiiCounts collected, update all actions. + actionSubset.forEach(a -> { + a.colorItem(distinctStateCounts, stateCounts); + rootLegends.get(Representation.STATES).add(a); + rootLegends.get(Representation.STATES_DISTINCT).add(a); + }); + + final List<Representation> values = Arrays.asList(Representation.values()).stream() + .filter(rep -> rep != Representation.STATES && rep != Representation.STATES_DISTINCT) + .collect(Collectors.toList()); + + // Style the CIIs for each representation. + subset.removeAll(actionSubset); + for (Representation rep : values) { + final TreeSet<Long> ciiCounts = new TreeSet<>(); + + for (final CoverageInformationItem item : subset) { + ciiCounts.add(rep.getValue(item, Grouping.INDIVIDUAL)); + ciiCounts.add(rep.getValue(item, Grouping.COMBINED)); + } + // Color each item according to the previously calculated ranges. + final Set<CoverageInformationItem> set = rootLegends.get(rep); + for (final CoverageInformationItem item : subset) { + // Calculate colors for CII. + item.colorItem(ciiCounts, rep); + + set.add(item); + } + } + } + + // false if a module has no actions (e.g. standard modules). + public boolean hasStates() { + return this.allItems.stream().filter(i -> i.isInFile(this.file) && i instanceof ActionInformationItem) + .count() > 0L; + } + + public CoverageInformationItem getRoot() { + if (this.root == null) { + // Create the tree out of the flat list of items (the tree might span multiple + // files which is why we pass allItems). getRoot is expected to be called + // outside the UI thread. + this.root = getRoot(allItems, file); + } + return root; + } + + private List<CoverageInformationItem> getNodes(final int offset) { + final Entry<Integer, List<CoverageInformationItem>> entry = this.offset2cii.floorEntry(offset); + if (entry != null) { + return entry.getValue().stream() + .filter(cii -> offset <= cii.getRegion().getOffset() + cii.getRegion().getLength()) + .collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + public CoverageInformationItem getNode(final int offset) { + return getNodes(offset).stream().findFirst().orElse(null); + } + + public String getHoverInfo(final int offset) { + final List<CoverageInformationItem> nodes = getNodes(offset); + + final List<CoverageInformationItem> sorted = nodes.stream() + .filter(cii -> !(cii instanceof ActionInformationItem)) + .sorted((c1, c2) -> c1.isActive() ? -1 : c2.isActive() ? 1 : Long.compare(c1.getCount(), c2.getCount())) + .collect(Collectors.toList()); + + String hover = "", plus = ""; + Long sum = 0L; + for (CoverageInformationItem cii : sorted) { + final long count = cii.getCount(); + sum += count; + String cost = ""; + if (cii.getCost() > 0) { + cost = String.format(", cost %s", cii.getCost()); + } + hover = String.format("%s%s%,d invocation%s%s (%s)\n", hover, plus, count, count == 1 ? "" : "s", cost, + cii.getRoot().getLocation()); + plus = "+"; + } + + if (sorted.size() > 1 && sum > 0) { + hover += String.format("---------\n%,d invocations", sum); + } + + + final List<CoverageInformationItem> actionItems = nodes.stream().filter(cii -> cii instanceof ActionInformationItem) + .collect(Collectors.toList()); + if (!actionItems.isEmpty()) { + hover += "\n"; + for (CoverageInformationItem cii : actionItems) { + final ActionInformationItem aii = (ActionInformationItem) cii; + hover += aii.getHover(); + hover += "\n"; + } + } + + return hover.replaceAll("^\n", "").replaceAll("\n$", ""); + } + + public TreeSet<CoverageInformationItem> getLegend(final Representation rep) { + return rootLegends.get(rep); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/Representation.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/Representation.java new file mode 100644 index 0000000000000000000000000000000000000000..48d375a26e544f810c3952978f0198a6b045e7aa --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/Representation.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.Comparator; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.Color; + +public enum Representation { + + INV, COST, INVCOST, STATES, STATES_DISTINCT; + + public static Object valuesNoStates() { + final Representation[] values = new Representation[3]; + values[0] = INV; + values[1] = COST; + values[2] = INVCOST; + return values; + } + + public enum Grouping { + INDIVIDUAL, COMBINED; + } + + public String getToolTipText() { + if (this == INV) { + return "Invocations: %,d\nClick to jump to location %s."; + } else if (this == COST) { + return "Cost: %,d\nClick to jump to location %s."; + } else if (this == INVCOST) { + return "Inv + Cost: %,d\nClick to jump to location %s."; + } else if (this == STATES) { + return "States Found: %,d\nClick to jump to location %s."; + } else if (this == STATES_DISTINCT) { + return "Distinct States: %,d\nClick to jump to location %s."; + } + return ""; + } + + public String toString() { + if (this == INV) { + return "Invocations"; + } else if (this == COST) { + return "Cost"; + } else if (this == INVCOST) { + return "Inv + Cost"; + } else if (this == STATES) { + return "States Found"; + } else if (this == STATES_DISTINCT) { + return "Distinct States"; + } + return ""; + } + + public long getValue(CoverageInformationItem item, Grouping grouping) { + if (grouping == Grouping.COMBINED) { + return getTotal(item); + } else { + return getValue(item); + } + } + + private long getValue(CoverageInformationItem item) { + if (this == INV) { + return item.getCount(); + } else if (this == COST) { + return item.getCost(); + } else if (this == INVCOST) { + return item.getCountAndCost(); + } else if (this == STATES) { + return item.getCount(); + } else if (this == STATES_DISTINCT) { + return item.getCost(); + } + return 0L; + } + + private long getTotal(CoverageInformationItem item) { + if (this == INV) { + return item.getTotalCount(); + } else if (this == COST) { + return item.getTotalCost(); + } else if (this == INVCOST) { + return item.getTotalCost() + item.getTotalCount(); + } else if (this == STATES) { + return item.getTotalCount(); + } else if (this == STATES_DISTINCT) { + return item.getTotalCost(); + } + return 0L; + } + + public Color getColor(CoverageInformationItem cii, final Grouping group) { + final Color[] colors = cii.representations.get(this); + if (colors != null) { + return colors[group.ordinal()]; + } + return JFaceResources.getColorRegistry().get(ModuleCoverageInformation.GRAY); + } + + public Comparator<CoverageInformationItem> getComparator(Grouping grouping) { + if (this == STATES) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getCount(), o2.getCount()); + } + }; + } else if (this == STATES_DISTINCT) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getCost(), o2.getCost()); + } + }; + } + if (grouping == Grouping.COMBINED) { + if (this == INV) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getTotalCount(), o2.getTotalCount()); + } + }; + } else if (this == COST) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getTotalCost(), o2.getTotalCost()); + } + }; + } else if (this == INVCOST) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getTotalCountAndCost(), o2.getTotalCountAndCost()); + } + }; + } + } else { + if (this == INV) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getCount(), o2.getCount()); + } + }; + } else if (this == COST) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getCost(), o2.getCost()); + } + }; + } else if (this == INVCOST) { + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return Long.compare(o1.getCountAndCost(), o2.getCountAndCost()); + } + }; + } + } + return new Comparator<CoverageInformationItem>() { + @Override + public int compare(CoverageInformationItem o1, CoverageInformationItem o2) { + return 0; + } + }; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/RootCoverageInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/RootCoverageInformationItem.java new file mode 100644 index 0000000000000000000000000000000000000000..66e085576639d8738c346d18b805afc69c6ecd60 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/RootCoverageInformationItem.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.output.data; + +import java.util.List; + +public class RootCoverageInformationItem extends CoverageInformationItem { + + public static final int rootLayer = -2; + + public RootCoverageInformationItem() { + layer = rootLayer; + } + + @Override + protected boolean isRoot() { + return true; + } + + @Override + CoverageInformationItem setRoot(ActionInformationItem root) { + throw new RuntimeException("Root must not have siblings."); + } + + @Override + CoverageInformationItem setSiblings(List<CoverageInformationItem> siblings) { + throw new RuntimeException("Root must not have siblings."); + } + + @Override + boolean hasSiblings() { + return false; + } + + @Override + CoverageInformationItem addChild(CoverageInformationItem child) { + if (child instanceof ActionInformationItem) { + return super.addChild(child); + } + throw new IllegalArgumentException("Only ActionInformationItem allowed for root."); + } + + @Override + CoverageInformationItem setLayer(int i) { + throw new RuntimeException("Root has fixed layer."); + } + + @Override + public CoverageInformationItem getParent() { + throw new RuntimeException("Root has no parent."); + } + + @Override + public ActionInformationItem getRoot() { + throw new RuntimeException("Root has no ActionInformationItem."); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java index 0965c83c9095d7a8f7800eff6bd219393f207fcd..c3f83cbf0501b9afecf94b4f34c3b7c016d50d46 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java @@ -1,8 +1,5 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,7 +9,6 @@ import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; /** * Representation of the state space progress item * @author Simon Zambrovski - * @version $Id$ */ public class StateSpaceInformationItem { @@ -55,6 +51,16 @@ public class StateSpaceInformationItem this.distinctSPM = distinctSPM; } + private StateSpaceInformationItem(Date time, long foundStates, long distinctStates) { + // Set leftStates to distinctStates: If we found 10 initial states, those 10 + // states go into the queue. + this(time, 0, foundStates, distinctStates, distinctStates, 0, 0); + } + + private StateSpaceInformationItem(Date time, long distinctStates) { + this(time, distinctStates, distinctStates); + } + private StateSpaceInformationItem(long foundStates, long distinctStates) { this(new Date(), 0, foundStates, distinctStates, distinctStates, 0, 0); } @@ -131,6 +137,16 @@ public class StateSpaceInformationItem return distinctSPM; } + private static long localizedNum2Long(final String number) { + // Strip all locale-specific delimiters from input. This assumes number is + // rounded to zero decimal places which should be the case for + // StateSpaceInfomrationItems. So far we haven't seen fractions of TLA+ state. + // States appear to be atomic. Per-minutes states are also reported without + // decimal places. + final String justDigits = number.replaceAll("[^0-9]", ""); + return Long.parseLong(justDigits); + } + /** * @param outputMessage * @return @@ -156,6 +172,10 @@ public class StateSpaceInformationItem for (int j = 0; j < i.length; j++) { if (i[j] == -1) { + // Old does not only mean previously written MC.out files. Current TLC still emits old format through: + // tlc2.tool.distributed.TLCServer.modelCheck() + // tlc2.tool.distributed.TLCServer.printSummary(int, long, long, long, boolean) + // tlc2.tool.ModelChecker.modelCheck() <- Liveness checking return parseOld(outputMessage); } } @@ -163,33 +183,29 @@ public class StateSpaceInformationItem // assuming the previous check suffices, it should now be possible to // parse the string back to its real types try { - final Date time = SDF.parse(outputMessage.substring( + final Date time = TLCModelLaunchDataProvider.parseDate(outputMessage.substring( i[1] + AT.length(), i[2])); - final NumberFormat nf = NumberFormat.getNumberInstance(); - - final long diameter = Long.parseLong(outputMessage.substring(i[0] - + OB.length(), i[1])); - final long foundStates = Long.parseLong(outputMessage.substring( - i[2] + COLON.length(), i[3])); - final long statesPerMinute = nf.parse(outputMessage - .substring(i[3] + GENERATED.length(), i[4]).replace(",", "")).longValue(); + final long diameter = localizedNum2Long( + outputMessage.substring(i[0] + OB.length(), i[1])); + final long foundStates = localizedNum2Long( + outputMessage.substring(i[2] + COLON.length(), i[3])); + final long statesPerMinute = localizedNum2Long( + outputMessage.substring(i[3] + GENERATED.length(), i[4])); - final long distinctStates = Long.parseLong(outputMessage.substring( - i[4] + SPM.length(), i[5])); - final long distinctStatesPerMinute = nf.parse(outputMessage - .substring(i[5] + DISTINCT.length(), i[6]).replace(",", "")).longValue(); + final long distinctStates = localizedNum2Long( + outputMessage.substring(i[4] + SPM.length(), i[5])); + final long distinctStatesPerMinute = localizedNum2Long( + outputMessage.substring(i[5] + DISTINCT.length(), i[6])); - final long leftStates = Long.parseLong(outputMessage.substring(i[6] - + DISTINCT_SPM.length(), i[7])); + final long leftStates = localizedNum2Long( + outputMessage.substring(i[6] + DISTINCT_SPM.length(), i[7])); return new StateSpaceInformationItem(time, diameter, foundStates, distinctStates, leftStates, statesPerMinute, distinctStatesPerMinute); } catch (NumberFormatException e) { TLCUIActivator.getDefault().logError("Error reading progress information", e); - } catch (ParseException e) { - TLCUIActivator.getDefault().logError("Error reading progress information", e); } return null; } @@ -200,6 +216,7 @@ public class StateSpaceInformationItem // b.append("Finished computing initial states: %1% distinct state%2% generated."); // b.append("Finished computing initial states: %1% state%2% generated, with %3% of them distinct."); + // Legacy pattern without date. Pattern pattern = Pattern.compile("^Finished computing initial states: ([0-9]+) distinct state[s]* generated.$"); Matcher matcher = pattern.matcher(outputMessage); if (matcher.find()) { @@ -215,11 +232,29 @@ public class StateSpaceInformationItem final long distinctStates = Long.parseLong(matcher.group(2)); return new StateSpaceInformationItem(foundStates, distinctStates); } + + // New patterns with date. + pattern = Pattern.compile("^Finished computing initial states: ([0-9]+) distinct state[s]* generated at (.*).$"); + matcher = pattern.matcher(outputMessage); + if (matcher.find()) { + final long distinctStates = Long.parseLong(matcher.group(1)); + final Date date = TLCModelLaunchDataProvider.parseDate(matcher.group(2)); + return new StateSpaceInformationItem(date, distinctStates); + } + + pattern = Pattern.compile( + "^Finished computing initial states: ([0-9]+) states generated, with ([0-9]+) of them distinct at (.*).$"); + matcher = pattern.matcher(outputMessage); + if (matcher.find()) { + final long foundStates = Long.parseLong(matcher.group(1)); + final long distinctStates = Long.parseLong(matcher.group(2)); + final Date date = TLCModelLaunchDataProvider.parseDate(matcher.group(3)); + return new StateSpaceInformationItem(date, foundStates, distinctStates); + } return null; } - - - /** + + /** * @param outputMessage * @return */ @@ -247,26 +282,18 @@ public class StateSpaceInformationItem } try { - return new StateSpaceInformationItem(SDF.parse(outputMessage - .substring(i[1] + AT.length(), i[2])), - Long.parseLong(outputMessage.substring(i[0] + OB.length(), - i[1])), Long.parseLong(outputMessage.substring(i[2] - + COLON.length(), i[3])), - Long.parseLong(outputMessage.substring( - i[3] + GENERATED.length(), i[4])), - Long.parseLong(outputMessage.substring( - i[4] + DISTINCT.length(), i[5])), 0, 0); + return new StateSpaceInformationItem( + TLCModelLaunchDataProvider.parseDate(outputMessage.substring(i[1] + AT.length(), i[2])), + localizedNum2Long(outputMessage.substring(i[0] + OB.length(), i[1])), + localizedNum2Long(outputMessage.substring(i[2] + COLON.length(), i[3])), + localizedNum2Long(outputMessage.substring(i[3] + GENERATED.length(), i[4])), + localizedNum2Long(outputMessage.substring(i[4] + DISTINCT.length(), i[5])), 0, 0); } catch (NumberFormatException e) { TLCUIActivator.getDefault().logError("Error reading progress information", e); - } catch (ParseException e) { - TLCUIActivator.getDefault().logError("Error reading progress information", e); } return null; } - public final static SimpleDateFormat SDF = new SimpleDateFormat( - "yyyy-MM-dd HH:mm:ss"); - /* (non-Javadoc) * @see java.lang.Object#hashCode() */ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java index a4586aeb4457bf148e956a1d41280793eb3f1ec8..5de7fe25e8bc9a4718dcf5bbde9043a01c4a1e0f 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java @@ -26,9 +26,18 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; +import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; +import java.util.Hashtable; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; +import org.lamport.tla.toolbox.tool.tlc.model.Formula; /** * Representation of the TLC error @@ -40,19 +49,42 @@ public class TLCError ALL, RESTRICTED; } + public enum Order { + OneToN, NToOne; + + public static Order valueOf(final boolean b) { + if (b) { + return NToOne; + } + return OneToN; + } + } + private String message = ""; private LinkedList<TLCState> states = new LinkedList<TLCState>(); private TLCError cause; private int errorCode; private int numberOfStatesToShow = Integer.MAX_VALUE; // no restriction by default + /** + * Sort order in which states are sorted in the variable viewer + */ + private Order stateSortDirection; + public TLCError() { + this(Order.OneToN); + } + + public TLCError(final Order order) { + this.stateSortDirection = order; + } + /** * Add a state to a trace * @param state state to add */ - public void addState(TLCState state, boolean stateSortDirection) + public void addState(TLCState state) { - if (stateSortDirection) { + if (stateSortDirection == Order.NToOne) { states.addFirst(state); } else { states.add(state); @@ -188,6 +220,249 @@ public class TLCError } public void reverseTrace() { + stateSortDirection = stateSortDirection == Order.OneToN ? Order.NToOne : Order.OneToN; Collections.reverse(states); } + + private void orderTrace(Order order) { + if (stateSortDirection != order) { + Collections.reverse(states); + stateSortDirection = order; + } + } + + public void applyFrom(final TLCError originalErrorWithTrace, final Map<String, Formula> traceExplorerExpressions, + final Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable, + final String modelName) { + + // retrieve the original trace + // this is necessary for items (3) and (5) from the list in the + // documentation for this method + List<TLCState> originalTrace = originalErrorWithTrace.getStates(Length.ALL); + Assert.isNotNull(originalTrace, "Could not get original trace after running trace explorer. This is a bug."); + + // a comparator used for sorting the variables within each + // state so that the variables representing the trace explorer + // expressions appear first in each state + final Comparator<TLCVariable> varComparator = new Comparator<TLCVariable>() { + + public int compare(TLCVariable var0, TLCVariable var1) { + if ((var0.isTraceExplorerVar() && var1.isTraceExplorerVar()) + || (!var0.isTraceExplorerVar() && !var1.isTraceExplorerVar())) { + // both represent TE expressions or neither does + // use string comparison to make sure + // that the variables appear in the same order + // in every state + return var0.getName().compareTo(var1.getName()); + } else if (var0.isTraceExplorerVar()) { + // var0 should appear before + return -1; + } else { + // var1 represents TE expression, so it should appear before + return 1; + } + } + }; + + final Order requestedOrder = originalErrorWithTrace.stateSortDirection; + + // Aligning both traces to the canonical order (OneToN) as precondition to the + // code below which hasn't been written to support the NToOne order. The requested + // order is applied at the end. + this.orderTrace(Order.OneToN); + originalErrorWithTrace.orderTrace(Order.OneToN); + + // found an error with a trace + // this is the trace produced by the run + // of TLC for the trace explorer + List<TLCState> newTrace = this.getStates(); + + Iterator<TLCState> newTraceIt = newTrace.iterator(); + Iterator<TLCState> originalTraceIt = originalTrace.iterator(); + + TLCState currentStateNewTrace = newTraceIt.next(); + TLCState nextStateNewTrace = null; + + TLCState currentStateOriginalTrace = originalTraceIt.next(); + + /* + * The following while loop performs items 1-4 for some of the states. In + * particular, if the original trace has n states and the trace produced by the + * trace explorer has m states, this loop performs items 1-4 for states 1 + * through min(n-1, m-1). The trace produced by the trace explorer can be + * shorter than the original trace if there is a TLC error during evaluation of + * one of the states. The trace produced by the trace explorer can be longer + * than the original trace as in the example of item 5. + * + * The final state of the trace produced by the trace explorer is processed + * after this loop. Item 5 is also accomplished after this loop. + */ + while (newTraceIt.hasNext() && originalTraceIt.hasNext()) { + + // change the label of the state of newTrace to the label of the state + // of the original trace + currentStateNewTrace.setLabel(currentStateOriginalTrace.getLabel()); + + // set the location of the current state of the new trace + currentStateNewTrace.setLocation(currentStateOriginalTrace.getModuleLocation()); + + // need to get the next state in order to perform any + // shifting of expression values (item 2 in the documentation) + nextStateNewTrace = (TLCState) newTraceIt.next(); + + TLCVariable[] currentStateNewTraceVariables = currentStateNewTrace.getVariables(); + TLCVariable[] nextStateNewTraceVariables = nextStateNewTrace.getVariables(); + + applyFrom(traceExplorerExpressions, traceExpressionDataTable, nextStateNewTrace, + currentStateNewTraceVariables, nextStateNewTraceVariables); + + // sort the variables so that the variables representing trace explorer + // expressions appear first + Arrays.sort(currentStateNewTraceVariables, varComparator); + + currentStateNewTrace = nextStateNewTrace; + + currentStateOriginalTrace = originalTraceIt.next(); + } + + /* + * Remove any extra states (item 5). + * + * This is only necessary for looping or stuttering traces (n elements in + * original trace, m elements in new trace)- if (m >= n) remove states n..m else + * do nothing + * + * if (m >= n), the new trace will be left with n-1 elements. Later code adds + * the final stuttering or "back to state" state to these traces. + * + * There should never be extra states for non-looping, non-stuttering traces. + */ + if ((currentStateOriginalTrace.isBackToState() || currentStateOriginalTrace.isStuttering()) + && newTrace.size() >= originalTrace.size()) { + newTrace.subList(originalTrace.size() - 1, newTrace.size()).clear(); + } + + this.restrictTraceTo(originalErrorWithTrace.getTraceRestriction()); + + // new trace should now be no longer than the original trace + Assert.isTrue(newTrace.size() <= originalTrace.size(), + "States from trace explorer trace not removed properly."); + + // fix the final state + final TLCState finalStateOriginalTrace = (TLCState) originalTrace.get(originalTrace.size() - 1); + + if (newTrace.size() < originalTrace.size() - 1 + || (!finalStateOriginalTrace.isStuttering() && !finalStateOriginalTrace.isBackToState())) { + /* + * For a non-looping and non-stuttering state, just set the expressions with + * primed variables equal to "--" for the last state. + * + * Do the same thing if the new trace is less than the original trace size minus + * 1. This means there was a TLC error before evaluating all of the states, so + * even if the original trace finished with a looping state or a stuttering + * state, the trace that is displayed to the user should not. It should + * terminate before the TLC error occurred. + */ + + TLCState finalStateNewTrace = (TLCState) newTrace.get(newTrace.size() - 1); + + // state in the original trace at the same position as finalStateNewTrace + TLCState samePositionOriginalTrace = (TLCState) originalTrace.get(newTrace.size() - 1); + + // set the label of the final state of the new trace + finalStateNewTrace.setLabel(samePositionOriginalTrace.getLabel()); + + // set the location of the final state of the new trace + finalStateNewTrace.setLocation(samePositionOriginalTrace.getModuleLocation()); + + TLCVariable[] finalStateNewTraceVariables = finalStateNewTrace.getVariables(); + + // iterate through the variables + for (int i = 0; i < finalStateNewTraceVariables.length; i++) { + + TraceExpressionInformationHolder traceExpressionData = traceExpressionDataTable + .get(finalStateNewTraceVariables[i].getName().trim()); + + if (traceExpressionData != null) { + // we have located a trace expression variable + + if (traceExpressionData.getLevel() == 2) { + // expression with primed variables + // shift the value from the next state to the current state + finalStateNewTraceVariables[i].setValue(TLCVariableValue.parseValue("\"--\"")); + } + + // set the name to be the expression the variable represents + finalStateNewTraceVariables[i].setName(traceExpressionData.getExpression()); + // flag this as a variable representing a trace explorer expression + finalStateNewTraceVariables[i].setTraceExplorerVar(true); + } + } + + // sort the variables of the final state + Arrays.sort(finalStateNewTraceVariables, varComparator); + } else if (finalStateOriginalTrace.isBackToState()) { + this.addState(TLCState.BACK_TO_STATE(finalStateOriginalTrace.getStateNumber(), modelName)); + } else { + // stuttering trace + this.addState(TLCState.STUTTERING_STATE(finalStateOriginalTrace.getStateNumber(), modelName)); + } + + this.orderTrace(requestedOrder); + } + + private void applyFrom(final Map<String, Formula> traceExplorerExpressions, + final Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable, + TLCState nextStateNewTrace, TLCVariable[] currentStateNewTraceVariables, + TLCVariable[] nextStateNewTraceVariables) { + // iterate through the variables + for (int i = 0; i < currentStateNewTraceVariables.length; i++) { + // This code assumes that the variables are in the same order in each state + String variableName = currentStateNewTraceVariables[i].getName(); + // if next state is back to state or stuttering, it has no variables, so the + // code + // contained within the if block would cause an NPE + if (!nextStateNewTrace.isBackToState() && !nextStateNewTrace.isStuttering()) { + Assert.isTrue(variableName.equals(nextStateNewTraceVariables[i].getName()), + "Variables are not in the same order in each state. This is unexpected."); + } + + // retrieve the object containing the data corresponding to the variable. + // this object will be null if the variable currently being looked at does + // not represent a trace explorer expression + // If the variable does represent a trace explorer expression, then the + // following + // object will contain the variable name, the expression, and the level of the + // expression + TraceExpressionInformationHolder traceExpressionData = traceExpressionDataTable.get(variableName.trim()); + + if (traceExpressionData != null) { + // we have located a trace expression variable + + // If next state is back to state or stuttering, it has no variables, so the + // code contained within this if block would not apply. It should be unnecessary + // to check for this because the while loop should terminate before this + // happens. + if (!nextStateNewTrace.isBackToState() && !nextStateNewTrace.isStuttering() + && traceExpressionData.getLevel() == 2) { + // found expression with primed variables + // shift the value from the next state to the current state + currentStateNewTraceVariables[i].setValue(nextStateNewTraceVariables[i].getValue()); + + } + + // set the name to be the expression the variable represents + currentStateNewTraceVariables[i].setName(traceExpressionData.getExpression()); + + // flag this as a variable representing a trace explorer expression + currentStateNewTraceVariables[i].setTraceExplorerVar(true); + + continue; + } + + if (traceExplorerExpressions.containsKey(variableName.trim())) { + currentStateNewTraceVariables[i].setTraceExplorerVar(true); + } + } + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java index 589622770ddc22ec377d0309379ec0e49fba99b7..b19d085111d55d2127efb59d3095b05cc9806dd0 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java @@ -26,10 +26,15 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Vector; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -57,6 +62,7 @@ import org.lamport.tla.toolbox.tool.tlc.model.Formula; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; import org.lamport.tla.toolbox.tool.tlc.output.ITLCOutputListener; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegion; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegionContainer; @@ -77,7 +83,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener { public static final String STATESORTORDER = "STATESORTORDER"; - public static final String NO_OUTPUT_AVAILABLE = "No user output is available"; + public static final String NO_OUTPUT_AVAILABLE = "No output is available"; public static final String NO_ERRORS = "No errors"; // strings for current status reporting @@ -91,6 +97,11 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener public static final String SERVER_RUNNING = "Master waiting for workers"; public static final String SINGLE_WORKER_REGISTERED = " worker registered"; public static final String MULTIPLE_WORKERS_REGISTERED = " workers registered"; + // strings for the types of searches + public static final String BREADTH_FIRST_SEARCH = "Breadth-first search"; + public static final String DEPTH_FIRST_SEARCH = "Depth-first search"; + // string for simulation mode + public static final String SIMULATION_MODE = "Simulation"; // pattern for the output of evaluating constant expressions public static final Pattern CONSTANT_EXPRESSION_OUTPUT_PATTERN = Pattern.compile("(?s)" + ModelWriter.BEGIN_TUPLE @@ -98,8 +109,10 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener + "(.*)"/*calc output group*/ + ModelWriter.END_TUPLE); - // presenter for the current process - protected ITLCModelLaunchDataPresenter presenter; + + + // presenters for the current process + private final CopyOnWriteArrayList<ITLCModelLaunchDataPresenter> m_dataPresenters; // list of errors protected List<TLCError> errors; // start time @@ -117,7 +130,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // reports the probability of a fingerprint collision protected String fingerprintCollisionProbability; // coverage items - protected List<CoverageInformationItem> coverageInfo; + protected CoverageInformation coverageInfo; // One of the coverage infos indicate zero coverage. protected boolean zeroCoverage = false; // progress information @@ -133,24 +146,27 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener protected Document userOutput; // calc output protected String constantExprEvalOutput; - /** - * Sort order in which states are sorted in the variable viewer - */ - protected boolean stateSortDirection; - // the model, which is represented by the current launch data provider private final Model model; // flag indicating that TLC has started // currently this is used to indicate - // that tlc output not surrounded by message tags - // should be put in the user output widget + // that tlc output not surrounded by message tags + // should be put in the user output widget. This does not indicate the state of + // the TLC process. Instead it only indicates that the TLC process is past + // the spec parsing stage with SANY. protected boolean isTLCStarted = false; protected int numWorkers = 0; - public TLCModelLaunchDataProvider(Model model) - { - this.model = model; + private int fpIndex; + + private boolean isSymmetryWithLiveness = false; + + public TLCModelLaunchDataProvider(final Model tlcModel) { + Assert.isNotNull(tlcModel); + model = tlcModel; + + m_dataPresenters = new CopyOnWriteArrayList<>(); // init provider, but not connect it to the source! initialize(); @@ -172,7 +188,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener lastDetectedError = null; model.removeMarkers(ModelHelper.TLC_MODEL_ERROR_MARKER_TLC); - coverageInfo = new Vector<CoverageInformationItem>(); + coverageInfo = new CoverageInformation(); progressInformation = new Vector<StateSpaceInformationItem>(); startTimestamp = Long.MIN_VALUE; finishTimestamp = Long.MIN_VALUE; @@ -184,33 +200,27 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener progressOutput = new Document(NO_OUTPUT_AVAILABLE); userOutput = new Document(NO_OUTPUT_AVAILABLE); constantExprEvalOutput = ""; - - final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); - stateSortDirection = dialogSettings.getBoolean(STATESORTORDER); + isSymmetryWithLiveness = false; } /** * Inform the view, if any * @param fieldId */ - protected void informPresenter(int fieldId) - { - if (presenter != null) - { + protected void informPresenter(final int fieldId) { + m_dataPresenters.stream().forEach((presenter) -> { presenter.modelChanged(this, fieldId); - } + }); } /** * Populate data to the presenter */ - public void populate() - { - for (int i = 0; i < ITLCModelLaunchDataPresenter.ALL_FIELDS.length; i++) - { - informPresenter(ITLCModelLaunchDataPresenter.ALL_FIELDS[i]); - } - } + public void populate() { + for (int i = 0; i < ITLCModelLaunchDataPresenter.ALL_FIELDS.length; i++) { + informPresenter(ITLCModelLaunchDataPresenter.ALL_FIELDS[i]); + } + } /** * Name of the model @@ -276,7 +286,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener case MP.STATE: Assert.isNotNull(this.lastDetectedError, "The state encountered without the error describing the reason for it. This is a bug."); - this.lastDetectedError.addState(TLCState.parseState(outputMessage, getModelName()), stateSortDirection); + this.lastDetectedError.addState(TLCState.parseState(outputMessage, getModelName())); break; case MP.ERROR: case MP.TLCBUG: @@ -290,8 +300,12 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // send to progress output case EC.TLC_FEATURE_UNSUPPORTED: + setDocumentText(this.progressOutput, outputMessage, true); + break; case EC.TLC_FEATURE_UNSUPPORTED_LIVENESS_SYMMETRY: + this.isSymmetryWithLiveness = true; setDocumentText(this.progressOutput, outputMessage, true); + informPresenter(ITLCModelLaunchDataPresenter.WARNINGS); break; // usual errors @@ -333,6 +347,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // case EC.TLC_SUCCESS: case EC.TLC_PROGRESS_START_STATS_DFID: case EC.TLC_INITIAL_STATE: + case EC.TLC_COMPUTING_INIT_PROGRESS: case EC.TLC_STATS: case EC.TLC_STATS_DFID: case EC.TLC_STATS_SIMU: @@ -343,17 +358,19 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener setDocumentText(this.progressOutput, outputMessage, true); break; case EC.TLC_MODE_MC: - this.tlcMode = "Breadth-first search"; + this.tlcMode = BREADTH_FIRST_SEARCH; + this.fpIndex = getFPIndex(outputMessage); informPresenter(ITLCModelLaunchDataPresenter.TLC_MODE); setDocumentText(this.progressOutput, outputMessage, true); break; case EC.TLC_MODE_MC_DFS: - this.tlcMode = "Depth-first search"; + this.tlcMode = DEPTH_FIRST_SEARCH; + this.fpIndex = getFPIndex(outputMessage); informPresenter(ITLCModelLaunchDataPresenter.TLC_MODE); setDocumentText(this.progressOutput, outputMessage, true); break; case EC.TLC_MODE_SIMU: - this.tlcMode = "Simulation"; + this.tlcMode = SIMULATION_MODE; informPresenter(ITLCModelLaunchDataPresenter.TLC_MODE); setDocumentText(this.progressOutput, outputMessage, true); break; @@ -436,24 +453,45 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // Coverage information case EC.TLC_COVERAGE_START: this.coverageTimestamp = CoverageInformationItem.parseCoverageTimestamp(outputMessage); - this.coverageInfo = new Vector<CoverageInformationItem>(); + this.coverageInfo = new CoverageInformation(model.getSavedTLAFiles()); informPresenter(ITLCModelLaunchDataPresenter.COVERAGE_TIME); informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); break; + case EC.TLC_COVERAGE_PROPERTY: + this.coverageInfo.add(ActionInformationItem.parseProp(outputMessage, getModelName())); + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); + break; + case EC.TLC_COVERAGE_INIT: + this.coverageInfo.add(ActionInformationItem.parseInit(outputMessage, getModelName())); + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); + break; + case EC.TLC_COVERAGE_NEXT: + this.coverageInfo.add(ActionInformationItem.parseNext(outputMessage, getModelName())); + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); + break; + case EC.TLC_COVERAGE_VALUE_COST: + CoverageInformationItem item = CoverageInformationItem.parseCost(outputMessage, getModelName()); + this.coverageInfo.add(item); + if (item.getCount() == 0) { + this.zeroCoverage = true; + } + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); + break; case EC.TLC_COVERAGE_VALUE: - // Commented out by LL for testing on 25 sep 2010 - CoverageInformationItem item = CoverageInformationItem.parse(outputMessage, getModelName()); - if (!item.getModule().equals(ModelHelper.MC_MODEL_NAME)) - { - // only add coverage of the spec files - this.coverageInfo.add(item); - if (item.getCount() == 0) { - this.zeroCoverage = true; - } - informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); + item = CoverageInformationItem.parse(outputMessage, getModelName()); + this.coverageInfo.add(item); + if (item.getCount() == 0) { + this.zeroCoverage = true; } + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE); break; + case EC.TLC_COVERAGE_END_OVERHEAD: + if (getModel().isRunning()) { + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE_END_OVERHEAD); + break; + } case EC.TLC_COVERAGE_END: + informPresenter(ITLCModelLaunchDataPresenter.COVERAGE_END); break; case EC.TLC_DISTRIBUTED_SERVER_RUNNING: numWorkers = 0; @@ -548,6 +586,14 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener } } + static int getFPIndex(final String startupMessage) { + final Matcher matcher = startupMessagePattern.matcher(startupMessage); + if (matcher.find()) { + return Integer.parseInt(matcher.group(2)); + } + return 0; // legacy support + } + /** * @param latest * @return true iff the presenter should be updated @@ -592,7 +638,9 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener protected TLCError createError(TLCRegion tlcRegion, String message) { // the root of the error trace - TLCError topError = new TLCError(); + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + final boolean stateSortOrder = dialogSettings.getBoolean(STATESORTORDER); + final TLCError topError = new TLCError(Order.valueOf(stateSortOrder)); if (tlcRegion instanceof TLCRegionContainer) { @@ -625,7 +673,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener * a memory leak. */ IFile mcFile = getModel().getTLAFile(); - FileEditorInput mcFileEditorInput = new FileEditorInput((IFile) mcFile); + FileEditorInput mcFileEditorInput = new FileEditorInput(mcFile); FileDocumentProvider mcFileDocumentProvider = new FileDocumentProvider(); try @@ -672,7 +720,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // create the error properties for this id // this method find the corresponding attribute and // create the map with attributes, required to create a marker - props[j] = ModelHelper.createMarkerDescription(mcDocument, mcSearcher, + props[j] = ModelHelper.createMarkerDescription(mcFile, mcDocument, mcSearcher, errorMessage, IMarker.SEVERITY_ERROR, coordinates); // read the attribute name @@ -747,8 +795,16 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener for (int j = 0; j < locations.length; j++) { // restore the location from the region - String locationString = errorDocument.get(locations[j].getOffset(), locations[j] - .getLength()); + String locationString = ""; + try { + locationString = errorDocument.get(locations[j].getOffset(), locations[j] + .getLength()); + } catch (BadLocationException ble) { + // Do not break from the loop when the spaghetti code above crashes for a + // whatever reason (life is too short). The region (locations!?) might point to + // another file which cannot be mapped to errorDocument which will throw the BLE. + continue; + } Location location = Location.parseLocation(locationString); // look only for location in the MC file if (location.source().equals( @@ -835,6 +891,10 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener private static final String CR = "\n"; private static final String EMPTY = ""; + private static final Pattern startupMessagePattern = Pattern + .compile("^Running (depth|breadth)-first search Model-Checking with fp ([0-9]+) and seed " + + "[-0-9]+ with [0-9]+ worker[s]? on [0-9]+ cores with .*? heap and .*? offheap memory (\\[pid: [0-9]+\\])? \\(.*\\).$"); + /** * Sets text to a document * @param document @@ -892,13 +952,21 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener } /** - * Set the presenter. - * @param presenter a presenter to update on data changes + * Add a presenter. + * @param presenter */ - public void setPresenter(ITLCModelLaunchDataPresenter presenter) - { - this.presenter = presenter; - populate(); + public void addDataPresenter(final ITLCModelLaunchDataPresenter presenter) { + m_dataPresenters.add(presenter); + populate(); + } + + /** + * Remove a presenter added via {@link #addDataPresenter(ITLCModelLaunchDataPresenter)} + * @param presenter + */ + public void removeDataPresenter(final ITLCModelLaunchDataPresenter presenter) { + m_dataPresenters.remove(presenter); + populate(); } public List<TLCError> getErrors() @@ -935,16 +1003,11 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener this.coverageTimestamp = coverageTimestamp; } - public List<CoverageInformationItem> getCoverageInfo() + public CoverageInformation getCoverageInfo() { return coverageInfo; } - public void setCoverageInfo(List<CoverageInformationItem> coverageInfo) - { - this.coverageInfo = coverageInfo; - } - public boolean hasZeroCoverage() { return this.zeroCoverage; } @@ -964,21 +1027,11 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener return userOutput; } - public void setUserOutput(Document userOutput) - { - this.userOutput = userOutput; - } - public Document getProgressOutput() { return progressOutput; } - public void setProgressOutput(Document progressOutput) - { - this.progressOutput = progressOutput; - } - public long getLastCheckpointTimeStamp() { return lastCheckpointTimeStamp; @@ -996,7 +1049,6 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener } public boolean isDone() { - assert currentStatus.equals("Not running"); return isDone; } @@ -1020,6 +1072,14 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener { return constantExprEvalOutput; } + + private static final Pattern collisionProbabilityPattern = Pattern.compile( + "^Model checking completed\\. No error has been found\\.\\n Estimates of the probability " + + "that TLC did not check all reachable states\\n because two distinct states had the " + + "same fingerprint:\\n calculated \\(optimistic\\): val = " + + "([0-9]*\\.?[0-9]+[eE][-+]?[0-9]+?)" // group 1 + + "(\\n based on the actual fingerprints: val = " + + "([0-9]*\\.?[0-9]+[eE][-+]?[0-9]+?))?$"); // group 3 iff present (group 2 is last two lines) /** * Extracts the fingerprint collision probability information line @@ -1032,29 +1092,17 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener */ private String extractCollisionProbability(String outputMessage) { - String result = ""; - int valIndex; - int endValIndex; - int startIndex = 0; - String[] labels = { "calculated: ", ", observed: " }; - for (int i = 0; i < 2; i++) - { - result = result + labels[i]; - valIndex = outputMessage.indexOf(" val = ", startIndex); - if (valIndex > 0) - { - startIndex = valIndex + 7; - endValIndex = startIndex; - while (endValIndex < outputMessage.length() - && (! Character.isWhitespace(outputMessage.charAt(endValIndex)))) - { - endValIndex++; - } - result = result + outputMessage.substring(startIndex, endValIndex); - startIndex = endValIndex; - } - } - return result; + final Matcher matcher = collisionProbabilityPattern.matcher(outputMessage); + if (matcher.find()) { + final String optimistic = matcher.group(1); + final String actual = matcher.group(3); + if (actual != null) { + return String.format("calculated: %s observed: %s", optimistic, actual); + } else { + return String.format("calculated: %s", optimistic); + } + } + return ""; // legacy support } /** @@ -1069,4 +1117,34 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener public String toString() { return getModel().getSpec().getName() + "___" + getModelName(); } + + public int getFPIndex() { + return this.fpIndex; + } + + public boolean isSymmetryWithLiveness() { + return isSymmetryWithLiveness; + } + + + private final static SimpleDateFormat SDF = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + + public static Date parseDate(final String str) { + try { + return SDF.parse(str); + } catch (ParseException e) { + return new Date(); + } + } + + public static String formatInterval(final long firstTS, final long secondTS) { + final long interval = secondTS - firstTS; + final long hr = TimeUnit.MILLISECONDS.toHours(interval); + final long min = TimeUnit.MILLISECONDS.toMinutes(interval - TimeUnit.HOURS.toMillis(hr)); + final long sec = TimeUnit.MILLISECONDS + .toSeconds(interval - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)); + + return String.format("%02d:%02d:%02d", hr, min, sec); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java index d3272b3a0792f74de0b57cb8cfb761087aba3631..cab3e51bac1329451d795b244bdc7046d681c09e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java @@ -29,7 +29,10 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import org.lamport.tla.toolbox.tool.tlc.ui.util.IModuleLocatable; @@ -346,6 +349,21 @@ public class TLCState implements IModuleLocatable firstValue.diff(secondValue); } } + + public Map<String, TLCVariable> getDiff(final TLCState other) { + final Map<String, TLCVariable> map = new HashMap<>(); + + NEXT: for (TLCVariable v1 : variables) { + for (TLCVariable v2 : other.variables) { + if (v1.getName().equals(v2.getName()) && v1.getValue().toString().equals(v2.getValue().toString())) { + continue NEXT; + } + } + map.put(v1.getName(), v1); + } + + return map; + } public int getVariableCount(int level) { if (level > 1) { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java index 0cc5b4b080d500e68604a6abd1b705d6c6a161cd..f17b3ada84a9a579f47dc2245f573fa6c8064dfe 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java @@ -1,16 +1,16 @@ package org.lamport.tla.toolbox.tool.tlc.output.data; -import java.util.Arrays; -import java.util.Comparator; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.FindReplaceDocumentAdapter; import org.eclipse.jface.text.IDocument; @@ -18,10 +18,12 @@ import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.ui.editors.text.FileDocumentProvider; import org.eclipse.ui.part.FileEditorInput; +import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; +import org.lamport.tla.toolbox.tool.tlc.model.Formula; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Length; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegion; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegionContainer; @@ -177,7 +179,7 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider /** * Performs processing for the error and the error trace produced after a run of the trace explorer. * - * This method does the following to a trace: + * This method (and nested ones) does the following to a trace: * * 1.) Changes the names of the variables corresponding to trace * explorer expressions to the actual expressions. @@ -313,12 +315,8 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider */ TLCError successfulTEError = null; - // retrieve the original trace - // this is necessary for items (3) and (5) from the list in the - // documentation for this method - List<TLCState> originalTrace = originalErrorWithTrace.getStates(Length.ALL); - Assert.isNotNull(originalTrace, "Could not get original trace after running trace explorer. This is a bug."); - + final Map<String, Formula> traceExplorerExpressions = getModel().getNamedTraceExplorerExpressionsAsFormula(); + // iterate through the errors to find one with a trace Iterator<TLCError> it = getErrors().iterator(); while (it.hasNext()) @@ -327,245 +325,28 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider if (error.hasTrace()) { - // Set the message, cause, and code of the error to the message of the original - // error for which the trace explorer was run if the new error - // message is for an invariant or property violation or deadlock. An invariant - // or property violation or deadlock indicates that the trace explorer ran - // successfully. This is item (6). - int errorCode = error.getErrorCode(); - if (errorCode == EC.TLC_DEADLOCK_REACHED || errorCode == EC.TLC_TEMPORAL_PROPERTY_VIOLATED - || errorCode == EC.TLC_INVARIANT_VIOLATED_BEHAVIOR - || errorCode == EC.TLC_INVARIANT_VIOLATED_INITIAL) - { - error.setErrorCode(originalErrorWithTrace.getErrorCode()); - error.setMessage(originalErrorWithTrace.getMessage()); - error.setCause(originalErrorWithTrace.getCause()); - - successfulTEError = error; - } else - { - error.setMessage(TE_ERROR_HEADER + error.getMessage()); - } - - // a comparator used for sorting the variables within each - // state so that the variables representing the trace explorer - // expressions appear first in each state - final Comparator<TLCVariable> varComparator = new Comparator<TLCVariable>() { - - public int compare(TLCVariable var0, TLCVariable var1) - { - if ((var0.isTraceExplorerVar() && var1.isTraceExplorerVar()) - || (!var0.isTraceExplorerVar() && !var1.isTraceExplorerVar())) - { - // both represent TE expressions or neither does - // use string comparison to make sure - // that the variables appear in the same order - // in every state - return var0.getName().compareTo(var1.getName()); - } else if (var0.isTraceExplorerVar()) - { - // var0 should appear before - return -1; - } else - { - // var1 represents TE expression, so it should appear before - return 1; - } - } - }; - - // found an error with a trace - - // this is the trace produced by the run - // of TLC for the trace explorer - List<TLCState> newTrace = error.getStates(); - - Iterator<TLCState> newTraceIt = newTrace.iterator(); - Iterator<TLCState> originalTraceIt = originalTrace.iterator(); - - TLCState currentStateNewTrace = newTraceIt.next(); - TLCState nextStateNewTrace = null; - - TLCState currentStateOriginalTrace = originalTraceIt.next(); - - /* - * The following while loop performs items 1-4 for some of the states. - * In particular, if the original trace has n states and the trace produced - * by the trace explorer has m states, this loop performs - * items 1-4 for states 1 through min(n-1, m-1). The trace produced by the - * trace explorer can be shorter than the original trace if there is a TLC error - * during evaluation of one of the states. The trace produced by the trace explorer - * can be longer than the original trace as in the example of item 5. - * - * The final state of the trace produced by the trace explorer is processed - * after this loop. Item 5 is also accomplished after this loop. - */ - while (newTraceIt.hasNext() && originalTraceIt.hasNext()) - { - - // change the label of the state of newTrace to the label of the state - // of the original trace - currentStateNewTrace.setLabel(currentStateOriginalTrace.getLabel()); - - // set the location of the current state of the new trace - currentStateNewTrace.setLocation(currentStateOriginalTrace.getModuleLocation()); - - // need to get the next state in order to perform any - // shifting of expression values (item 2 in the documentation) - nextStateNewTrace = (TLCState) newTraceIt.next(); - - TLCVariable[] currentStateNewTraceVariables = currentStateNewTrace.getVariables(); - TLCVariable[] nextStateNewTraceVariables = nextStateNewTrace.getVariables(); - - // iterate through the variables - for (int i = 0; i < currentStateNewTraceVariables.length; i++) - { - // This code assumes that the variables are in the same order in each state - String variableName = currentStateNewTraceVariables[i].getName(); - // if next state is back to state or stuttering, it has no variables, so the code - // contained within the if block would cause an NPE - if (!nextStateNewTrace.isBackToState() && !nextStateNewTrace.isStuttering()) - { - Assert.isTrue(variableName.equals(nextStateNewTraceVariables[i].getName()), - "Variables are not in the same order in each state. This is unexpected."); - } - - // retrieve the object containing the data corresponding to the variable. - // this object will be null if the variable currently being looked at does - // not represent a trace explorer expression - // If the variable does represent a trace explorer expression, then the following - // object will contain the variable name, the expression, and the level of the expression - TraceExpressionInformationHolder traceExpressionData = traceExpressionDataTable - .get(variableName.trim()); - - if (traceExpressionData != null) - { - // we have located a trace expression variable - - // If next state is back to state or stuttering, it has no variables, so the - // code contained within this if block would not apply. It should be unnecessary - // to check for this because the while loop should terminate before this happens. - if (!nextStateNewTrace.isBackToState() && !nextStateNewTrace.isStuttering() - && traceExpressionData.getLevel() == 2) - { - // found expression with primed variables - // shift the value from the next state to the current state - currentStateNewTraceVariables[i].setValue(nextStateNewTraceVariables[i].getValue()); - - } - - // set the name to be the expression the variable represents - currentStateNewTraceVariables[i].setName(traceExpressionData.getExpression()); - - // flag this as a variable representing a trace explorer expression - currentStateNewTraceVariables[i].setTraceExplorerVar(true); - - } - } - - // sort the variables so that the variables representing trace explorer - // expressions appear first - Arrays.sort(currentStateNewTraceVariables, varComparator); - - currentStateNewTrace = nextStateNewTrace; - - currentStateOriginalTrace = originalTraceIt.next(); - } - - /* - * Remove any extra states (item 5). - * - * This is only necessary for looping or stuttering traces - * (n elements in original trace, m elements in new trace)- - * if (m >= n) remove states n..m - * else do nothing - * - * if (m >= n), the new trace will be left with n-1 elements. - * Later code adds the final stuttering or "back to state" state - * to these traces. - * - * There should never be extra states for non-looping, non-stuttering - * traces. - */ - if ((currentStateOriginalTrace.isBackToState() || currentStateOriginalTrace.isStuttering()) - && newTrace.size() >= originalTrace.size()) - { - newTrace.subList(originalTrace.size() - 1, newTrace.size()).clear(); - } - - error.restrictTraceTo(originalErrorWithTrace.getTraceRestriction()); - - // new trace should now be no longer than the original trace - Assert.isTrue(newTrace.size() <= originalTrace.size(), - "States from trace explorer trace not removed properly."); - - // fix the final state - TLCState finalStateOriginalTrace = (TLCState) originalTrace.get(originalTrace.size() - 1); - - if (newTrace.size() < originalTrace.size() - 1 - || (!finalStateOriginalTrace.isStuttering() && !finalStateOriginalTrace.isBackToState())) - { - /* - * For a non-looping and non-stuttering state, just set the expressions - * with primed variables equal to "--" for the last state. - * - * Do the same thing if the new trace is less than the original trace size minus 1. - * This means there was a TLC error before evaluating all of the states, so - * even if the original trace finished with a looping state or a stuttering state, the - * trace that is displayed to the user should not. It should terminate before the TLC error - * occurred. - */ - - TLCState finalStateNewTrace = (TLCState) newTrace.get(newTrace.size() - 1); - - // state in the original trace at the same position as finalStateNewTrace - TLCState samePositionOriginalTrace = (TLCState) originalTrace.get(newTrace.size() - 1); - - // set the label of the final state of the new trace - finalStateNewTrace.setLabel(samePositionOriginalTrace.getLabel()); - - // set the location of the final state of the new trace - finalStateNewTrace.setLocation(samePositionOriginalTrace.getModuleLocation()); - - TLCVariable[] finalStateNewTraceVariables = finalStateNewTrace.getVariables(); - - // iterate through the variables - for (int i = 0; i < finalStateNewTraceVariables.length; i++) - { - - TraceExpressionInformationHolder traceExpressionData = traceExpressionDataTable - .get(finalStateNewTraceVariables[i].getName().trim()); - - if (traceExpressionData != null) - { - // we have located a trace expression variable - - if (traceExpressionData.getLevel() == 2) - { - // expression with primed variables - // shift the value from the next state to the current state - finalStateNewTraceVariables[i].setValue(TLCVariableValue.parseValue("\"--\"")); - } - - // set the name to be the expression the variable represents - finalStateNewTraceVariables[i].setName(traceExpressionData.getExpression()); - // flag this as a variable representing a trace explorer expression - finalStateNewTraceVariables[i].setTraceExplorerVar(true); - } - } - - // sort the variables of the final state - Arrays.sort(finalStateNewTraceVariables, varComparator); - } else if (finalStateOriginalTrace.isBackToState()) - { - error.addState(TLCState.BACK_TO_STATE(finalStateOriginalTrace.getStateNumber(), - getModel().getName()), stateSortDirection); - } else - { - // stuttering trace - error.addState(TLCState.STUTTERING_STATE(finalStateOriginalTrace.getStateNumber(), - getModel().getName()), stateSortDirection); - } + // Set the message, cause, and code of the error to the message of the original + // error for which the trace explorer was run if the new error + // message is for an invariant or property violation or deadlock. An invariant + // or property violation or deadlock indicates that the trace explorer ran + // successfully. This is item (6). + int errorCode = error.getErrorCode(); + if (errorCode == EC.TLC_DEADLOCK_REACHED || errorCode == EC.TLC_TEMPORAL_PROPERTY_VIOLATED + || errorCode == EC.TLC_INVARIANT_VIOLATED_BEHAVIOR + || errorCode == EC.TLC_INVARIANT_VIOLATED_INITIAL) + { + error.setErrorCode(originalErrorWithTrace.getErrorCode()); + error.setMessage(originalErrorWithTrace.getMessage()); + error.setCause(originalErrorWithTrace.getCause()); + + successfulTEError = error; + } else + { + error.setMessage(TE_ERROR_HEADER + error.getMessage()); + } + + error.applyFrom(originalErrorWithTrace, traceExplorerExpressions, traceExpressionDataTable, + getModel().getName()); } else { @@ -618,7 +399,9 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider protected TLCError createError(TLCRegion tlcRegion, String message) { // the root of the error trace - TLCError topError = new TLCError(); + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + final boolean stateSortOrder = dialogSettings.getBoolean(STATESORTORDER); + final TLCError topError = new TLCError(Order.valueOf(stateSortOrder)); if (tlcRegion instanceof TLCRegionContainer) { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java index f5ee62caf36c8a5f6ab32b5a3863e6a58be06f13..9c1db294fa474596ebfa59c289506a25e6dffd85 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java @@ -251,6 +251,11 @@ public class TLCOutputSourceRegistry } return provider; } + + public synchronized boolean hasProvider(Model model) + { + return providers.containsKey(model); + } /** * Clients should not invoke this constructor directly, but use {@link TLCOutputSourceRegistry#getModelCheckSourceRegistry()} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParser.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParser.java index 6a67bc6b79c6c8c6758505584c5dc63b4ff6c5df..088d519c4572c0aa51970884ecdb01c8a506c9e8 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParser.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParser.java @@ -391,7 +391,7 @@ public class TagBasedTLCOutputIncrementalParser return; } else if(text.charAt(text.length() - 1) != 10) { // 10 ascii for '\n' // e.g. when a model check gets interrupted - throw new BadLocationException("Input does not end with newline"); + throw new BadLocationException("Input does not end with newline: " + text); //text = text + (char) 10; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java index 5f70cb61fe3a87f5d0bf2305803108cf1e427d36..799bae18889a7ac011a9b434ab7f91812c6601f8 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java @@ -26,6 +26,9 @@ package org.lamport.tla.toolbox.tool.tlc.traceexplorer; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import java.util.Vector; import org.eclipse.core.resources.ResourcesPlugin; @@ -36,32 +39,46 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.ICheckStateListener; -import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceAdapter; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetAdapter; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; +import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate; import org.lamport.tla.toolbox.tool.tlc.model.Formula; +import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter; import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; import org.lamport.tla.toolbox.tool.tlc.ui.editor.provider.FormulaContentProvider; import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; @@ -96,7 +113,11 @@ import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; */ public class TraceExplorerComposite { + private static final String EXPANDED_STATE = "EXPANDED_STATE"; + + protected CheckboxTableViewer tableViewer; + private Button buttonAdd; private Button buttonEdit; private Button buttonRemove; @@ -105,13 +126,15 @@ public class TraceExplorerComposite private Section section; private TLCErrorView view; + private int m_tableIndexOfLastDragStart; + // a listener reacting on button clicks // this calls the appropriate method when a user // clicks a button next to the table protected SelectionListener fSelectionListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { - Object source = e.getSource(); + final Object source = e.getSource(); if (source == buttonAdd) { doAdd(); @@ -134,15 +157,12 @@ public class TraceExplorerComposite // a listener reacting on selection in the table viewer // this calls the method that changes button enablement // depending on whether a formula is selected or not - protected ISelectionChangedListener fSelectionChangedListener = new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) - { - Object source = event.getSource(); - if (source != null && source == tableViewer) - { - changeButtonEnablement(); - } - } + protected ISelectionChangedListener m_formulaEnablementListener = (event) -> { + final Object source = event.getSource(); + + if ((source != null) && (source == tableViewer)) { + changeButtonEnablement(); + } }; public TraceExplorerComposite(Composite parent, String title, String description, FormToolkit toolkit, @@ -163,9 +183,22 @@ public class TraceExplorerComposite GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false); section.setLayoutData(gd); sectionInitialize(toolkit); - // initially, we don't want the section to be expanded - // so that the user has more room to look at the trace - section.setExpanded(false); + // Initially, we want the section to be expanded for users to recognize the + // error-trace exploration feature. If a user collapses the section, it will + // remain collapsed. + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + if (dialogSettings.get(EXPANDED_STATE) != null) { + final boolean expand = dialogSettings.getBoolean(EXPANDED_STATE); + section.setExpanded(expand); + } else { + section.setExpanded(true); + } + section.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + dialogSettings.put(EXPANDED_STATE, section.isExpanded()); + } + }); } /** @@ -198,6 +231,8 @@ public class TraceExplorerComposite // cell, so the table must span 5 vertical cells gd.verticalSpan = 5; table.setLayoutData(gd); + + table.setToolTipText("Drag formulae to reorder."); // create the table viewer tableViewer = createTableViewer(table); @@ -215,32 +250,25 @@ public class TraceExplorerComposite * @param table * @return */ - protected CheckboxTableViewer createTableViewer(Table table) - { + protected CheckboxTableViewer createTableViewer(Table table) { // create - CheckboxTableViewer tableViewer = new CheckboxTableViewer(table); + final CheckboxTableViewer tableViewer = new CheckboxTableViewer(table); // represent formulas in the view tableViewer.setContentProvider(new FormulaContentProvider()); // on changed selection change button enablement - tableViewer.addSelectionChangedListener(fSelectionChangedListener); + tableViewer.addSelectionChangedListener(m_formulaEnablementListener); // edit on double-click on a formula - tableViewer.addDoubleClickListener(new IDoubleClickListener() { - public void doubleClick(DoubleClickEvent event) - { - doEdit(); - } - }); + tableViewer.addDoubleClickListener((event) -> { + doEdit(); + }); // save the input when an element is checked or unchecked - tableViewer.addCheckStateListener(new ICheckStateListener() { + tableViewer.addCheckStateListener((event) -> { + view.getModel().save(new NullProgressMonitor()); + }); - public void checkStateChanged(CheckStateChangedEvent event) - { - view.getModel().save(new NullProgressMonitor()); - } - }); - - tableViewer.setInput(new Vector()); + tableViewer.setInput(new Vector<Formula>()); + return tableViewer; } @@ -251,12 +279,159 @@ public class TraceExplorerComposite * @param sectionArea * @return */ - protected Table createTable(Composite sectionArea, FormToolkit toolkit) - { - Table table = toolkit.createTable(sectionArea, SWT.MULTI | SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL + protected Table createTable(Composite sectionArea, FormToolkit toolkit) { + final Table table = toolkit.createTable(sectionArea, SWT.MULTI | SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); + table.setLinesVisible(false); table.setHeaderVisible(false); + + table.addKeyListener(new KeyListener() { + @Override + public void keyPressed(final KeyEvent ke) { } + + @Override + public void keyReleased(final KeyEvent ke) { + if ((ke.keyCode == SWT.BS) || (ke.keyCode == SWT.DEL)) { + doRemove(); + } + } + }); + + final Transfer[] types = new Transfer[] { LocalSelectionTransfer.getTransfer() }; + final DragSource source = new DragSource(table, DND.DROP_MOVE); + source.setTransfer(types); + source.addDragListener(new DragSourceAdapter() { + @Override + public void dragStart(final DragSourceEvent event) { + final Table table = tableViewer.getTable(); + TableItem ti = (TableItem) table.getItem(new Point(event.x, event.y)); + + if (ti != null) { + m_tableIndexOfLastDragStart = table.indexOf(ti); + } else { + m_tableIndexOfLastDragStart = -1; + } + } + + @Override + public void dragSetData(final DragSourceEvent event) { + final IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); + + LocalSelectionTransfer.getTransfer().setSelection(selection); + } + }); + + // Create the drop target + final DropTarget target = new DropTarget(table, DND.DROP_MOVE); + target.setTransfer(types); + target.addDropListener(new DropTargetAdapter() { + public void dragOver(final DropTargetEvent event) { + event.feedback = DND.FEEDBACK_INSERT_BEFORE | DND.FEEDBACK_SCROLL; + super.dragOver(event); + } + + public void drop(final DropTargetEvent event) { + final Object data = event.data; + + if (data instanceof IStructuredSelection) { + final IStructuredSelection selection = (IStructuredSelection) data; + if ((selection.size() > 0) && (selection.getFirstElement() instanceof Formula)) { + final TableItem ti = (TableItem) event.item; + final DropTarget target = (DropTarget) event.widget; + final Table table = (Table) target.getControl(); + final int dropIndex = (ti == null) ? table.getItemCount() : table.indexOf(ti); + @SuppressWarnings("unchecked") + final Vector<Formula> model = (Vector<Formula>) tableViewer.getInput(); + final Iterator<?> it = selection.iterator(); + final int[] selectionIndices = new int[selection.size()]; + + int counter = 0; + while (it.hasNext()) { + final Formula f = (Formula) it.next(); + + selectionIndices[counter] = model.indexOf(f); + counter++; + } + Arrays.sort(selectionIndices); + + final int dragDelta; + if (m_tableIndexOfLastDragStart == -1) { + dragDelta = dropIndex - selectionIndices[0]; + } else { + dragDelta = dropIndex - m_tableIndexOfLastDragStart; + } + if (dragDelta == 0) { + return; + } + + final List<String> serializedOriginalModel = FormHelper.getSerializedInput(tableViewer); + final int itemCount = serializedOriginalModel.size(); + final String[] movingItems = new String[selectionIndices.length]; + for (int i = 0; i < selectionIndices.length; i++) { + movingItems[i] = serializedOriginalModel.get(selectionIndices[i]); + } + if (dragDelta > 0) { + counter = selectionIndices.length - 1; + for (int i = (itemCount - 1); i > -1; i--) { + if (selectionIndices[counter] == i) { + final String toMove = movingItems[counter]; + // i tried all manner of working solely with the selectionIndices but could get no + // obvious global solution more moving multiple contiguous and moving multiple + // disjoint items - so i ended up with this indexOf lookup + final int adjustedMoveIndex = serializedOriginalModel.indexOf(toMove); + int newIndex = i + dragDelta; + + if (newIndex > itemCount) { + newIndex = itemCount; + } + + serializedOriginalModel.add(newIndex, toMove); + serializedOriginalModel.remove(adjustedMoveIndex); + + counter--; + if (counter < 0) { + break; + } + } + } + } else { + counter = 0; + for (int i = 0; i < itemCount; i++) { + if (selectionIndices[counter] == i) { + final String toMove = movingItems[counter]; + // i tried all manner of working solely with the selectionIndices but could get no + // obvious global solution more moving multiple contiguous and moving multiple + // disjoint items - so i ended up with this indexOf lookup + final int adjustedMoveIndex = serializedOriginalModel.indexOf(toMove); + int newIndex = i + dragDelta; + + if (newIndex < 0) { + newIndex = 0; + } + + serializedOriginalModel.remove(adjustedMoveIndex); + serializedOriginalModel.add(newIndex, toMove); + + counter++; + if (counter == selectionIndices.length) { + break; + } + } + } + } + + tableViewer.setInput(new Vector<Formula>()); + FormHelper.setSerializedInput(tableViewer, serializedOriginalModel); + + changeButtonEnablement(); + + saveModel(); + } + } + } + }); + return table; } @@ -272,48 +447,35 @@ public class TraceExplorerComposite */ protected void createButtons(Composite sectionArea, FormToolkit toolkit) { - GridData gd; + final GridData gd = new GridData(); + gd.verticalAlignment = SWT.TOP; + gd.horizontalAlignment = SWT.FILL; // add button buttonAdd = toolkit.createButton(sectionArea, "Add", SWT.PUSH); buttonAdd.addSelectionListener(fSelectionListener); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; - buttonAdd.setLayoutData(gd); + buttonAdd.setLayoutData(GridDataFactory.copyData(gd)); // edit button buttonEdit = toolkit.createButton(sectionArea, "Edit", SWT.PUSH); buttonEdit.addSelectionListener(fSelectionListener); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; - buttonEdit.setLayoutData(gd); + buttonEdit.setLayoutData(GridDataFactory.copyData(gd)); // remove button buttonRemove = toolkit.createButton(sectionArea, "Remove", SWT.PUSH); buttonRemove.addSelectionListener(fSelectionListener); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; - buttonRemove.setLayoutData(gd); + buttonRemove.setLayoutData(GridDataFactory.copyData(gd)); // explore button buttonExplore = toolkit.createButton(sectionArea, "Explore", SWT.PUSH); buttonExplore.addSelectionListener(fSelectionListener); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; - buttonExplore.setLayoutData(gd); + buttonExplore.setLayoutData(GridDataFactory.copyData(gd)); // restore button buttonRestore = toolkit.createButton(sectionArea, "Restore", SWT.PUSH); buttonRestore.addSelectionListener(fSelectionListener); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; - buttonRestore.setLayoutData(gd); - + buttonRestore.setLayoutData(GridDataFactory.copyData(gd)); + buttonRestore.setEnabled(false); } /** @@ -324,20 +486,28 @@ public class TraceExplorerComposite { return tableViewer; } + + /** + * @return the <code>Section</code> instance for this composite. + */ + public Section getSection() { + return section; + } /** * Remove the selected formulas */ protected void doRemove() { - IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); - Vector input = (Vector) tableViewer.getInput(); + final IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); + final Vector<?> input = (Vector<?>)tableViewer.getInput(); + input.removeAll(selection.toList()); tableViewer.setInput(input); changeButtonEnablement(); - view.getModel().setTraceExplorerExpression(FormHelper.getSerializedInput(tableViewer)); + saveModel(); } /** @@ -348,44 +518,58 @@ public class TraceExplorerComposite Formula formula = doEditFormula(null); // add a formula - if (formula != null) - { + if (formula != null) { @SuppressWarnings("unchecked") Vector<Formula> input = ((Vector<Formula>) tableViewer.getInput()); input.add(formula); tableViewer.setInput(input); - if (tableViewer instanceof CheckboxTableViewer) - { + if (tableViewer instanceof CheckboxTableViewer) { ((CheckboxTableViewer) tableViewer).setChecked(formula, true); } changeButtonEnablement(); - view.getModel().setTraceExplorerExpression(FormHelper.getSerializedInput(tableViewer)); + saveModel(); } } /** * Edit selected formula */ - protected void doEdit() - { - IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); - Formula formula = (Formula) selection.getFirstElement(); - Formula editedFormula = doEditFormula(formula); - if (editedFormula != null) - { - formula.setFormula(editedFormula.getFormula()); - if (tableViewer instanceof CheckboxTableViewer) - { - ((CheckboxTableViewer) tableViewer).setChecked(formula, true); + protected void doEdit() { + final IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); + final Formula formula; + + if (selection.size() == 1) { + formula = (Formula) selection.getFirstElement(); + } else { + formula = (Formula) tableViewer.getElementAt(0); + } + + final Formula editedFormula = doEditFormula(formula); + if (editedFormula != null) { + formula.setFormula(editedFormula.getFormula()); + if (tableViewer instanceof CheckboxTableViewer) { + ((CheckboxTableViewer) tableViewer).setChecked(formula, true); } tableViewer.refresh(); } - changeButtonEnablement(); - + saveModel(); + } + + private void saveModel() { view.getModel().setTraceExplorerExpression(FormHelper.getSerializedInput(tableViewer)); + + final Job job = new WorkspaceJob("Saving updated model...") { + public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { + view.getModel().save(monitor); + return Status.OK_STATUS; + } + }; + job.setRule(ResourcesPlugin.getWorkspace().getRoot()); + job.setUser(true); + job.schedule(); } /** @@ -443,6 +627,9 @@ public class TraceExplorerComposite return; } + // If we don't do this, the selection of formulas will not be carried to the execution + view.getModel().setTraceExplorerExpression(FormHelper.getSerializedInput(tableViewer)); + // Save model without validating. // Validating would erase MC.out, which we dont want // the trace explorer to do. @@ -452,8 +639,7 @@ public class TraceExplorerComposite // save the launch configuration // if the trace is empty, then do nothing - if (!view.getTrace().isTraceEmpty()) - { + if (!view.getTrace().isTraceEmpty()) { // TraceExplorerHelper.serializeTrace(modelConfig); // Wrap the launch in a WorkspaceJob to guarantee that the @@ -464,7 +650,7 @@ public class TraceExplorerComposite // run the SANY parser and SANY does not support concurrent execution. final Job job = new WorkspaceJob("Exploring the trace...") { - public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { view.getModel().save(monitor).launch(TraceExplorerDelegate.MODE_TRACE_EXPLORE, monitor, true); return Status.OK_STATUS; } @@ -472,6 +658,15 @@ public class TraceExplorerComposite job.setRule(ResourcesPlugin.getWorkspace().getRoot()); job.setUser(true); job.schedule(); + + tableViewer.getTable().setEnabled(false); + + buttonExplore.setEnabled(false); + buttonAdd.setEnabled(false); + buttonEdit.setEnabled(false); + buttonRemove.setEnabled(false); + + buttonRestore.setEnabled(true); } } @@ -485,40 +680,49 @@ public class TraceExplorerComposite // update the error view with this provider view.updateErrorView(); + + tableViewer.getTable().setEnabled(true); + + buttonExplore.setEnabled(true); + buttonAdd.setEnabled(true); + buttonEdit.setEnabled(true); + buttonRemove.setEnabled(!((IStructuredSelection)tableViewer.getSelection()).isEmpty()); + + buttonRestore.setEnabled(false); } /** - * If a formula in the table is selected, then enable the - * Remove and Edit buttons, else disable them. - */ - protected void changeButtonEnablement() - { + * If a formula in the table is selected, then enable the Remove and Edit + * buttons, else disable the Remove button, and the Edit button iff there are 0 + * or many formulas in the table. + */ + public void changeButtonEnablement() { + if (tableViewer == null) { + return; + } + IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); + if (!tableViewer.getTable().isEnabled()) { + return; + } if (buttonRemove != null) { buttonRemove.setEnabled(!selection.isEmpty()); } + if (buttonEdit != null) { - buttonEdit.setEnabled(selection.size() == 1); + buttonEdit.setEnabled((selection.size() == 1) || (tableViewer.getTable().getItemCount() == 1)); } + if (buttonExplore != null) { - buttonExplore.setEnabled(view.getTrace() != null && !view.getTrace().isTraceEmpty() - && tableViewer.getCheckedElements().length > 0); + buttonExplore.setEnabled((view.getTrace() != null) && !view.getTrace().isTraceEmpty() + && (tableViewer.getCheckedElements().length> 0)); } } - /** - * Sets the explore button enablement status to isTrace. - * @param isTrace - */ - public void changeExploreEnablement(boolean isTrace) - { - buttonExplore.setEnabled(isTrace); - } - /** * Opens a dialog for formula processing and returns the edited formula * @param formula initial formula, can be <code>null</code> @@ -527,8 +731,13 @@ public class TraceExplorerComposite protected Formula doEditFormula(Formula formula) { // Create the wizard - FormulaWizard wizard = new FormulaWizard(section.getText(), section.getDescription()); - wizard.setFormula(formula); + FormulaWizard wizard = new FormulaWizard(section.getText(), + "Enter an expression to be evaluated at each state of the trace.", + String.format( + "The expression may be named and may include the %s and %s operators (click question mark below for details).", + TraceExpressionModelWriter.TRACE, TraceExpressionModelWriter.POSITION), + "ErrorTraceExplorerExpression"); + wizard.setFormula(formula); // Create the wizard dialog WizardDialog dialog = new WizardDialog(getTableViewer().getTable().getShell(), wizard); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java index 9667093cddf58e44c6e7776029c4398d767ec88e..ce5fd7346ab98d712494f07e40bbd674c4a9cbaf 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java @@ -1,13 +1,22 @@ package org.lamport.tla.toolbox.tool.tlc.ui; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; import org.lamport.tla.toolbox.AbstractTLCActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.util.ExecutionStatisticsDialog; import org.lamport.tla.toolbox.util.UIHelper; import org.osgi.framework.BundleContext; +import util.ExecutionStatisticsCollector; + /** * The activator class controls the plug-in life cycle */ @@ -73,6 +82,18 @@ public class TLCUIActivator extends AbstractTLCActivator changedColor = new Color(null, 255, 200, 200); addedColor = new Color(null, 255, 255, 200); deletedColor = new Color(null, 240, 240, 255); + + + if (Display.getCurrent() != null && ExecutionStatisticsCollector.promptUser()) { // Display is null during unit test execution. + final UIJob j = new UIJob(Display.getCurrent(), "TLA+ execution statistics approval.") { + @Override + public IStatus runInUIThread(final IProgressMonitor monitor) { + new ExecutionStatisticsDialog(PlatformUI.createDisplay().getActiveShell()).open(); + return Status.OK_STATUS; + } + }; + j.schedule(5 * 60 * 1000L); + } } public Color getChangedColor() diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java index 84c51a15cea5d167852c523b7591bb3323a59e2b..707fe89745443263f1b45ed2fd003a1379292dec 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java @@ -1,6 +1,8 @@ package org.lamport.tla.toolbox.tool.tlc.ui.dialog; import java.util.Comparator; +import java.util.HashSet; +import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -16,6 +18,7 @@ import org.eclipse.ui.IMemento; import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ModuleNode; @@ -44,7 +47,18 @@ public class FilteredDefinitionSelectionDialog extends FilteredItemsSelectionDia // the names of all operators that have already been overridden. // These are the names by which they are known to the root module, such // as "frob!bar!id". - private String[] names; + private final Set<String> names = new HashSet<>(); + + private static String toString(OpDefNode node) { + // strip off leading F!B!... prefix and attach suffix [ModuleName] in case + // definition comes from foreign module. + String name = node.getName().toString(); + if (node.getSource() != node) { + name = name.substring(name.lastIndexOf("!") + 1); + name += " [" + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]"; + } + return name; + } /** * Constructs new dialog instance @@ -62,7 +76,11 @@ public class FilteredDefinitionSelectionDialog extends FilteredItemsSelectionDia setListLabelProvider(getListLabelProvider()); setDetailsLabelProvider(getDetailLabelProvider()); setSelectionHistory(new DefinitionHistory()); - this.names = names; + + for (String name : names) { + OpDefNode opDefNode = ModelHelper.getOpDefNode(specObj, name); + this.names.add(toString(opDefNode)); + } } /** @@ -165,33 +183,30 @@ public class FilteredDefinitionSelectionDialog extends FilteredItemsSelectionDia return; } OpDefNode[] opDefs = specObj.getExternalModuleTable().getRootModule().getOpDefs(); - progressMonitor.beginTask("Looking up for definitions...", opDefs.length); + final Set<String> dupes = new HashSet<>(opDefs.length); + + progressMonitor.beginTask("Looking up definitions...", opDefs.length); for (int i = 0; i < opDefs.length; i++) { - if (isNotInArray(opDefs[i].getName().toString(), this.names)) { - contentProvider.add(opDefs[i], itemsFilter); - progressMonitor.worked(1); - } + final OpDefNode opDefNode = opDefs[i]; + final String string = toString(opDefNode); + + // a) Skip those nodes that are already shown in the table. + // b) Skip duplicate nodes (duplicate means e.g. F!Next and G!Next if F and G + // both instantiated the same module). + // The comment for getElementName below also relates to duplicates but I'm not + // sure it is about the same type of dupes. + if (names.contains(string) || dupes.contains(string)) { + continue; + } + dupes.add(string); + + contentProvider.add(opDefNode, itemsFilter); + progressMonitor.worked(1); } progressMonitor.done(); } - - /** - * Returns true iff str is not an element of array. - * - * @param str - * @param array - * @return - */ - private boolean isNotInArray(String str, String[] array) { - for (int i = 0; i < array.length; i++) { - if (str.equals(array[i])) { - return false; - } - } - return true; - } /* (non-Javadoc) * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#getElementName(java.lang.Object) diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/TLAFilteredItemsSelectionDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/TLAFilteredItemsSelectionDialog.java index 021e19b0c0b8dae16c5912fc8ecd3a346930cdbc..76f2a0752eb5d32c21e640226d04d1682e280c35 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/TLAFilteredItemsSelectionDialog.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/TLAFilteredItemsSelectionDialog.java @@ -60,7 +60,6 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.ide.IDE.SharedImages; import org.eclipse.ui.navigator.IDescriptionProvider; import org.lamport.org.eclipse.ui.dialogs.FilteredItemsSelectionDialog; import org.lamport.tla.toolbox.Activator; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java index 54cb10dd3284ed56db769a825c9bdf46fc7bb37f..da891a479b1f874523bb04e58c806eeea6d3ec21 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java @@ -11,14 +11,18 @@ import org.eclipse.ui.forms.widgets.Section; /** * Takes care of section on pages, and attributes on sections - * @author Simon Zambrovski - * @version $Id$ - */ -/** * @author Simon Zambrovski */ public class DataBindingManager implements ISectionConstants { + /** + * Oh how much time i wasted tracking this down... someone had a famously bad idea of having code that walks an + * entire page of sections setting all direct children as enabled - regardless of, well, everything. Widgets + * should be updated to setting this data key if they'd like to left out of that party. + */ + public static final String WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE = "tla.dbm.enable.sigh"; + + private static final String[] EMPTY = new String[0]; // section parts containing the sections @@ -76,7 +80,7 @@ public class DataBindingManager implements ISectionConstants SectionPart part = sectionParts.get(id); if (part == null) { - throw new IllegalArgumentException("No section for id"); + throw new IllegalArgumentException("No section for id [" + id + "]"); } Section section = part.getSection(); Control[] children = section.getChildren(); @@ -91,24 +95,19 @@ public class DataBindingManager implements ISectionConstants } /** - * Sets the enablement state of a section's composite. More precisely, this - * means setting the enablement state of any child of the - * composite that is not a {@link Section} - * to enabled. - * - * @param composite - */ - private void enableSectionComposite(Composite composite, boolean enable) - { - Control[] children = composite.getChildren(); - for (int i = 0; i < children.length; i++) - { - if (!(children[i] instanceof Section)) - { - children[i].setEnabled(enable); - } - } - } + * Sets the enablement state of a section's composite. More precisely, this + * means setting the enablement state of any child of the composite that is not + * a {@link Section} to enabled. + * + * @param composite + */ + private void enableSectionComposite(final Composite composite, final boolean enabled) { + for (final Control child : composite.getChildren()) { + if (!(child instanceof Section) && (child.getData(WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE) == null)) { + child.setEnabled(enabled); + } + } + } /** * retrieves the id of the page the section is on @@ -148,6 +147,41 @@ public class DataBindingManager implements ISectionConstants sectionIds.add(id); } + + /** + * Given an attribute name, remove all binding to it and its section. + * + * @param attributeName + */ + public void unbindSectionAndAttribute(final String attributeName) { + viewerForAttribute.remove(attributeName); + + final String sectionId = sectionForAttribute.remove(attributeName); + if (sectionId != null) { + sectionParts.remove(sectionId); + + final String pageId = pageForSection.remove(sectionId); + if (pageId != null) { + final Vector<String> sectionIds = sectionsForPage.get(pageId); + if (sectionIds != null) { + sectionIds.remove(sectionId); + } + } + } + } + + /** + * Given an attribute name, remove all binding to it and its section. + * + * @param attributeName + */ + public void unbindSectionFromPage(final String sectionId, final String pageId) { + final Vector<String> sectionIds = sectionsForPage.get(pageId); + + if (sectionIds != null) { + sectionIds.remove(sectionId); + } + } /** * Retrieves the section of the current page diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java index ae51516878bc148900ad7ea5cc4b99aa9b4bbd23..4d590493f833b8c370e81f062a06bf16202ed6c9 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java @@ -31,7 +31,7 @@ package org.lamport.tla.toolbox.tool.tlc.ui.editor; */ public interface ISectionConstants { - // sections of the first page + // sections of the Main page public final static String SEC_COMMENTS = "__what_is_the_description"; public final static String SEC_WHAT_IS_THE_SPEC = "__what_is_the_spec"; @@ -41,15 +41,24 @@ public interface ISectionConstants public final static String SEC_WHAT_IS_THE_MODEL = "__what_is_the_model"; public final static String SEC_HOW_TO_RUN = "__how_to_run"; - // section on the second page + + + // sections on the Spec Options page public final static String SEC_NEW_DEFINITION = "__additional_definition"; public final static String SEC_DEFINITION_OVERRIDE = "__definition_override"; public final static String SEC_STATE_CONSTRAINT = "__state_constraints"; public final static String SEC_ACTION_CONSTRAINT = "__action_constraints"; public final static String SEC_MODEL_VALUES = "__model_values"; - public final static String SEC_LAUNCHING_SETUP = "__launching_setup"; + + + // sections on the TLC Options page + public final static String SEC_TLCOPT_CONFIGURATION = "__tlc_opt_config"; + public final static String SEC_TLCOPT_CHECK_MODE = "__tlc_opt_check_mode"; + public final static String SEC_TLCOPT_FEATURES = "__tlc_opt_features"; + public final static String SEC_TLCOPT_PARAMS = "__tlc_opt_params"; - // sections of the third page + + // sections of the Results page public final static String SEC_GENERAL = "__general"; // General Section public final static String SEC_OUTPUT = "__output"; // User output public static final String SEC_STATISTICS = "__coverage"; // Statistics diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java index 43d1ffae76c071130cb4c094e4d9e10a6a4bc7e1..6ce26045f793b72d222ac3cf67e1ea74998f0154 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java @@ -1,10 +1,17 @@ package org.lamport.tla.toolbox.tool.tlc.ui.editor; import java.io.ByteArrayInputStream; +import java.io.Closeable; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.tuple.Pair; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; @@ -24,12 +31,13 @@ import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.IPageChangedListener; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.PageChangedEvent; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabFolder2Adapter; @@ -48,6 +56,7 @@ import org.eclipse.ui.IPartService; import org.eclipse.ui.PartInitException; import org.eclipse.ui.forms.IMessageManager; import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.ITextEditor; @@ -55,6 +64,7 @@ import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.spec.parser.IParseConstants; import org.lamport.tla.toolbox.tool.tlc.TLCActivator; +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults; import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate; import org.lamport.tla.toolbox.tool.tlc.model.Model; @@ -63,10 +73,13 @@ import org.lamport.tla.toolbox.tool.tlc.model.TLCModelFactory; import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.AdvancedModelPage; import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.ErrorMessage; import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.ResultPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedModelPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedTLCOptionsPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.EvaluateConstantExpressionPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.ResultPage; import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; import org.lamport.tla.toolbox.tool.tlc.ui.util.ModelEditorPartListener; import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper; @@ -83,27 +96,36 @@ import com.abstratt.graphviz.GraphViz; import tla2sany.semantic.ModuleNode; /** - * Editor for the model + * Editor for the model. + * + * TODO this class should be cleaned up - there's no consistent grouping of static v instance methods; nor scoped + * instance methods; nor ... + * * @author Simon Zambrovski */ -public class ModelEditor extends FormEditor -{ - private static final SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss"); - +public class ModelEditor extends FormEditor { /** * Editor ID */ public static final String ID = "org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor"; + + public static final String ZERO_COVERAGE_ACTION_MARKER = "org.lamport.tla.toolbox.tlc.zerocoverage"; - /* + private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss"); + + + /* * working copy of the model */ // helper to resolve semantic matches of words private SemanticHelper helper; private final Model.StateChangeListener modelStateListener = new Model.StateChangeListener() { + private State m_lastState = State.NOT_RUNNING; + @Override public boolean handleChange(final ChangeEvent event) { if (event.getState().in(State.NOT_RUNNING, State.RUNNING)) { + final State lastStateCopy = m_lastState; UIHelper.runUIAsync(new Runnable() { public void run() { for (int i = 0; i < getPageCount(); i++) { @@ -116,18 +138,32 @@ public class ModelEditor extends FormEditor if (event.getState().in(State.RUNNING)) { // Switch to Result Page (put on top) of model editor stack. A user wants to see // the status of a model run she has just started. - ModelEditor.this.showResultPage(); - } - if (event.getState().in(State.NOT_RUNNING)) { + final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore(); + final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB); + + if (!eceInItsOwnTab || !modelIsConfiguredWithNoBehaviorSpec()) { + showResultPage(); + } + } else if (event.getState().in(State.NOT_RUNNING)) { // Model checking finished, lets open state graph if any. if (event.getModel().hasStateGraphDump()) { try { - ModelEditor.this.addOrUpdateStateGraphEditor(event.getModel().getStateGraphDump()); + addOrUpdateStateGraphEditor(event.getModel().getStateGraphDump()); } catch (CoreException e) { TLCUIActivator.getDefault().logError("Error initializing editor", e); } } + if (lastStateCopy.in(State.RUNNING, State.REMOTE_RUNNING)) { + final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore(); + final boolean eceInItsOwnTab = ips + .getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB); + + if (eceInItsOwnTab && modelIsConfiguredWithNoBehaviorSpec()) { + setActivePage(EvaluateConstantExpressionPage.ID); + } + } + // MAK 01/2018: Re-validate the page because running the model removes or sets // problem markers (Model#setMarkers) which are presented to the user by // ModelEditor#handleProblemMarkers. If we don't re-validate once a model is @@ -146,6 +182,9 @@ public class ModelEditor extends FormEditor } }); } + + m_lastState = event.getState(); + return false; } }; @@ -160,9 +199,10 @@ public class ModelEditor extends FormEditor */ private final ValidateRunnable validateRunable = new ValidateRunnable(); - private class ValidateRunnable implements Runnable - { - + // TODO this is pretty poor design - there is one instance of this inner class per instance of ModelEditor; the + // code below tweaks the switchToErrorPage ivar and then hands it off to a run async method, i guess just + // hoping that the flag isn't tweaked again before the async method does what was originally intended... + private class ValidateRunnable implements Runnable { private boolean switchToErrorPage = false; public void run() @@ -171,7 +211,7 @@ public class ModelEditor extends FormEditor // Also check if the model is nulled by now which // happens if the ModelEditor disposed before a scheduled run gets // executed. - if (model != null && !model.isRunning()) + if (model != null && !model.isRunning()) { /* * Note that all pages are not necessarily @@ -244,6 +284,56 @@ public class ModelEditor extends FormEditor } }; + + /** + * This IPageChangedListener is responsible to mark the current page in the + * navigation location history (stack). It is here in addition to a + * FocusListener in BasicFormPage which additionally track the in-page + * selection. However, if the user does not click into the page effectively + * changing the selection, the FocusListener isn't triggered. + */ + private final IPageChangedListener pageChangedListener = (event) -> { + final INavigationHistory navigationHistory = getSite().getPage().getNavigationHistory(); + navigationHistory.markLocation((IEditorPart) event.getSelectedPage()); + }; + + private final IPropertyChangeListener m_preferenceChangeListener = (event) -> { + if (ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB.equals(event.getProperty())) { + final boolean eceAsTab = ((Boolean) event.getNewValue()).booleanValue(); + final Pair<Integer, FormPage> pair = getLastFormPage(); + final String id = pair.getRight().getId(); + + if (eceAsTab) { + if (!EvaluateConstantExpressionPage.ID.equals(id)) { + try { + final EvaluateConstantExpressionPage ecePage = new EvaluateConstantExpressionPage(this); + addPage((pair.getLeft().intValue() + 1), ecePage, getEditorInput()); + + final ResultPage rp = (ResultPage) findPage(ResultPage.ID); + final EvaluateConstantExpressionPage.State eceState = rp.getECEContent(); + ecePage.setECEContent(eceState); + rp.pageShouldDisplayEvaluateConstantUI(false); + } catch (final Exception e) { + TLCUIActivator.getDefault().logError("Error attempting to open ECE page.", e); + } + } + } else { + if (EvaluateConstantExpressionPage.ID.equals(id)) { + try { + final EvaluateConstantExpressionPage ecePage = (EvaluateConstantExpressionPage)pair.getRight(); + final EvaluateConstantExpressionPage.State eceState = ecePage.getECEContent(); + final ResultPage rp = (ResultPage) findPage(ResultPage.ID); + rp.pageShouldDisplayEvaluateConstantUI(true); + rp.setECEContent(eceState); + + removePage(pair.getLeft().intValue()); + } catch (final Exception e) { + TLCUIActivator.getDefault().logError("Error attempting to close ECE page.", e); + } + } + } + } + }; // data binding manager private DataBindingManager dataBindingManager = new DataBindingManager(); @@ -254,6 +344,8 @@ public class ModelEditor extends FormEditor * See the class documentation for more details. */ private CTabFolder2Listener listener = new CloseModuleTabListener(); + + private final Map<Integer, Closeable> m_indexCloseableMap; // array of pages to add private BasicFormPage[] pagesToAdd; @@ -263,17 +355,16 @@ public class ModelEditor extends FormEditor /** * Simple editor constructor */ - public ModelEditor() - { - helper = new SemanticHelper(); - pagesToAdd = new BasicFormPage[] { new MainModelPage(this), new AdvancedModelPage(this), new ResultPage(this) }; - } + public ModelEditor() { + helper = new SemanticHelper(); + m_indexCloseableMap = new HashMap<>(); + } /** * Initialize the editor */ - public void init(IEditorSite site, IEditorInput input) throws PartInitException - { + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { // TLCUIActivator.getDefault().logDebug("entering ModelEditor#init(IEditorSite site, IEditorInput input)"); super.init(site, input); @@ -281,15 +372,52 @@ public class ModelEditor extends FormEditor final FileEditorInput finput = getFileEditorInput(); // the file might not exist anymore (e.g. manually removed by the user) - if (finput == null || !finput.exists()) { + if ((finput == null) || !finput.exists()) { throw new PartInitException("Editor input does not exist: " + finput.getName()); } model = TLCModelFactory.getBy(finput.getFile()); + int openTabsValue = 0; + try { + openTabsValue = model.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.EDITOR_OPEN_TABS, 0); + } catch (CoreException e) { } + + final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore(); + final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB); + + if (openTabsValue == IModelConfigurationConstants.EDITOR_OPEN_TAB_NONE) { + if (eceInItsOwnTab) { + pagesToAdd = new BasicFormPage[] { new MainModelPage(this), new ResultPage(this), new EvaluateConstantExpressionPage(this) }; + } else { + pagesToAdd = new BasicFormPage[] { new MainModelPage(this), new ResultPage(this) }; + } + } else { + ArrayList<BasicFormPage> pages = new ArrayList<>(); + + pages.add(new MainModelPage(this)); + if ((openTabsValue + & IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL) == IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL) { + pages.add(new AdvancedModelPage(this)); + } + if ((openTabsValue + & IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC) == IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC) { + pages.add(new AdvancedTLCOptionsPage(this)); + } + pages.add(new ResultPage(this)); + if (eceInItsOwnTab) { + pages.add(new EvaluateConstantExpressionPage(this)); + } + + pagesToAdd = pages.toArray(new BasicFormPage[pages.size()]); + } + + ips.addPropertyChangeListener(m_preferenceChangeListener); + + // setContentDescription(path.toString()); if (model.isSnapshot()) { - final String date = sdf.format(model.getSnapshotTimeStamp()); + final String date = SIMPLE_DATE_FORMAT.format(model.getSnapshotTimeStamp()); this.setPartName(model.getSnapshotFor().getName() + " (" + date + ")"); } else { this.setPartName(model.getName()); @@ -324,31 +452,31 @@ public class ModelEditor extends FormEditor model.add(modelStateListener); } - - /** - * This IPageChangedListener is responsible to mark the current page in the - * navigation location history (stack). It is here in addition to a - * FocusListener in BasicFormPage which additionally track the in-page - * selection. However, if the user does not click into the page effectively - * changing the selection, the FocusListener isn't triggered. + + /** + * @param index the tab index + * @return null if the index is greater than or equal to the number of tabs, + * else the id of the {@link FormPage} which is at that index */ - private final IPageChangedListener pageChangedListener = new IPageChangedListener() { - /* (non-Javadoc) - * @see org.eclipse.jface.dialogs.IPageChangedListener#pageChanged(org.eclipse.jface.dialogs.PageChangedEvent) - */ - public void pageChanged(final PageChangedEvent event) { - final INavigationHistory navigationHistory = getSite().getPage() - .getNavigationHistory(); - navigationHistory.markLocation((IEditorPart) event - .getSelectedPage()); - } - }; + public String getIdForEditorAtIndex(final int index) { + final FormPage editor = (FormPage)getEditor(index); + + if (editor != null) { + return editor.getId(); + } + + return null; + } /** * @see org.eclipse.ui.forms.editor.FormEditor#dispose() */ + @Override public void dispose() { removePageChangedListener(pageChangedListener); + + TLCUIActivator.getDefault().getPreferenceStore().removePropertyChangeListener(m_preferenceChangeListener); + // TLCUIActivator.getDefault().logDebug("entering ModelEditor#dispose()"); // remove the listeners ResourcesPlugin.getWorkspace().removeResourceChangeListener(workspaceResourceChangeListener); @@ -361,7 +489,6 @@ public class ModelEditor extends FormEditor // TLCUIActivator.getDefault().logDebug("leaving ModelEditor#dispose()"); } - public boolean isDisposed() { return model == null; } @@ -381,7 +508,7 @@ public class ModelEditor extends FormEditor // remove existing markers model.removeMarkers(Model.TLC_MODEL_ERROR_MARKER_SANY); - boolean revalidate = TLCUIActivator.getDefault().getPreferenceStore().getBoolean( + final boolean revalidate = TLCUIActivator.getDefault().getPreferenceStore().getBoolean( ITLCPreferenceConstants.I_TLC_REVALIDATE_ON_MODIFY); if (revalidate) { @@ -481,7 +608,10 @@ public class ModelEditor extends FormEditor // // TLCUIActivator.getDefault().logDebug("Focusing " + getConfig().getName() + // // " editor"); - super.setFocus(); + final IFormPage page = getActivePageInstance(); + if (page != null) { + page.setFocus(); + } } /* @@ -526,17 +656,11 @@ public class ModelEditor extends FormEditor // TLCUIActivator.getDefault().logDebug("entering ModelEditor#addPages()"); try { - // This code moves the tabs to the top of the page. // This makes them more obvious to the user. - if (getContainer() instanceof CTabFolder) - { - ((CTabFolder) getContainer()).setTabPosition(SWT.TOP); - ((CTabFolder) getContainer()).addCTabFolder2Listener(listener); - } else - { - TLCUIActivator.getDefault().logDebug("The model editor container is not a CTabFolder. This is a bug."); - } + final CTabFolder tabFolder = (CTabFolder)getContainer(); + tabFolder.setTabPosition(SWT.TOP); + tabFolder.addCTabFolder2Listener(listener); for (int i = 0; i < pagesToAdd.length; i++) { @@ -549,9 +673,19 @@ public class ModelEditor extends FormEditor // the dirty listeners will be activated if (pagesToAdd[i].getPartControl() == null) { - pagesToAdd[i].createPartControl(getContainer()); + pagesToAdd[i].createPartControl(tabFolder); setControl(i, pagesToAdd[i].getPartControl()); - pagesToAdd[i].getPartControl().setMenu(getContainer().getMenu()); + pagesToAdd[i].getPartControl().setMenu(tabFolder.getMenu()); + } + + final CTabItem item = tabFolder.getItem(i); + // we have to do this to allow our superclass' getEditor(int) to work correctly since we don't + // add the page via addPage(IEditorPart,IEditorInput) + item.setData(pagesToAdd[i]); + if (pagesToAdd[i] instanceof Closeable) { + item.setShowClose(true); + + m_indexCloseableMap.put(new Integer(i), (Closeable)pagesToAdd[i]); } } @@ -560,10 +694,9 @@ public class ModelEditor extends FormEditor UIHelper.runUIAsync(validateRunable); - ModuleNode rootModule = SemanticHelper.getRootModuleNode(); - if (rootModule != null && rootModule.getVariableDecls().length == 0 - && rootModule.getConstantDecls().length == 0) - { + final ModuleNode rootModule = SemanticHelper.getRootModuleNode(); + if ((rootModule != null) && (rootModule.getVariableDecls().length == 0) + && (rootModule.getConstantDecls().length == 0)) { showResultPage(); } @@ -578,6 +711,19 @@ public class ModelEditor extends FormEditor // TLCUIActivator.getDefault().logDebug("leaving ModelEditor#addPages()"); } + /** + * For some reason, the superclass comments out the setPageImage(...) code. + * + * {@inheritDoc} + */ + @Override + protected void configurePage(final int index, final IFormPage page) + throws PartInitException { + setPageImage(index, page.getTitleImage()); + + super.configurePage(index, page); + } + public void addOrUpdateStateGraphEditor(final IFile stateGraphDotDump) throws CoreException { // For historical reasons this preference is found in the tlatex bundle. Thus, // we read the value from there, but don't refer to the corresponding string @@ -597,9 +743,9 @@ public class ModelEditor extends FormEditor } // Load a previously generated pdf file. - final IFile file = model.getFolder().getFile(model.getName() + ".pdf"); - if (file.exists()) { - addPage(findEditor, new FileEditorInput(file)); + final IFile pdfFile = model.getFolder().getFile(model.getName() + ".pdf"); + if (pdfFile.exists()) { + saferAddPage(stateGraphDotDump, findEditor, pdfFile, useEmbeddedViewer); return; } @@ -617,23 +763,11 @@ public class ModelEditor extends FormEditor final byte[] load = GraphViz.load(new FileInputStream(stateGraphDotDump.getLocation().toFile()), "pdf", 0, 0); // Write byte[] into IFile file - file.create(new ByteArrayInputStream(load), IResource.NONE, null); + pdfFile.create(new ByteArrayInputStream(load), IResource.NONE, null); UIHelper.runUISync(new Runnable() { @Override public void run() { - try { - addPage(findEditor, new FileEditorInput(file)); - } catch (PartInitException e) { - final Shell shell = Display.getDefault().getActiveShell(); - MessageDialog.openError(shell == null ? new Shell() : shell, - "Opening state graph visualization failed.", - "Opening state graph visualization failed: " + e.getMessage()); - } catch (OutOfMemoryError e) { - final Shell shell = Display.getDefault().getActiveShell(); - MessageDialog.openError(shell == null ? new Shell() : shell, "Opening state graph visualization ran out of memory.", - "Opening state graph visualization ran out of memory. The state graph is likely too large. " - + "Try using a standalone PDF viewer if the Toolbox is currently set to use the built-in one."); - } + ModelEditor.this.saferAddPage(stateGraphDotDump, findEditor, pdfFile, useEmbeddedViewer); } }); } catch (CoreException e) { @@ -654,6 +788,44 @@ public class ModelEditor extends FormEditor j.schedule(); } + // Attempt to handle (primarily) OutOfMemory errors when opening large pdf files. + private void saferAddPage(final IFile stateGraphDotDump, final IEditorPart findEditor, final IFile file, final boolean usesEmbeddedViewer) { + try { + addPage(findEditor, new FileEditorInput(file)); + } catch (PartInitException e) { + final Shell shell = Display.getDefault().getActiveShell(); + MessageDialog.openError(shell == null ? new Shell() : shell, + "Opening state graph visualization failed.", + "Opening state graph visualization failed: " + e.getMessage()); + } catch (OutOfMemoryError oom) { + // Try to reclaim memory to be able to keep code below from running into more OOMs. + System.gc(); + + // Rename dot and pdf files with too large input to keep them from causing + // troubles in the future (just renaming pdf means the Toolbox will generate a + // new pdf from the .dot input on the next invocation). + try { + stateGraphDotDump.move(stateGraphDotDump.getFullPath().addFileExtension("large"), true, new NullProgressMonitor()); + file.move(file.getFullPath().addFileExtension("large"), true, new NullProgressMonitor()); + } catch (CoreException e) { + TLCUIActivator.getDefault().logWarning(e.getMessage()); + } + + // Instruct user about what happened and what to do. + final Shell shell = Display.getDefault().getActiveShell(); + String label = "Opening state graph visualization ran out of memory. The state graph is likely too large. "; + if (usesEmbeddedViewer) { + label += "\n\nTry switching from the built-in to a standalone PDF viewer by unchecking " + + "\"Use built-in PDF viewer\" on the Toolbox's \"PDF Viewer\" preference page.\n\n"; + } + label += String.format("To prevent future problems, the file %s has been renamed to %s.", + file.getLocation().toOSString(), file.getLocation().addFileExtension("large").toOSString()); + label += "\n\nPlease restart the Toolbox in case it now behaves strangely."; + MessageDialog.openError(shell == null ? new Shell() : shell, + "Opening state graph visualization ran out of memory.", label); + } + } + // Shorten message to 1024 chars in case GraphViz attached the complete dot // input which can be huge. // https://github.com/abstratt/eclipsegraphviz/issues/8 @@ -685,6 +857,37 @@ public class ModelEditor extends FormEditor return in; } + private Pair<Integer, FormPage> getLastFormPage() { + int index = getPageCount() - 1; + + while (index >= 0) { + final IEditorPart iep = getEditor(index); + + if (iep instanceof FormPage) { + return Pair.of(new Integer(index), (FormPage)iep); + } + + index--; + } + + return null; + } + + /** + * @return true if the model is currently configured with no behavior spec + */ + public boolean modelIsConfiguredWithNoBehaviorSpec() { + try { + return (IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_NO_SPEC == model + .getAttribute(IModelConfigurationConstants.MODEL_BEHAVIOR_SPEC_TYPE, Integer.MIN_VALUE)); + } catch (final CoreException ce) { + TLCUIActivator.getDefault() + .logError("Encountered error attempting to determine previous run configuration.", ce); + } + + return false; + } + /* --------------------------------------------------------------------- */ public void launchModel(final String mode, final boolean userPased) { @@ -695,13 +898,12 @@ public class ModelEditor extends FormEditor * Launch TLC or SANY * * @param mode - * @param userPased - * true, if the action is performed on behalf of the user action - * (explicit click on the launch button) + * @param userInvoked true, if the action is performed on behalf of the user + * action (explicit click on the launch button) * @throws CoreException */ - public void launchModel(final String mode, final boolean userPased, final IProgressMonitor monitor) { - if (userPased && model.isSnapshot()) { + public void launchModel(final String mode, final boolean userInvoked, final IProgressMonitor monitor) { + if (userInvoked && model.isSnapshot()) { final boolean launchSnapshot = MessageDialog.openConfirm(getSite().getShell(), "Model is a snapshot", "The model which is about to launch is a snapshot of another model. " + "Beware that no snapshots of snapshots are taken. " @@ -740,7 +942,7 @@ public class ModelEditor extends FormEditor .openError(getSite().getShell(), "Model checking not allowed", "The spec status is not \"parsed\". The status must be \"parsed\" before model checking is allowed."); } else if (mode == TLCModelLaunchDelegate.MODE_GENERATE) { - if (userPased) { + if (userInvoked) { MessageDialog .openError(getSite().getShell(), "Revalidation not allowed", "The spec status is not \"parsed\". The status must be \"parsed\" before model revalidation is allowed."); @@ -762,17 +964,21 @@ public class ModelEditor extends FormEditor MessageDialog.openError(getSite().getShell(), "Illegal module name", "Model validation and checking is not allowed on a spec containing a module named " + ModelHelper.MC_MODEL_NAME + "." - + (userPased ? "" : " However, the model can still be saved.")); + + (userInvoked ? "" : " However, the model can still be saved.")); return; } if (ModelHelper.containsTraceExplorerModuleConflict(rootModuleName)) { MessageDialog.openError(getSite().getShell(), "Illegal module name", "Model validation and checking is not allowed on a spec containing a module named " + ModelHelper.TE_MODEL_NAME + "." - + (userPased ? "" : " However, the model can still be saved.")); + + (userInvoked ? "" : " However, the model can still be saved.")); return; } } + + // Delete any zero coverage markers when model checking starts. The outcome of + // model checking can invalidate old markers. Noop if no markers are present. + spec.deleteMarker(ZERO_COVERAGE_ACTION_MARKER); } else { Activator.getDefault().logDebug("The spec manager has not been instantiated. This is a bug."); return; @@ -822,35 +1028,38 @@ public class ModelEditor extends FormEditor // save the model editor if not saved if (isDirty()) { // TODO decouple from ui thread - doSave(new SubProgressMonitor(monitor, 1)); + doSave(SubMonitor.convert(monitor, 1)); } if (!isComplete()) { // user clicked launch - if (userPased) { + if (userInvoked) { MessageDialog.openError(getSite().getShell(), "Model processing not allowed", "The model contains errors, which should be corrected before further processing"); return; } } else { // launching the config - model.launch(mode, new SubProgressMonitor(monitor, 1), true); + model.launch(mode, SubMonitor.convert(monitor, 1), true); /* - * Close any tabs in this editor containing read-only - * versions of modules. They will be changed by the - * launch, regardless of the mode. We could do something - * more sophisticated like listening to resource changes - * and updating the editors when the underlying files - * change, but the doesn't seem worth the effort. + * Close any tabs in this editor containing read-only versions of modules. They + * will be changed by the launch, regardless of the mode. We could do something + * more sophisticated like listening to resource changes and updating the + * editors when the underlying files change, but the doesn't seem worth the + * effort. + * + * Close pages in reverse order because removing a page invalidates indices. */ - for (int i = 0; i < getPageCount(); i++) { - /* - * The normal form pages (main model page, advanced options, results) are remain - * open, all other pages get closed i.e. Saved Module Editor and State Graph - * editor. - */ - if (!(pages.get(i) instanceof BasicFormPage)) { + for (int i = getPageCount() - 1; i >= 0; i--) { + if (pages.get(i) instanceof BasicFormPage) { + ((BasicFormPage)pages.get(i)).modelCheckingHasBegun(); + } else { + /* + * The normal form pages (main model page, advanced options, results) are remain + * open, all other pages get closed i.e. Saved Module Editor and State Graph + * editor. + */ removePage(i); } } @@ -942,15 +1151,6 @@ public class ModelEditor extends FormEditor IMarker[] modelProblemMarkers = model.getMarkers(); DataBindingManager dm = getDataBindingManager(); - // The loop is going to update the page's messages for potentially - // each marker (nested loop). Thus, turn auto update off during the - // loop for all pages (we don't yet know which marker gets displayed - // on which page). - for (int i = 0; i < this.pagesToAdd.length; i++) { - IMessageManager mm = this.pagesToAdd[i].getManagedForm().getMessageManager(); - mm.setAutoUpdate(false); - } - for (int j = 0; j < getPageCount(); j++) { /* @@ -964,7 +1164,13 @@ public class ModelEditor extends FormEditor // get the current page BasicFormPage page = (BasicFormPage) pages.get(j); Assert.isNotNull(page.getManagedForm(), "Page not initialized, this is a bug."); - + + // The loop is going to update the page's messages for potentially + // each marker (nested loop). Thus, turn auto update off during the + // loop for all pages (we don't yet know which marker gets displayed + // on which page). + page.getManagedForm().getMessageManager().setAutoUpdate(false); + for (int i = 0; i < modelProblemMarkers.length; i++) { String attributeName = modelProblemMarkers[i].getAttribute( @@ -989,23 +1195,32 @@ public class ModelEditor extends FormEditor { final String message = modelProblemMarkers[i].getAttribute(IMarker.MESSAGE, IModelConfigurationDefaults.EMPTY_STRING); - final int pageId = modelProblemMarkers[i] + int pageId = modelProblemMarkers[i] .getAttribute(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, -1); // no attribute, this is a global error, not bound to a particular attribute // install it on the first page // if it is a global TLC error, then we call addGlobalTLCErrorMessage() // to add a hyperlink to the TLC Error view - if (pageId != -1 && bubbleType == IMessageProvider.WARNING + if ((pageId != -1) && (bubbleType == IMessageProvider.WARNING) && !IModelConfigurationDefaults.EMPTY_STRING.equals(message)) { // Used by the ResultPage to display an error on // incomplete state space exploration. - this.pagesToAdd[pageId].addGlobalTLCErrorMessage(ResultPage.RESULT_PAGE_PROBLEM, message); + if (pageId >= pagesToAdd.length) { + pageId = pagesToAdd.length - 1; + } + pagesToAdd[pageId].addGlobalTLCErrorMessage(ResultPage.RESULT_PAGE_PROBLEM, message); } else if (bubbleType == IMessageProvider.WARNING) { - this.pagesToAdd[0].addGlobalTLCErrorMessage("modelProblem_" + i); - this.pagesToAdd[1].addGlobalTLCErrorMessage("modelProblem_" + i); + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + final BasicFormPage bfp = iterator.next(); + + if (!bfp.getId().equals(ResultPage.ID)) { + bfp.addGlobalTLCErrorMessage("modelProblem_" + i); + } + } } else { // else install as with other messages - IMessageManager mm = this.pagesToAdd[0].getManagedForm().getMessageManager(); + IMessageManager mm = pagesToAdd[0].getManagedForm().getMessageManager(); mm.addMessage("modelProblem_" + i, message, null, bubbleType); } } else @@ -1054,10 +1269,11 @@ public class ModelEditor extends FormEditor } // Once all markers have been processed, re-enable auto update again. - for (int i = 0; i < this.pagesToAdd.length; i++) { - final IMessageManager mm = this.pagesToAdd[i].getManagedForm().getMessageManager(); - mm.setAutoUpdate(true); - } + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + final IMessageManager mm = iterator.next().getManagedForm().getMessageManager(); + mm.setAutoUpdate(true); + } if (switchToErrorPage && errorPageIndex != -1 && currentPageIndex != errorPageIndex) { @@ -1157,43 +1373,55 @@ public class ModelEditor extends FormEditor * Expands the given sections on the model editor pages. */ public void expandSections(final String[] sections) { - for (int i = 0; i < pagesToAdd.length; i++) { - final BasicFormPage basicFormPage = pagesToAdd[i]; - basicFormPage.expandSections(sections); + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + iterator.next().expandSections(sections); } } + + public void expandSections(final String pageId, final List<String> sections) { + final BasicFormPage formPage = getFormPage(pageId); + formPage.expandSections(sections.toArray(new String[sections.size()])); + } - // TODO remove - public void setUpPage(BasicFormPage newPage, int index) - { - if (newPage.getPartControl() == null) - { - newPage.createPartControl(this.getContainer()); - setControl(index, newPage.getPartControl()); - newPage.getPartControl().setMenu(getContainer().getMenu()); - } - } + public BasicFormPage getFormPage(final String id) { + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + final BasicFormPage basicFormPage = iterator.next(); + if (basicFormPage.getId().equals(id)) { + return basicFormPage; + } + } + return null; + } /** * This adds error messages to all pages for the given control. * If the control is null, it will do nothing. * + * WARNING: Because of addMessage(...) this is an expensive operation. + * * @param key the unique message key * @param messageText the message to add * @param pageId the id of the page that contains the control * @param type the message type * @param control the control to associate the message with */ - public void addErrorMessage(Object key, String messageText, String pageId, int type, Control control) - { - if (control != null) - { - for (int i = 0; i < pagesToAdd.length; i++) - { - pagesToAdd[i].getManagedForm().getMessageManager().addMessage(key, messageText, pageId, type, control); + public void addErrorMessage(Object key, String messageText, String pageId, int type, Control control) { + if (control != null) { + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + iterator.next().getManagedForm().getMessageManager().addMessage(key, messageText, pageId, type, control); } } } + + public void addErrorMessage(final ErrorMessage errorMessage) { + addErrorMessage(errorMessage.getKey(), errorMessage.getMessage(), errorMessage.getModelEditorPageId(), + IMessageProvider.WARNING, + UIHelper.getWidget(getDataBindingManager().getAttributeControl(errorMessage.getViewerId()))); + expandSections(errorMessage.getModelEditorPageId(), errorMessage.getSections()); + } /** * This removes the error "message" added by the corresponding call to @@ -1223,24 +1451,77 @@ public class ModelEditor extends FormEditor * @param key the unique message key * @param control the control to associate the message with */ - public void removeErrorMessage(Object key, Control control) - { - if (control != null) - { - for (int i = 0; i < pagesToAdd.length; i++) - { - pagesToAdd[i].getManagedForm().getMessageManager().removeMessage(key, control); + public void removeErrorMessage(Object key, Control control) { + if (control != null) { + final PageIterator iterator = new PageIterator(); + while (iterator.hasNext()) { + iterator.next().getManagedForm().getMessageManager().removeMessage(key, control); } } } + /** - * Returns the validateRunnable so that the pages - * can be validated by code outside of this class. - * @return + * This updates the appropriate model attribute and saves the model. + * + * @param newValue the new value representing currently open close-able tabs. + * @see IModelConfigurationConstants#EDITOR_OPEN_TABS */ - public ValidateRunnable getValidateRunnable() - { - return validateRunable; + public void updateOpenTabsState(final int newValue) { + getModel().setOpenTabsValue(newValue); + + saveModel(); + } + + /** + * Invoke this to save the model. + */ + public void saveModel() { + final Job job = new WorkspaceJob("Saving updated model...") { + public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { + getModel().save(monitor); + return Status.OK_STATUS; + } + }; + job.setRule(ResourcesPlugin.getWorkspace().getRoot()); + job.setUser(true); + job.schedule(); + } + + public void addOrShowAdvancedModelPage() { + if (setActivePage(AdvancedModelPage.ID) == null) { + try { + addPage(1, new AdvancedModelPage(this), getEditorInput()); + setActivePage(AdvancedModelPage.ID); + + final int openTabState = getModel().getOpenTabsValue(); + updateOpenTabsState(openTabState | IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL); + } catch (Exception e) { + TLCActivator.getDefault().getLog().log(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, + "Could not add advanced model options page", e)); + } + } + } + + public void addOrShowAdvancedTLCOptionsPage() { + if (setActivePage(AdvancedTLCOptionsPage.ID) == null) { + try { + int pageIndex = 1; + final String id = getIdForEditorAtIndex(1); + + if (AdvancedModelPage.ID.equals(id)) { + pageIndex++; + } + + addPage(pageIndex, new AdvancedTLCOptionsPage(this), getEditorInput()); + setActivePage(AdvancedTLCOptionsPage.ID); + + final int openTabState = getModel().getOpenTabsValue(); + updateOpenTabsState(openTabState | IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC); + } catch (Exception e) { + TLCActivator.getDefault().getLog().log(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, + "Could not add advanced TLC options page", e)); + } + } } /** @@ -1259,6 +1540,7 @@ public class ModelEditor extends FormEditor public void addPage(int index, IEditorPart editor, IEditorInput input) throws PartInitException { super.addPage(index, editor, input); + //TODO This method screams to be refactored and simplified, but sadly life is short. /* * Do stuff if the input is a tla file. * @@ -1267,24 +1549,36 @@ public class ModelEditor extends FormEditor * * 2.) Set the page to be closeable. */ - if (input instanceof FileEditorInput - && ((FileEditorInput) input).getFile().getFileExtension().equals(ResourceHelper.TLA_EXTENSION)) - { + if (editor instanceof TLACoverageEditor) { + // ... just add another special case to this supposed-to-be generic method. We + // want the tab for the TLACoverageEditor to show not just the file name and an + // icon indicating the editor type. + this.setPageText(index, editor.getTitle()); + this.setPageImage(index, editor.getTitleImage()); + ((CTabFolder) getContainer()).getItem(index).setShowClose(true); + } else if (input instanceof FileEditorInput + && ((FileEditorInput) input).getFile().getFileExtension().equals(ResourceHelper.TLA_EXTENSION)) { setPageText(index, input.getName()); - /* - * When I implemented this method, getContainer() - * returned a CTabFolder. If this somehow stops - * being the case, then I do not know how to set - * the tla file pages to be closeable. - */ - if (getContainer() instanceof CTabFolder) - { - ((CTabFolder) getContainer()).getItem(index).setShowClose(true); - } + ((CTabFolder) getContainer()).getItem(index).setShowClose(true); // setPageImage(pageIndex, image); } else if (input instanceof FileEditorInput && "pdf".equals(((FileEditorInput) input).getFile().getFileExtension())) { setPageText(index, "State Graph"); + } else if (editor instanceof Closeable) { + final CTabFolder tabFolder = (CTabFolder)getContainer(); + + tabFolder.getItem(index).setShowClose(true); + + final int tabCount = tabFolder.getItemCount(); + for (int i = tabCount - 2; i >= index; i--) { + final Closeable c = m_indexCloseableMap.remove(new Integer(i)); + + if (c != null) { + m_indexCloseableMap.put(new Integer(i + 1), c); + } + } + + m_indexCloseableMap.put(new Integer(index), (Closeable)editor); } } @@ -1300,21 +1594,94 @@ public class ModelEditor extends FormEditor * @author Daniel Ricketts * */ - private class CloseModuleTabListener extends CTabFolder2Adapter - { + private class CloseModuleTabListener extends CTabFolder2Adapter { + /** + * {@inheritDoc} + */ + @Override + public void close(CTabFolderEvent event) { + Assert.isTrue(event.item instanceof CTabItem, + "Something other than a CTabItem was closed in a CTabFolder."); + + final CTabItem item = (CTabItem) event.item; + final CTabFolder tabFolder = item.getParent(); + final int index = tabFolder.indexOf(item); + + // block the CTabFolder from directly removing the tab + event.doit = false; + + // oh glorious, crappy, SWT - honestly meritous of a class action lawsuit for the untold thousands of + // man-years wasted writing and dealing with you.. + // event.item is already disposed by the time we get notified so we can't use its data holder which is + // what is being used to hold the editor part by our super-superclass... kwality + final Closeable c = m_indexCloseableMap.remove(new Integer(index)); + if (c != null) { + final int tabCount = tabFolder.getItemCount(); + for (int i = index; i <= tabCount; i++) { + final Closeable remaining = m_indexCloseableMap.remove(new Integer(i)); + + if (remaining != null) { + m_indexCloseableMap.put(new Integer(i - 1), remaining); + } + } - public void close(CTabFolderEvent event) - { - Assert - .isTrue(event.item instanceof CTabItem, - "Something other than a CTabItem was closed in a CTabFolder."); - CTabItem item = (CTabItem) event.item; + try { + c.close(); + } catch (Exception e) { } + } + + // remove the page properly + removePage(index); + } + } + + + /** + * We were, for some reason, only looping over the initially added page array at many places in this class; this + * way of doing things became insufficient when we started having optionally open pages. + */ + private class PageIterator implements Iterator<BasicFormPage> { + + private final List<Object> m_pages; + private int m_counter; + + private BasicFormPage m_nextPage; + + PageIterator() { + m_pages = new ArrayList<>(pages); + m_counter = 0; + + m_nextPage = findNextPage(); + } + + private BasicFormPage findNextPage() { + BasicFormPage page = null; + + while ((page == null) && (m_counter < m_pages.size())) { + final Object o = m_pages.get(m_counter); + + if (o instanceof BasicFormPage) { + page = (BasicFormPage)o; + } + + m_counter++; + } + + return page; + } + + @Override + public boolean hasNext() { + return (m_nextPage != null); + } - // block the CTabFolder from directly removing the tab - event.doit = false; + @Override + public BasicFormPage next() { + final BasicFormPage next = m_nextPage; + + m_nextPage = findNextPage(); - // remove the page properly - removePage(item.getParent().indexOf(item)); - } - } + return next; + } + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java new file mode 100644 index 0000000000000000000000000000000000000000..f9be7e21ccc63cdfcbbe3ed6997ba1ec1df765c5 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java @@ -0,0 +1,588 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.editor; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.DefaultTextHover; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextInputListener; +import org.eclipse.jface.text.ITextPresentationListener; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.JFaceTextUtil; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAEditorReadOnly; +import org.lamport.tla.toolbox.editor.basic.TLASourceViewerConfiguration; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; +import org.lamport.tla.toolbox.tool.tlc.TLCActivator; +import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.ModuleCoverageInformation; +import org.lamport.tla.toolbox.tool.tlc.output.data.Representation; +import org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.util.UIHelper; + +public class TLACoverageEditor extends TLAEditorReadOnly { + + static { + JFaceResources.getColorRegistry().put("LIGHT_GRAY", new RGB(245,245,245)); + JFaceResources.getColorRegistry().put("DARK_GRAY", new RGB(200,200,200)); + } + + private static final Color lightGray = JFaceResources.getColorRegistry().get("LIGHT_GRAY"); + private static final Color darkGray = JFaceResources.getColorRegistry().get("DARK_GRAY"); + + // Icon displayed left of the editor tab's name. + protected final Image coverageEditorImage = TLAEditorActivator + .imageDescriptorFromPlugin(TLCUIActivator.PLUGIN_ID, "/icons/full/report2_obj.gif").createImage(); + + private static class ResizeListener implements Listener { + + private final Point size = new Point(1024,768); + + @Override + public void handleEvent(final Event event) { + final Widget widget = event.widget; + if (widget instanceof Composite) { + final Composite c = (Composite) widget; + size.x = c.getSize().x; + size.y = c.getSize().y; + } + } + + public int getWidth() { + return size.x; + } + } + + /* TLACoverageEditor */ + + private final ResizeListener resizeListener = new ResizeListener(); + + private ModuleCoverageInformation coverage; + + private Composite heatMapComposite; + + private TLACoveragePainter painter; + + public TLACoverageEditor(final ModuleCoverageInformation coverage) { + this.coverage = coverage; + } + + @Override + public void dispose() { + painter.queue.offer(TERMINATE); + super.dispose(); + } + + @Override + protected ISourceViewer createSourceViewer(final Composite parent, IVerticalRuler ruler, int styles) { + // Create composite inside of parent (of which we don't control the layout) to + // place heatMap with a fixed height below the editor. + + final Composite composite = new Composite(parent, SWT.BORDER); + final GridLayout layout = new GridLayout(1, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + composite.setLayout(layout); + composite.addListener(SWT.Resize, resizeListener); + + // Inside editor use again a FillLayout to let super.create... use all available + // space. + final Composite editorComposite = new Composite(composite, SWT.NONE); + editorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + final FillLayout fillLayout = new FillLayout(SWT.VERTICAL); + fillLayout.marginHeight = 0; + fillLayout.marginWidth = 0; + fillLayout.spacing = 0; + editorComposite.setLayout(fillLayout); + + heatMapComposite = new Composite(composite, SWT.BORDER); + final GridData layoutData = new GridData(SWT.FILL, SWT.TOP, true, false); + heatMapComposite.setLayoutData(layoutData); + + // Inside of heatMap, use a horizontally FillLayout to place individuals heat + // map item next to each other. + heatMapComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + final ISourceViewer createSourceViewer = super.createSourceViewer(editorComposite, ruler, styles); + + // Make TLACoverageEditor distinguishable from regular TLAEditor. + final StyledText textWidget = createSourceViewer.getTextWidget(); + textWidget.setCursor(new Cursor(textWidget.getDisplay(), SWT.CURSOR_HAND)); + // Flash the editor on keystrokes as a form of a visual bell. + textWidget.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + // whitelist modifier keys to not flash on ctrl+click to navigate the spec. + if (e.keyCode == SWT.MOD1 || e.keyCode == SWT.MOD2 || e.keyCode == SWT.MOD3 || e.keyCode == SWT.MOD4) { + return; + } + textWidget.setBackground(darkGray); + } + @Override + public void keyReleased(KeyEvent e) { + if (e.keyCode == SWT.MOD1 || e.keyCode == SWT.MOD2 || e.keyCode == SWT.MOD3 || e.keyCode == SWT.MOD4) { + return; + } + textWidget.setBackground(lightGray); + } + }); + + return createSourceViewer; + } + + @Override + protected void initEditorNameAndDescription(final IEditorInput input) { + if (input instanceof FileEditorInput) { + final FileEditorInput fei = (FileEditorInput) input; + // Replace useless filename extension in tab title with read-only indicator. + this.setPartName(fei.getName().replaceFirst(".tla$", " (ro)")); + // Use dedicated image to distinguish from regular TLA editor. + this.setTitleImage(coverageEditorImage); + } else { + TLCActivator.logDebug("Unexpected input for TLACoverageEditor of type: " + input.getClass().getName()); + } + } + + @Override + protected boolean isEditorInputIncludedInContextMenu() { + // Exclude menu items from the editor's right-click context menu, contributed by + // the Eclipse foundation such as "Run As..." or "Debug As...". Those are + // completely bogus in the Toolbox's context and especially for the coverage + // editor. The crux is, that AbstractTextEditor sucks the contributions in and + // this seems to be the way to exclude them. + return false; + } + + @Override + protected TLASourceViewerConfiguration getTLASourceViewerConfiguration(IPreferenceStore preferenceStore) { + return new TLACoverageSourceViewerConfiguration(preferenceStore, this); + } + + @Override + protected SourceViewerDecorationSupport getSourceViewerDecorationSupport(ISourceViewer viewer) { + //TODO Initialize painter after editor input has been set. + painter = new TLACoveragePainter(this); + ((TextViewer) viewer).addTextPresentationListener(painter); + + return super.getSourceViewerDecorationSupport(viewer); + } + + public void resetInput(final ModuleCoverageInformation ci) throws PartInitException { + if (this.coverage == ci) { + // The CoverageInformation from which the FileCoverageInformation has been + // projected, is identical to the one already open. No need to update the ui. + // This case occurs when the TLCModelLaunchDataProvider parses the MC.out of a + // finished model with more than one block of coverage statistics. For each it + // notifies ResultPage but - due to TLCModelLaunchDataProvider sending strings + // instead of the actual values and threading - we read a newer/more up-to-date + // instance of CoverageInformation before a notification reaches us. + return; + } + this.coverage = ci; + // Trigger the editor's coverage painter. + painter.queue.offer(ALL); + } + + /* TLASourceViewerConfiguration */ + + private class TLACoverageSourceViewerConfiguration extends TLASourceViewerConfiguration { + + public TLACoverageSourceViewerConfiguration(IPreferenceStore preferenceStore, + TLAEditor tlaCoverageEditor) { + super(preferenceStore, tlaCoverageEditor); + } + + @Override + public ITextHover getTextHover(final ISourceViewer sourceViewer, String contentType) { + return new DefaultTextHover(sourceViewer) { + @Override + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + return coverage.getHoverInfo(hoverRegion.getOffset()); + } + }; + } + } + + private static final DecimalFormat df = new DecimalFormat("0.0E0"); + + private static class Pair { + public final int offset; + public final Representation rep; + + public Pair(int offset) { + this(offset, Representation.INV); + } + + public Pair(int offset, Representation rep) { + this.offset = offset; + this.rep = rep; + } + } + + private static final Pair ALL = new Pair(-1); + + private static final Pair TERMINATE = new Pair(-42); + + public class TLACoveragePainter implements ITextPresentationListener { + + private ComboViewer viewer; + + private final TLACoverageEditor editor; + + private final BlockingQueue<Pair> queue = new ArrayBlockingQueue<>(10); + + // Each module editor has a painter (system) job which serializes the + // paint/annotation requests. Requests are generated either by opening the + // editor, via editor selection changes or legend changes. Requests have + // to be serialized because ModuleCoverageInformation and its nested data + // structures are not thread-safe. Additional we try to minimize the requests + // by skipping redundant requests triggered by rapid mouse clicks. + private final Job painter = new Job("Coverage Painter") { + @Override + protected IStatus run(IProgressMonitor monitor) { + while (true) { + final Pair p = getPair(); + if (TERMINATE.offset == p.offset || monitor.isCanceled()) { + return Status.OK_STATUS; + } else { + monitor.beginTask(String.format("Painting coverage for %s", p.offset), 1); + } + + // Do not clear old style ranges before creating new ones as clear removes TLA+ syntax highlighting. + //textPresentation.clear(); + + final Grouping grouping = ALL.offset == p.offset ? Grouping.COMBINED : Grouping.INDIVIDUAL; + + // Create new style ranges (and the legend) + TreeSet<CoverageInformationItem> legend = new TreeSet<>(); + if (grouping == Grouping.COMBINED) { + coverage.getRoot().style(textPresentation, p.rep); + legend = coverage.getLegend(p.rep); + } else { + final CoverageInformationItem node = coverage.getNode(p.offset); + if (node != null) { + // Style all unrelated parts gray. + coverage.getRoot().style(textPresentation, JFaceResources.getColorRegistry().get(ModuleCoverageInformation.GRAY), p.rep); + + node.style(textPresentation, p.rep); + legend = node.getLegend(p.rep); + } + } + + if (monitor.isCanceled()) { + return Status.OK_STATUS; + } + + final Collection<CoverageInformationItem> fLegend = collapseLegend(legend); + UIHelper.runUISync(new Runnable() { + @Override + public void run() { + final TextViewer viewer = editor.getViewer(); + // viewer might have been disposed by the time the outer thread styled the presentation. + if (viewer == null || viewer.getTextWidget() == null + || viewer.getTextWidget().isDisposed()) { + return; + } + viewer.getTextWidget().removeListener(SWT.MouseDown, listener); + + viewer.changeTextPresentation(textPresentation, true); + updateLegend(fLegend, grouping); + + viewer.getTextWidget().addListener(SWT.MouseDown, listener); + } + }); + + monitor.done(); + } + } + + private Collection<CoverageInformationItem> collapseLegend(final TreeSet<CoverageInformationItem> legend) { + final double numLabel = resizeListener.getWidth() / 47d; // 47 pixel per label seems to fit most text and still looks pleasant. + if (legend.size() <= (int) Math.ceil(numLabel)) { + // can fit all elements, nothing to do. + return legend; + } + + // TODO Select a subset of legend of size numLabels s.t. the distance between + // any two elements in subset is maximized. The code below approximates the + // problem by simply constructing the subset where the distance is the position + // in the set not the actual value. In other words, the set of distances of all + // adjacent elements in the legend will be non-uniform. + + // Cannot fit more than N labels into the legend. Thus, only take N elements + // out of legend (even distribution). + final int nth = (int) Math.ceil(legend.size() / numLabel); + + // Add lowest/first CCI. + final List<CoverageInformationItem> result = new ArrayList<>((int)Math.ceil(numLabel)); + result.add(legend.first()); + + // Pick nth - 2 CCIs in-between. + int i = 1; + final Iterator<CoverageInformationItem> iterator = legend.iterator(); + while (iterator.hasNext()) { + final CoverageInformationItem cii = iterator.next(); + if (i++ % nth == 0) { + result.add(cii); + } + } + + // Add highest/last CCI from legend. + result.add(legend.last()); + return result; + } + + private Pair getPair() { + try { + return queue.take(); + } catch (InterruptedException notExpectedException) { + notExpectedException.printStackTrace(); + return TERMINATE; + } + } + + private void updateLegend(Collection<CoverageInformationItem> legend, final Representation.Grouping grouping) { + final Composite parent = heatMapComposite.getParent(); + if (legend.isEmpty()) { + heatMapComposite.setVisible(false); + } else { + final Representation currentRepresentation = getActiveRepresentation(); + heatMapComposite.dispose(); + + // Assume a spec with a Next action such as Next == (x' \in S) \/ (x' \in T) + // In other words, consider a spec where an action has sub-actions (disjuncts). + // If this is reported as COMBINED, the legend is bogus bc the value for Next + // appears twice (for the first and second disjunct) but the value is both + // times the combined one. + Representation.Grouping grpng = grouping; + if (currentRepresentation == Representation.STATES + || currentRepresentation == Representation.STATES_DISTINCT) { + grpng = Grouping.INDIVIDUAL; + } + + heatMapComposite = new Composite(parent, SWT.BORDER); + final GridData layoutData = new GridData(SWT.FILL, SWT.TOP, true, false); + heatMapComposite.setLayoutData(layoutData); + + // Inside of heatMap, use a horizontally FillLayout to place individuals heat + // map item next to each other. + heatMapComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + // Create the actual SWT labels for the elements in legend. + // TODO Rendering the text vertically would save horizontal screen estate but is + // unfortunately not easily possible with SWT. + for (CoverageInformationItem cii : legend) { + final Label label = new Label(heatMapComposite, SWT.BORDER); + label.setAlignment(SWT.CENTER); + + // A label has a background color and a text indicating the actual value + // (cost/invocations/...). + label.setBackground(currentRepresentation.getColor(cii, grpng)); + + final long value = currentRepresentation.getValue(cii, grpng); + // Format numbers > 1000 in scientific notation. + if (value > 1000) { + label.setText(df.format(value)); + } else { + label.setText(String.format("%,d", value)); + } + + // Indicate the location to where the mouse click takes the user. + label.setToolTipText(String.format(currentRepresentation.getToolTipText(), value, cii.getLocation())); + + // The mouse listener takes the user to the related + // region in the module. + label.addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(final MouseEvent e) { + final IRegion region = cii.getRegion(); + editor.selectAndReveal(region.getOffset(), cii.getRegion().getLength()); + } + }); + } + + // Show a drop-down list (combo) to let the user select a different representation. + viewer = new ComboViewer(heatMapComposite, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER | SWT.WRAP); + viewer.setContentProvider(ArrayContentProvider.getInstance()); + viewer.setLabelProvider(new LabelProvider() { + @Override + public String getText(Object element) { + if (element instanceof Representation) { + Representation current = (Representation) element; + return current.toString(); + } + return super.getText(element); + } + }); + + // Do not allow users to set the legend to states or distinct states if the + // module does not have values for these two representations. Otherwise, update + // legend will hide the legend (because legend is empty) without means to switch + // back (the buttons are hidden). + viewer.setInput(coverage.hasStates() ? Representation.values() : Representation.valuesNoStates()); + viewer.setSelection(new StructuredSelection(currentRepresentation)); + viewer.addSelectionChangedListener(event -> { + final IStructuredSelection selection = (IStructuredSelection) event.getSelection(); + final Representation rep = (Representation)selection.getFirstElement(); + final int offset = JFaceTextUtil.getOffsetForCursorLocation(editor.getViewer()); + queue.offer(new Pair(offset, rep)); + }); + } + parent.layout(); + } + }; + + private Representation getActiveRepresentation() { + if (viewer != null) { + final IStructuredSelection structuredSelection = viewer.getStructuredSelection(); + return (Representation) structuredSelection.getFirstElement(); + } + return Representation.INV; + } + + private final Listener listener = new Listener() { + @Override + public void handleEvent(final Event event) { + final Representation activeRepresentation = getActiveRepresentation(); + final int offset = JFaceTextUtil.getOffsetForCursorLocation(editor.getViewer()); + final Pair peek = queue.peek(); + final boolean isControlClick = ((event.stateMask & SWT.MOD1) != 0); + + if (isControlClick) { + editor.getViewer().getTextWidget().notifyListeners(SWT.MouseUp, null); + event.doit = false; + + final String moduleName = getModuleName() + ".tla"; + final TLAEditor editor = EditorUtil.openTLAEditor(moduleName); + + if (editor != null) { + editor.selectAndReveal(offset, 0); + } else { + TLCUIActivator.getDefault().logError("Unable to open editor for name: " + moduleName); + } + } else if ((peek == null) || (peek.offset != offset) || (peek.rep != activeRepresentation)) { +// System.out.println(String.format("Scheduling offset %s, %s after %s", offset, activeRepresentation, peek)); + queue.offer(new Pair(offset, activeRepresentation)); + } else { + //System.out.println("Skipping redundant offset " + offset); + } + } + }; + + private TextPresentation textPresentation; + + public TLACoveragePainter(TLACoverageEditor editor) { + this.editor = editor; + + this.painter.setPriority(Job.LONG); + this.painter.setRule(null); + this.painter.setSystem(true); + } + + @Override + public synchronized void applyTextPresentation(final TextPresentation textPresentation) { + // Set the background color down here instead of in createSourceViewer above + // where it is overridden by the OS's default background color. + editor.getSourceViewer().getTextWidget().setBackground(lightGray); + + // Unregister this to not rerun the initialization again. + editor.getViewer().removeTextPresentationListener(this); + + this.textPresentation = textPresentation; + + editor.getViewer().addTextInputListener(new ITextInputListener() { + @Override + public synchronized void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + editor.getViewer().removeTextInputListener(this); + + // Register listener to update coverage information based on mouse clicks. + final StyledText textWidget = editor.getViewer().getTextWidget(); + textWidget.addListener(SWT.MouseDown, listener); + + // Color the editor with coverage information initially. + queue.add(ALL); + painter.schedule(); + } + + @Override + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + } + }); + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/AdvancedModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/AdvancedModelPage.java deleted file mode 100644 index 207b803ade6d217a0cccd70df54e41b1f7c35e80..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/AdvancedModelPage.java +++ /dev/null @@ -1,1064 +0,0 @@ -package org.lamport.tla.toolbox.tool.tlc.ui.editor.page; - -import java.util.Arrays; -import java.util.Hashtable; -import java.util.List; -import java.util.Vector; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.source.SourceViewer; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Spinner; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.IMessageManager; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.lamport.tla.toolbox.tool.ToolboxHandle; -import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants; -import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationDefaults; -import org.lamport.tla.toolbox.tool.tlc.model.Assignment; -import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; -import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableOverridesSectionPart; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; -import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; -import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; -import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; -import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper; -import org.lamport.tla.toolbox.util.IHelpConstants; -import org.lamport.tla.toolbox.util.UIHelper; - -import tla2sany.modanalyzer.SpecObj; -import tla2sany.semantic.OpDefNode; -import tlc2.TLCGlobals; -import tlc2.tool.fp.FPSet; -import tlc2.tool.fp.MultiFPSet; - -/** - * Represent all advanced model elements - * - * @author Simon Zambrovski - */ -public class AdvancedModelPage extends BasicFormPage implements IConfigurationConstants, IConfigurationDefaults -{ - - public static final String ID = "advancedModelPage"; - - private SourceViewer constraintSource; - private SourceViewer actionConstraintSource; - private SourceViewer newDefinitionsSource; - private SourceViewer viewSource; - private SourceViewer modelValuesSource; - private Button dfidOption; - private Button mcOption; - private Button simulationOption; - private Button deferLiveness; - private Button visualizeStateGraph; - private Text dfidDepthText; - private Text simuDepthText; - private Text simuSeedText; - private Text simuArilText; - /** - * Offset for the -fp parameter passed to TLC process to select the hash seed - */ - private Spinner fpIndexSpinner; - /** - * -fpbits parameter designed to select how many fp bits are used for hash - * lookup - */ - private Spinner fpBits; - /** - * -maxSetSize input to set the upper bound of the TLA set - * @see Bug #264 in general/bugzilla/index.html - */ - private Spinner maxSetSize; - /** - * Text box to pass additional/extra JVM arguments/system properties to - * nested TLC java process. - */ - private Text extraVMArgumentsText; - /** - * Text box to pass additional/extra parameters to nested process. - */ - private Text extraTLCParametersText; - - private TableViewer definitionsTable; - - /** - * Constructs the page - * - * @param editor - */ - public AdvancedModelPage(FormEditor editor) - { - super(editor, AdvancedModelPage.ID, "Advanced Options"); - this.helpId = IHelpConstants.ADVANCED_MODEL_PAGE; - this.imagePath = "icons/full/choice_sc_obj.gif"; - } - - /** - * Loads data from the model - */ - protected void loadData() throws CoreException - { - // definition overrides - List<String> definitions = getModel().getAttribute(MODEL_PARAMETER_DEFINITIONS, new Vector<String>()); - FormHelper.setSerializedInput(definitionsTable, definitions); - - // new definitions - String newDefinitions = getModel().getAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, EMPTY_STRING); - newDefinitionsSource.setDocument(new Document(newDefinitions)); - - // advanced model values - String modelValues = getModel().getAttribute(MODEL_PARAMETER_MODEL_VALUES, EMPTY_STRING); - modelValuesSource.setDocument(new Document(modelValues)); - - // constraint - String constraint = getModel().getAttribute(MODEL_PARAMETER_CONSTRAINT, EMPTY_STRING); - constraintSource.setDocument(new Document(constraint)); - - // view - String view = getModel().getAttribute(LAUNCH_VIEW, EMPTY_STRING); - viewSource.setDocument(new Document(view)); - - // action constraint - String actionConstraint = getModel().getAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, EMPTY_STRING); - actionConstraintSource.setDocument(new Document(actionConstraint)); - - // run mode mode - boolean isMCMode = getModel().getAttribute(LAUNCH_MC_MODE, LAUNCH_MC_MODE_DEFAULT); - mcOption.setSelection(isMCMode); - simulationOption.setSelection(!isMCMode); - - // DFID mode - boolean isDFIDMode = getModel().getAttribute(LAUNCH_DFID_MODE, LAUNCH_DFID_MODE_DEFAULT); - dfidOption.setSelection(isDFIDMode); - - // DFID depth - int dfidDepth = getModel().getAttribute(LAUNCH_DFID_DEPTH, LAUNCH_DFID_DEPTH_DEFAULT); - dfidDepthText.setText("" + dfidDepth); - - // simulation depth - int simuDepth = getModel().getAttribute(LAUNCH_SIMU_DEPTH, LAUNCH_SIMU_DEPTH_DEFAULT); - simuDepthText.setText("" + simuDepth); - - // simulation aril - int simuAril = getModel().getAttribute(LAUNCH_SIMU_SEED, LAUNCH_SIMU_ARIL_DEFAULT); - if (LAUNCH_SIMU_ARIL_DEFAULT != simuAril) - { - simuArilText.setText("" + simuAril); - } else - { - simuArilText.setText(""); - } - - // simulation seed - int simuSeed = getModel().getAttribute(LAUNCH_SIMU_ARIL, LAUNCH_SIMU_SEED_DEFAULT); - if (LAUNCH_SIMU_SEED_DEFAULT != simuSeed) - { - simuSeedText.setText("" + simuSeed); - } else - { - simuSeedText.setText(""); - } - - // Defer Liveness - deferLiveness.setSelection(getModel().getAttribute(LAUNCH_DEFER_LIVENESS, LAUNCH_DEFER_LIVENESS_DEFAULT)); - - // fp index - final int fpIndex = getModel().getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); - fpIndexSpinner.setSelection(fpIndex); - - // fpBits - int defaultFPBits = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT); - fpBits.setSelection(getModel().getAttribute(LAUNCH_FPBITS, defaultFPBits)); - - // maxSetSize - int defaultMaxSetSize = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_MAXSETSIZE_DEFAULT); - maxSetSize.setSelection(getModel().getAttribute(LAUNCH_MAXSETSIZE, defaultMaxSetSize)); - - // visualize state graph - visualizeStateGraph.setSelection(getModel().getAttribute(LAUNCH_VISUALIZE_STATEGRAPH, LAUNCH_VISUALIZE_STATEGRAPH_DEFAULT)); - - // Extra JVM arguments and system properties - final String vmArgs = getModel().getAttribute(LAUNCH_JVM_ARGS, LAUNCH_JVM_ARGS_DEFAULT); - this.extraVMArgumentsText.setText(vmArgs); - - // Extra JVM arguments and system properties - final String tlcParameters = getModel().getAttribute(LAUNCH_TLC_PARAMETERS, LAUNCH_TLC_PARAMETERS_DEFAULT); - this.extraTLCParametersText.setText(tlcParameters); - } - - /** - * Save data back to config - */ - public void commit(boolean onSave) - { - // TLCUIActivator.getDefault().logDebug("Advanced page commit"); - - boolean isMCMode = mcOption.getSelection(); - getModel().setAttribute(LAUNCH_MC_MODE, isMCMode); - - // DFID mode - boolean isDFIDMode = dfidOption.getSelection(); - getModel().setAttribute(LAUNCH_DFID_MODE, isDFIDMode); - - int dfidDepth = Integer.parseInt(dfidDepthText.getText()); - int simuDepth = Integer.parseInt(simuDepthText.getText()); - int simuAril = LAUNCH_SIMU_ARIL_DEFAULT; - int simuSeed = LAUNCH_SIMU_SEED_DEFAULT; - - if (!"".equals(simuArilText.getText())) - { - simuAril = Integer.parseInt(simuArilText.getText()); - } - if (!"".equals(simuSeedText.getText())) - { - simuSeed = Integer.parseInt(simuSeedText.getText()); - } - - // DFID depth - getModel().setAttribute(LAUNCH_DFID_DEPTH, dfidDepth); - // simulation depth - getModel().setAttribute(LAUNCH_SIMU_DEPTH, simuDepth); - // simulation aril - getModel().setAttribute(LAUNCH_SIMU_SEED, simuSeed); - // simulation seed - getModel().setAttribute(LAUNCH_SIMU_ARIL, simuAril); - - // Defer Liveness - getModel().setAttribute(LAUNCH_DEFER_LIVENESS, deferLiveness.getSelection()); - - // FP Seed index - getModel().setAttribute(LAUNCH_FP_INDEX, fpIndexSpinner.getSelection()); - - // fpBits - getModel().setAttribute(LAUNCH_FPBITS, fpBits.getSelection()); - - // fpBits - getModel().setAttribute(LAUNCH_MAXSETSIZE, maxSetSize.getSelection()); - - // Visualize State Graph - getModel().setAttribute(LAUNCH_VISUALIZE_STATEGRAPH, visualizeStateGraph.getSelection()); - - // definitions - List<String> definitions = FormHelper.getSerializedInput(definitionsTable); - getModel().setAttribute(MODEL_PARAMETER_DEFINITIONS, definitions); - - // new definitions - String newDefinitions = FormHelper.trimTrailingSpaces(newDefinitionsSource.getDocument().get()); - getModel().setAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, newDefinitions); - - // model values - String modelValues = FormHelper.trimTrailingSpaces(modelValuesSource.getDocument().get()); - TypedSet modelValuesSet = TypedSet.parseSet(modelValues); - getModel().setAttribute(MODEL_PARAMETER_MODEL_VALUES, modelValuesSet.toString()); - - // constraint formula - String constraintFormula = FormHelper.trimTrailingSpaces(constraintSource.getDocument().get()); - getModel().setAttribute(MODEL_PARAMETER_CONSTRAINT, constraintFormula); - - // view - String viewFormula = FormHelper.trimTrailingSpaces(viewSource.getDocument().get()); - getModel().setAttribute(LAUNCH_VIEW, viewFormula); - - // action constraint formula - String actionConstraintFormula = FormHelper.trimTrailingSpaces(actionConstraintSource.getDocument().get()); - getModel().setAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, actionConstraintFormula); - - // extra vm arguments (replace newlines which otherwise cause the - // process to ignore all args except the first one) - final String vmArgs = this.extraVMArgumentsText.getText().replace("\r\n", " ").replace("\n", " "); - getModel().setAttribute(LAUNCH_JVM_ARGS, vmArgs); - - // extra tlc parameters - final String tlcParameters = this.extraTLCParametersText.getText(); - getModel().setAttribute(LAUNCH_TLC_PARAMETERS, tlcParameters); - - super.commit(onSave); - } - - /** - * - */ - public void validatePage(boolean switchToErrorPage) - { - if (getManagedForm() == null) - { - return; - } - IMessageManager mm = getManagedForm().getMessageManager(); - mm.setAutoUpdate(false); - - ModelEditor modelEditor = (ModelEditor) getEditor(); - - // clean old messages - // this is now done in validateRunnable of - // ModelEditor - // mm.removeAllMessages(); - // make the run possible - setComplete(true); - - // setup the names from the current page - getLookupHelper().resetModelNames(this); - - try - { - int dfidDepth = Integer.parseInt(dfidDepthText.getText()); - if (dfidDepth <= 0) - { - modelEditor.addErrorMessage("dfid1", "Depth of DFID launch must be a positive integer", this.getId(), - IMessageProvider.ERROR, dfidDepthText); - setComplete(false); - expandSection(SEC_LAUNCHING_SETUP); - } - else { - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("dfid1", dfidDepthText); - } - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("dfid2", dfidDepthText); - } catch (NumberFormatException e) - { - modelEditor.addErrorMessage("dfid2", "Depth of DFID launch must be a positive integer", this.getId(), - IMessageProvider.ERROR, dfidDepthText); - setComplete(false); - expandSection(SEC_LAUNCHING_SETUP); - } - try - { - int simuDepth = Integer.parseInt(simuDepthText.getText()); - if (simuDepth <= 0) - { - modelEditor.addErrorMessage("simuDepth1", "Length of the simulation tracemust be a positive integer", - this.getId(), IMessageProvider.ERROR, simuDepthText); - setComplete(false); - expandSection(SEC_LAUNCHING_SETUP); - } - else { - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("simuDepth1", simuDepthText); - } - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("simuDepth2", simuDepthText); - } catch (NumberFormatException e) - { - modelEditor.addErrorMessage("simuDepth2", "Length of the simulation trace must be a positive integer", this - .getId(), IMessageProvider.ERROR, simuDepthText); - setComplete(false); - expandSection(SEC_LAUNCHING_SETUP); - } - if (!EMPTY_STRING.equals(simuArilText.getText())) - { - try - { - long simuAril = Long.parseLong(simuArilText.getText()); - if (simuAril <= 0) - { - modelEditor.addErrorMessage("simuAril1", "The simulation aril must be a positive integer", this - .getId(), IMessageProvider.ERROR, simuArilText); - setComplete(false); - } - else { - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("simuAril1", simuArilText); - } - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("simuAril2", simuArilText); - } catch (NumberFormatException e) - { - modelEditor.addErrorMessage("simuAril2", "The simulation aril must be a positive integer", - this.getId(), IMessageProvider.ERROR, simuArilText); - setComplete(false); - expandSection(SEC_LAUNCHING_SETUP); - } - } - if (!EMPTY_STRING.equals(simuSeedText.getText())) - { - try - { - // long simuSeed = - Long.parseLong(simuSeedText.getText()); - // Call of removeErrorMessage added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage("simuSeed1", simuSeedText); - - } catch (NumberFormatException e) - { - modelEditor.addErrorMessage("simuSeed1", "The simulation aril must be a positive integer", - this.getId(), IMessageProvider.ERROR, simuSeedText); - expandSection(SEC_LAUNCHING_SETUP); - setComplete(false); - } - } - - // get data binding manager - DataBindingManager dm = getDataBindingManager(); - - // check the model values - TypedSet modelValuesSet = TypedSet.parseSet(FormHelper - .trimTrailingSpaces(modelValuesSource.getDocument().get())); - if (modelValuesSet.getValueCount() > 0) - { - // there were values defined - - // check if those are numbers? - /* - * if (modelValuesSet.hasANumberOnlyValue()) { - * mm.addMessage("modelValues1", - * "A model value can not be an number", modelValuesSet, - * IMessageProvider.ERROR, modelValuesSource.getControl()); - * setComplete(false); } - */ - List<String> values = modelValuesSet.getValuesAsList(); - // check list of model values if these are already used - validateUsage(MODEL_PARAMETER_MODEL_VALUES, values, "modelValues2_", "A model value", - "Advanced Model Values", true); - // check whether the model values are valid ids - validateId(MODEL_PARAMETER_MODEL_VALUES, values, "modelValues2_", "A model value"); - - // get widget for model values - Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_MODEL_VALUES)); - - // check if model values are config file keywords - for (int j = 0; j < values.size(); j++) - { - String value = (String) values.get(j); - if (SemanticHelper.isConfigFileKeyword(value)) - { - modelEditor.addErrorMessage(value, "The toolbox cannot handle the model value " + value + ".", this - .getId(), IMessageProvider.ERROR, widget); - setComplete(false); - } -// else { -// // Call of removeErrorMessage added by LL on 21 Mar 2013 -// // However, it did nothing because the value argument is a string - // currently in the field, which is not going to be the one that - // caused any existing error message. -// modelEditor.removeErrorMessage(value, widget); -// } - } - - } - - // opDefNodes necessary for determining if a definition in definition - // overrides is still in the specification - SpecObj specObj = ToolboxHandle.getCurrentSpec().getValidRootModule(); - OpDefNode[] opDefNodes = null; - if (specObj != null) - { - opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs(); - } - Hashtable<String, OpDefNode> nodeTable = new Hashtable<String, OpDefNode>(); - - if (opDefNodes != null) - { - for (int j = 0; j < opDefNodes.length; j++) - { - String key = opDefNodes[j].getName().toString(); - nodeTable.put(key, opDefNodes[j]); - } - } - - // get widget for definition overrides - Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_DEFINITIONS)); - // check the definition overrides - @SuppressWarnings("unchecked") - List<Assignment> definitions = (List<Assignment>) definitionsTable.getInput(); - - for (int i = 0; i < definitions.size(); i++) - { - Assignment definition = definitions.get(i); - List<String> values = Arrays.asList(definition.getParams()); - // check list of parameters - validateUsage(MODEL_PARAMETER_DEFINITIONS, values, "param1_", "A parameter name", "Definition Overrides", - false); - // check whether the parameters are valid ids - validateId(MODEL_PARAMETER_DEFINITIONS, values, "param1_", "A parameter name"); - - // The following if test was added by LL on 11 Nov 2009 to prevent an unparsed - // file from producing bogus error messages saying that overridden definitions - // have been removed from the spec. - if (opDefNodes != null) - { - // Note added by LL on 21 Mar 2013: We do not remove error messages - // for overridden definitions that are set by this code because doing so - // may remove error messages set for these definitions by checks elsewhere - // in the code. - - // check if definition still appears in root module - if (!nodeTable.containsKey(definition.getLabel())) - { - // the following would remove - // the definition override from the table - // right now, an error message appears instead - // definitions.remove(i); - // definitionsTable.setInput(definitions); - // dm.getSection(DEF_OVERRIDES_PART).markDirty(); - modelEditor.addErrorMessage(definition.getLabel(), "The defined symbol " - + definition.getLabel().substring(definition.getLabel().lastIndexOf("!") + 1) - + " has been removed from the specification." - + " It must be removed from the list of definition overrides.", this.getId(), - IMessageProvider.ERROR, widget); - setComplete(false); - } else - { - // add error message if the number of parameters has changed - OpDefNode opDefNode = (OpDefNode) nodeTable.get(definition.getLabel()); - if (opDefNode.getSource().getNumberOfArgs() != definition.getParams().length) - { - modelEditor.addErrorMessage(definition.getLabel(), "Edit the definition override for " - + opDefNode.getSource().getName() + " to match the correct number of arguments.", this - .getId(), IMessageProvider.ERROR, widget); - setComplete(false); - } - } - } - } - for (int j = 0; j < definitions.size(); j++) - { - Assignment definition = (Assignment) definitions.get(j); - String label = definition.getLabel(); - if (SemanticHelper.isConfigFileKeyword(label)) - { - modelEditor.addErrorMessage(label, "The toolbox cannot override the definition of " + label - + " because it is a configuration file keyword.", this.getId(), IMessageProvider.ERROR, widget); - setComplete(false); - } - } - - // check if the view field contains a cfg file keyword - Control viewWidget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_VIEW)); - String viewString = FormHelper.trimTrailingSpaces(viewSource.getDocument().get()); - if (SemanticHelper.containsConfigFileKeyword(viewString)) - { - modelEditor.addErrorMessage(viewString, "The toolbox cannot handle the string " + viewString - + " because it contains a configuration file keyword.", this.getId(), IMessageProvider.ERROR, - viewWidget); - setComplete(false); - } - - mm.setAutoUpdate(true); - - - - // fpBits - if (!FPSet.isValid(fpBits.getSelection())) - { - modelEditor.addErrorMessage("wrongNumber3", "fpbits must be a positive integer number smaller than 31", this - .getId(), IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(LAUNCH_FPBITS))); - setComplete(false); - expandSection(SEC_HOW_TO_RUN); - } -// else { -// // Call of removeErrorMessage added by LL on 21 Mar 2013 -// // However, it seems to be a no-op because you can't enter an illegal -// // value into the widget. I've commented this out in case it has some -// // unknown evil side effects. -// modelEditor.removeErrorMessage("wrongNumber3", -// UIHelper.getWidget(dm.getAttributeControl(LAUNCH_FPBITS))); -// } - - // maxSetSize - if (!TLCGlobals.isValidSetSize(maxSetSize.getSelection())) - { - modelEditor.addErrorMessage("wrongNumber3", "maxSetSize must be a positive integer number", this - .getId(), IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(LAUNCH_MAXSETSIZE))); - setComplete(false); - expandSection(SEC_HOW_TO_RUN); - } -// else { -// // Call of removeErrorMessage added by LL on 21 Mar 2013 -// // However, it seems to be a no-op because you can't enter an illegal -// // value into the widget, so this was all commented out. -// modelEditor.removeErrorMessage("wrongNumber3", -// UIHelper.getWidget(dm.getAttributeControl(LAUNCH_MAXSETSIZE))); -// } - - super.validatePage(switchToErrorPage); - } - - /** - * Creates the UI - * - * Its helpful to know what the standard SWT widgets look like. - * Pictures can be found at http://www.eclipse.org/swt/widgets/ - * - * Layouts are used throughout this method. - * A good explanation of layouts is given in the article - * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html - */ - protected void createBodyContent(IManagedForm managedForm) - { - - DataBindingManager dm = getDataBindingManager(); - int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE; - - FormToolkit toolkit = managedForm.getToolkit(); - Composite body = managedForm.getForm().getBody(); - - GridData gd; - TableWrapData twd; - - // left - Composite left = toolkit.createComposite(body); - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.grabHorizontal = true; - left.setLayout(new GridLayout(1, false)); - left.setLayoutData(twd); - - // right - Composite right = toolkit.createComposite(body); - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.grabHorizontal = true; - right.setLayoutData(twd); - right.setLayout(new GridLayout(1, false)); - - Section section; - - // --------------------------------------------------------------- - // new definitions - - section = FormHelper - .createSectionComposite( - left, - "Additional Definitions", - "Definitions required for the model checking, in addition to the definitions in the specification modules.", - toolkit, sectionFlags, getExpansionListener()); - ValidateableSectionPart newDefinitionsPart = new ValidateableSectionPart(section, this, SEC_NEW_DEFINITION); - managedForm.addPart(newDefinitionsPart); - DirtyMarkingListener newDefinitionsListener = new DirtyMarkingListener(newDefinitionsPart, true); - - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 3; - section.setLayoutData(gd); - - Composite newDefinitionsArea = (Composite) section.getClient(); - newDefinitionsSource = FormHelper.createFormsSourceViewer(toolkit, newDefinitionsArea, SWT.V_SCROLL); - // layout of the source viewer - twd = new TableWrapData(TableWrapData.FILL); - twd.heightHint = 60; - twd.grabHorizontal = true; - newDefinitionsSource.getTextWidget().setLayoutData(twd); - newDefinitionsSource.addTextListener(newDefinitionsListener); - newDefinitionsSource.getTextWidget().addFocusListener(focusListener); - - dm.bindAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, newDefinitionsSource, newDefinitionsPart); - - // --------------------------------------------------------------- - // definition overwrite - // Change added by LL on 10 April 2011 to cause model page to be created with the - // definitions override section open iff there are overridden definitions. This is - // done so the user will be aware of automatically generated overrides. - // - int expand = 0; - try - { - List<String> definitions = getModel().getAttribute(MODEL_PARAMETER_DEFINITIONS, new Vector<String>()); - if ((definitions != null) && (definitions.size() != 0)) { - expand = Section.EXPANDED; - } - } catch (CoreException e) - { - // Just ignore this since I have no idea what an exception might mean. - } - - ValidateableOverridesSectionPart definitionsPart = new ValidateableOverridesSectionPart(right, - "Definition Override", "Directs TLC to use alternate definitions for operators.", toolkit, - sectionFlags | expand, this); - - managedForm.addPart(definitionsPart); - // layout - gd = new GridData(GridData.FILL_HORIZONTAL); - definitionsPart.getSection().setLayoutData(gd); - gd = new GridData(GridData.FILL_BOTH); - gd.widthHint = 100; - gd.verticalSpan = 3; - definitionsPart.getTableViewer().getTable().setLayoutData(gd); - definitionsTable = definitionsPart.getTableViewer(); - dm.bindAttribute(MODEL_PARAMETER_DEFINITIONS, definitionsTable, definitionsPart); - - // --------------------------------------------------------------- - // constraint - section = FormHelper.createSectionComposite(left, "State Constraint", - "A state constraint is a formula restricting the possible states by a state predicate.", toolkit, - sectionFlags, getExpansionListener()); - ValidateableSectionPart constraintPart = new ValidateableSectionPart(section, this, SEC_STATE_CONSTRAINT); - managedForm.addPart(constraintPart); - DirtyMarkingListener constraintListener = new DirtyMarkingListener(constraintPart, true); - - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 3; - section.setLayoutData(gd); - - Composite constraintArea = (Composite) section.getClient(); - constraintSource = FormHelper.createFormsSourceViewer(toolkit, constraintArea, SWT.V_SCROLL); - // layout of the source viewer - twd = new TableWrapData(TableWrapData.FILL); - twd.heightHint = 60; - twd.grabHorizontal = true; - constraintSource.getTextWidget().setLayoutData(twd); - constraintSource.addTextListener(constraintListener); - constraintSource.getTextWidget().addFocusListener(focusListener); - dm.bindAttribute(MODEL_PARAMETER_CONSTRAINT, constraintSource, constraintPart); - - // --------------------------------------------------------------- - // action constraint - section = FormHelper.createSectionComposite(right, "Action Constraint", - "An action constraint is a formula restricting the possible transitions.", toolkit, sectionFlags, - getExpansionListener()); - ValidateableSectionPart actionConstraintPart = new ValidateableSectionPart(section, this, SEC_ACTION_CONSTRAINT); - managedForm.addPart(actionConstraintPart); - DirtyMarkingListener actionConstraintListener = new DirtyMarkingListener(actionConstraintPart, true); - - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 3; - section.setLayoutData(gd); - - Composite actionConstraintArea = (Composite) section.getClient(); - actionConstraintSource = FormHelper.createFormsSourceViewer(toolkit, actionConstraintArea, SWT.V_SCROLL); - // layout of the source viewer - twd = new TableWrapData(TableWrapData.FILL); - twd.heightHint = 60; - twd.grabHorizontal = true; - actionConstraintSource.getTextWidget().setLayoutData(twd); - actionConstraintSource.addTextListener(actionConstraintListener); - actionConstraintSource.getTextWidget().addFocusListener(focusListener); - dm.bindAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, actionConstraintSource, actionConstraintPart); - - // --------------------------------------------------------------- - // modelValues - section = FormHelper.createSectionComposite(left, "Model Values", "An additional set of model values.", - toolkit, sectionFlags, getExpansionListener()); - ValidateableSectionPart modelValuesPart = new ValidateableSectionPart(section, this, SEC_MODEL_VALUES); - managedForm.addPart(modelValuesPart); - DirtyMarkingListener modelValuesListener = new DirtyMarkingListener(modelValuesPart, true); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 3; - section.setLayoutData(gd); - - Composite modelValueArea = (Composite) section.getClient(); - modelValuesSource = FormHelper.createFormsSourceViewer(toolkit, modelValueArea, SWT.V_SCROLL); - // layout of the source viewer - twd = new TableWrapData(TableWrapData.FILL); - twd.heightHint = 60; - twd.grabHorizontal = true; - modelValuesSource.getTextWidget().setLayoutData(twd); - modelValuesSource.addTextListener(modelValuesListener); - modelValuesSource.getTextWidget().addFocusListener(focusListener); - dm.bindAttribute(MODEL_PARAMETER_MODEL_VALUES, modelValuesSource, modelValuesPart); - - // --------------------------------------------------------------- - // launch - section = createAdvancedLaunchSection(toolkit, right, sectionFlags); - ValidateableSectionPart launchPart = new ValidateableSectionPart(section, this, SEC_LAUNCHING_SETUP); - managedForm.addPart(launchPart); - DirtyMarkingListener launchListener = new DirtyMarkingListener(launchPart, true); - dm.bindAttribute(MODEL_PARAMETER_VIEW, viewSource, launchPart); - - // dirty listeners - simuArilText.addModifyListener(launchListener); - simuSeedText.addModifyListener(launchListener); - simuDepthText.addModifyListener(launchListener); - fpIndexSpinner.addModifyListener(launchListener); - fpBits.addModifyListener(launchListener); - maxSetSize.addModifyListener(launchListener); - dfidDepthText.addModifyListener(launchListener); - simulationOption.addSelectionListener(launchListener); - deferLiveness.addSelectionListener(launchListener); - dfidOption.addSelectionListener(launchListener); - mcOption.addSelectionListener(launchListener); - viewSource.addTextListener(launchListener); - visualizeStateGraph.addSelectionListener(launchListener); - extraTLCParametersText.addModifyListener(launchListener); - extraVMArgumentsText.addModifyListener(launchListener); - - // add section ignoring listeners - dirtyPartListeners.add(newDefinitionsListener); - dirtyPartListeners.add(actionConstraintListener); - dirtyPartListeners.add(modelValuesListener); - dirtyPartListeners.add(constraintListener); - dirtyPartListeners.add(launchListener); - } - - /** - * @param toolkit - * @param parent - * @param flags - */ - private Section createAdvancedLaunchSection(FormToolkit toolkit, Composite parent, int sectionFlags) - { - GridData gd; - - // advanced section - Section advancedSection = FormHelper.createSectionComposite(parent, "TLC Options", - "Advanced settings of the TLC model checker", toolkit, sectionFlags, getExpansionListener()); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - gd.grabExcessHorizontalSpace = true; - advancedSection.setLayoutData(gd); - - Composite area = (Composite) advancedSection.getClient(); - area.setLayout(new GridLayout(2, false)); - -// // label fp -// Label fpLabel = toolkit.createLabel(area, "Fingerprint seed index:"); -// fpLabel.setText(, false, false); -// gd = new GridData(); -// gd.horizontalIndent = 10; -// fpLabel.setLayoutData(gd); -// -// // field fpIndex -// fpIndexSpinner = new Spinner(area, SWT.NONE); -// fpIndexSpinner.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); -// fpIndexSpinner.setToolTipText("Index of irreducible polynominal used as a seed for fingerprint hashing (corresponds to \"-fp value-1\")"); -// gd = new GridData(); -// gd.widthHint = 200; -// fpIndexSpinner.setLayoutData(gd); -// -// // validation for fpIndex spinner -// fpIndexSpinner.setMinimum(1); -// fpIndexSpinner.setMaximum(64); -// -// fpIndexSpinner.addFocusListener(focusListener); - - // Model checking mode - mcOption = toolkit.createButton(area, "Model-checking mode", SWT.RADIO); - gd = new GridData(); - gd.horizontalSpan = 2; - mcOption.setLayoutData(gd); - - // label view - Label viewLabel = toolkit.createLabel(area, "View:"); - gd = new GridData(); - gd.verticalAlignment = SWT.BEGINNING; - gd.horizontalIndent = 10; - viewLabel.setLayoutData(gd); - // field view - viewSource = FormHelper.createFormsSourceViewer(toolkit, area, SWT.V_SCROLL); - // layout of the source viewer - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.grabExcessHorizontalSpace = true; - gd.heightHint = 60; - gd.widthHint = 200; - viewSource.getTextWidget().setLayoutData(gd); - - dfidOption = toolkit.createButton(area, "Depth-first", SWT.CHECK); - gd = new GridData(); - gd.horizontalSpan = 2; - gd.horizontalIndent = 10; - dfidOption.setLayoutData(gd); - // label depth - Label dfidDepthLabel = toolkit.createLabel(area, "Depth:"); - gd = new GridData(); - gd.horizontalIndent = 10; - dfidDepthLabel.setLayoutData(gd); - // field depth - dfidDepthText = toolkit.createText(area, "100"); - gd = new GridData(); - gd.widthHint = 100; - dfidDepthText.setLayoutData(gd); - dfidDepthText.addFocusListener(focusListener); - - simulationOption = toolkit.createButton(area, "Simulation mode", SWT.RADIO); - gd = new GridData(); - gd.horizontalSpan = 2; - simulationOption.setLayoutData(gd); - simulationOption.addFocusListener(focusListener); - - // label depth - Label depthLabel = toolkit.createLabel(area, "Maximum length of the trace:"); - gd = new GridData(); - gd.horizontalIndent = 10; - depthLabel.setLayoutData(gd); - // field depth - simuDepthText = toolkit.createText(area, "100"); - gd = new GridData(); - gd.widthHint = 100; - simuDepthText.setLayoutData(gd); - simuDepthText.addFocusListener(focusListener); - - // label seed - Label seedLabel = toolkit.createLabel(area, "Seed:"); - gd = new GridData(); - gd.horizontalIndent = 10; - seedLabel.setLayoutData(gd); - - // field seed - simuSeedText = toolkit.createText(area, ""); - gd = new GridData(); - gd.widthHint = 200; - simuSeedText.setLayoutData(gd); - simuSeedText.addFocusListener(focusListener); - - // label seed - Label arilLabel = toolkit.createLabel(area, "Aril:"); - gd = new GridData(); - gd.horizontalIndent = 10; - arilLabel.setLayoutData(gd); - - // field seed - simuArilText = toolkit.createText(area, ""); - gd = new GridData(); - gd.widthHint = 200; - simuArilText.setLayoutData(gd); - simuArilText.addFocusListener(focusListener); - - // add horizontal divider that makes the separation clear - toolkit.createSeparator(area, SWT.HORIZONTAL); - // add empty composite to make the two column grid layout happy - toolkit.createComposite(area); - - // label deferred liveness checking - final String deferLivenessHelp = "Defer verification of temporal properties (liveness) to the end of model checking" - + " to reduce overall model checking time. Liveness violations will be found late compared to invariant " - + "violations. In other words check liveness only once on the complete state space."; - Label deferLivenessLabel = toolkit.createLabel(area, "Verify temporal properties upon termination only:"); - gd = new GridData(); - gd.horizontalIndent = 0; - deferLivenessLabel.setLayoutData(gd); - deferLivenessLabel.setToolTipText(deferLivenessHelp); - - deferLiveness = toolkit.createButton(area, "", SWT.CHECK); - gd = new GridData(); - gd.widthHint = 200; - gd.verticalIndent = 20; - gd.horizontalIndent = 0; - deferLiveness.addFocusListener(focusListener); - deferLiveness.setToolTipText(deferLivenessHelp); - - // label fp - Label fpLabel = toolkit.createLabel(area, "Fingerprint seed index:"); - gd = new GridData(); - gd.horizontalIndent = 0; - fpLabel.setLayoutData(gd); - - // field fpIndex - fpIndexSpinner = new Spinner(area, SWT.NONE); - fpIndexSpinner.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); - fpIndexSpinner.setToolTipText("Index of irreducible polynominal used as a seed for fingerprint hashing (corresponds to \"-fp value-1\")"); - gd = new GridData(); - gd.widthHint = 200; - gd.verticalIndent = 20; - gd.horizontalIndent = 0; - fpIndexSpinner.setLayoutData(gd); - - // validation for fpIndex spinner - fpIndexSpinner.setMinimum(1); - fpIndexSpinner.setMaximum(64); - - fpIndexSpinner.addFocusListener(focusListener); - - // fpbits label - Label fpBitsLabel = toolkit.createLabel(area, "Log base 2 of number of disk storage files:"); - gd = new GridData(); - gd.horizontalIndent = 0; - fpBitsLabel.setLayoutData(gd); - - // fpbits spinner - fpBits = new Spinner(area, SWT.NONE); - fpBits.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); - fpBits.addFocusListener(focusListener); - gd = new GridData(); - gd.widthHint = 200; - gd.verticalIndent = 20; - gd.horizontalIndent = 0; - fpBits.setLayoutData(gd); - - fpBits.setMinimum(MultiFPSet.MIN_FPBITS); - fpBits.setMaximum(MultiFPSet.MAX_FPBITS); - - int defaultFPBits = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT); - fpBits.setSelection(defaultFPBits); - - // maxSetSize label - Label maxSetSizeLabel = toolkit.createLabel(area, "Cardinality of largest enumerable set:"); - gd = new GridData(); - gd.horizontalIndent = 0; - maxSetSizeLabel.setLayoutData(gd); - - // maxSetSize spinner - maxSetSize = new Spinner(area, SWT.NONE); - maxSetSize.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); - maxSetSize.addFocusListener(focusListener); - gd = new GridData(); - gd.widthHint = 200; - gd.verticalIndent = 20; - gd.horizontalIndent = 0; - maxSetSize.setLayoutData(gd); - - maxSetSize.setMinimum(1); - maxSetSize.setMaximum(Integer.MAX_VALUE); - - int defaultMaxSetSize = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_MAXSETSIZE_DEFAULT); - maxSetSize.setSelection(defaultMaxSetSize); - - // Visualize State Graph with GraphViz (dot) - final String visualizeStateGraphHelp = "Draw the state graph after completion of model checking provided the " - + "state graph is sufficiently small (cannot handle more than a few dozen states and slows down model checking)."; - Label visualizeStateGraphLabel = toolkit.createLabel(area, "Visualize state graph after completion of model checking:"); - gd = new GridData(); - gd.horizontalIndent = 0; - visualizeStateGraphLabel.setLayoutData(gd); - visualizeStateGraphLabel.setToolTipText(visualizeStateGraphHelp); - - visualizeStateGraph = toolkit.createButton(area, "", SWT.CHECK); - gd = new GridData(); - gd.widthHint = 200; - gd.verticalIndent = 20; - gd.horizontalIndent = 0; - visualizeStateGraph.addFocusListener(focusListener); - visualizeStateGraph.setToolTipText(visualizeStateGraphHelp); - - // Extra/Additional VM arguments and system properties - toolkit.createLabel(area, "JVM arguments:"); - - extraVMArgumentsText = toolkit.createText(area, "", SWT.MULTI | SWT.WRAP); - extraVMArgumentsText.setEditable(true); - extraVMArgumentsText - .setToolTipText("Optionally pass additional JVM arguments to TLC process (e.g. -Djava.rmi.server.hostname=ThisHostName)"); - extraVMArgumentsText.addFocusListener(focusListener); - gd = new GridData(); - gd.horizontalIndent = 0; - gd.verticalIndent = 20; - gd.widthHint = 300; - gd.heightHint = 40; - extraVMArgumentsText.setLayoutData(gd); - - // Extra/Additional TLC arguments - toolkit.createLabel(area, "TLC command line parameters:"); - - extraTLCParametersText = toolkit.createText(area, "", SWT.MULTI | SWT.WRAP); - extraTLCParametersText.setEditable(true); - extraTLCParametersText - .setToolTipText("Optionally pass additional TLC process parameters (e.g. -Dcheckpoint 0)"); - extraTLCParametersText.addFocusListener(focusListener); - gd = new GridData(); - gd.horizontalIndent = 0; - gd.verticalIndent = 20; - gd.widthHint = 300; - gd.heightHint = 40; - extraTLCParametersText.setLayoutData(gd); - - return advancedSection; - } -} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java index d40dcfc0bc8ce9827cb0016cd9c520068fae3836..1db6b859fcc398e39773fba8491ec26cea8f8aa6 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java @@ -1,8 +1,8 @@ package org.lamport.tla.toolbox.tool.tlc.ui.editor.page; -import java.util.Enumeration; import java.util.Hashtable; import java.util.List; +import java.util.function.Consumer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.ListenerList; @@ -15,6 +15,7 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; @@ -88,12 +89,21 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat { public static final String CRASHED_TITLE = " ( model checking has crashed )"; public static final String RUNNING_TITLE = " ( model checking is in progress )"; + public static final String IMAGE_TEMPLATE_TOKEN = "[XXXXX]"; + + /** + * If a section has a data with this key, the returned object is assumed to be an implementor of Consumer<Boolean> + * which will be invoked during {@link #compensateForExpandableCompositesPoorDesign(Section, boolean)} with + * the boolean value being true if the section is expanding. + */ + protected static final String SECTION_EXPANSION_LISTENER = "_why_oh_why_..._sigh"; + private static final String TLC_ERROR_STRING = "TLC Error"; - + /** * a list of dirty part listeners, which marks parts as dirty on input and cause the re-validation of the input */ - protected ListenerList<DirtyMarkingListener> dirtyPartListeners = new ListenerList<DirtyMarkingListener>(); + protected ListenerList<DirtyMarkingListener> dirtyPartListeners = new ListenerList<DirtyMarkingListener>(); /** * the initialization status. Becomes true, after the {@link BasicFormPage#pageInitializationComplete()} method is executed */ @@ -103,9 +113,10 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ protected String helpId = null; /** - * Image used in the heading of the page + * Image path template used in the heading of the page */ - protected String imagePath = null; + private String imagePathTemplate; + /** * Fomr rebuilding listener responsible for page reflow */ @@ -218,16 +229,35 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat }; /** - * Creates the main editor page - * @param editor - * @param id - * @param title - */ - public BasicFormPage(FormEditor editor, String id, String title) - { + * Creates the main editor page + * + * @param editor + * @param id + * @param title + * @param pageImagePathTemplate should contain <code>IMAGE_TEMPLATE_TOKEN</code> + * which will be replaced with 16 or 24 depending + * on the application; images of such naming are + * assumed to exist on the filesystem. + */ + public BasicFormPage(final FormEditor editor, final String id, final String title, + final String pageImagePathTemplate) { super(editor, id, title); + + imagePathTemplate = pageImagePathTemplate; } - + + /** + * {@inheritDoc} + */ + @Override + public Image getTitleImage() { + // Display the page's image left of the page's name on the tar bar. E.g. the + // main model page displays three sliders left of its "Model + // Overview" label. createFormContent below additionally sets a slightly + // larger version of the same image on the page itself (not on the tab bar). + return createRegisteredImage(16); + } + /** * Called during FormPage life cycle and delegates the form creation * to three methods {@link BasicFormPage#createBodyContent(IManagedForm)}, @@ -237,9 +267,12 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat { ScrolledForm formWidget = managedForm.getForm(); formWidget.setText(getTitle()); - if (imagePath != null) + if (imagePathTemplate != null) { - formWidget.setImage(createRegisteredImage(imagePath)); + // Show the given image left of the form page's title and beneath the tab + // bar. E.g. the main model page displays three sliders left of its "Model + // Overview" label. + formWidget.setImage(createRegisteredImage(24)); } Composite body = formWidget.getBody(); @@ -247,26 +280,11 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat FormToolkit toolkit = managedForm.getToolkit(); toolkit.decorateFormHeading(formWidget.getForm()); - // head construction --------------------- - IToolBarManager toolbarManager = formWidget.getForm().getToolBarManager(); - - // run button - toolbarManager.add(new DynamicContributionItem(new RunAction())); - toolbarManager.add(new DynamicContributionItem(new GenerateAction())); - // stop button - toolbarManager.add(new DynamicContributionItem(new StopAction())); - - // refresh the tool-bar - toolbarManager.update(true); - /* - * The head client is the second row of the header section, - * below the title. There should be the same buttons as in the - * toolbar on the first row, right corner of the header section - * because sometimes those buttons are not visible unless - * the user scrolls over to them. + * The head client is the second row of the header section, below the title; if we don't create this + * with 'NO_FOCUS' then the toolbar will always take focus on a form page that gains focus. */ - ToolBar headClientTB = new ToolBar(formWidget.getForm().getHead(), SWT.HORIZONTAL); + ToolBar headClientTB = new ToolBar(formWidget.getForm().getHead(), SWT.HORIZONTAL | SWT.NO_FOCUS); headClientTBM = new ToolBarManager(headClientTB); // run button headClientTBM.add(new DynamicContributionItem(new RunAction())); @@ -341,10 +359,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat * Subclasses should override this method and fill the data in to the widgets * @throws CoreException thrown on any error during loading */ - protected void loadData() throws CoreException - { - - } + protected void loadData() throws CoreException { } /** * Method finalizing the page initialization @@ -406,22 +421,45 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } return this.formRebuildingListener; } + + // There is no way to exaggerate how poorly designed SWT and SWT-adjacent Eclipse code is... the ExpandableComposite + // does not fire an expansion listener notification on setExpanded and there is no way to get to the + // listeners to do it ourselves... i mean the whole thing is so absurdly bad. + // .. and the only reason we have to worry about the listeners being notified is because the form page won't + // layout correct unless we turn the section's grid layout data's vertical grab on and off... + // It is disabled turtles all the way down over at eclipse.org... + @SuppressWarnings("unchecked") // generic casting + protected void compensateForExpandableCompositesPoorDesign(final Section section, final boolean expand) { + section.setExpanded(expand); + + if (section.getData(FormHelper.SECTION_IS_NOT_SPACE_GRABBING) == null) { + final GridData gd = (GridData) section.getLayoutData(); + gd.grabExcessVerticalSpace = expand; + section.setLayoutData(gd); + } + + final Object o = section.getData(SECTION_EXPANSION_LISTENER); + if (o != null) { + ((Consumer<Boolean>)o).accept(Boolean.valueOf(expand)); + } + } /** * Retrieves the image and remember it for later reuse / dispose - * @param imageName + * @param size the pixel dimension of the image desired * @return */ - protected Image createRegisteredImage(String imageName) + protected Image createRegisteredImage(final int size) { - Image image = (Image) images.get(imageName); + final String imagePath = imagePathTemplate.replace(IMAGE_TEMPLATE_TOKEN, Integer.toString(size)); + Image image = (Image) images.get(imagePath); if (image == null) { - ImageDescriptor descr = TLCUIActivator.imageDescriptorFromPlugin(TLCUIActivator.PLUGIN_ID, imageName); - if (descr != null) + final ImageDescriptor id = TLCUIActivator.imageDescriptorFromPlugin(TLCUIActivator.PLUGIN_ID, imagePath); + if (id != null) { - image = descr.createImage(); - images.put(imageName, image); + image = id.createImage(); + images.put(imagePath, image); } } @@ -429,7 +467,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } public Model getModel() { - return ((ModelEditor) getEditor()).getModel(); + return getModelEditor().getModel(); } /** @@ -461,9 +499,13 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat private void handleProblemMarkers(boolean switchToErrorPage) { // delegate to the editor - ((ModelEditor) getEditor()).handleProblemMarkers(switchToErrorPage); + getModelEditor().handleProblemMarkers(switchToErrorPage); } + protected ModelEditor getModelEditor() { + return (ModelEditor) getEditor(); + } + /** * Returns if the input is complete and the page contains no errors * @return @@ -532,11 +574,9 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public void dispose() { - Enumeration<Image> elements = images.elements(); - while (elements.hasMoreElements()) - { - elements.nextElement().dispose(); - } + for (final Image i : images.values()) { + i.dispose(); + } super.dispose(); } @@ -555,7 +595,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat // refresh the title String title = mForm.getForm().getText(); - int titleIndex = Math.max(title.indexOf(RUNNING_TITLE), title.indexOf(CRASHED_TITLE)); + int titleIndex = Math.max(title.indexOf(RUNNING_TITLE), title.indexOf(CRASHED_TITLE)); // restore the title if (titleIndex != -1) { @@ -591,7 +631,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } // refresh enablement status - setEnabled(!modelRunning); + setEnabled(!modelRunning); mForm.getForm().update(); } @@ -626,7 +666,13 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } // retrieve the control Control widget = UIHelper.getWidget(dm.getAttributeControl(attributeName)); + + validateUsage(sectionId, widget, values, errorMessagePrefix, elementType, listSourceDescription, addToContext); + } + public void validateUsage(final String sectionId, final Control widget, List<String> values, String errorMessagePrefix, String elementType, + String listSourceDescription, boolean addToContext) + { IMessageManager mm = getManagedForm().getMessageManager(); SemanticHelper helper = getLookupHelper(); String message; @@ -699,7 +745,12 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } // retrieve the control Control widget = UIHelper.getWidget(dm.getAttributeControl(attributeName)); + + validateId(sectionId, widget, values, errorMessagePrefix, elementType); + } + public void validateId(final String sectionId, final Control widget, List<String> values, String errorMessagePrefix, String elementType) + { String message; IMessageManager mm = getManagedForm().getMessageManager(); for (int i = 0; i < values.size(); i++) @@ -727,12 +778,17 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat } } + /** + * Subclasses may override this to be notified when model checking has been launched. + */ + public void modelCheckingHasBegun() { } + /** * Retrieves the data binding manager */ public DataBindingManager getDataBindingManager() { - return ((ModelEditor) getEditor()).getDataBindingManager(); + return getModelEditor().getDataBindingManager(); } /** @@ -740,7 +796,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public void doRun() { - ((ModelEditor) getEditor()).launchModel(TLCModelLaunchDelegate.MODE_MODELCHECK, true); + getModelEditor().launchModel(TLCModelLaunchDelegate.MODE_MODELCHECK, true); } /** @@ -748,7 +804,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public void doGenerate() { - ((ModelEditor) getEditor()).launchModel(TLCModelLaunchDelegate.MODE_GENERATE, true); + getModelEditor().launchModel(TLCModelLaunchDelegate.MODE_GENERATE, true); } /** @@ -756,7 +812,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public void doStop() { - ((ModelEditor) getEditor()).stop(); + getModelEditor().stop(); } /** @@ -837,7 +893,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public boolean isEnabled() { - return !getModel().isRunning(); + return !getModel().isRunning(); } } @@ -864,7 +920,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public boolean isEnabled() { - return !getModel().isRunning(); + return !getModel().isRunning(); } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ErrorMessage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ErrorMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..0770f26b412e9173ed89e27248abc383fe911c77 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ErrorMessage.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page; + +import java.util.List; + +public class ErrorMessage { + + private final String message; + private final String key; + private final String modelEditorPageId; + private final List<String> sections; + private final String viewerId; + + public ErrorMessage(final String message, final String key, final String modelEditorPageId, + final List<String> sections, final String viewerId) { + this.message = message; + this.key = key; + this.modelEditorPageId = modelEditorPageId; + this.sections = sections; + this.viewerId = viewerId; + } + + public List<String> getSections() { + return sections; + } + + public String getModelEditorPageId() { + return modelEditorPageId; + } + + public String getViewerId() { + return viewerId; + } + + public String getKey() { + return key; + } + + public String getMessage() { + return message; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java index 3e97ed82522546a4c597ea4e4169154073dae67e..89e07a28a28be925d1efcd8e4a6b8f1a15804e10 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java @@ -5,40 +5,38 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.Vector; -import java.util.function.Consumer; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRunnable; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -46,571 +44,543 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Scale; +import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Spinner; import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.HyperlinkGroup; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.IMessageManager; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Hyperlink; -import org.eclipse.ui.forms.widgets.ImageHyperlink; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.forms.widgets.TableWrapLayout; import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants; import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationDefaults; import org.lamport.tla.toolbox.tool.tlc.model.Assignment; +import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager; import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedTLCOptionsPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.EvaluateConstantExpressionPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.ResultPage; import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableConstantSectionPart; import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableTableSectionPart; import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; -import org.lamport.tla.toolbox.tool.tlc.ui.preference.TLCPreferenceInitializer; import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; import org.lamport.tla.toolbox.util.HelpButton; import org.lamport.tla.toolbox.util.IHelpConstants; -import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.UIHelper; import tla2sany.semantic.ModuleNode; import util.TLCRuntime; /** - * Main model page represents information for most users - * <br> - * This class is a a sub-class of the BasicFormPage and is used to represent the first tab of the - * multi-page-editor which is used to edit the model files. + * Main model page represents information for most users <br> + * This class is a a sub-class of the BasicFormPage and is used to represent the + * first tab of the multi-page-editor which is used to edit the model files. * * - * @author Simon Zambrovski - * This is the FormPage class for the Model Overview tabbed page of - * the model editor. + * @author Simon Zambrovski This is the FormPage class for the Model Overview + * tabbed page of the model editor. */ -public class MainModelPage extends BasicFormPage implements IConfigurationConstants, IConfigurationDefaults -{ - public static final String ID = "MainModelPage"; - public static final String TITLE = "Model Overview"; - - private Button noSpecRadio; // re-added on 10 Sep 2009 - private Button closedFormulaRadio; - private Button initNextFairnessRadio; +public class MainModelPage extends BasicFormPage implements IConfigurationConstants, IConfigurationDefaults { + public static final String ID = "MainModelPage"; + public static final String CUSTOM_TLC_PROFILE_PREFERENCE_VALUE = "local custom"; + + static final String CLOUD_CONFIGURATION_KEY = "jclouds"; + + private static final String TITLE = "Model Overview"; + + private static final String INIT_NEXT_COMBO_LABEL = "Initial predicate and next-state"; + private static final String TEMPORAL_FORMULA_COMBO_LABEL = "Temporal formula"; + private static final String NO_SPEC_COMBO_LABEL = "No behavior spec"; + private static final String[] VARIABLE_BEHAVIOR_COMBO_ITEMS = { INIT_NEXT_COMBO_LABEL, TEMPORAL_FORMULA_COMBO_LABEL, + NO_SPEC_COMBO_LABEL }; + private static final String[] NO_VARIABLE_BEHAVIOR_COMBO_ITEMS = { NO_SPEC_COMBO_LABEL }; + + private static final String TLC_PROFILE_LOCAL_SEPARATOR = "\u2014\u2014 Local \u2014\u2014"; + private static final String TLC_PROFILE_REMOTE_SEPARATOR = "\u2014\u2014 Remote \u2014\u2014"; + private static final String CUSTOM_TLC_PROFILE_DISPLAY_NAME = "Custom"; + + private static final String[] TLC_PROFILE_DISPLAY_NAMES; + + private static final DecimalFormat MEMORY_FORMAT = new DecimalFormat("#,###"); + + static { + final TLCConsumptionProfile[] profiles = TLCConsumptionProfile.values(); + final int size = profiles.length; + + TLC_PROFILE_DISPLAY_NAMES = new String[size + 2]; + TLC_PROFILE_DISPLAY_NAMES[0] = TLC_PROFILE_LOCAL_SEPARATOR; + int indexIncrement = 1; + boolean haveStartedRemoteProfiles = false; + for (int i = 0; i < size; i++) { + if (profiles[i].profileIsForRemoteWorkers() && !haveStartedRemoteProfiles) { + TLC_PROFILE_DISPLAY_NAMES[i + indexIncrement] = TLC_PROFILE_REMOTE_SEPARATOR; + haveStartedRemoteProfiles = true; + indexIncrement++; + } + + TLC_PROFILE_DISPLAY_NAMES[i + indexIncrement] = profiles[i].getDisplayName(); + } + } + + static public String generateMemoryDisplayText(final int percentage, final long megabytes) { + return percentage + "%" + " (" + MEMORY_FORMAT.format(megabytes) + " mb)"; + } + + + private Combo behaviorCombo; + private int previousBehaviorComboSelection; private SourceViewer commentsSource; - private SourceViewer initFormulaSource; - private SourceViewer nextFormulaSource; - // private SourceViewer fairnessFormulaSource; - private SourceViewer specSource; - private Button checkDeadlockButton; - private Spinner workers; - /** - * Spinner to set the number of (expected) distributed FPSets. + + private SourceViewer initFormulaSource; + private SourceViewer nextFormulaSource; + // private SourceViewer fairnessFormulaSource; + private SourceViewer specSource; + private Button checkDeadlockButton; + + private Combo tlcProfileCombo; + private AtomicInteger lastSelectedTLCProfileIndex; + private Label tlcResourceSummaryLabel; + private Hyperlink tlcTuneHyperlink; + // We cache this since want to reference it frequently on heap slider drag + private AtomicBoolean currentProfileIsAdHoc; + + // We keep certain items of UI state derived from the model here and reference + // it from the loadData of pages + // which need not necessarily be open, and should they be opened after the model + // editor's state has been + // modified but not saved, would get incorrect data. + private AtomicInteger workerThreadCount; + private AtomicInteger heapPercentage; + private AtomicBoolean workerValueCanBeModified; + private AtomicBoolean heapPercentageCanBeModified; + + /** + * Widgets related to distributed mode configuration */ - private Spinner distributedFPSetCountSpinner; - private Spinner distributedNodesCountSpinner; - private Combo networkInterfaceCombo; - private Scale maxHeapSize; - private TableViewer invariantsTable; - private TableViewer propertiesTable; - private TableViewer constantTable; - private ModifyListener widgetActivatingListener = new ModifyListener() { - // select the section (radio button) the text field belong to - public void modifyText(ModifyEvent e) - { - if (e.widget == specSource.getControl()) - { - noSpecRadio.setSelection(false); - closedFormulaRadio.setSelection(true); - initNextFairnessRadio.setSelection(false); - } else if (e.widget == initFormulaSource.getControl() || e.widget == nextFormulaSource.getControl() - /* || e.widget == fairnessFormulaSource.getControl() */) - { - noSpecRadio.setSelection(false); - closedFormulaRadio.setSelection(false); - initNextFairnessRadio.setSelection(true); - } + private Spinner distributedFPSetCountSpinner; + private Spinner distributedNodesCountSpinner; + private Text resultMailAddressText; + private Combo networkInterfaceCombo; + + private TableViewer invariantsTable; + private TableViewer propertiesTable; + private TableViewer constantTable; + + protected HyperlinkAdapter advancedModelOptionsOpener = new HyperlinkAdapter() { + public void linkActivated(final HyperlinkEvent he) { + getModelEditor().addOrShowAdvancedModelPage(); } }; + protected HyperlinkAdapter advancedTLCOptionsOpener = new HyperlinkAdapter() { + public void linkActivated(final HyperlinkEvent he) { + getModelEditor().addOrShowAdvancedTLCOptionsPage(); + } + }; - private ImageHyperlink runLink; - private ImageHyperlink generateLink; - - /** - * section expanding adapter - * {@link Hyperlink#getHref()} must deliver the section id as described in {@link DataBindingManager#bindSection(ExpandableComposite, String, String)} - */ - protected HyperlinkAdapter sectionExpandingAdapter = new HyperlinkAdapter() { - public void linkActivated(HyperlinkEvent e) - { - String sectionId = (String) e.getHref(); - // first switch to the page (and construct it if not yet - // constructed) - getEditor().setActivePage(AdvancedModelPage.ID); - // then expand the section - expandSection(sectionId); - } - }; - private Button checkpointButton; - private Text checkpointIdText; - - /* - * Checkbox and input box for distributed model checking - * - * combo: choose distribution and cloud to run on - * text: additional vm arguments (e.g. -Djava.rmi...) - * text: pre-flight script - */ - private Combo distributedCombo; - private Text resultMailAddressText; - - // The widgets to display the checkpoint size and - // the delete button. - private Label chkpointSizeLabel; - private Text checkpointSizeText; - private Button chkptDeleteButton; - /** - * Used to interpolate y-values for memory scale + * Stacked composites for displaying options based on user selection in combo + * boxes */ - private final Interpolator linearInterpolator; + private Composite behaviorOptions; private Composite distributedOptions; - - /** - * constructs the main model page - * @param editor - */ - public MainModelPage(FormEditor editor) - { - super(editor, MainModelPage.ID, MainModelPage.TITLE); - this.helpId = IHelpConstants.MAIN_MODEL_PAGE; - this.imagePath = "icons/full/choice_sc_obj.gif"; - - // available system memory - final long phySysMem = TLCRuntime.getInstance().getAbsolutePhysicalSystemMemory(1.0d); - - // 0.) Create LinearInterpolator with two additional points 0,0 and 1,0 which - int s = 0; - double[] x = new double[6]; - double[] y = new double[x.length]; - - // base point - y[s] = 0d; - x[s++] = 0d; - - // 1.) Minumum TLC requirements - // Use hard-coded minfpmemsize value * 4 * 10 regardless of how big the - // model is. *4 because .25 mem is used for FPs - double lowerLimit = ( (TLCRuntime.MinFpMemSize / 1024 / 1024 * 4d) / phySysMem) / 2; - x[s] = lowerLimit; - y[s++] = 0d; - - // a.) - // Current bloat in software is assumed to grow according to Moore's law => - // 2^((Year-1993)/ 2)+2) - // (1993 as base results from a statistic of windows OS memory requirements) - final int currentYear = Calendar.getInstance().get(Calendar.YEAR); - double estimateSoftwareBloatInMBytes = Math.pow(2, ((currentYear - 1993) / 3) + 3.5); - - // 2.) Optimal range - x[s] = lowerLimit * 2d; - y[s++] = 1.0d; - x[s] = 1.0d - (estimateSoftwareBloatInMBytes / phySysMem); - y[s++] = 1.0d; - - // 3.) Calculate OS reserve - double upperLimit = 1.0d - (estimateSoftwareBloatInMBytes / phySysMem) / 2; - x[s] = upperLimit; - y[s++] = 0d; - - // base point - x[s] = 1d; - y[s] = 0d; - - linearInterpolator = new Interpolator(x, y); -} - /** - * @see BasicFormPage#loadData() - */ - protected void loadData() throws CoreException - { - int specType = getModel().getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT); - - // set up the radio buttons - setSpecSelection(specType); - - // closed spec - String modelSpecification = getModel().getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, EMPTY_STRING); - Document closedDoc = new Document(modelSpecification); - this.specSource.setDocument(closedDoc); - - // init - String modelInit = getModel().getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, EMPTY_STRING); - Document initDoc = new Document(modelInit); - this.initFormulaSource.setDocument(initDoc); - - // next - String modelNext = getModel().getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, EMPTY_STRING); - Document nextDoc = new Document(modelNext); - this.nextFormulaSource.setDocument(nextDoc); - - // fairness - // String modelFairness = - // getModel().getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, - // EMPTY_STRING); - // Document fairnessDoc = new Document(modelFairness); - // this.fairnessFormulaSource.setDocument(fairnessDoc); - - // number of workers - workers.setSelection(getModel().getAttribute(LAUNCH_NUMBER_OF_WORKERS, LAUNCH_NUMBER_OF_WORKERS_DEFAULT)); - - // max JVM heap size - final int defaultMaxHeapSize = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); - final int maxHeapSizeValue = getModel().getAttribute(LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); - maxHeapSize.setSelection(maxHeapSizeValue); - - // check deadlock - boolean checkDeadlock = getModel().getAttribute(MODEL_CORRECTNESS_CHECK_DEADLOCK, - MODEL_CORRECTNESS_CHECK_DEADLOCK_DEFAULT); - this.checkDeadlockButton.setSelection(checkDeadlock); - - // invariants - List<String> serializedList = getModel().getAttribute(MODEL_CORRECTNESS_INVARIANTS, new Vector<String>()); - FormHelper.setSerializedInput(invariantsTable, serializedList); - - // properties - serializedList = getModel().getAttribute(MODEL_CORRECTNESS_PROPERTIES, new Vector<String>()); - FormHelper.setSerializedInput(propertiesTable, serializedList); - - // constants from the model - List<String> savedConstants = getModel().getAttribute(MODEL_PARAMETER_CONSTANTS, new Vector<String>()); - FormHelper.setSerializedInput(constantTable, savedConstants); - if (!savedConstants.isEmpty()) { - expandSection(SEC_WHAT_IS_THE_MODEL); - } + /** + * constructs the main model page + * + * @param editor + */ + public MainModelPage(final FormEditor editor) { + super(editor, MainModelPage.ID, MainModelPage.TITLE, + "icons/full/model_options_" + IMAGE_TEMPLATE_TOKEN + ".png"); + helpId = IHelpConstants.MAIN_MODEL_PAGE; - // recover from the checkpoint - boolean recover = getModel().getAttribute(LAUNCH_RECOVER, LAUNCH_RECOVER_DEFAULT); - this.checkpointButton.setSelection(recover); - - /* - * Distributed mode - */ - String cloud = "off"; - try { - cloud = getModel().getAttribute(LAUNCH_DISTRIBUTED, LAUNCH_DISTRIBUTED_DEFAULT); - } catch (CoreException e) { - // LAUNCH_DISTRIBUTED might still be stored in a legacy format. The user is - // opening an old model. - boolean distributed = getModel().getAttribute(LAUNCH_DISTRIBUTED, false); - if (distributed) { - cloud = "ad hoc"; - } - } - final String[] items = distributedCombo.getItems(); - for (int i = 0; i < items.length; i++) { - final String string = items[i]; - if (cloud.equals(string)) { - distributedCombo.select(i); - break; + currentProfileIsAdHoc = new AtomicBoolean(false); + workerValueCanBeModified = new AtomicBoolean(true); + heapPercentageCanBeModified = new AtomicBoolean(true); + } + + /** + * @see BasicFormPage#loadData() + */ + @Override + protected void loadData() throws CoreException { + final Model model = getModel(); + final int specType = model.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT); + + // set up the radio buttons + setSpecSelection(specType); + + // closed spec + String modelSpecification = model.getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, EMPTY_STRING); + Document closedDoc = new Document(modelSpecification); + this.specSource.setDocument(closedDoc); + + // init + String modelInit = model.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, EMPTY_STRING); + Document initDoc = new Document(modelInit); + this.initFormulaSource.setDocument(initDoc); + + // next + String modelNext = model.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, EMPTY_STRING); + Document nextDoc = new Document(modelNext); + this.nextFormulaSource.setDocument(nextDoc); + + // fairness + // String modelFairness = + // model.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, + // EMPTY_STRING); + // Document fairnessDoc = new Document(modelFairness); + // this.fairnessFormulaSource.setDocument(fairnessDoc); + + // check deadlock + boolean checkDeadlock = model.getAttribute(MODEL_CORRECTNESS_CHECK_DEADLOCK, + MODEL_CORRECTNESS_CHECK_DEADLOCK_DEFAULT); + this.checkDeadlockButton.setSelection(checkDeadlock); + + // invariants + List<String> serializedList = model.getAttribute(MODEL_CORRECTNESS_INVARIANTS, new Vector<String>()); + FormHelper.setSerializedInput(invariantsTable, serializedList); + + // properties + serializedList = model.getAttribute(MODEL_CORRECTNESS_PROPERTIES, new Vector<String>()); + FormHelper.setSerializedInput(propertiesTable, serializedList); + + // constants from the model + List<String> savedConstants = model.getAttribute(MODEL_PARAMETER_CONSTANTS, new Vector<String>()); + FormHelper.setSerializedInput(constantTable, savedConstants); + if (!savedConstants.isEmpty()) { + expandSection(SEC_WHAT_IS_THE_MODEL); + } + + final int threadCount; + final int memoryPercentage; + currentProfileIsAdHoc.set(false); + final IPreferenceStore prefStore = TLCUIActivator.getDefault().getPreferenceStore(); + if (model.hasAttribute(TLC_RESOURCES_PROFILE)) { + final String tlcProfile = model.getAttribute(TLC_RESOURCES_PROFILE, (String) null); + + if (tlcProfile.equals(CUSTOM_TLC_PROFILE_PREFERENCE_VALUE)) { + threadCount = model.getAttribute(LAUNCH_NUMBER_OF_WORKERS, + prefStore.getInt(ITLCPreferenceConstants.I_TLC_DEFAULT_WORKERS_COUNT)); + final int defaultMaxHeapSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); + memoryPercentage = model.getAttribute(LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); + + setTLCProfileComboSelection(CUSTOM_TLC_PROFILE_DISPLAY_NAME); + } else { + final TLCConsumptionProfile profile = TLCConsumptionProfile.getProfileWithPreferenceValue(tlcProfile); + + setTLCProfileComboSelection(profile.getDisplayName()); + + if (profile.profileIsForRemoteWorkers()) { + final String configuration = profile.getConfigurationKey(); // currentProfileIsAdHoc + final boolean isAdHoc = configuration + .equals(TLCConsumptionProfile.REMOTE_AD_HOC.getConfigurationKey()); + + currentProfileIsAdHoc.set(isAdHoc); + moveToTopOfDistributedOptionsStack(configuration, false, isAdHoc); + + if (configuration.equals(CLOUD_CONFIGURATION_KEY)) { + final String email = model.getAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, + LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS_DEFAULT); + resultMailAddressText.setText(email); + } + } else { + moveToTopOfDistributedOptionsStack(LAUNCH_DISTRIBUTED_NO, true, true); + } + + threadCount = profile.getWorkerThreads(); + memoryPercentage = currentProfileIsAdHoc.get() + ? model.getAttribute(LAUNCH_MAX_HEAP_SIZE, profile.getMemoryPercentage()) + : profile.getMemoryPercentage(); + } + } else { // for pre-1.6.0 models... + String remoteWorkers = LAUNCH_DISTRIBUTED_NO; + + try { + remoteWorkers = model.getAttribute(LAUNCH_DISTRIBUTED, LAUNCH_DISTRIBUTED_DEFAULT); + } catch (CoreException e) { // for very old models + if (model.getAttribute(LAUNCH_DISTRIBUTED, false)) { + remoteWorkers = TLCConsumptionProfile.REMOTE_AD_HOC.getConfigurationKey(); + currentProfileIsAdHoc.set(true); + } + } + + if (remoteWorkers.equals(LAUNCH_DISTRIBUTED_NO)) { + moveToTopOfDistributedOptionsStack(LAUNCH_DISTRIBUTED_NO, true, true); + threadCount = model.getAttribute(LAUNCH_NUMBER_OF_WORKERS, + prefStore.getInt(ITLCPreferenceConstants.I_TLC_DEFAULT_WORKERS_COUNT)); + final int defaultMaxHeapSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); + memoryPercentage = model.getAttribute(LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); + + setTLCProfileComboSelection(CUSTOM_TLC_PROFILE_DISPLAY_NAME); + } else { + final TLCConsumptionProfile profile = TLCConsumptionProfile + .getProfileWithPreferenceValue(remoteWorkers); + final String configuration = profile.getConfigurationKey(); + final boolean isAdHoc = configuration.equals(TLCConsumptionProfile.REMOTE_AD_HOC.getConfigurationKey()); + + currentProfileIsAdHoc.set(isAdHoc); + moveToTopOfDistributedOptionsStack(configuration, false, isAdHoc); + + if (configuration.equals(CLOUD_CONFIGURATION_KEY)) { + final String email = model.getAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, + LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS_DEFAULT); + resultMailAddressText.setText(email); + } + + threadCount = 0; + + if (isAdHoc) { + final int defaultMaxHeapSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); + memoryPercentage = model.getAttribute(LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); + } else { + memoryPercentage = 0; + } + + setTLCProfileComboSelection(profile.getDisplayName()); } } + workerThreadCount = new AtomicInteger(threadCount); + heapPercentage = new AtomicInteger(memoryPercentage); + + // distribute FPSet count + distributedFPSetCountSpinner.setSelection( + model.getAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, LAUNCH_DISTRIBUTED_FPSET_COUNT_DEFAULT)); + + // distribute FPSet count + distributedNodesCountSpinner.setSelection( + model.getAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, LAUNCH_DISTRIBUTED_NODES_COUNT_DEFAULT)); + + // comments/description/notes + String commentsStr = model.getAttribute(MODEL_COMMENTS, EMPTY_STRING); + commentsSource.setDocument(new Document(commentsStr)); + if (!EMPTY_STRING.equals(commentsStr)) { + expandSection(SEC_COMMENTS); + } + + updateTLCResourcesLabel(); + } - if (cloud.equalsIgnoreCase("aws-ec2") || cloud.equalsIgnoreCase("Azure")) { - MainModelPage.this.putOnTopOfStack("jclouds", false, false); - String email = getModel().getAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS_DEFAULT); - resultMailAddressText.setText(email); - } else if(cloud.equalsIgnoreCase("ad hoc")) { - MainModelPage.this.putOnTopOfStack("ad hoc", false, true); + /** + * @param noSpec if false, the spec choice at index 0 of the combobox will be + * chosen; in the case of the spec having no variables defined, + * this will again be a no-behavior-spec + */ + public void setNoBehaviorSpec(final boolean noSpec) { + if (noSpec) { + previousBehaviorComboSelection = behaviorCombo.getSelectionIndex(); + setSpecSelection(MODEL_BEHAVIOR_TYPE_NO_SPEC); } else { - MainModelPage.this.putOnTopOfStack("off", true, true); + behaviorCombo.select(previousBehaviorComboSelection); + moveToTopOfBehaviorOptionsStack(behaviorCombo.getText()); + } + final DataBindingManager dm = getDataBindingManager(); + dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_NO_SPEC)).markDirty(); + + validatePage(false); + } + + @Override + public void validatePage(boolean switchToErrorPage) { + if (getManagedForm() == null) { + return; } - - // distribute FPSet count - distributedFPSetCountSpinner.setSelection(getModel().getAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, LAUNCH_DISTRIBUTED_FPSET_COUNT_DEFAULT)); - - // distribute FPSet count - distributedNodesCountSpinner.setSelection(getModel().getAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, LAUNCH_DISTRIBUTED_NODES_COUNT_DEFAULT)); - - // comments/description/notes - String commentsStr = getModel().getAttribute(MODEL_COMMENTS, EMPTY_STRING); - commentsSource.setDocument(new Document(commentsStr)); - if (!EMPTY_STRING.equals(commentsStr)) { - expandSection(SEC_COMMENTS); - } - } - - public void validatePage(boolean switchToErrorPage) - { - if (getManagedForm() == null) - { - return; - } - DataBindingManager dm = getDataBindingManager(); - IMessageManager mm = getManagedForm().getMessageManager(); - ModelEditor modelEditor = (ModelEditor) getEditor(); - - // The following comment was apparently written by Simon: - // delete the messages - // this is now done in validateRunnable - // in ModelEditor - // resetAllMessages(false); - // validateRunnable is in ModelEditor. I believe it is executed only when - // the user executes the Run or Validate Model command. - // Errors that the validatePage method checks for should be cleared - // whenever the method is called. However, calling resetAllMessages - // seems to be the wrong way to do it because error messages from all - // pages are reported on each page. Hence, that would require validating - // all pages whenever any one is validated. See the ModelEditor.removeErrorMessage - // method for a further discussion of this problem. - // Comments added by LL on 21 Mar 2013. - - // getting the root module node of the spec - // this can be null! - ModuleNode rootModuleNode = SemanticHelper.getRootModuleNode(); - - // setup the names from the current page - getLookupHelper().resetModelNames(this); - - // constants in the table - @SuppressWarnings("unchecked") - List<Assignment> constants = (List<Assignment>) constantTable.getInput(); - // merge constants with currently defined in the specobj, if any - if (rootModuleNode != null) - { - List<Assignment> toDelete = ModelHelper.mergeConstantLists(constants, ModelHelper.createConstantsList(rootModuleNode)); - if (!toDelete.isEmpty()) - { - // if constants have been removed, these should be deleted from - // the model too - SectionPart constantSection = dm.getSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); - if (constantSection != null) - { - // mark the constants dirty - constantSection.markDirty(); - } - } - constantTable.setInput(constants); - } + final DataBindingManager dm = getDataBindingManager(); + final IMessageManager mm = getManagedForm().getMessageManager(); + mm.setAutoUpdate(false); + + final ModelEditor modelEditor = (ModelEditor) getEditor(); + + // The following comment was apparently written by Simon: + // delete the messages + // this is now done in validateRunnable + // in ModelEditor + // resetAllMessages(false); + // validateRunnable is in ModelEditor. I believe it is executed only when + // the user executes the Run or Validate Model command. + // Errors that the validatePage method checks for should be cleared + // whenever the method is called. However, calling resetAllMessages + // seems to be the wrong way to do it because error messages from all + // pages are reported on each page. Hence, that would require validating + // all pages whenever any one is validated. See the + // ModelEditor.removeErrorMessage + // method for a further discussion of this problem. + // Comments added by LL on 21 Mar 2013. + + // getting the root module node of the spec + // this can be null! + ModuleNode rootModuleNode = SemanticHelper.getRootModuleNode(); + + // setup the names from the current page + getLookupHelper().resetModelNames(this); + + // constants in the table + List<Assignment> constants = getConstants(); + // merge constants with currently defined in the specobj, if any + final String sectionId = dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS); + if (rootModuleNode != null) { + List<Assignment> toDelete = ModelHelper.mergeConstantLists(constants, + ModelHelper.createConstantsList(rootModuleNode)); + if (!toDelete.isEmpty()) { + // if constants have been removed, these should be deleted from + // the model too + SectionPart constantSection = dm.getSection(sectionId); + if (constantSection != null) { + // mark the constants dirty + constantSection.markDirty(); + } + } + constantTable.setInput(constants); + } - // The following string is used to test whether two differently-typed model - // values appear in symmetry sets (sets of model values declared to be symmetric). - // It is set to the type of the first typed model value found in a symmetry set. - String symmetryType = null; - // boolean symmetryUsed = false; - // iterate over the constants - for (int i = 0; i < constants.size(); i++) - { - Assignment constant = (Assignment) constants.get(i); - - List<String> values = Arrays.asList(constant.getParams()); - // check parameters - validateId(MODEL_PARAMETER_CONSTANTS, values, "param1_", "A parameter name"); - - // the constant is still in the list - if (constant.getRight() == null || EMPTY_STRING.equals(constant.getRight())) - { - // right side of assignment undefined - modelEditor.addErrorMessage(constant.getLabel(), "Provide a value for constant " + constant.getLabel(), - this.getId(), IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - setComplete(false); - expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); - - } else - { // Following added by LL on 21 Mar 2013 - modelEditor.removeErrorMessage(constant.getLabel(), UIHelper.getWidget(dm - .getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - if (constant.isSetOfModelValues()) - { - TypedSet modelValuesSet = TypedSet.parseSet(constant.getRight()); - - if (constant.isSymmetricalSet()) - { - if (((CheckboxTableViewer) propertiesTable).getCheckedElements().length > 0) { - modelEditor.addErrorMessage(constant.getLabel(), constant.getLabel() - + " declared to be symmetric. Liveness checking under symmetry might fail to find a violation.", - this.getId(), IMessageProvider.WARNING, + // The following string is used to test whether two differently-typed model + // values appear in symmetry sets (sets of model values declared to be + // symmetric). + // It is set to the type of the first typed model value found in a symmetry set. + String symmetryType = null; + final Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTANTS)); + for (int i = 0; i < constants.size(); i++) { + Assignment constant = (Assignment) constants.get(i); + + List<String> values = Arrays.asList(constant.getParams()); + // check parameters + validateId(sectionId, widget, values, "param1_", "A parameter name"); + + // the constant is still in the list + String label = constant.getLabel(); + if (constant.getRight() == null || EMPTY_STRING.equals(constant.getRight())) { + // right side of assignment undefined + modelEditor.addErrorMessage(label, "Provide a value for constant " + label, + this.getId(), IMessageProvider.ERROR, + widget); + setComplete(false); + expandSection(sectionId); + + } else { // Following added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage(label, + widget); + if (constant.isSetOfModelValues()) { + TypedSet modelValuesSet = TypedSet.parseSet(constant.getRight()); + + if (constant.isSymmetricalSet()) { + if (((CheckboxTableViewer) propertiesTable).getCheckedElements().length > 0) { + modelEditor.addErrorMessage(constant.getLabel(), String.format( + "%s declared to be symmetric while one or more temporal formulas are set to be checked.\n" + + "If the temporal formula is a liveness property, liveness checking might fail to find\n" + + "violations. The Model Checking Result page will show a warning during TLC startup if\n" + + "any one of the temporal formulas is a liveness property.", + constant.getLabel()), this.getId(), IMessageProvider.INFORMATION, UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); - expandSection(dm.getSectionForAttribute(MODEL_CORRECTNESS_PROPERTIES)); - } - - boolean hasTwoTypes = false; // set true if this symmetry set has two differently-typed model - // values. - String typeString = null; // set to the type of the first typed model value in this symmetry - // set. - if (modelValuesSet.hasType()) - { - typeString = modelValuesSet.getType(); - } else - { - for (int j = 0; j < modelValuesSet.getValues().length; j++) - { - String thisTypeString = TypedSet.getTypeOfId(modelValuesSet.getValues()[j]); - if (thisTypeString != null) - { - if (typeString != null && !typeString.equals(thisTypeString)) - { - hasTwoTypes = true; - } else - { - typeString = thisTypeString; - } - } - } - } - if (hasTwoTypes - || (symmetryType != null && typeString != null && !typeString.equals(symmetryType))) - { - modelEditor.addErrorMessage(constant.getLabel(), - "Two differently typed model values used in symmetry sets.", - this.getId()/*constant*/, IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - setComplete(false); - expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); - } else - { - if (typeString != null) - { - symmetryType = typeString; - } - } - - // symmetry can be used for only one set of model values - - } - if (modelValuesSet.getValueCount() > 0) - { - // there were values defined - // check if those are numbers? - /* - * if (modelValuesSet.hasANumberOnlyValue()) { - * mm.addMessage("modelValues1", - * "A model value can not be an number", modelValuesSet, - * IMessageProvider.ERROR, constantTable.getTable()); - * setComplete(false); } - */ - - List<String> mvList = modelValuesSet.getValuesAsList(); - // check list of model values - validateUsage(MODEL_PARAMETER_CONSTANTS, mvList, "modelValues2_", "A model value", - "Constant Assignment", true); - // check if the values are correct ids - validateId(MODEL_PARAMETER_CONSTANTS, mvList, "modelValues2_", "A model value"); - - // get widget for model values assigned to constant - Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTANTS)); - // check if model values are config file keywords - for (int j = 0; j < mvList.size(); j++) - { - String value = (String) mvList.get(j); - if (SemanticHelper.isConfigFileKeyword(value)) - { - modelEditor.addErrorMessage(value, "The toolbox cannot handle the model value " + value - + ".", this.getId(), IMessageProvider.ERROR, widget); - setComplete(false); - } - } - } else - { - // This made an error by LL on 15 Nov 2009 - modelEditor.addErrorMessage(constant.getLabel(), - "The set of model values should not be empty.", this.getId(), IMessageProvider.ERROR, - UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - setComplete(false); - } - } - } - - // the constant identifier is a config file keyword - if (SemanticHelper.isConfigFileKeyword(constant.getLabel())) - { - modelEditor.addErrorMessage(constant.getLabel(), "The toolbox cannot handle the constant identifier " - + constant.getLabel() + ".", this.getId(), IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(MODEL_PARAMETER_CONSTANTS))); - setComplete(false); - } - } + expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); + expandSection(dm.getSectionForAttribute(MODEL_CORRECTNESS_PROPERTIES)); + } + + boolean hasTwoTypes = false; // set true if this symmetry set has two differently-typed model + // values. + String typeString = null; // set to the type of the first typed model value in this symmetry + // set. + if (modelValuesSet.hasType()) { + typeString = modelValuesSet.getType(); + } else { + for (int j = 0; j < modelValuesSet.getValues().length; j++) { + String thisTypeString = TypedSet.getTypeOfId(modelValuesSet.getValues()[j]); + if (thisTypeString != null) { + if (typeString != null && !typeString.equals(thisTypeString)) { + hasTwoTypes = true; + } else { + typeString = thisTypeString; + } + } + } + } + if (hasTwoTypes + || (symmetryType != null && typeString != null && !typeString.equals(symmetryType))) { + modelEditor.addErrorMessage(constant.getLabel(), + "Two differently typed model values used in symmetry sets.", + this.getId()/* constant */, IMessageProvider.ERROR, + UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTANTS))); + setComplete(false); + expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTANTS)); + } else { + if (typeString != null) { + symmetryType = typeString; + } + } - // iterate over the constants again, and check if the parameters are used as Model Values - for (int i = 0; i < constants.size(); i++) - { - Assignment constant = (Assignment) constants.get(i); - List<String> values = Arrays.asList(constant.getParams()); - // check list of parameters - validateUsage(MODEL_PARAMETER_CONSTANTS, values, "param1_", "A parameter name", "Constant Assignment", - false); - } + // symmetry can be used for only one set of model values - // number of workers - int number = workers.getSelection(); - if (number > Runtime.getRuntime().availableProcessors()) - { - modelEditor.addErrorMessage("strangeNumber1", "Specified number of workers is " + number - + ". The number of processors available on the system is " - + Runtime.getRuntime().availableProcessors() - + ".\n The number of workers should not exceed the number of processors.", - this.getId(), IMessageProvider.WARNING, UIHelper.getWidget(dm - .getAttributeControl(LAUNCH_NUMBER_OF_WORKERS))); - expandSection(SEC_HOW_TO_RUN); - } else { - modelEditor.removeErrorMessage("strangeNumber1", UIHelper.getWidget(dm - .getAttributeControl(LAUNCH_NUMBER_OF_WORKERS))); - } - - // legacy value? - // better handle legacy models - try { - final int defaultMaxHeapSize = TLCUIActivator - .getDefault() - .getPreferenceStore() - .getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); - final int legacyValue = getModel().getAttribute( - LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); - // old default, silently convert to new default - if (legacyValue == 500) { - getModel().setAttribute( - LAUNCH_MAX_HEAP_SIZE, TLCPreferenceInitializer.MAX_HEAP_SIZE_DEFAULT); - maxHeapSize.setSelection(TLCPreferenceInitializer.MAX_HEAP_SIZE_DEFAULT); - } else if (legacyValue >= 100) { - modelEditor - .addErrorMessage( - "strangeNumber1", - "Found legacy value for physically memory of (" - + legacyValue - + "mb) that needs manual conversion. 25% is a safe setting on most computers.", - this.getId(), IMessageProvider.WARNING, - maxHeapSize); + } + if (modelValuesSet.getValueCount() > 0) { + // there were values defined + // check if those are numbers? + /* + * if (modelValuesSet.hasANumberOnlyValue()) { mm.addMessage("modelValues1", + * "A model value can not be an number", modelValuesSet, IMessageProvider.ERROR, + * constantTable.getTable()); setComplete(false); } + */ + + List<String> mvList = modelValuesSet.getValuesAsList(); + // check list of model values + validateUsage(sectionId, widget, mvList, "modelValues2_", "A model value", + "Constant Assignment", true); + // check if the values are correct ids + validateId(sectionId, widget, mvList, "modelValues2_", "A model value"); + + // get widget for model values assigned to constant + // check if model values are config file keywords + for (int j = 0; j < mvList.size(); j++) { + String value = (String) mvList.get(j); + if (SemanticHelper.isConfigFileKeyword(value)) { + modelEditor.addErrorMessage(value, + "The toolbox cannot handle the model value " + value + ".", this.getId(), + IMessageProvider.ERROR, widget); + setComplete(false); + } + } + } else { + // This made an error by LL on 15 Nov 2009 + modelEditor.addErrorMessage(label, "The set of model values should not be empty.", + this.getId(), IMessageProvider.ERROR, + widget); + setComplete(false); + } + } + } + + // the constant identifier is a config file keyword + if (SemanticHelper.isConfigFileKeyword(label)) { + modelEditor.addErrorMessage(label, + "The toolbox cannot handle the constant identifier " + label + ".", this.getId(), + IMessageProvider.ERROR, widget); setComplete(false); - expandSection(SEC_HOW_TO_RUN); } - } catch (CoreException e) { - TLCUIActivator.getDefault().logWarning("Faild to read heap value", - e); } - - // max heap size - // color the scale according to OS and TLC requirements - int maxHeapSizeValue = maxHeapSize.getSelection(); - double x = maxHeapSizeValue / 100d; - float y = (float) linearInterpolator.interpolate(x); - maxHeapSize.setBackground(new Color(Display.getDefault(), new RGB( - 120 * y, 1 - y, 1f))); + + // iterate over the constants again, and check if the parameters are used as + // Model Values + for (int i = 0; i < constants.size(); i++) { + Assignment constant = (Assignment) constants.get(i); + List<String> values = Arrays.asList(constant.getParams()); + // check list of parameters + validateUsage(sectionId, widget, values, "param1_", "A parameter name", "Constant Assignment", + false); + } // IP/network address correct? final int networkAddressIndex = this.networkInterfaceCombo.getSelectionIndex(); @@ -619,917 +589,892 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta modelEditor.addErrorMessage("strangeAddress1", String.format( "Found the manually inserted master's network address %s. " - + "This is usually unnecessary and hints at a misconfiguration. " - + "Make sure your computer running the TLC master is reachable at address %s.", + + "This is usually unnecessary and hints at a misconfiguration. " + + "Make sure your computer running the TLC master is reachable at address %s.", this.networkInterfaceCombo.getText(), this.networkInterfaceCombo.getText()), this.getId(), IMessageProvider.WARNING, networkInterfaceCombo); expandSection(SEC_HOW_TO_RUN); } - - // fill the checkpoints - updateCheckpoints(); - - // recover from checkpoint - if (checkpointButton.getSelection()) - { - if (EMPTY_STRING.equals(checkpointIdText.getText())) - { - modelEditor.addErrorMessage("noChckpoint", "No checkpoint data found", this.getId(), - IMessageProvider.ERROR, UIHelper.getWidget(dm.getAttributeControl(LAUNCH_RECOVER))); - setComplete(false); - expandSection(SEC_HOW_TO_RUN); - } - } - - // The following code added by LL and DR on 10 Sep 2009. - // Reset the enabling and selection of spec type depending on the number number - // of variables in the spec. - // This code needs to be modified when we modify the model launcher - // to allow the No Spec option to be selected when there are variables. - if (rootModuleNode != null) - { - final Control errorMsgControl = UIHelper.getWidget(getDataBindingManager().getAttributeControl(MODEL_BEHAVIOR_NO_SPEC)); + + // The following code added by LL and DR on 10 Sep 2009. + // Reset the enabling and selection of spec type depending on the number number + // of variables in the spec. + // This code needs to be modified when we modify the model launcher + // to allow the No Spec option to be selected when there are variables. + if (rootModuleNode != null) { + final Control errorMsgControl = UIHelper + .getWidget(getDataBindingManager().getAttributeControl(MODEL_BEHAVIOR_NO_SPEC)); final String errorMsgKey = MODEL_BEHAVIOR_NO_SPEC + "ErrorMsgKey"; - if (rootModuleNode.getVariableDecls().length == 0) - { - setHasVariables(false); + if (rootModuleNode.getVariableDecls().length == 0) { + setHasVariables(false); modelEditor.addErrorMessage(errorMsgKey, - "\"What is the behavior spec?\" automatically set to \"No Behavior Spec\" because spec has no declared variables.", this.getId(), - IMessageProvider.INFORMATION, errorMsgControl); - - // set selection to the NO SPEC field - if (!noSpecRadio.getSelection()) - { - // mark dirty so that changes must be written to config file - setSpecSelection(MODEL_BEHAVIOR_TYPE_NO_SPEC); - dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_NO_SPEC)).markDirty(); - - } - } else - { - setHasVariables(true); + "\"What is the behavior spec?\" automatically set to \"No Behavior Spec\" because spec has no declared variables.", + this.getId(), IMessageProvider.INFORMATION, errorMsgControl); + + // set selection to the NO SPEC field + if (!NO_SPEC_COMBO_LABEL.equals(behaviorCombo.getText())) { + // mark dirty so that changes must be written to config file + setSpecSelection(MODEL_BEHAVIOR_TYPE_NO_SPEC); + dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_NO_SPEC)).markDirty(); + + } + } else { + setHasVariables(true); modelEditor.removeErrorMessage(errorMsgKey, errorMsgControl); - // if there are variables, the user - // may still want to choose no spec - // so the selection is not changed - // - // if (noSpecRadio.getSelection()) - // { - // // mark dirty so that changes must be written to config file - // dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION)).markDirty(); - // // set selection to the default - // setSpecSelection(MODEL_BEHAVIOR_TYPE_DEFAULT); - // } - } - } + // if there are variables, the user + // may still want to choose no spec + // so the selection is not changed + // + // if (noSpecRadio.getSelection()) + // { + // // mark dirty so that changes must be written to config file + // dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION)).markDirty(); + // // set selection to the default + // setSpecSelection(MODEL_BEHAVIOR_TYPE_DEFAULT); + // } + } + } + + // This code disables or enables sections + // depending on whether whether no spec is selected + // or not. + // This must occur after the preceeding code in case + // that code changes the selection. + final Section whatToCheckSection = dm.getSection(SEC_WHAT_TO_CHECK).getSection(); + final ResultPage rp = (ResultPage) modelEditor.findPage(ResultPage.ID); + final EvaluateConstantExpressionPage ecep = (EvaluateConstantExpressionPage) modelEditor + .findPage(EvaluateConstantExpressionPage.ID); + + final Set<Section> resultPageSections = rp.getSections(SEC_GENERAL, SEC_STATISTICS); - // This code disables or enables sections - // depending on whether whether no spec is selected - // or not. - // This must occur after the preceeding code in case - // that code changes the selection. - final Section whatToCheckSection = dm.getSection(SEC_WHAT_TO_CHECK).getSection(); - final Set<Section> resultPageSections = ((ResultPage) modelEditor.findPage(ResultPage.ID)).getSections(SEC_GENERAL, SEC_STATISTICS); - final String hint = " (\"What is the behavior spec?\" above has no behavior spec)"; final String hintResults = " (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)"; - if (noSpecRadio.getSelection()) { + if (NO_SPEC_COMBO_LABEL.equals(behaviorCombo.getText())) { whatToCheckSection .setText(!whatToCheckSection.getText().endsWith(hint) ? whatToCheckSection.getText() + hint : whatToCheckSection.getText()); whatToCheckSection.setExpanded(false); whatToCheckSection.setEnabled(false); - resultPageSections.forEach(new Consumer<Section>() { - @Override - public void accept(Section sec) { - sec.setText(!sec.getText().endsWith(hintResults) ? sec.getText() + hintResults : sec.getText()); - sec.setEnabled(false); - sec.setExpanded(false); - } + resultPageSections.forEach((section) -> { + section.setText(!section.getText().endsWith(hintResults) ? section.getText() + hintResults : section.getText()); + section.setEnabled(false); + compensateForExpandableCompositesPoorDesign(section, false); }); + + if (ecep != null) { + ecep.setNoBehaviorSpecToggleState(true); + } else { + rp.setNoBehaviorSpecToggleState(true); + } } else { whatToCheckSection.setText(whatToCheckSection.getText().replace(hint, "")); whatToCheckSection.setExpanded(true); whatToCheckSection.setEnabled(true); - resultPageSections.forEach(new Consumer<Section>() { - @Override - public void accept(Section sec) { - sec.setText(sec.getText().replace(hintResults, "")); - sec.setEnabled(true); - sec.setExpanded(true); - } + resultPageSections.forEach((section) -> { + section.setText(section.getText().replace(hintResults, "")); + section.setEnabled(true); + compensateForExpandableCompositesPoorDesign(section, true); }); + + if (ecep != null) { + ecep.setNoBehaviorSpecToggleState(false); + } else { + rp.setNoBehaviorSpecToggleState(false); + } } - // The following code is not needed now because we automatically change - // the selection to No Spec if there are no variables. - // - // if (selectedAttribute != null) { - // // the user selected to use a spec - // // check if there are variables declared - // if (rootModuleNode != null - // && rootModuleNode.getVariableDecls().length == 0) { - // // no variables => install an error - // mm.addMessage("noVariables", - // "There were no variables declared in the root module", - // null, IMessageProvider.ERROR, UIHelper.getWidget(dm - // .getAttributeControl(selectedAttribute))); - // setComplete(false); - // expandSection(dm.getSectionForAttribute(selectedAttribute)); - // } - // } - - // check if the selected fields are filled - if (closedFormulaRadio.getSelection() && specSource.getDocument().get().trim().equals("")) - { - modelEditor.addErrorMessage("noSpec", "The formula must be provided", this.getId(), IMessageProvider.ERROR, - UIHelper.getWidget(dm.getAttributeControl(MODEL_BEHAVIOR_CLOSED_SPECIFICATION))); - setComplete(false); - expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION)); - } else if (initNextFairnessRadio.getSelection()) - { - String init = initFormulaSource.getDocument().get().trim(); - String next = nextFormulaSource.getDocument().get().trim(); - - if (init.equals("")) - { - modelEditor.addErrorMessage("noInit", "The Init formula must be provided", this.getId(), - IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT))); - setComplete(false); - expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT)); - } - if (next.equals("")) - { - modelEditor.addErrorMessage("noNext", "The Next formula must be provided", this.getId(), - IMessageProvider.ERROR, UIHelper.getWidget(dm - .getAttributeControl(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT))); - setComplete(false); - expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT)); - } - } + // The following code is not needed now because we automatically change + // the selection to No Spec if there are no variables. + // + // if (selectedAttribute != null) { + // // the user selected to use a spec + // // check if there are variables declared + // if (rootModuleNode != null + // && rootModuleNode.getVariableDecls().length == 0) { + // // no variables => install an error + // mm.addMessage("noVariables", + // "There were no variables declared in the root module", + // null, IMessageProvider.ERROR, UIHelper.getWidget(dm + // .getAttributeControl(selectedAttribute))); + // setComplete(false); + // expandSection(dm.getSectionForAttribute(selectedAttribute)); + // } + // } + + // check if the selected fields are filled + final Control initTA = UIHelper.getWidget(dm.getAttributeControl(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT)); + final Control nextTA = UIHelper.getWidget(dm.getAttributeControl(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT)); + final Control specTA = UIHelper.getWidget(dm.getAttributeControl(MODEL_BEHAVIOR_CLOSED_SPECIFICATION)); + modelEditor.removeErrorMessage("noInit", initTA); + modelEditor.removeErrorMessage("noNext", nextTA); + modelEditor.removeErrorMessage("noSpec", specTA); + if (TEMPORAL_FORMULA_COMBO_LABEL.equals(behaviorCombo.getText()) + && (specSource.getDocument().get().trim().length() == 0)) { + modelEditor.addErrorMessage("noSpec", "The formula must be provided", this.getId(), IMessageProvider.ERROR, + specTA); + setComplete(false); + expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION)); + } else if (INIT_NEXT_COMBO_LABEL.equals(behaviorCombo.getText())) { + final String init = initFormulaSource.getDocument().get().trim(); + final String next = nextFormulaSource.getDocument().get().trim(); + + if (init.length() == 0) { + modelEditor.addErrorMessage("noInit", "The Init formula must be provided", this.getId(), + IMessageProvider.ERROR, initTA); + setComplete(false); + expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT)); + } + if (next.length() == 0) { + modelEditor.addErrorMessage("noNext", "The Next formula must be provided", this.getId(), + IMessageProvider.ERROR, nextTA); + setComplete(false); + expandSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT)); + } + } + final Control emails = UIHelper.getWidget(dm.getAttributeControl(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS)); + modelEditor.removeErrorMessage("email address invalid", emails); + modelEditor.removeErrorMessage("email address missing", emails); // Verify that the user provided email address is valid and can be used to send // the model checking result to. - if (this.distributedCombo.getSelectionIndex() > 1) { + final TLCConsumptionProfile profile = getSelectedTLCProfile(); + if ((profile != null) && CLOUD_CONFIGURATION_KEY.equals(profile.getConfigurationKey())) { final String text = resultMailAddressText.getText(); + try { - javax.mail.internet.InternetAddress.parse(text, true); - } catch (javax.mail.internet.AddressException exp) { + InternetAddress.parse(text, true); + } catch (AddressException exp) { modelEditor.addErrorMessage("email address invalid", "For Cloud TLC to work please enter a valid email address.", this.getId(), - IMessageProvider.ERROR, - UIHelper.getWidget(dm.getAttributeControl(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS))); + IMessageProvider.ERROR, emails); setComplete(false); expandSection(SEC_HOW_TO_RUN); } if ("".equals(text.trim())) { modelEditor.addErrorMessage("email address missing", "For Cloud TLC to work please enter an email address.", this.getId(), IMessageProvider.ERROR, - UIHelper.getWidget(dm.getAttributeControl(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS))); + emails); setComplete(false); expandSection(SEC_HOW_TO_RUN); } } - - mm.setAutoUpdate(true); - - super.validatePage(switchToErrorPage); - } - - /** - * This method is used to enable and disable UI widgets depending on the fact if the specification - * has variables. - * @param hasVariables true if the spec contains variables - */ - private void setHasVariables(boolean hasVariables) - { - - // the no spec option can be selected if there - // are variables or no variables - // this.noSpecRadio.setEnabled(!hasVariables); - this.closedFormulaRadio.setEnabled(hasVariables); - this.initNextFairnessRadio.setEnabled(hasVariables); - - // the input fields are enabled only if there are variables - this.initFormulaSource.getControl().setEnabled(hasVariables); - this.nextFormulaSource.getControl().setEnabled(hasVariables); - this.specSource.getControl().setEnabled(hasVariables); - } - - /** - * This method sets the selection on the - * @param selectedFormula - */ - private void setSpecSelection(int specType) - { - switch (specType) { - case MODEL_BEHAVIOR_TYPE_NO_SPEC: - this.noSpecRadio.setSelection(true); - this.initNextFairnessRadio.setSelection(false); - this.closedFormulaRadio.setSelection(false); - break; - case MODEL_BEHAVIOR_TYPE_SPEC_CLOSED: - this.noSpecRadio.setSelection(false); - this.initNextFairnessRadio.setSelection(false); - this.closedFormulaRadio.setSelection(true); - break; - case MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT: - this.noSpecRadio.setSelection(false); - this.initNextFairnessRadio.setSelection(true); - this.closedFormulaRadio.setSelection(false); - break; - default: - throw new IllegalArgumentException("Wrong spec type, this is a bug"); - } - } + mm.setAutoUpdate(true); + + super.validatePage(switchToErrorPage); + } + + public boolean workerCountCanBeModified() { + return workerValueCanBeModified.get(); + } + + public int getWorkerCount() { + return workerThreadCount.get(); + } + + public void setWorkerCount(final int count) { + workerThreadCount.set(count); + + setTLCProfileComboSelection(CUSTOM_TLC_PROFILE_DISPLAY_NAME); + + updateTLCResourcesLabel(); + } + + public boolean heapPercentageCanBeModified() { + return heapPercentageCanBeModified.get(); + } + + public int getHeapPercentage() { + return heapPercentage.get(); + } + + public void setHeapPercentage(final int percentage) { + heapPercentage.set(percentage); + + if (!currentProfileIsAdHoc.get()) { + setTLCProfileComboSelection(CUSTOM_TLC_PROFILE_DISPLAY_NAME); + } + + updateTLCResourcesLabel(); + } + + /** + * This method is used to enable and disable UI widgets depending on the fact if + * the specification has variables. + * + * @param hasVariables true if the spec contains variables + */ + private void setHasVariables(final boolean hasVariables) { + String[] newItems = null; - /** - * Save data back to model - */ - public void commit(boolean onSave) - { + if (hasVariables) { + if (behaviorCombo.indexOf(INIT_NEXT_COMBO_LABEL) == -1) { + newItems = VARIABLE_BEHAVIOR_COMBO_ITEMS; + } + } else { + if (behaviorCombo.indexOf(INIT_NEXT_COMBO_LABEL) != -1) { + newItems = NO_VARIABLE_BEHAVIOR_COMBO_ITEMS; + } + } + + if (newItems != null) { + final String currentSelection = behaviorCombo.getText(); + + behaviorCombo.removeAll(); + behaviorCombo.setItems(newItems); + + final int index = behaviorCombo.indexOf(currentSelection); + if (index != -1) { + behaviorCombo.select(index); + } + } + } + + /** + * This method sets the selection on the + * + * @param selectedFormula + */ + private void setSpecSelection(int specType) { + int index = -1; + + switch (specType) { + case MODEL_BEHAVIOR_TYPE_NO_SPEC: + index = behaviorCombo.indexOf(NO_SPEC_COMBO_LABEL); + break; + case MODEL_BEHAVIOR_TYPE_SPEC_CLOSED: + index = behaviorCombo.indexOf(TEMPORAL_FORMULA_COMBO_LABEL); + break; + case MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT: + index = behaviorCombo.indexOf(INIT_NEXT_COMBO_LABEL); + break; + default: + throw new IllegalArgumentException("Wrong spec type, this is a bug"); + } + + if (index != -1) { + behaviorCombo.select(index); + moveToTopOfBehaviorOptionsStack(behaviorCombo.getText()); + } + } + + private int getModelConstantForSpecSelection() { + final String selectedBehavior = behaviorCombo.getText(); + final int specType; + + if (TEMPORAL_FORMULA_COMBO_LABEL.equals(selectedBehavior)) { + specType = MODEL_BEHAVIOR_TYPE_SPEC_CLOSED; + } else if (INIT_NEXT_COMBO_LABEL.equals(selectedBehavior)) { + specType = MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT; + } else if (NO_SPEC_COMBO_LABEL.equals(selectedBehavior)) { + specType = MODEL_BEHAVIOR_TYPE_NO_SPEC; + } else { + specType = MODEL_BEHAVIOR_TYPE_DEFAULT; + } + + return specType; + } + + /** + * Save data back to model + */ + public void commit(boolean onSave) { + final Model model = getModel(); final String comments = FormHelper.trimTrailingSpaces(commentsSource.getDocument().get()); - getModel().setAttribute(MODEL_COMMENTS, comments); - - // TLCUIActivator.getDefault().logDebug("Main page commit"); - // closed formula - String closedFormula = FormHelper.trimTrailingSpaces(this.specSource.getDocument().get()); - getModel().setAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, closedFormula); - - // init formula - String initFormula = FormHelper.trimTrailingSpaces(this.initFormulaSource.getDocument().get()); - getModel().setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, initFormula); - - // next formula - String nextFormula = FormHelper.trimTrailingSpaces(this.nextFormulaSource.getDocument().get()); - getModel().setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, nextFormula); - - // fairness formula - // String fairnessFormula = - // FormHelper.trimTrailingSpaces(this.fairnessFormulaSource.getDocument().get()); - // getModel().setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, - // fairnessFormula); - - // mode - int specType; - if (this.closedFormulaRadio.getSelection()) - { - specType = MODEL_BEHAVIOR_TYPE_SPEC_CLOSED; - } else if (this.initNextFairnessRadio.getSelection()) - { - specType = MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT; - } else if (this.noSpecRadio.getSelection()) - { - specType = MODEL_BEHAVIOR_TYPE_NO_SPEC; - } else - { - specType = MODEL_BEHAVIOR_TYPE_DEFAULT; - } + model.setAttribute(MODEL_COMMENTS, comments); + + // TLCUIActivator.getDefault().logDebug("Main page commit"); + // closed formula + String closedFormula = FormHelper.trimTrailingSpaces(this.specSource.getDocument().get()); + model.setAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, closedFormula); + + // init formula + String initFormula = FormHelper.trimTrailingSpaces(this.initFormulaSource.getDocument().get()); + model.setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, initFormula); + + // next formula + String nextFormula = FormHelper.trimTrailingSpaces(this.nextFormulaSource.getDocument().get()); + model.setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, nextFormula); + + // fairness formula + // String fairnessFormula = + // FormHelper.trimTrailingSpaces(this.fairnessFormulaSource.getDocument().get()); + // model.setAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, + // fairnessFormula); + + // mode + model.setAttribute(MODEL_BEHAVIOR_SPEC_TYPE, getModelConstantForSpecSelection()); - getModel().setAttribute(MODEL_BEHAVIOR_SPEC_TYPE, specType); - - // number of workers - getModel().setAttribute(LAUNCH_NUMBER_OF_WORKERS, workers.getSelection()); - - int maxHeapSizeValue = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); - maxHeapSizeValue = maxHeapSize.getSelection(); - getModel().setAttribute(LAUNCH_MAX_HEAP_SIZE, maxHeapSizeValue); - - // recover from deadlock - boolean recover = this.checkpointButton.getSelection(); - getModel().setAttribute(LAUNCH_RECOVER, recover); - - // check deadlock - boolean checkDeadlock = this.checkDeadlockButton.getSelection(); - getModel().setAttribute(MODEL_CORRECTNESS_CHECK_DEADLOCK, checkDeadlock); - - // run in distributed mode - String distributed = this.distributedCombo.getItem(this.distributedCombo.getSelectionIndex()); - getModel().setAttribute(LAUNCH_DISTRIBUTED, distributed); - - String resultMailAddress = this.resultMailAddressText.getText(); - getModel().setAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, resultMailAddress); - - // distributed FPSet count - getModel().setAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, distributedFPSetCountSpinner.getSelection()); - - // distributed FPSet count - getModel().setAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, distributedNodesCountSpinner.getSelection()); - - // network interface - String iface = ""; - final int index = this.networkInterfaceCombo.getSelectionIndex(); - if (index == -1) { + // check deadlock + boolean checkDeadlock = this.checkDeadlockButton.getSelection(); + model.setAttribute(MODEL_CORRECTNESS_CHECK_DEADLOCK, checkDeadlock); + + final TLCConsumptionProfile profile = getSelectedTLCProfile(); + final String profileValue = (profile != null) ? profile.getPreferenceValue() + : CUSTOM_TLC_PROFILE_PREFERENCE_VALUE; + + model.setAttribute(TLC_RESOURCES_PROFILE, profileValue); + + model.setAttribute(LAUNCH_NUMBER_OF_WORKERS, workerThreadCount.get()); + model.setAttribute(LAUNCH_MAX_HEAP_SIZE, heapPercentage.get()); + + // run in distributed mode + if ((profile != null) && profile.profileIsForRemoteWorkers()) { + model.setAttribute(LAUNCH_DISTRIBUTED, profile.getPreferenceValue()); + } else { + model.setAttribute(LAUNCH_DISTRIBUTED, LAUNCH_DISTRIBUTED_NO); + } + + String resultMailAddress = this.resultMailAddressText.getText(); + model.setAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, resultMailAddress); + + // distributed FPSet count + model.setAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, distributedFPSetCountSpinner.getSelection()); + + // distributed FPSet count + model.setAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, distributedNodesCountSpinner.getSelection()); + + // network interface + String iface = ""; + final int index = this.networkInterfaceCombo.getSelectionIndex(); + if (index == -1) { // Normally, the user selects an address from the provided list. // This branch handles the case where the user manually entered an // address. We don't verify it though. - iface = this.networkInterfaceCombo.getText(); - } else { - iface = this.networkInterfaceCombo.getItem(index); - } - getModel().setAttribute(LAUNCH_DISTRIBUTED_INTERFACE, iface); - - // invariants - List<String> serializedList = FormHelper.getSerializedInput(invariantsTable); - getModel().setAttribute(MODEL_CORRECTNESS_INVARIANTS, serializedList); - - // properties - serializedList = FormHelper.getSerializedInput(propertiesTable); - getModel().setAttribute(MODEL_CORRECTNESS_PROPERTIES, serializedList); - - // constants - List<String> constants = FormHelper.getSerializedInput(constantTable); - getModel().setAttribute(MODEL_PARAMETER_CONSTANTS, constants); - - // variables - String variables = ModelHelper.createVariableList(SemanticHelper.getRootModuleNode()); - getModel().setAttribute(MODEL_BEHAVIOR_VARS, variables); - - super.commit(onSave); - } - - /** - * Checks if checkpoint information changed - */ - private void updateCheckpoints() - { - IResource[] checkpoints = null; - try - { - // checkpoint id - checkpoints = getModel().getCheckpoints(false); - } catch (CoreException e) - { - TLCUIActivator.getDefault().logError("Error checking chekpoint data", e); - } + iface = this.networkInterfaceCombo.getText(); + } else { + iface = this.networkInterfaceCombo.getItem(index); + } + model.setAttribute(LAUNCH_DISTRIBUTED_INTERFACE, iface); - if (checkpoints != null && checkpoints.length > 0) - { - this.checkpointIdText.setText(checkpoints[0].getName()); - } else - { - this.checkpointIdText.setText(EMPTY_STRING); - } + // invariants + List<String> serializedList = FormHelper.getSerializedInput(invariantsTable); + model.setAttribute(MODEL_CORRECTNESS_INVARIANTS, serializedList); - if ((checkpoints == null) || (checkpoints.length == 0)) - { - checkpointSizeText.setVisible(false); - chkpointSizeLabel.setVisible(false); - chkptDeleteButton.setVisible(false); - } else - { - checkpointSizeText.setText(String.valueOf(ResourceHelper.getSizeOfJavaFileResource(checkpoints[0]) / 1000)); - checkpointSizeText.setVisible(true); - chkpointSizeLabel.setVisible(true); - chkptDeleteButton.setVisible(true); - } - } - - /** - * Creates the UI - * This method is called to create the widgets and arrange them on the page - * - * Its helpful to know what the standard SWT widgets look like. - * Pictures can be found at http://www.eclipse.org/swt/widgets/ - * - * Layouts are used throughout this method. - * A good explanation of layouts is given in the article - * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html - */ - protected void createBodyContent(IManagedForm managedForm) - { - DataBindingManager dm = getDataBindingManager(); - int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE; - FormToolkit toolkit = managedForm.getToolkit(); - Composite body = managedForm.getForm().getBody(); - - GridData gd; - TableWrapData twd; - - Section section; - GridLayout layout; - - /* - * Comments/notes section spanning two columns - */ - Composite top = toolkit.createComposite(body); - top.setLayout(FormHelper.createFormTableWrapLayout(false, 2)); - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.colspan = 2; - top.setLayoutData(twd); - - section = FormHelper.createSectionComposite(top, "Model description", "", toolkit, sectionFlags, getExpansionListener()); - - final ValidateableSectionPart commentsPart = new ValidateableSectionPart(section, this, SEC_COMMENTS); - managedForm.addPart(commentsPart); - final DirtyMarkingListener commentsListener = new DirtyMarkingListener(commentsPart, true); - - final Composite commentsArea = (Composite) section.getClient(); - commentsArea.setLayout(new TableWrapLayout()); - - commentsSource = FormHelper.createFormsSourceViewer(toolkit, commentsArea, SWT.V_SCROLL | SWT.WRAP); - // layout of the source viewer - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.heightHint = 60; - commentsSource.addTextListener(commentsListener); - commentsSource.getTextWidget().setLayoutData(twd); - commentsSource.getTextWidget().addFocusListener(focusListener); - toolkit.paintBordersFor(commentsArea); - - dm.bindAttribute(MODEL_COMMENTS, commentsSource, commentsPart); - - /* - * Because the two Composite objects `left' and `right' are added to the - * object `body' in this order, `left' is displayed to the left of `right'. - */ - // left - Composite left = toolkit.createComposite(body); - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.grabHorizontal = true; - left.setLayout(new GridLayout(1, false)); - left.setLayoutData(twd); - - // right - Composite right = toolkit.createComposite(body); - twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.grabHorizontal = true; - right.setLayoutData(twd); - right.setLayout(new GridLayout(1, false)); - - // ------------------------------------------ - // what is the spec - section = FormHelper.createSectionComposite(left, "What is the behavior spec?", "", toolkit, sectionFlags - | Section.EXPANDED, getExpansionListener()); - // only grab horizontal space - gd = new GridData(GridData.FILL_HORIZONTAL); - section.setLayoutData(gd); - - Composite behaviorArea = (Composite) section.getClient(); - layout = new GridLayout(); - layout.numColumns = 2; - behaviorArea.setLayout(layout); - - ValidateableSectionPart behaviorPart = new ValidateableSectionPart(section, this, SEC_WHAT_IS_THE_SPEC); - managedForm.addPart(behaviorPart); - DirtyMarkingListener whatIsTheSpecListener = new DirtyMarkingListener(behaviorPart, true); - // split formula option - initNextFairnessRadio = toolkit.createButton(behaviorArea, "Initial predicate and next-state relation", - SWT.RADIO); - initNextFairnessRadio.addFocusListener(focusListener); - - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - initNextFairnessRadio.setLayoutData(gd); - initNextFairnessRadio.addSelectionListener(whatIsTheSpecListener); - initNextFairnessRadio.addFocusListener(focusListener); - - // init - toolkit.createLabel(behaviorArea, "Init:"); - initFormulaSource = FormHelper.createFormsSourceViewer(toolkit, behaviorArea, SWT.NONE | SWT.SINGLE); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.heightHint = 18; - initFormulaSource.getTextWidget().setLayoutData(gd); - initFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); - initFormulaSource.getTextWidget().addModifyListener(widgetActivatingListener); - initFormulaSource.getTextWidget().addFocusListener(focusListener); - dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, initFormulaSource, behaviorPart); - - // next - toolkit.createLabel(behaviorArea, "Next:"); - nextFormulaSource = FormHelper.createFormsSourceViewer(toolkit, behaviorArea, SWT.NONE | SWT.SINGLE); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.heightHint = 18; - nextFormulaSource.getTextWidget().setLayoutData(gd); - nextFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); - nextFormulaSource.getTextWidget().addModifyListener(widgetActivatingListener); - nextFormulaSource.getTextWidget().addFocusListener(focusListener); - dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, nextFormulaSource, behaviorPart); - - // fairness - // toolkit.createLabel(behaviorArea, "Fairness:"); - // fairnessFormulaSource = FormHelper.createSourceViewer(toolkit, - // behaviorArea, SWT.NONE | SWT.SINGLE); - // gd = new GridData(GridData.FILL_HORIZONTAL); - // gd.heightHint = 18; - // fairnessFormulaSource.getTextWidget().setLayoutData(gd); - // fairnessFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); - // fairnessFormulaSource.getTextWidget().addModifyListener(widgetActivatingListener); - // dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, - // fairnessFormulaSource, behaviorPart); - - // closed formula option - closedFormulaRadio = toolkit.createButton(behaviorArea, "Temporal formula", SWT.RADIO); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - closedFormulaRadio.setLayoutData(gd); - closedFormulaRadio.addSelectionListener(whatIsTheSpecListener); - - // spec - Label specLabel = toolkit.createLabel(behaviorArea, ""); - // changed from "Spec:" 10 Sep 09 - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - specLabel.setLayoutData(gd); - specSource = FormHelper.createFormsSourceViewer(toolkit, behaviorArea, SWT.V_SCROLL); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.heightHint = 55; - specSource.getTextWidget().setLayoutData(gd); - specSource.getTextWidget().addModifyListener(whatIsTheSpecListener); - specSource.getTextWidget().addModifyListener(widgetActivatingListener); - dm.bindAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, specSource, behaviorPart); - - noSpecRadio = toolkit.createButton(behaviorArea, "No Behavior Spec", SWT.RADIO); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - noSpecRadio.setLayoutData(gd); - noSpecRadio.addSelectionListener(whatIsTheSpecListener); - dm.bindAttribute(MODEL_BEHAVIOR_NO_SPEC, noSpecRadio, behaviorPart); - - // ------------------------------------------ - // what to check - section = FormHelper.createSectionComposite(left, "What to check?", "", toolkit, sectionFlags - | Section.EXPANDED, getExpansionListener()); - // only grab horizontal space - gd = new GridData(GridData.FILL_HORIZONTAL); - section.setLayoutData(gd); - - Composite toBeCheckedArea = (Composite) section.getClient(); - layout = new GridLayout(); - layout.numColumns = 1; - toBeCheckedArea.setLayout(layout); - - checkDeadlockButton = toolkit.createButton(toBeCheckedArea, "Deadlock", SWT.CHECK); - - ValidateableSectionPart toBeCheckedPart = new ValidateableSectionPart(section, this, SEC_WHAT_TO_CHECK); - managedForm.addPart(toBeCheckedPart); - DirtyMarkingListener whatToCheckListener = new DirtyMarkingListener(toBeCheckedPart, true); - checkDeadlockButton.addSelectionListener(whatToCheckListener); - - // Invariants - ValidateableTableSectionPart invariantsPart = new ValidateableTableSectionPart(toBeCheckedArea, "Invariants", - "Formulas true in every reachable state.", toolkit, sectionFlags, this, SEC_WHAT_TO_CHECK_INVARIANTS); - managedForm.addPart(invariantsPart); - invariantsTable = invariantsPart.getTableViewer(); - dm.bindAttribute(MODEL_CORRECTNESS_INVARIANTS, invariantsTable, invariantsPart); - - // Properties - ValidateableTableSectionPart propertiesPart = new ValidateableTableSectionPart(toBeCheckedArea, "Properties", - "Temporal formulas true for every possible behavior.", toolkit, sectionFlags, this, - SEC_WHAT_TO_CHECK_PROPERTIES); - managedForm.addPart(propertiesPart); - propertiesTable = propertiesPart.getTableViewer(); - dm.bindAttribute(MODEL_CORRECTNESS_PROPERTIES, propertiesTable, propertiesPart); - - // ------------------------------------------ - // what is the model - - // Constants - ValidateableConstantSectionPart constantsPart = new ValidateableConstantSectionPart(right, - "What is the model?", "Specify the values of declared constants.", toolkit, sectionFlags, this, - SEC_WHAT_IS_THE_MODEL); - managedForm.addPart(constantsPart); - constantTable = constantsPart.getTableViewer(); - dm.bindAttribute(MODEL_PARAMETER_CONSTANTS, constantTable, constantsPart); - Composite parametersArea = (Composite) constantsPart.getSection().getClient(); - HyperlinkGroup group = new HyperlinkGroup(parametersArea.getDisplay()); - - // TESTING XXXXXX - // managedForm.removePart(constantsPart); - // Control saved = right.getChildren()[0] ; - // constantTable.getTable().setSize(1000, 1000); - // constantTable.getTable().setVisible(false); - // - // System.out.println("GetSize returns " + - // constantTable.getTable().getSize().x); - // right.getChildren()[0].setVisible(false); - // parametersArea.setVisible(false); - - // create a composite to put the text into - Composite linksPanelToAdvancedPage = toolkit.createComposite(parametersArea); - gd = new GridData(); - gd.horizontalSpan = 2; - - linksPanelToAdvancedPage.setLayoutData(gd); - linksPanelToAdvancedPage.setLayout(new FillLayout(SWT.VERTICAL)); - - // first line with hyperlinks - Composite elementLine = toolkit.createComposite(linksPanelToAdvancedPage); - elementLine.setLayout(new FillLayout(SWT.HORIZONTAL)); - - // the text - toolkit.createLabel(elementLine, "Advanced parts of the model:"); - - // the hyperlinks - Hyperlink hyper; - - hyper = toolkit.createHyperlink(elementLine, "Additional definitions,", SWT.NONE); - hyper.setHref(SEC_NEW_DEFINITION); - hyper.addHyperlinkListener(sectionExpandingAdapter); - - hyper = toolkit.createHyperlink(elementLine, "Definition override,", SWT.NONE); - hyper.setHref(SEC_DEFINITION_OVERRIDE); - hyper.addHyperlinkListener(sectionExpandingAdapter); - - // second line with hyperlinks - Composite elementLine2 = toolkit.createComposite(linksPanelToAdvancedPage); - elementLine2.setLayout(new FillLayout(SWT.HORIZONTAL)); - - hyper = toolkit.createHyperlink(elementLine2, "State constraints,", SWT.NONE); - hyper.setHref(SEC_STATE_CONSTRAINT); - hyper.addHyperlinkListener(sectionExpandingAdapter); - - hyper = toolkit.createHyperlink(elementLine2, "Action constraints,", SWT.NONE); - hyper.setHref(SEC_ACTION_CONSTRAINT); - hyper.addHyperlinkListener(sectionExpandingAdapter); - - hyper = toolkit.createHyperlink(elementLine2, "Additional model values.", SWT.NONE); - hyper.setHref(SEC_MODEL_VALUES); - hyper.addHyperlinkListener(sectionExpandingAdapter); - - // ------------------------------------------ - // run tab - section = FormHelper.createSectionComposite(right, "How to run?", "TLC Parameters", toolkit, sectionFlags, - getExpansionListener()); - gd = new GridData(GridData.FILL_HORIZONTAL); - section.setLayoutData(gd); - - final Composite howToRunArea = (Composite) section.getClient(); - group = new HyperlinkGroup(howToRunArea.getDisplay()); - layout = new GridLayout(2, true); - howToRunArea.setLayout(layout); - - ValidateableSectionPart howToRunPart = new ValidateableSectionPart(section, this, SEC_HOW_TO_RUN); - managedForm.addPart(howToRunPart); - - DirtyMarkingListener howToRunListener = new DirtyMarkingListener(howToRunPart, true); - - /* - * Workers Spinner - */ - - // label workers - toolkit.createLabel(howToRunArea, "Number of worker threads:"); - - // field workers - workers = new Spinner(howToRunArea, SWT.NONE); - workers.addSelectionListener(howToRunListener); - workers.addFocusListener(focusListener); - gd = new GridData(); - gd.horizontalIndent = 10; - gd.widthHint = 40; - workers.setLayoutData(gd); - - workers.setMinimum(1); - workers.setPageIncrement(1); - workers.setToolTipText("Determines how many threads will be spawned working on the next state relation."); - workers.setSelection(IConfigurationDefaults.LAUNCH_NUMBER_OF_WORKERS_DEFAULT); - - dm.bindAttribute(LAUNCH_NUMBER_OF_WORKERS, workers, howToRunPart); - - /* - * MapHeap Scale - */ - - // max heap size label - toolkit.createLabel(howToRunArea, "Fraction of physical memory allocated to TLC:"); - - // Create a composite inside the right "cell" of the "how to run" - // section grid layout to fit the scale and the maxHeapSizeFraction - // label into a single row. - final Composite maxHeapScale = new Composite(howToRunArea, SWT.NONE); - layout = new GridLayout(2, false); - maxHeapScale.setLayout(layout); - - // field max heap size - int defaultMaxHeapSize = TLCUIActivator.getDefault().getPreferenceStore().getInt( - ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); - maxHeapSize = new Scale(maxHeapScale, SWT.NONE); - maxHeapSize.addSelectionListener(howToRunListener); - maxHeapSize.addFocusListener(focusListener); - gd = new GridData(); - gd.horizontalIndent = 0; - gd.widthHint = 250; - maxHeapSize.setLayoutData(gd); - maxHeapSize.setMaximum(99); - maxHeapSize.setMinimum(1); - maxHeapSize.setPageIncrement(5); - maxHeapSize.setSelection(defaultMaxHeapSize); - maxHeapSize.setToolTipText("Specifies the heap size of the Java VM that runs TLC."); - - dm.bindAttribute(LAUNCH_MAX_HEAP_SIZE, maxHeapSize, howToRunPart); - - // label next to the scale showing the current fraction selected - final TLCRuntime instance = TLCRuntime.getInstance(); - long memory = instance.getAbsolutePhysicalSystemMemory(defaultMaxHeapSize / 100d); - final Label maxHeapSizeFraction = toolkit.createLabel(maxHeapScale, - defaultMaxHeapSize + "%" + " (" + memory + " mb)"); - maxHeapSize.addPaintListener(new PaintListener() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent) - */ - public void paintControl(PaintEvent e) { - // update the label - int value = ((Scale) e.getSource()).getSelection(); - final TLCRuntime instance = TLCRuntime.getInstance(); - long memory = instance.getAbsolutePhysicalSystemMemory(value / 100d); - maxHeapSizeFraction.setText(value + "%" + " (" + memory + " mb)"); + // properties + serializedList = FormHelper.getSerializedInput(propertiesTable); + model.setAttribute(MODEL_CORRECTNESS_PROPERTIES, serializedList); + + // constants + List<String> constants = FormHelper.getSerializedInput(constantTable); + model.setAttribute(MODEL_PARAMETER_CONSTANTS, constants); + + // variables + String variables = ModelHelper.createVariableList(SemanticHelper.getRootModuleNode()); + model.setAttribute(MODEL_BEHAVIOR_VARS, variables); + + super.commit(onSave); + } + + @SuppressWarnings("unchecked") + public List<Assignment> getConstants() { + final List<Assignment> constants = (List<Assignment>) constantTable.getInput(); + if (constants == null) { + return new ArrayList<>(); + } + return constants; + } + + /** + * Creates the UI This method is called to create the widgets and arrange them + * on the page + * + * Its helpful to know what the standard SWT widgets look like. Pictures can be + * found at http://www.eclipse.org/swt/widgets/ + * + * Layouts are used throughout this method. A good explanation of layouts is + * given in the article + * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html + */ + protected void createBodyContent(IManagedForm managedForm) { + DataBindingManager dm = getDataBindingManager(); + int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE; + FormToolkit toolkit = managedForm.getToolkit(); + Composite body = managedForm.getForm().getBody(); + + GridLayout gl; + GridData gd; + TableWrapData twd; + + Section section; + + installTopMargin(body); + + TableWrapLayout twl = new TableWrapLayout(); + twl.leftMargin = 0; + twl.rightMargin = 0; + twl.numColumns = 2; + body.setLayout(twl); + + /* + * Comments/notes section spanning two columns + */ + + section = FormHelper.createSectionComposite(body, "Model description", "", toolkit, sectionFlags, + getExpansionListener()); + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.FILL; + section.setLayoutData(twd); + + // No need for a ValidatableSectionPart for the model description as there is + // nothing to validate when the free-form text gets changed. The model + // validation can be expensive especially when re-executed over and over again + // on every keystroke. + final SectionPart commentsPart = new SectionPart(section); + getDataBindingManager().bindSection(commentsPart, SEC_COMMENTS, getId()); + managedForm.addPart(commentsPart); + final DirtyMarkingListener commentsListener = new DirtyMarkingListener(commentsPart, true); + + final Composite commentsArea = (Composite) section.getClient(); + commentsArea.setLayout(new TableWrapLayout()); + + commentsSource = FormHelper.createFormsSourceViewer(toolkit, commentsArea, SWT.V_SCROLL | SWT.WRAP); + // layout of the source viewer + twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.heightHint = 60; + commentsSource.addTextListener(commentsListener); + commentsSource.getTextWidget().setLayoutData(twd); + commentsSource.getTextWidget().addFocusListener(focusListener); + toolkit.paintBordersFor(commentsArea); + + dm.bindAttribute(MODEL_COMMENTS, commentsSource, commentsPart); + + + + Composite advancedLinkLine = new Composite(body, SWT.NONE); + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.RIGHT; + advancedLinkLine.setLayoutData(twd); + advancedLinkLine.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE)); + gl = new GridLayout(1, false); + gl.marginWidth = 0; + gl.marginRight = 36; + gl.horizontalSpacing = 0; + advancedLinkLine.setLayout(gl); + Hyperlink hyper = toolkit.createHyperlink(advancedLinkLine, "Additional Spec Options", SWT.NONE); + hyper.addHyperlinkListener(advancedModelOptionsOpener); + Font baseFont = JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); + FontData[] baseFD = baseFont.getFontData(); + FontData biggerLinkFD = new FontData(baseFD[0].getName(), baseFD[0].getHeight() + 1, baseFD[0].getStyle()); + Font biggerLinkFont = new Font(body.getDisplay(), biggerLinkFD); + hyper.setFont(biggerLinkFont); + + + /* + * Because the two Composite objects `left' and `right' are added to the object + * `body' in this order, `left' is displayed to the left of `right'. + */ + // left + final Composite left = toolkit.createComposite(body); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + left.setLayout(gl); + twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.grabHorizontal = true; + left.setLayoutData(twd); + + // right + final Composite right = toolkit.createComposite(body); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + right.setLayout(gl); + twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.grabHorizontal = true; + right.setLayoutData(twd); + + // ------------------------------------------ + // what is the spec + + section = FormHelper.createSectionComposite(left, "What is the behavior spec?", "", toolkit, + sectionFlags | Section.EXPANDED, getExpansionListener()); + // only grab horizontal space + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + section.setLayoutData(gd); + + Composite behaviorArea = (Composite) section.getClient(); + behaviorArea.setLayout(new GridLayout(1, false)); + + ValidateableSectionPart behaviorPart = new ValidateableSectionPart(section, this, SEC_WHAT_IS_THE_SPEC); + managedForm.addPart(behaviorPart); + DirtyMarkingListener whatIsTheSpecListener = new DirtyMarkingListener(behaviorPart, true); + + behaviorCombo = new Combo(behaviorArea, SWT.READ_ONLY); + behaviorCombo.setItems(VARIABLE_BEHAVIOR_COMBO_ITEMS); + behaviorCombo.addFocusListener(focusListener); + behaviorCombo.addSelectionListener(whatIsTheSpecListener); + behaviorCombo.addSelectionListener(new SelectionListener() { + public void widgetSelected(final SelectionEvent se) { + moveToTopOfBehaviorOptionsStack(behaviorCombo.getText()); } - }); - -// // label workers -// toolkit.createLabel(howToRunArea, "Number of worker threads:"); -// -// // field workers -// workers = toolkit.createText(howToRunArea, "1"); -// workers.addModifyListener(howToRunListener); -// workers.addFocusListener(focusListener); -// gd = new GridData(); -// gd.horizontalIndent = 10; -// gd.widthHint = 40; -// workers.setLayoutData(gd); -// -// dm.bindAttribute(LAUNCH_NUMBER_OF_WORKERS, workers, howToRunPart); - - /* - * run from the checkpoint. Checkpoint help button added by LL on 17 Jan 2013 - */ - Composite ckptComp = new Composite(howToRunArea, SWT.NONE) ; - layout = new GridLayout(2, true); - ckptComp.setLayout(layout); - - gd = new GridData(); - gd.horizontalSpan = 2; - gd.verticalIndent = 20; - ckptComp.setLayoutData(gd); - - checkpointButton = toolkit.createButton(ckptComp, "Recover from checkpoint", SWT.CHECK); - checkpointButton.addSelectionListener(howToRunListener); - checkpointButton.addFocusListener(focusListener); - HelpButton.helpButton(ckptComp, "model/overview-page.html#checkpoint") ; - - toolkit.createLabel(howToRunArea, "Checkpoint ID:"); - - checkpointIdText = toolkit.createText(howToRunArea, ""); - checkpointIdText.setEditable(false); - gd = new GridData(); - gd.horizontalIndent = 10; - gd.widthHint = 100; - checkpointIdText.setLayoutData(gd); - dm.bindAttribute(LAUNCH_RECOVER, checkpointButton, howToRunPart); - - chkpointSizeLabel = toolkit.createLabel(howToRunArea, "Checkpoint size (kbytes):"); - checkpointSizeText = toolkit.createText(howToRunArea, ""); - gd = new GridData(); - gd.horizontalIndent = 10; - gd.widthHint = 100; - checkpointSizeText.setLayoutData(gd); - chkptDeleteButton = toolkit.createButton(howToRunArea, "Delete Checkpoint", SWT.PUSH); - chkptDeleteButton.addSelectionListener(new SelectionListener() { - - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - public void widgetSelected(SelectionEvent e) - { - final IResource[] checkpoints; - try - { - checkpoints = getModel().getCheckpoints(false); - - if ((checkpoints != null) && checkpoints.length > 0) - { - ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) throws CoreException - { - checkpoints[0].delete(true, new SubProgressMonitor(monitor, 1)); - - } - }, null); - } - } catch (CoreException e1) - { - return; - } - - } - - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) - */ - public void widgetDefaultSelected(SelectionEvent e) - { - } - }); - chkptDeleteButton.addFocusListener(focusListener); - - /* - * Distribution. Help button added by LL on 17 Jan 2013 - */ - Composite distComp = new Composite(howToRunArea, SWT.NONE) ; - layout = new GridLayout(3, true); - distComp.setLayout(layout); - - gd = new GridData(); - gd.horizontalSpan = 2; - distComp.setLayoutData(gd); - - toolkit.createLabel(distComp, "Run in distributed mode"); - distributedCombo = new Combo(distComp, SWT.READ_ONLY); - distributedCombo.setItems(new String[] {"off", "ad hoc", "aws-ec2", "Azure"}); - distributedCombo.select(0); - HelpButton.helpButton(distComp, "model/distributed-mode.html") ; - distributedCombo.addSelectionListener(howToRunListener); - distributedCombo.setToolTipText("If other than 'off' selected, state computation will be performed by (remote) workers."); - distributedCombo.addFocusListener(focusListener); + public void widgetDefaultSelected(final SelectionEvent se) { } + }); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + behaviorCombo.setLayoutData(gd); + dm.bindAttribute(MODEL_BEHAVIOR_NO_SPEC, behaviorCombo, behaviorPart); + + behaviorOptions = new Composite(behaviorArea, SWT.NONE); + StackLayout stackLayout = new StackLayout(); + behaviorOptions.setLayout(stackLayout); + + final Composite noSpecComposite = new Composite(behaviorOptions, SWT.NONE); + behaviorOptions.setData(NO_SPEC_COMBO_LABEL, noSpecComposite); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.minimumHeight = 1; + behaviorOptions.setLayoutData(gd); + stackLayout.topControl = noSpecComposite; + + // split formula option + final Composite initNextComposite = new Composite(behaviorOptions, SWT.NONE); + behaviorOptions.setData(INIT_NEXT_COMBO_LABEL, initNextComposite); + initNextComposite.setLayout(new GridLayout(2, false)); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + initNextComposite.setLayoutData(gd); + + // init + toolkit.createLabel(initNextComposite, "Init:"); + initFormulaSource = FormHelper.createFormsSourceViewer(toolkit, initNextComposite, + SWT.NONE | SWT.MULTI | SWT.V_SCROLL | SWT.BORDER); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.heightHint = 48; + initFormulaSource.getTextWidget().setLayoutData(gd); + initFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); + initFormulaSource.getTextWidget().addFocusListener(focusListener); + dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, initFormulaSource, behaviorPart); + + // next + toolkit.createLabel(initNextComposite, "Next:"); + nextFormulaSource = FormHelper.createFormsSourceViewer(toolkit, initNextComposite, + SWT.NONE | SWT.MULTI | SWT.V_SCROLL | SWT.BORDER); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.heightHint = 48; + nextFormulaSource.getTextWidget().setLayoutData(gd); + nextFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); + nextFormulaSource.getTextWidget().addFocusListener(focusListener); + dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, nextFormulaSource, behaviorPart); + + // fairness + // toolkit.createLabel(behaviorArea, "Fairness:"); + // fairnessFormulaSource = FormHelper.createSourceViewer(toolkit, + // behaviorArea, SWT.NONE | SWT.SINGLE); + // gd = new GridData(GridData.FILL_HORIZONTAL); + // gd.heightHint = 18; + // fairnessFormulaSource.getTextWidget().setLayoutData(gd); + // fairnessFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener); + // fairnessFormulaSource.getTextWidget().addModifyListener(widgetActivatingListener); + // dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_FAIRNESS, + // fairnessFormulaSource, behaviorPart); + + // closed formula option + final Composite temporalFormulaComposite = new Composite(behaviorOptions, SWT.NONE); + behaviorOptions.setData(TEMPORAL_FORMULA_COMBO_LABEL, temporalFormulaComposite); + temporalFormulaComposite.setLayout(new GridLayout(1, true)); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + temporalFormulaComposite.setLayoutData(gd); + + specSource = FormHelper.createFormsSourceViewer(toolkit, temporalFormulaComposite, SWT.V_SCROLL | SWT.BORDER); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.minimumHeight = 55; + specSource.getTextWidget().setLayoutData(gd); + specSource.getTextWidget().addModifyListener(whatIsTheSpecListener); + dm.bindAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, specSource, behaviorPart); + + // ------------------------------------------ + // what to check + section = FormHelper.createSectionComposite(body, "What to check?", "", toolkit, + (sectionFlags & ~Section.DESCRIPTION | Section.EXPANDED), getExpansionListener()); + // only grab horizontal space + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.FILL; + section.setLayoutData(twd); + + Composite toBeCheckedArea = (Composite) section.getClient(); + gl = new GridLayout(1, false); + gl.verticalSpacing = 0; + toBeCheckedArea.setLayout(gl); + + checkDeadlockButton = toolkit.createButton(toBeCheckedArea, "Deadlock", SWT.CHECK); + + ValidateableSectionPart toBeCheckedPart = new ValidateableSectionPart(section, this, SEC_WHAT_TO_CHECK); + managedForm.addPart(toBeCheckedPart); + DirtyMarkingListener whatToCheckListener = new DirtyMarkingListener(toBeCheckedPart, true); + checkDeadlockButton.addSelectionListener(whatToCheckListener); + + // Invariants + ValidateableTableSectionPart invariantsPart = new ValidateableTableSectionPart(toBeCheckedArea, "Invariants", + "Formulas true in every reachable state.", toolkit, sectionFlags, this, SEC_WHAT_TO_CHECK_INVARIANTS); + managedForm.addPart(invariantsPart); + invariantsTable = invariantsPart.getTableViewer(); + dm.bindAttribute(MODEL_CORRECTNESS_INVARIANTS, invariantsTable, invariantsPart); + + // Properties + ValidateableTableSectionPart propertiesPart = new ValidateableTableSectionPart(toBeCheckedArea, "Properties", + "Temporal formulas true for every possible behavior.", toolkit, sectionFlags, this, + SEC_WHAT_TO_CHECK_PROPERTIES); + managedForm.addPart(propertiesPart); + propertiesTable = propertiesPart.getTableViewer(); + dm.bindAttribute(MODEL_CORRECTNESS_PROPERTIES, propertiesTable, propertiesPart); + + // ------------------------------------------ + // what is the model + + // Constants + ValidateableConstantSectionPart constantsPart = new ValidateableConstantSectionPart(right, "What is the model?", + "Specify the values of declared constants.", toolkit, sectionFlags, this, SEC_WHAT_IS_THE_MODEL); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + constantsPart.getSection().setLayoutData(gd); + managedForm.addPart(constantsPart); + constantTable = constantsPart.getTableViewer(); + dm.bindAttribute(MODEL_PARAMETER_CONSTANTS, constantTable, constantsPart); + + advancedLinkLine = new Composite(body, SWT.NONE); + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.RIGHT; + advancedLinkLine.setLayoutData(twd); + advancedLinkLine.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE)); + gl = new GridLayout(1, false); + gl.marginWidth = 0; + gl.marginRight = 36; + gl.horizontalSpacing = 0; + advancedLinkLine.setLayout(gl); + hyper = toolkit.createHyperlink(advancedLinkLine, "Additional TLC Options", SWT.NONE); + hyper.addHyperlinkListener(advancedTLCOptionsOpener); + hyper.setFont(biggerLinkFont); + + // ------------------------------------------ + // run tab + section = FormHelper.createSectionComposite(body, "How to run?", "", toolkit, sectionFlags, + getExpansionListener()); + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.FILL; + section.setLayoutData(twd); + + final Composite howToRunArea = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginWidth = 0; + gl.verticalSpacing = 2; + howToRunArea.setLayout(gl); + + final ValidateableSectionPart howToRunPart = new ValidateableSectionPart(section, this, SEC_HOW_TO_RUN); + managedForm.addPart(howToRunPart); + + final DirtyMarkingListener howToRunListener = new DirtyMarkingListener(howToRunPart, true); + + toolkit.createLabel(howToRunArea, "System resources dedicated to TLC:"); + + tlcProfileCombo = new Combo(howToRunArea, SWT.READ_ONLY); + tlcProfileCombo.setItems(TLC_PROFILE_DISPLAY_NAMES); + tlcProfileCombo.addSelectionListener(howToRunListener); + tlcProfileCombo.addSelectionListener(new SelectionListener() { + public void widgetSelected(final SelectionEvent se) { + final String selectedText = tlcProfileCombo.getText(); + final boolean needReset = TLC_PROFILE_LOCAL_SEPARATOR.equals(selectedText) + || TLC_PROFILE_REMOTE_SEPARATOR.equals(selectedText); + + if (needReset) { + tlcProfileCombo.select(lastSelectedTLCProfileIndex.get()); + } else { + final TLCConsumptionProfile profile = TLCConsumptionProfile.getProfileWithDisplayName(selectedText); + + lastSelectedTLCProfileIndex.set(tlcProfileCombo.getSelectionIndex()); + + currentProfileIsAdHoc.set(false); + if (profile != null) { + workerThreadCount.set(profile.getWorkerThreads()); + heapPercentage.set(profile.getMemoryPercentage()); + + final IFormPage iep = getEditor().findPage(AdvancedTLCOptionsPage.ID); + if (iep != null) { + ((AdvancedTLCOptionsPage) iep).updateWorkersAndMemory(profile.getWorkerThreads(), + profile.getMemoryPercentage()); + } + + removeCustomTLCProfileComboItemIfPresent(); + + if (profile.profileIsForRemoteWorkers()) { + final String configuration = profile.getConfigurationKey(); + final boolean isAdHoc = configuration + .equals(TLCConsumptionProfile.REMOTE_AD_HOC.getConfigurationKey()); + + moveToTopOfDistributedOptionsStack(configuration, false, isAdHoc); + if (isAdHoc) { + currentProfileIsAdHoc.set(true); + clearEmailErrors(); + } + } else { + moveToTopOfDistributedOptionsStack(LAUNCH_DISTRIBUTED_NO, true, true); + clearEmailErrors(); + } + } else { + moveToTopOfDistributedOptionsStack(LAUNCH_DISTRIBUTED_NO, true, true); + clearEmailErrors(); + } + } + + updateTLCResourcesLabel(); + } + + public void widgetDefaultSelected(final SelectionEvent se) { + } + }); + gd = new GridData(); + gd.horizontalIndent = 30; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.FILL; + tlcProfileCombo.setLayoutData(gd); + lastSelectedTLCProfileIndex = new AtomicInteger(tlcProfileCombo.getSelectionIndex()); + + tlcResourceSummaryLabel = toolkit.createLabel(howToRunArea, ""); + tlcResourceSummaryLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + gd = new GridData(); + gd.horizontalSpan = 2; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.CENTER; + tlcResourceSummaryLabel.setLayoutData(gd); + + advancedLinkLine = new Composite(howToRunArea, SWT.NONE); + gd = new GridData(); + gd.horizontalSpan = 2; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.CENTER; + advancedLinkLine.setLayoutData(gd); + gl = new GridLayout(1, false); + gl.marginWidth = 0; + gl.horizontalSpacing = 0; + advancedLinkLine.setLayout(gl); + tlcTuneHyperlink = toolkit.createHyperlink(advancedLinkLine, "Tune these parameters and set defaults", SWT.NONE); + tlcTuneHyperlink.addHyperlinkListener(advancedTLCOptionsOpener); + baseFont = JFaceResources.getFont(JFaceResources.DIALOG_FONT); + baseFD = baseFont.getFontData(); + final FontData smaller = new FontData(baseFD[0].getName(), baseFD[0].getHeight() - 2, baseFD[0].getStyle()); + tlcTuneHyperlink.setFont(new Font(body.getDisplay(), smaller)); + + + /* + * Distribution. Help button added by LL on 17 Jan 2013 + */ distributedOptions = new Composite(howToRunArea, SWT.NONE); - final StackLayout stackLayout = new StackLayout(); + stackLayout = new StackLayout(); distributedOptions.setLayout(stackLayout); - - gd = new GridData(); - gd.horizontalSpan = 2; - distributedOptions.setLayoutData(gd); - + + gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + distributedOptions.setLayoutData(gd); + // No distribution has no options final Composite offComposite = new Composite(distributedOptions, SWT.NONE); - distributedOptions.setData("off", offComposite); + distributedOptions.setData(LAUNCH_DISTRIBUTED_NO, offComposite); stackLayout.topControl = offComposite; - + /* * Composite wrapping number of distributed FPSet and iface when ad hoc selected */ - final Composite builtInOptions = new Composite(distributedOptions, SWT.NONE); - layout = new GridLayout(2, true); - builtInOptions.setLayout(layout); - gd = new GridData(); - gd.horizontalSpan = 2; - builtInOptions.setLayoutData(gd); - distributedOptions.setData("ad hoc", builtInOptions); - + final Composite adHocOptions = new Composite(distributedOptions, SWT.NONE); + gl = new GridLayout(2, false); + gl.marginWidth = 0; + adHocOptions.setLayout(gl); + distributedOptions.setData(TLCConsumptionProfile.REMOTE_AD_HOC.getConfigurationKey(), adHocOptions); + + Button helpButton = HelpButton.helpButton(adHocOptions, "model/distributed-mode.html"); + gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalAlignment = SWT.END; + helpButton.setLayoutData(gd); + /* - * Server interface/hostname (This text shows the hostname detected by the Toolbox under which TLCServer will listen + * Server interface/hostname (This text shows the hostname detected by the + * Toolbox under which TLCServer will listen) */ - // composite - final Composite networkInterface = new Composite(builtInOptions, SWT.NONE) ; - layout = new GridLayout(2, true); - networkInterface.setLayout(layout); - gd = new GridData(); - gd.horizontalSpan = 2; - networkInterface.setLayoutData(gd); - - // label - toolkit.createLabel(networkInterface, "Master's network address:"); - - // field - networkInterfaceCombo = new Combo(networkInterface, SWT.NONE); - networkInterfaceCombo.addSelectionListener(howToRunListener); - networkInterfaceCombo.addFocusListener(focusListener); - gd = new GridData(); - gd.horizontalIndent = 10; - networkInterfaceCombo.setLayoutData(gd); - - networkInterfaceCombo.setToolTipText("IP address to which workers (and distributed fingerprint sets) will connect."); - networkInterfaceCombo.addSelectionListener(howToRunListener); - networkInterfaceCombo.addFocusListener(focusListener); - try { - final Comparator<InetAddress> comparator = new Comparator<InetAddress>() { - // Try to "guess" the best possible match. - public int compare(InetAddress o1, InetAddress o2) { - // IPv4 < IPv6 (v6 is less common even today) - if (o1 instanceof Inet4Address && o2 instanceof Inet6Address) { - return -1; - } else if (o1 instanceof Inet6Address && o2 instanceof Inet4Address) { - return 1; - } - - // anything < LoopBack (loopback only useful if master and worker are on the same host) - if (!o1.isLoopbackAddress() && o2.isLoopbackAddress()) { - return -1; - } else if (o1.isLoopbackAddress() && !o2.isLoopbackAddress()) { - return 1; - } - - // Public Addresses < Non-private RFC 1918 (I guess this is questionable) - if (!o1.isSiteLocalAddress() && o2.isSiteLocalAddress()) { - return -1; - } else if (o1.isSiteLocalAddress() && !o2.isSiteLocalAddress()) { - return 1; - } - - return 0; - } - }; - - // Get all IP addresses of the host and sort them according to the Comparator. - final List<InetAddress> addresses = new ArrayList<InetAddress>(); + + // label + toolkit.createLabel(adHocOptions, "Master's network address:"); + + // field + networkInterfaceCombo = new Combo(adHocOptions, SWT.NONE); + networkInterfaceCombo.addSelectionListener(howToRunListener); + networkInterfaceCombo.addFocusListener(focusListener); + gd = new GridData(); + gd.horizontalIndent = 10; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.FILL; + networkInterfaceCombo.setLayoutData(gd); + + networkInterfaceCombo + .setToolTipText("IP address to which workers (and distributed fingerprint sets) will connect."); + networkInterfaceCombo.addSelectionListener(howToRunListener); + networkInterfaceCombo.addFocusListener(focusListener); + try { + final Comparator<InetAddress> comparator = new Comparator<InetAddress>() { + // Try to "guess" the best possible match. + public int compare(InetAddress o1, InetAddress o2) { + // IPv4 < IPv6 (v6 is less common even today) + if (o1 instanceof Inet4Address && o2 instanceof Inet6Address) { + return -1; + } else if (o1 instanceof Inet6Address && o2 instanceof Inet4Address) { + return 1; + } + + // anything < LoopBack (loopback only useful if master and worker are on the + // same host) + if (!o1.isLoopbackAddress() && o2.isLoopbackAddress()) { + return -1; + } else if (o1.isLoopbackAddress() && !o2.isLoopbackAddress()) { + return 1; + } + + // Public Addresses < Non-private RFC 1918 (I guess this is questionable) + if (!o1.isSiteLocalAddress() && o2.isSiteLocalAddress()) { + return -1; + } else if (o1.isSiteLocalAddress() && !o2.isSiteLocalAddress()) { + return 1; + } + + return 0; + } + }; + + // Get all IP addresses of the host and sort them according to the Comparator. + final List<InetAddress> addresses = new ArrayList<InetAddress>(); final Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); while (nets.hasMoreElements()) { final NetworkInterface iface = (NetworkInterface) nets.nextElement(); @@ -1543,7 +1488,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta addresses.add(addr); } } - + // Add the sorted IP addresses and select the first one which - // according to the comparator - is assumed to be the best match. Collections.sort(addresses, comparator); @@ -1555,104 +1500,83 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta e1.printStackTrace(); } - dm.bindAttribute(LAUNCH_DISTRIBUTED_INTERFACE, networkInterfaceCombo, howToRunPart); + dm.bindAttribute(LAUNCH_DISTRIBUTED_INTERFACE, networkInterfaceCombo, howToRunPart); /* * Distributed FPSet count */ - // composite - final Composite distributedFPSetCount = new Composite(builtInOptions, SWT.NONE); - layout = new GridLayout(2, false); - distributedFPSetCount.setLayout(layout); - gd = new GridData(); - gd.horizontalSpan = 2; - distributedFPSetCount.setLayoutData(gd); - - // label - toolkit.createLabel(distributedFPSetCount, "Number of distributed fingerprint sets (zero for single built-in set):"); - - // field - distributedFPSetCountSpinner = new Spinner(distributedFPSetCount, SWT.NONE); - distributedFPSetCountSpinner.addSelectionListener(howToRunListener); - distributedFPSetCountSpinner.addFocusListener(focusListener); - gd = new GridData(); - gd.grabExcessHorizontalSpace = true; - gd.horizontalIndent = 10; - gd.widthHint = 40; - distributedFPSetCountSpinner.setLayoutData(gd); - - distributedFPSetCountSpinner.setMinimum(0); - distributedFPSetCountSpinner.setMaximum(64); // Haven't really tested this many distributed fpsets - distributedFPSetCountSpinner.setPageIncrement(1); - distributedFPSetCountSpinner.setToolTipText("Determines how many distributed FPSets will be expected by the TLCServer process"); - distributedFPSetCountSpinner.setSelection(IConfigurationDefaults.LAUNCH_DISTRIBUTED_FPSET_COUNT_DEFAULT); - - dm.bindAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, distributedFPSetCountSpinner, howToRunPart); - + // label + toolkit.createLabel(adHocOptions, "Number of distributed fingerprint sets (zero for single built-in set):"); + + // field + distributedFPSetCountSpinner = new Spinner(adHocOptions, SWT.NONE); + distributedFPSetCountSpinner.addSelectionListener(howToRunListener); + distributedFPSetCountSpinner.addFocusListener(focusListener); + gd = new GridData(); + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 10; + gd.widthHint = 40; + distributedFPSetCountSpinner.setLayoutData(gd); + + distributedFPSetCountSpinner.setMinimum(0); + distributedFPSetCountSpinner.setMaximum(64); // Haven't really tested this many distributed fpsets + distributedFPSetCountSpinner.setPageIncrement(1); + distributedFPSetCountSpinner + .setToolTipText("Determines how many distributed FPSets will be expected by the TLCServer process"); + distributedFPSetCountSpinner.setSelection(IConfigurationDefaults.LAUNCH_DISTRIBUTED_FPSET_COUNT_DEFAULT); + + dm.bindAttribute(LAUNCH_DISTRIBUTED_FPSET_COUNT, distributedFPSetCountSpinner, howToRunPart); + /* * Composite wrapping all widgets related to jclouds */ - final Composite jcloudsOptions = new Composite(distributedOptions, SWT.NONE); - layout = new GridLayout(2, true); - jcloudsOptions.setLayout(layout); - gd = new GridData(); - gd.horizontalSpan = 2; - jcloudsOptions.setLayoutData(gd); - - /* - * Distributed nodes count - */ - - // composite - final Composite distributedNodesCount = new Composite(jcloudsOptions, SWT.NONE); - layout = new GridLayout(2, false); - distributedNodesCount.setLayout(layout); - gd = new GridData(); - gd.horizontalSpan = 2; - distributedNodesCount.setLayoutData(gd); - - // label - toolkit.createLabel(distributedNodesCount, "Number of compute nodes to use:"); - - // field - distributedNodesCountSpinner = new Spinner(distributedNodesCount, SWT.NONE); - distributedNodesCountSpinner.addSelectionListener(howToRunListener); - distributedNodesCountSpinner.addFocusListener(focusListener); - gd = new GridData(); - gd.grabExcessHorizontalSpace = true; - gd.horizontalIndent = 10; - gd.widthHint = 40; - distributedNodesCountSpinner.setLayoutData(gd); - - distributedNodesCountSpinner.setMinimum(1); - distributedNodesCountSpinner.setMaximum(64); // Haven't really tested this many distributed fpsets - distributedNodesCountSpinner.setPageIncrement(1); - distributedNodesCountSpinner.setToolTipText( + final Composite jcloudsOptions = new Composite(distributedOptions, SWT.NONE); + gl = new GridLayout(2, false); + gl.marginWidth = 0; + jcloudsOptions.setLayout(gl); + + /* + * Distributed nodes count + */ + + helpButton = HelpButton.helpButton(jcloudsOptions, "cloudtlc/index.html"); + gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalAlignment = SWT.END; + helpButton.setLayoutData(gd); + + // label + toolkit.createLabel(jcloudsOptions, "Number of compute nodes to use:"); + + // field + distributedNodesCountSpinner = new Spinner(jcloudsOptions, SWT.NONE); + distributedNodesCountSpinner.addSelectionListener(howToRunListener); + distributedNodesCountSpinner.addFocusListener(focusListener); + gd = new GridData(); + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 10; + gd.widthHint = 40; + distributedNodesCountSpinner.setLayoutData(gd); + + distributedNodesCountSpinner.setMinimum(1); + distributedNodesCountSpinner.setMaximum(64); // Haven't really tested this many distributed fpsets + distributedNodesCountSpinner.setPageIncrement(1); + distributedNodesCountSpinner.setToolTipText( "Determines how many compute nodes/VMs will be launched. More VMs means faster results and higher costs."); - distributedNodesCountSpinner.setSelection(IConfigurationDefaults.LAUNCH_DISTRIBUTED_NODES_COUNT_DEFAULT); + distributedNodesCountSpinner.setSelection(IConfigurationDefaults.LAUNCH_DISTRIBUTED_NODES_COUNT_DEFAULT); + + dm.bindAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, distributedNodesCountSpinner, howToRunPart); - dm.bindAttribute(LAUNCH_DISTRIBUTED_NODES_COUNT, distributedNodesCountSpinner, howToRunPart); - /* * Result mail address input */ - final Composite resultAddress = new Composite(jcloudsOptions, SWT.NONE) ; - layout = new GridLayout(2, true); - resultAddress.setLayout(layout); + toolkit.createLabel(jcloudsOptions, "Result mailto addresses:"); + resultMailAddressText = toolkit.createText(jcloudsOptions, "", SWT.BORDER); + resultMailAddressText.setMessage("my-name@my-domain.org,alternative-name@alternative-domain.org"); final String resultAddressTooltip = "A list (comma-separated) of one to N email addresses to send the model checking result to."; - resultAddress.setToolTipText(resultAddressTooltip); - - gd = new GridData(); - gd.horizontalSpan = 2; - resultAddress.setLayoutData(gd); - - toolkit.createLabel(resultAddress, "Result mailto addresses:"); - resultMailAddressText = toolkit.createText(resultAddress, "", SWT.BORDER); - resultMailAddressText.setMessage("my-name@my-domain.org,alternative-name@alternative-domain.org"); // hint resultMailAddressText.setToolTipText(resultAddressTooltip); resultMailAddressText.addKeyListener(new KeyAdapter() { - private final ModelEditor modelEditor = (ModelEditor) getEditor(); @Override @@ -1665,125 +1589,139 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta super.keyReleased(e); try { final String text = resultMailAddressText.getText(); - javax.mail.internet.InternetAddress.parse(text, true); - } catch (javax.mail.internet.AddressException exp) { - modelEditor.addErrorMessage("emailAddressInvalid", - "Invalid email address", getId(), + InternetAddress.parse(text, true); + } catch (AddressException exp) { + modelEditor.addErrorMessage("emailAddressInvalid", "Invalid email address", getId(), IMessageProvider.ERROR, resultMailAddressText); return; } - modelEditor.removeErrorMessage("emailAddressInvalid", resultMailAddressText); + clearEmailErrors(); } }); - gd = new GridData(); - gd.grabExcessHorizontalSpace = true; - gd.horizontalIndent = 10; - gd.widthHint = 400; - resultMailAddressText.setLayoutData(gd); - resultMailAddressText.addModifyListener(howToRunListener); - dm.bindAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, resultMailAddressText, howToRunPart); - - distributedOptions.setData("jclouds", jcloudsOptions); - - distributedCombo.addSelectionListener(new SelectionListener() { - public void widgetSelected(SelectionEvent e) { - int selectionIndex = distributedCombo.getSelectionIndex(); - String item = distributedCombo.getItem(selectionIndex); - if (item.equalsIgnoreCase("aws-ec2") || item.equalsIgnoreCase("Azure")) { - MainModelPage.this.putOnTopOfStack("jclouds", false, false); - } else if(item.equalsIgnoreCase("ad hoc")) { - MainModelPage.this.putOnTopOfStack("ad hoc", false, true); - } else { - MainModelPage.this.putOnTopOfStack("off", true, true); - } - } + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 10; + gd.minimumWidth = 330; + resultMailAddressText.setLayoutData(gd); + resultMailAddressText.addModifyListener(howToRunListener); + dm.bindAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, resultMailAddressText, howToRunPart); + + distributedOptions.setData(CLOUD_CONFIGURATION_KEY, jcloudsOptions); + + // add listeners propagating the changes of the elements to the changes + // of the parts to the list to be activated after the values has been loaded + dirtyPartListeners.add(commentsListener); + dirtyPartListeners.add(whatIsTheSpecListener); + dirtyPartListeners.add(whatToCheckListener); + dirtyPartListeners.add(howToRunListener); + } + + private void moveToTopOfDistributedOptionsStack(final String id, final boolean enableWorker, + final boolean enableMaxHeap) { + workerValueCanBeModified.set(enableWorker); + heapPercentageCanBeModified.set(enableMaxHeap); + + final IFormPage iep = getEditor().findPage(AdvancedTLCOptionsPage.ID); + if (iep != null) { + ((AdvancedTLCOptionsPage) iep).setWorkerAndMemoryEnable(enableWorker, enableMaxHeap); + } + + moveCompositeWithIdToTopOfStack(id, distributedOptions); + + distributedOptions.getParent().getParent().layout(); + } + + private void moveToTopOfBehaviorOptionsStack(final String id) { + moveCompositeWithIdToTopOfStack(id, behaviorOptions); + } + + private void moveCompositeWithIdToTopOfStack(final String id, final Composite parent) { + final Composite composite = (Composite) parent.getData(id); + final StackLayout stackLayout = (StackLayout) parent.getLayout(); - public void widgetDefaultSelected(SelectionEvent e) { - } - }); - - /* - * run link - */ - runLink = toolkit.createImageHyperlink(howToRunArea, SWT.NONE); - runLink.setImage(createRegisteredImage("icons/full/lrun_obj.gif")); - runLink.addHyperlinkListener(new HyperlinkAdapter() { - public void linkActivated(HyperlinkEvent e) - { - doRun(); - } - }); - runLink.setText("Run TLC"); - gd = new GridData(); - gd.horizontalSpan = 2; - gd.widthHint = 200; - gd.verticalIndent = 20; - runLink.setLayoutData(gd); - group.add(runLink); - - generateLink = toolkit.createImageHyperlink(howToRunArea, SWT.NONE); - generateLink.setImage(createRegisteredImage("icons/full/debugt_obj.gif")); - generateLink.addHyperlinkListener(new HyperlinkAdapter() { - public void linkActivated(HyperlinkEvent e) - { - doGenerate(); - } - }); - generateLink.setText("Validate model"); - gd = new GridData(); - gd.horizontalSpan = 2; - gd.widthHint = 200; - generateLink.setLayoutData(gd); - group.add(generateLink); - - // add listeners propagating the changes of the elements to the changes - // of the - // parts to the list to be activated after the values has been loaded - dirtyPartListeners.add(commentsListener); - dirtyPartListeners.add(whatIsTheSpecListener); - dirtyPartListeners.add(whatToCheckListener); - dirtyPartListeners.add(howToRunListener); - } - - private void putOnTopOfStack(final String id, boolean enableWorker, boolean enableMaxHeap) { - workers.setEnabled(enableWorker); - maxHeapSize.setEnabled(enableMaxHeap); - - final Composite composite = (Composite) distributedOptions.getData(id); - final StackLayout stackLayout = (StackLayout) distributedOptions.getLayout(); stackLayout.topControl = composite; - distributedOptions.layout(); - } - - /** - * On a refresh, the checkpoint information is re-read - */ - public void refresh() - { - super.refresh(); - updateCheckpoints(); - } - - /** - * Interpolates based on LinearInterpolation - */ - private class Interpolator { - - private final double[] yCoords, xCoords; - - public Interpolator(double[] x, double[] y) { - this.xCoords = x; - this.yCoords = y; - } - - public double interpolate(double x) { - for (int i = 1; i < xCoords.length; i++) { - if (x < xCoords[i]) { - return yCoords[i] - (yCoords[i] - yCoords[i - 1]) - * (xCoords[i] - x) / (xCoords[i] - xCoords[i - 1]); + parent.layout(); + } + + private TLCConsumptionProfile getSelectedTLCProfile() { + return TLCConsumptionProfile.getProfileWithDisplayName(tlcProfileCombo.getText()); + } + + private void clearEmailErrors() { + ((ModelEditor) getEditor()).removeErrorMessage("emailAddressInvalid", resultMailAddressText); + } + + private void setTLCProfileComboSelection(final String displayName) { + final int index = tlcProfileCombo.indexOf(displayName); + + if (index != -1) { + tlcProfileCombo.select(index); + if (!CUSTOM_TLC_PROFILE_DISPLAY_NAME.equals(displayName)) { + removeCustomTLCProfileComboItemIfPresent(); + } + } else if (CUSTOM_TLC_PROFILE_DISPLAY_NAME.equals(displayName)) { + tlcProfileCombo.add(displayName, 1); + tlcProfileCombo.select(1); + } + + lastSelectedTLCProfileIndex.set(tlcProfileCombo.getSelectionIndex()); + } + + private void removeCustomTLCProfileComboItemIfPresent() { + if (tlcProfileCombo.getItem(1).equals(CUSTOM_TLC_PROFILE_DISPLAY_NAME)) { + tlcProfileCombo.remove(1); + } + } + + private void updateTLCResourcesLabel() { + final TLCConsumptionProfile profile = getSelectedTLCProfile(); + final StringBuilder sb = new StringBuilder(); + + if ((profile == null) || !profile.profileIsForRemoteWorkers() + || TLCConsumptionProfile.REMOTE_AD_HOC.equals(profile)) { + if ((profile != null) && profile.profileIsForRemoteWorkers()) { + sb.append("Allocating "); + } else { + final int workerCount = workerThreadCount.get(); + + sb.append(workerCount).append(" worker"); + if (workerCount > 1) { + sb.append('s'); } + + sb.append(" allocated "); + } + + sb.append(generateMemoryDisplayText()).append(" of system memory."); + } + + tlcResourceSummaryLabel.setText(sb.toString()); + tlcTuneHyperlink.setVisible(sb.toString().length() > 0); + } + + private String generateMemoryDisplayText() { + final int percentage = heapPercentage.get(); + final long megabytes = TLCRuntime.getInstance().getAbsolutePhysicalSystemMemory(percentage / 100d); + + return generateMemoryDisplayText(percentage, megabytes); + } + + private void installTopMargin(final Composite body) { + Composite c = body; + CTabFolder tabFolder = (c instanceof CTabFolder) ? (CTabFolder) c : null; + + while ((tabFolder == null) && (c.getParent() != null)) { + c = c.getParent(); + tabFolder = (c instanceof CTabFolder) ? (CTabFolder) c : null; + } + + if (tabFolder != null) { + final Layout l = tabFolder.getParent().getLayout(); + if (l instanceof FillLayout) { + final FillLayout fl = (FillLayout) l; + fl.marginHeight = 6; } - return 0d; } - } + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java deleted file mode 100644 index 3212972822f58d601c1a42b261c4333510e9a879..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java +++ /dev/null @@ -1,1405 +0,0 @@ -package org.lamport.tla.toolbox.tool.tlc.ui.editor.page; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.Vector; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.resources.WorkspaceJob; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.IDocumentPartitioner; -import org.eclipse.jface.text.ITextOperationTarget; -import org.eclipse.jface.text.source.SourceViewer; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.ITableColorProvider; -import org.eclipse.jface.viewers.ITableFontProvider; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.events.IHyperlinkListener; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Hyperlink; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.eclipse.ui.forms.widgets.TableWrapLayout; -import org.eclipse.ui.progress.UIJob; -import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; -import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner; -import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner; -import org.lamport.tla.toolbox.editor.basic.TLASourceViewerConfiguration; -import org.lamport.tla.toolbox.tool.tlc.model.Model; -import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem; -import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter; -import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; -import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; -import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; -import org.lamport.tla.toolbox.tool.tlc.ui.contribution.DynamicContributionItem; -import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; -import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; -import org.lamport.tla.toolbox.tool.tlc.ui.util.ActionClickListener; -import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; -import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; -import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView; -import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; -import org.lamport.tla.toolbox.util.FontPreferenceChangeListener; -import org.lamport.tla.toolbox.util.IHelpConstants; -import org.lamport.tla.toolbox.util.UIHelper; - -/** - * A page to display results of model checking (the "third tab" - * of the model editor). - * @author Simon Zambrovski - */ -public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPresenter -{ - - public static final String RESULT_PAGE_PROBLEM = "ResultPageProblem"; - - public static final String ID = "resultPage"; - - private static final String TOOLTIP = "Click on a row to go to action."; - - private Hyperlink errorStatusHyperLink; - /** - * UI elements - */ - private SourceViewer userOutput; - private SourceViewer progressOutput; - private SourceViewer expressionEvalResult; - private SourceViewer expressionEvalInput; - private long startTimestamp; - private Text startTimestampText; - // startTime is provided by the TLCModelLaunchDataProvider's getStartTime() - // method. - private Text finishTimestampText; - private Text tlcModeText; - private Text lastCheckpointTimeText; - private Text coverageTimestampText; - private Text currentStatusText; - private Text fingerprintCollisionProbabilityText; - private TableViewer coverage; - private TableViewer stateSpace; - private final Map<String, Section> sections = new HashMap<String, Section>(); - private final Lock disposeLock = new ReentrantLock(true); - - // listener on changes to the tlc output font preference - private FontPreferenceChangeListener fontChangeListener; - - // hyper link listener activated in case of errors - protected IHyperlinkListener errorHyperLinkListener = new HyperlinkAdapter() { - - public void linkActivated(HyperlinkEvent e) - { - if (getModel() != null) - { - getModel().setOriginalTraceShown(true); - TLCErrorView.updateErrorView(getModel()); - } - } - }; - - private IMarker incompleteStateExploration; - private IMarker zeroCoverage; - - /** - * Constructor for the page - * @param editor - */ - public ResultPage(FormEditor editor) - { - super(editor, ID, "Model Checking Results"); - this.helpId = IHelpConstants.RESULT_MODEL_PAGE; - this.imagePath = "icons/full/choice_sc_obj.gif"; - } - - /** - * Will be called by the provider on data changes - */ - public void modelChanged(final TLCModelLaunchDataProvider dataProvider, final int fieldId) - { - UIHelper.runUIAsync(new Runnable() { - public void run() { - // Acquire dispose lock prior to widget access. Using a single - // lock just to serialize dispose and modelChange seems - // overkill, but the wait-for graph becomes tricky with all the - // background jobs going on (at least too tricky to get it - // solved within an hour). - disposeLock.lock(); - try { - if (getPartControl().isDisposed()) { - // Don't update the widgets if the underlying SWT control has - // already been disposed. Otherwise it results in an - // "SWTException: Widget is disposed". - return; - } - switch (fieldId) { - case USER_OUTPUT: - ResultPage.this.userOutput.setDocument(dataProvider.getUserOutput()); - break; - case PROGRESS_OUTPUT: - ResultPage.this.progressOutput.setDocument(dataProvider.getProgressOutput()); - break; - case CONST_EXPR_EVAL_OUTPUT: - ResultPage.this.expressionEvalResult.getTextWidget().setText(dataProvider.getCalcOutput()); - break; - case START_TIME: - ResultPage.this.startTimestamp = dataProvider.getStartTimestamp(); - if (ResultPage.this.startTimestamp < 0) { - // Leave the starttime text empty on a negative - // timestamp. A negative one indicates that the - // model has never been checked. See Long.MIN_VALUE in - // org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider.initialize() - ResultPage.this.startTimestampText.setText(""); - break; - } - ResultPage.this.startTimestampText.setText(new Date(ResultPage.this.startTimestamp).toString()); - break; - case END_TIME: - long finishTimestamp = dataProvider.getFinishTimestamp(); - if(finishTimestamp < 0) { - ResultPage.this.finishTimestampText.setText(""); - break; - } - ResultPage.this.finishTimestampText.setText(new Date(finishTimestamp).toString()); - - // calc elapsed time and set as Tooltip - final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // explicitly set TZ to handle local offset - long elapsedTime = finishTimestamp - dataProvider.getStartTimestamp(); - ResultPage.this.finishTimestampText.setToolTipText(sdf.format(new Date(elapsedTime))); - ResultPage.this.startTimestampText.setToolTipText(sdf.format(new Date(elapsedTime))); - break; - case TLC_MODE: - ResultPage.this.tlcModeText.setText(dataProvider.getTLCMode()); - case LAST_CHECKPOINT_TIME: - long lastCheckpointTimeStamp = dataProvider.getLastCheckpointTimeStamp(); - if(lastCheckpointTimeStamp > 0) { - ResultPage.this.lastCheckpointTimeText.setText(new Date(lastCheckpointTimeStamp).toString()); - break; - } - ResultPage.this.lastCheckpointTimeText.setText(""); - break; - case CURRENT_STATUS: - ResultPage.this.currentStatusText.setText(dataProvider.getCurrentStatus()); - break; - case FINGERPRINT_COLLISION_PROBABILITY: - ResultPage.this.fingerprintCollisionProbabilityText.setText(dataProvider.getFingerprintCollisionProbability()); - break; - case COVERAGE_TIME: - ResultPage.this.coverageTimestampText.setText(dataProvider.getCoverageTimestamp()); - break; - case COVERAGE: - final List<CoverageInformationItem> coverageInfo = dataProvider.getCoverageInfo(); - ResultPage.this.coverage.setInput(coverageInfo); - if (dataProvider.isDone() && coverageInfo.size() > 0) { - if (dataProvider.hasZeroCoverage()) { - if (zeroCoverage == null) { - final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription( - "Coverage is zero for one or more modules.", IMarker.SEVERITY_WARNING); - marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2); - zeroCoverage = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC); - } - } else if (zeroCoverage != null) { - try { - zeroCoverage.delete(); - ResultPage.this.resetMessage(RESULT_PAGE_PROBLEM); - zeroCoverage = null; - } catch (CoreException e) { - TLCUIActivator.getDefault().logError(e.getMessage(), e); - } - } - } - break; - case PROGRESS: - ResultPage.this.stateSpace.setInput(dataProvider.getProgressInformation()); - - // The following code finds all the graph windows (shells) for this - // model and calls redraw() and update() on them, which apparently is the - // magic incantation to cause its listener to be called to issue the - // necessary commands to redraw the data and then displays the result. - String suffix = getGraphTitleSuffix(ResultPage.this); - Shell[] shells = UIHelper.getCurrentDisplay().getShells(); - for (int i = 0; i < shells.length; i++) - { - if (shells[i].getText().endsWith(suffix)) - { - shells[i].redraw(); - shells[i].update(); - // The following was commented out by LL on 6 Jul 2012 because it was filling - // up the Console log with useless stuff. - // TLCUIActivator.getDefault().logDebug("Called redraw/update on shell number" + i); - } - } - break; - case ERRORS: - String text; - Color color; - int errorCount = dataProvider.getErrors().size(); - switch (errorCount) { - case 0: - text = TLCModelLaunchDataProvider.NO_ERRORS; - color = TLCUIActivator.getColor(SWT.COLOR_BLACK); - ResultPage.this.errorStatusHyperLink - .removeHyperlinkListener(ResultPage.this.errorHyperLinkListener); - break; - case 1: - text = "1 Error"; - ResultPage.this.errorStatusHyperLink - .addHyperlinkListener(ResultPage.this.errorHyperLinkListener); - color = TLCUIActivator.getColor(SWT.COLOR_RED); - break; - default: - text = String.valueOf(errorCount) + " Errors"; - ResultPage.this.errorStatusHyperLink - .addHyperlinkListener(ResultPage.this.errorHyperLinkListener); - color = TLCUIActivator.getColor(SWT.COLOR_RED); - break; - } - - ResultPage.this.errorStatusHyperLink.setText(text); - ResultPage.this.errorStatusHyperLink.setForeground(color); - - // update the error view - TLCErrorView.updateErrorView(dataProvider.getModel()); - break; - default: - break; - } - - // Set label provider to highlight unexplored states if - // TLC is done but not all states are explored. - final StateSpaceLabelProvider sslp = (StateSpaceLabelProvider) ResultPage.this.stateSpace - .getLabelProvider(); - if (dataProvider.isDone() && dataProvider.getProgressInformation().size() > 0) { - final long statesLeft = dataProvider.getProgressInformation().get(0).getLeftStates(); - if (statesLeft > 0) { - sslp.setHighlightUnexplored(); - // Create a problem marker which gets displayed by - // BasicFormPage/ModelEditor as a warning on the - // result page. - if (incompleteStateExploration == null) { - final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription( - "State space exploration incomplete", IMarker.SEVERITY_WARNING); - marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2); - incompleteStateExploration = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC); - } - } else { - if (incompleteStateExploration != null) { - try { - incompleteStateExploration.delete(); - ResultPage.this.resetMessage(RESULT_PAGE_PROBLEM); - incompleteStateExploration = null; - } catch (CoreException e) { - TLCUIActivator.getDefault().logError(e.getMessage(), e); - } - } - sslp.unsetHighlightUnexplored(); - } - } - ResultPage.this.stateSpace.refresh(); - - - } finally { - disposeLock.unlock(); - } - } - }); - - } - - /** - * Gets the data provider for the current page - */ - public void loadData() throws CoreException - { - - TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry.getModelCheckSourceRegistry(); - TLCModelLaunchDataProvider provider = modelCheckSourceRegistry.getProvider(getModel()); - if (provider != null) { - provider.setPresenter(this); - } else { - // no data provider - reinit(); - } - - // constant expression - final Document document = new Document(getModel().getEvalExpression()); - final IDocumentPartitioner partitioner = new TLAFastPartitioner( - TLAEditorActivator.getDefault().getTLAPartitionScanner(), TLAPartitionScanner.TLA_PARTITION_TYPES); - document.setDocumentPartitioner(TLAPartitionScanner.TLA_PARTITIONING, partitioner); - partitioner.connect(document); - expressionEvalInput.setDocument(document); - } - - /** - * Reinitialize the fields - * has to be run in the UI thread - */ - private synchronized void reinit() - { - // TLCUIActivator.getDefault().logDebug("Entering reinit()"); - disposeLock.lock(); - try { - if (getPartControl().isDisposed()) { - // Cannot access widgets past their disposal - return; - } - this.startTimestampText.setText(""); - this.startTimestamp = 0; - this.finishTimestampText.setText(""); - this.tlcModeText.setText(""); - this.lastCheckpointTimeText.setText(""); - this.currentStatusText.setText(TLCModelLaunchDataProvider.NOT_RUNNING); - this.errorStatusHyperLink.setText(TLCModelLaunchDataProvider.NO_ERRORS); - this.coverage.setInput(new Vector<CoverageInformationItem>()); - this.stateSpace.setInput(new Vector<StateSpaceInformationItem>()); - this.progressOutput.setDocument(new Document(TLCModelLaunchDataProvider.NO_OUTPUT_AVAILABLE)); - this.userOutput.setDocument(new Document(TLCModelLaunchDataProvider.NO_OUTPUT_AVAILABLE)); - } finally { - disposeLock.unlock(); - } - // TLCUIActivator.getDefault().logDebug("Exiting reinit()"); - } - - /** - * Dispose the page - */ - public void dispose() - { - disposeLock.lock(); - try { - /* - * Remove graph windows raised for the page. - */ - String suffix = getGraphTitleSuffix(this); - Shell[] shells = UIHelper.getCurrentDisplay().getShells(); - for (int i = 0; i < shells.length; i++) { - if (shells[i].getText().endsWith(suffix)) { - shells[i].dispose(); - } - } - - if (incompleteStateExploration != null) { - incompleteStateExploration.delete(); - incompleteStateExploration = null; - } - - if (zeroCoverage != null) { - zeroCoverage.delete(); - zeroCoverage = null; - } - - JFaceResources.getFontRegistry().removeListener(fontChangeListener); - - TLCModelLaunchDataProvider provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry() - .getProvider(getModel()); - if (provider != null) { - provider.setPresenter(null); - } - super.dispose(); - } catch (CoreException e) { - e.printStackTrace(); - } finally { - disposeLock.unlock(); - } - } - - /** - * Draw the fields - * - * Its helpful to know what the standard SWT widgets look like. - * Pictures can be found at http://www.eclipse.org/swt/widgets/ - * - * Layouts are used throughout this method. - * A good explanation of layouts is given in the article - * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html - */ - protected void createBodyContent(IManagedForm managedForm) - { - final int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE | Section.EXPANDED | SWT.WRAP; - final int textFieldFlags = SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.FULL_SELECTION; - final int expressionFieldFlags = textFieldFlags | SWT.WRAP; - - FormToolkit toolkit = managedForm.getToolkit(); - Composite body = managedForm.getForm().getBody(); - TableWrapLayout layout = new TableWrapLayout(); - layout.numColumns = 1; - body.setLayout(layout); - - TableWrapData twd; - Section section; - GridData gd; - - // ------------------------------------------------------------------- - // general section - // There is no description line for this section, so it is - // necessary to eliminate that bit in the style flags that - // are passed in. If the bit were not changed to 0, an - // extra empty line would appear below the title. - section = FormHelper.createSectionComposite(body, "General", "" - /* "The current progress of model-checking"*/, toolkit, sectionFlags & ~Section.DESCRIPTION, - getExpansionListener()); - sections.put(SEC_GENERAL, section); - twd = new TableWrapData(TableWrapData.FILL); - twd.colspan = 1; - - section.setLayoutData(twd); - - Composite generalArea = (Composite) section.getClient(); - generalArea.setLayout(new GridLayout()); - - // ------------ status composite ------------ - Composite statusComposite = toolkit.createComposite(generalArea); - statusComposite.setLayout(new GridLayout(2, false)); - - // start - this.startTimestampText = FormHelper.createTextLeft("Start time:", statusComposite, toolkit); - this.startTimestampText.setEditable(false); - // elapsed time - this.finishTimestampText = FormHelper.createTextLeft("End time:", statusComposite, toolkit); - this.finishTimestampText.setEditable(false); - // elapsed time - this.tlcModeText = FormHelper.createTextLeft("TLC mode:", statusComposite, toolkit); - this.tlcModeText.setEditable(false); - // last checkpoint time - this.lastCheckpointTimeText = FormHelper.createTextLeft("Last checkpoint time:", statusComposite, toolkit); - this.lastCheckpointTimeText.setEditable(false); - // current status - this.currentStatusText = FormHelper.createTextLeft("Current status:", statusComposite, toolkit); - this.currentStatusText.setEditable(false); - this.currentStatusText.setText(TLCModelLaunchDataProvider.NOT_RUNNING); - // errors - // Label createLabel = - // toolkit.createLabel(statusComposite, "Errors detected:"); - // this.errorStatusHyperLink = toolkit.createHyperlink(statusComposite, "", SWT.RIGHT); - this.errorStatusHyperLink = FormHelper.createHyperlinkLeft("Errors detected:", statusComposite, toolkit); - // fingerprint collision probability - this.fingerprintCollisionProbabilityText = FormHelper.createTextLeft("Fingerprint collision probability:", statusComposite, toolkit); - this.fingerprintCollisionProbabilityText.setEditable(false); - this.fingerprintCollisionProbabilityText.setText(""); - - // ------------------------------------------------------------------- - // statistics section - // There is no description line for this section, so it is - // necessary to eliminate that bit in the style flags that - // are passed in. If the bit were not changed to 0, an - // extra empty line would appear below the title. - section = FormHelper.createSectionComposite(body, "Statistics", "", - /*"The current progress of model-checking",*/ - toolkit, (sectionFlags | Section.COMPACT) & ~Section.DESCRIPTION, getExpansionListener()); - sections.put(SEC_STATISTICS, section); - twd = new TableWrapData(TableWrapData.FILL); - twd.colspan = 1; - section.setLayoutData(twd); - Composite statArea = (Composite) section.getClient(); - RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); - // rowLayout.numColumns = 2; - statArea.setLayout(rowLayout); - - // progress stats - createAndSetupStateSpace("State space progress (click column header for graph)", statArea, toolkit); - // coverage stats - createAndSetupCoverage("Coverage at", statArea, toolkit); - - // ------------------------------------------------------------------- - // Calculator section - // There is no description line for this section, so it is - // necessary to eliminate that bit in the style flags that - // are passed in. If the bit were not changed to 0, an - // extra empty line would appear below the title. - section = FormHelper.createSectionComposite(body, "Evaluate Constant Expression", "", toolkit, sectionFlags - & ~Section.DESCRIPTION, getExpansionListener()); - sections.put(SEC_EXPRESSION, section); - - Composite resultArea = (Composite) section.getClient(); - GridLayout gLayout = new GridLayout(2, false); - gLayout.marginHeight = 0; - resultArea.setLayout(gLayout); - - Composite expressionComposite = toolkit.createComposite(resultArea); - expressionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); - gLayout = new GridLayout(1, false); - gLayout.marginHeight = 0; - gLayout.marginBottom = 5; - expressionComposite.setLayout(gLayout); - - toolkit.createLabel(expressionComposite, "Expression: "); - expressionEvalInput = FormHelper.createFormsSourceViewer(toolkit, expressionComposite, expressionFieldFlags, - new TLASourceViewerConfiguration()); - expressionEvalInput.getTextWidget().addKeyListener(new KeyListener() { - @Override - public void keyPressed(KeyEvent e) { - if (isUndoKeyPress(e)) { - expressionEvalInput.doOperation(ITextOperationTarget.UNDO); - } else if (isRedoKeyPress(e)) { - expressionEvalInput.doOperation(ITextOperationTarget.REDO); - } - } - - private boolean isRedoKeyPress(KeyEvent e) { - return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'y') || (e.keyCode == 'Y')); - } - - private boolean isUndoKeyPress(KeyEvent e) { - return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'z') || (e.keyCode =='Z')); - } - - @Override - public void keyReleased(KeyEvent e) { - } - }); - - // We want the value section to get larger as the window - // gets larger but not the expression section. - Composite valueComposite = toolkit.createComposite(resultArea); - valueComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - valueComposite.setLayout(gLayout); - toolkit.createLabel(valueComposite, "Value: "); - expressionEvalResult = FormHelper.createFormsOutputViewer(toolkit, valueComposite, expressionFieldFlags); - - // We dont want these items to fill excess - // vertical space because then in some cases - // this causes the text box to be extremely - // tall instead of having a scroll bar. - gd = new GridData(SWT.FILL, SWT.FILL, true, false); - gd.widthHint = 500; - gd.heightHint = 80; - expressionEvalResult.getTextWidget().setLayoutData(gd); - // The expression section should not grab excess horizontal - // space because if this flag is set to true and the length - // of the expression causes a vertical scroll bar to appear, - // then when the model is run, the expression text box - // will get wide enough to fit the entire expression on - // one line instead of wrapping the text. - gd = new GridData(SWT.FILL, SWT.FILL, false, false); - gd.widthHint = 500; - gd.heightHint = 80; - expressionEvalInput.getTextWidget().setLayoutData(gd); - // We want this font to be the same as the input. - // If it was not set it would be the same as the font - // in the module editor. - expressionEvalResult.getTextWidget().setFont(JFaceResources.getTextFont()); - expressionEvalInput.getTextWidget().setFont(JFaceResources.getTextFont()); - // This is required to paint the borders of the text boxes - // it must be called on the direct parent of the widget - // with a border. There is a call of this methon in - // FormHelper.createSectionComposite, but that is called - // on the section which is not a direct parent of the - // text box widget. - toolkit.paintBordersFor(expressionComposite); - toolkit.paintBordersFor(valueComposite); - - ValidateableSectionPart calculatorSectionPart = new ValidateableSectionPart(section, this, SEC_EXPRESSION); - // This ensures that when the part is made dirty, the model - // appears unsaved. - managedForm.addPart(calculatorSectionPart); - - // This makes the widget unsaved when text is entered. - expressionEvalInput.getTextWidget().addModifyListener(new DirtyMarkingListener(calculatorSectionPart, false)); - - getDataBindingManager().bindAttribute(Model.MODEL_EXPRESSION_EVAL, expressionEvalInput, calculatorSectionPart); - getDataBindingManager().bindSection(calculatorSectionPart, SEC_EXPRESSION, getId()); - - // ------------------------------------------------------------------- - // output section - section = FormHelper.createSectionComposite(body, "User Output", - "TLC output generated by evaluating Print and PrintT expressions.", toolkit, sectionFlags, - getExpansionListener()); - sections.put(SEC_OUTPUT, section); - Composite outputArea = (Composite) section.getClient(); - outputArea.setLayout(new GridLayout()); - // output viewer - userOutput = FormHelper.createFormsOutputViewer(toolkit, outputArea, textFieldFlags | SWT.WRAP); - - // We dont want this item to fill excess - // vertical space because then in some cases - // this causes the text box to be extremely - // tall instead of having a scroll bar. - gd = new GridData(SWT.FILL, SWT.LEFT, true, false); - gd.heightHint = 300; - gd.widthHint = 300; - userOutput.getControl().setLayoutData(gd); - userOutput.getControl().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); - - // ------------------------------------------------------------------- - // progress section - // There is no description line for this section, so it is - // necessary to eliminate that bit in the style flags that - // are passed in. If the bit were not changed to 0, an - // extra empty line would appear below the title. - section = FormHelper.createSectionComposite(body, "Progress Output", "", - /* "The current progress of model-checking",*/ - toolkit, sectionFlags & ~Section.DESCRIPTION, getExpansionListener()); - sections.put(SEC_PROGRESS, section); - section.setExpanded(false); - Composite progressArea = (Composite) section.getClient(); - progressArea = (Composite) section.getClient(); - progressArea.setLayout(new GridLayout()); - - progressOutput = FormHelper.createFormsOutputViewer(toolkit, progressArea, textFieldFlags); - // We dont want this item to fill excess - // vertical space because then in some cases - // this causes the text box to be extremely - // tall instead of having a scroll bar. - gd = new GridData(SWT.FILL, SWT.LEFT, true, false); - gd.heightHint = 300; - gd.minimumWidth = 300; - progressOutput.getControl().setLayoutData(gd); - progressOutput.getControl().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); - - Vector<Control> controls = new Vector<Control>(); - controls.add(userOutput.getControl()); - controls.add(progressOutput.getControl()); - fontChangeListener = new FontPreferenceChangeListener(controls, ITLCPreferenceConstants.I_TLC_OUTPUT_FONT); - - JFaceResources.getFontRegistry().addListener(fontChangeListener); - - headClientTBM.add(new DynamicContributionItem(new LoadOutputAction())); - } - - class LoadOutputAction extends Action { - public LoadOutputAction() { - super("Load output", TLCUIActivator.imageDescriptorFromPlugin( - TLCUIActivator.PLUGIN_ID, - "icons/full/copy_edit.gif")); - setDescription("Loads the output from an external model run (requires \"-tool\" parameter) corresponding to this model."); - setToolTipText( - "Loads an existing output (e.g. from a standlone TLC run that corresponds to this model). Output has to contain tool markers. Run TLC with \"-tool\" command line parameter. "); - } - - public void run() { - // Get the user input (the path to the TLC output file). - final FileDialog fileDialog = new FileDialog(new Shell()); - final String path = fileDialog.open(); - if (path == null) { - // User cancelled the dialog - return; - } - - // I/O operations should never run inside the UI thread. - final Job j = new WorkspaceJob("Loading output file...") { - public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { - try { - // Import the file into the Toolbox on the file/resource layer. - final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry - .getModelCheckSourceRegistry(); - modelCheckSourceRegistry - .removeTLCStatusSource(new Model[] { getModel() }); - getModel().createModelOutputLogFile(new FileInputStream(new File(path)), monitor); - - // Once the output has been imported on the - // file/resource layer, update the UI. - final Job job = new UIJob("Updating results page with loaded output...") { - public IStatus runInUIThread(IProgressMonitor monitor) { - try { - ResultPage.this.loadData(); - } catch (CoreException e) { - return new Status(IStatus.ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e); - } - return Status.OK_STATUS; - } - }; - job.schedule(); - - } catch (FileNotFoundException e) { - return new Status(IStatus.ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e); - } - return Status.OK_STATUS; - } - }; - final IWorkspace workspace = ResourcesPlugin.getWorkspace(); - j.setRule(workspace.getRuleFactory().buildRule()); - j.schedule(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.action.Action#isEnabled() - */ - public boolean isEnabled() { - if (getModel().isRunning()) { - return false; - } - return super.isEnabled(); - } - } - - - /** - * Save data back to model - */ - public void commit(boolean onSave) - { - String expression = this.expressionEvalInput.getDocument().get(); - getModel().unsavedSetEvalExpression(expression); - - super.commit(onSave); - } - - /** - * Creates the state space table (initializes the {@link stateSpace} variable) - * @param label - * @param parent - * @param toolkit - * @return the constructed composite - */ - private Composite createAndSetupStateSpace(String label, Composite parent, FormToolkit toolkit) - { - Composite statespaceComposite = toolkit.createComposite(parent, SWT.WRAP); - statespaceComposite.setLayout(new GridLayout(1, false)); - - toolkit.createLabel(statespaceComposite, label); - - Table stateTable = toolkit.createTable(statespaceComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL - | SWT.BORDER); - GridData gd = new GridData(StateSpaceLabelProvider.MIN_WIDTH, 100); - stateTable.setLayoutData(gd); - - stateTable.setHeaderVisible(true); - stateTable.setLinesVisible(true); - - StateSpaceLabelProvider.createTableColumns(stateTable, this); - - // create the viewer - this.stateSpace = new TableViewer(stateTable); - - // create list-based content provider - this.stateSpace.setContentProvider(new IStructuredContentProvider() { - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) - { - } - - public void dispose() - { - } - - public Object[] getElements(Object inputElement) - { - if (inputElement != null && inputElement instanceof List) - { - return ((List<?>) inputElement).toArray(new Object[((List<?>) inputElement).size()]); - } - return null; - } - }); - - this.stateSpace.setLabelProvider(new StateSpaceLabelProvider(this)); - getSite().setSelectionProvider(this.stateSpace); - return statespaceComposite; - } - - /** - * Creates the coverage table (initializes the {@link coverageTimestamp} and {@link coverage} variables) - * @param label - * @param parent - * @param toolkit - * @return returns the containing composite - */ - private Composite createAndSetupCoverage(String label, Composite parent, FormToolkit toolkit) - { - Composite coverageComposite = toolkit.createComposite(parent, SWT.WRAP); - coverageComposite.setLayout(new GridLayout(2, false)); - GridData gd = new GridData(); - toolkit.createLabel(coverageComposite, label); - - this.coverageTimestampText = toolkit.createText(coverageComposite, "", SWT.FLAT); - this.coverageTimestampText.setEditable(false); - gd = new GridData(); - gd.minimumWidth = 200; - gd.grabExcessHorizontalSpace = true; - this.coverageTimestampText.setLayoutData(gd); - - final Table stateTable = toolkit.createTable(coverageComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL - | SWT.BORDER | SWT.VIRTUAL); - gd = new GridData(CoverageLabelProvider.MIN_WIDTH, 100); - gd.horizontalSpan = 2; - stateTable.setLayoutData(gd); - - stateTable.setHeaderVisible(true); - stateTable.setLinesVisible(true); - stateTable.setToolTipText(TOOLTIP); - - CoverageLabelProvider.createTableColumns(stateTable); - - // create the viewer - this.coverage = new TableViewer(stateTable); - - coverage.getTable().addMouseListener(new ActionClickListener(this.coverage)); - - // create list-based content provider - this.coverage.setContentProvider(new IStructuredContentProvider() { - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) - { - } - - public void dispose() - { - } - - public Object[] getElements(Object inputElement) - { - if (inputElement != null && inputElement instanceof List) - { - return ((List<?>) inputElement).toArray(new Object[((List<?>) inputElement).size()]); - } - return null; - } - }); - - this.coverage.setLabelProvider(new CoverageLabelProvider()); - - getSite().setSelectionProvider(this.coverage); - - return coverageComposite; - } - - /** - * Returns the StateSpaceInformationItem objects currently being displayed in - * the "State space progress" area, except in temporal order--that is, in the - * opposite order from which they are displayed. - * - * @return - */ - @SuppressWarnings("unchecked") // generics cast - public StateSpaceInformationItem[] getStateSpaceInformation() - { - List<StateSpaceInformationItem> infoList = (List<StateSpaceInformationItem>) stateSpace.getInput(); - StateSpaceInformationItem[] result = new StateSpaceInformationItem[infoList.size()]; - for (int i = 0; i < result.length; i++) - { - result[i] = infoList.get(result.length - i - 1); - } - return result; - - } - - /** - * Provides labels for the state space table - */ - static class StateSpaceLabelProvider extends LabelProvider implements ITableLabelProvider, ITableFontProvider, ITableColorProvider - { - public final static String[] columnTitles = new String[] { "Time", "Diameter", "States Found", - "Distinct States", "Queue Size" }; - public final static int[] columnWidths = { 120, 60, 80, 100, 80 }; - public static final int MIN_WIDTH = columnWidths[0] + columnWidths[1] + columnWidths[2] + columnWidths[3] - + columnWidths[4]; - public final static int COL_TIME = 0; - public final static int COL_DIAMETER = 1; - public final static int COL_FOUND = 2; - public final static int COL_DISTINCT = 3; - public final static int COL_LEFT = 4; - - private boolean doHighlight = false; - private final ResultPage resultPage; - - public StateSpaceLabelProvider(ResultPage resultPage) { - this.resultPage = resultPage; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) - */ - public Image getColumnImage(Object element, int columnIndex) - { - return null; - } - - /** - * @param stateTable - */ - public static void createTableColumns(Table stateTable, ResultPage page) - { - // create table headers - for (int i = 0; i < columnTitles.length; i++) - { - TableColumn column = new TableColumn(stateTable, SWT.NULL); - column.setWidth(columnWidths[i]); - column.setText(columnTitles[i]); - - // The following statement attaches a listener to the column - // header. See the ResultPageColumnListener comments. - - column.addSelectionListener(new ResultPageColumnListener(i, page)); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) - */ - public String getColumnText(Object element, int columnIndex) - { - if (element instanceof StateSpaceInformationItem) - { - // the "N/A" values are used for simulation mode - StateSpaceInformationItem item = (StateSpaceInformationItem) element; - switch (columnIndex) { - case COL_TIME: - return formatInterval(resultPage.startTimestamp, item.getTime().getTime()); - case COL_DIAMETER: - if (item.getDiameter() >= 0) - { - return String.valueOf(item.getDiameter()); - } else - { - return "--"; - } - case COL_FOUND: - return String.valueOf(item.getFoundStates()); - case COL_DISTINCT: - if (item.getDistinctStates() >= 0) - { - return String.valueOf(item.getDistinctStates()); - } else - { - return "--"; - } - - case COL_LEFT: - if (item.getLeftStates() >= 0) - { - return String.valueOf(item.getLeftStates()); - } else - { - return "--"; - } - } - } - return null; - } - - public Color getForeground(Object element, int columnIndex) { - return null; // Use default color - } - - public Color getBackground(Object element, int columnIndex) { - final StateSpaceInformationItem ssii = (StateSpaceInformationItem) element; - if (doHighlight && columnIndex == COL_LEFT && ssii.isMostRecent()) { - return TLCUIActivator.getColor(SWT.COLOR_RED); - } - return null; - } - - public Font getFont(Object element, int columnIndex) { - final StateSpaceInformationItem ssii = (StateSpaceInformationItem) element; - if (doHighlight && columnIndex == COL_LEFT && ssii.isMostRecent()) { - return JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT); - } - return null; - } - - public void setHighlightUnexplored() { - doHighlight = true; - } - - public void unsetHighlightUnexplored() { - doHighlight = false; - } - - private static String formatInterval(final long firstTS, final long secondTS) { - final long interval = secondTS - firstTS; - final long hr = TimeUnit.MILLISECONDS.toHours(interval); - final long min = TimeUnit.MILLISECONDS.toMinutes(interval - TimeUnit.HOURS.toMillis(hr)); - final long sec = TimeUnit.MILLISECONDS - .toSeconds(interval - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)); - return String.format("%02d:%02d:%02d", hr, min, sec); - } - } - - /** - * Provides labels for the coverage table - */ - static class CoverageLabelProvider extends LabelProvider implements ITableLabelProvider, ITableColorProvider - { - public final static String[] columnTitles = new String[] { "Module", "Location", "Count" }; - public final static int[] columnWidths = { 80, 200, 80 }; - public static final int MIN_WIDTH = columnWidths[0] + columnWidths[1] + columnWidths[2]; - public final static int COL_MODULE = 0; - public final static int COL_LOCATION = 1; - public final static int COL_COUNT = 2; - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) - */ - public Image getColumnImage(Object element, int columnIndex) - { - return null; - } - - /** - * @param stateTable - */ - public static void createTableColumns(Table stateTable) - { - // create table headers - for (int i = 0; i < columnTitles.length; i++) - { - TableColumn column = new TableColumn(stateTable, SWT.NULL); - column.setWidth(columnWidths[i]); - column.setText(columnTitles[i]); - column.setToolTipText(TOOLTIP); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) - */ - public String getColumnText(Object element, int columnIndex) - { - if (element instanceof CoverageInformationItem) - { - CoverageInformationItem item = (CoverageInformationItem) element; - switch (columnIndex) { - case COL_MODULE: - return item.getModule(); - case COL_LOCATION: - return item.getLocation(); - case COL_COUNT: - return String.valueOf(item.getCount()); - } - } - return null; - } - - public Color getForeground(Object element, int columnIndex) { - return null; // Use default color - } - - public Color getBackground(Object element, int columnIndex) { - final CoverageInformationItem cii = (CoverageInformationItem) element; - if (cii.getCount() == 0) { - return TLCUIActivator.getColor(SWT.COLOR_YELLOW); - } - return null; - } - } - - /** - * A ResultPageColumnListener is a listener that handles clicks on - * the column headers of the "State space progress" region of the - * Result Page. The same class is used for all the column - * headers, with the column number indicating which column header - * was clicked on. - * - * @author lamport - * - */ - static class ResultPageColumnListener implements SelectionListener - { - - private int columnNumber; - private ResultPage resultPage; - - public ResultPageColumnListener(int columnNumber, ResultPage resultPage) - { - super(); - this.columnNumber = columnNumber; - this.resultPage = resultPage; - } - - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) - */ - public void widgetDefaultSelected(SelectionEvent e) - { - // nop - } - - /** - * This is called when the user clicks on the header of a column - * of the "State space progress" region of the ResultsPage. It - * raises a window with a graph of the specified column. - */ - public void widgetSelected(SelectionEvent e) - { - UIHelper.runUIAsync(new DataDisplay(resultPage, columnNumber)); - - } - - } - - /** - * The run method of this class creates a shell (a window) to display - * a graph of the appropriate State Space Progress information when the user clicks on - * a column heading. It then adds a PaintListener to that shell, and that - * listener draws the graph initially and whenever the window is resized or - * some other event requires it to be redrawn. - * - * The constructor is used to pass the arguments needed by the run method to - * display the data. - * - * Note: The location at which the shells are displayed is fixed in code - * buried deeply. There should probably be some thought given to where to - * pop up the window, and perhaps a window should be popped up in the same - * place as the last such window was popped--perhaps with a bit of random - * variation to prevent them all from piling up. - * - * @author lamport - * - */ - static class DataDisplay implements Runnable - { - int columnNumber; - ResultPage resultPage; - - /** - * The constructor returns an object with null data and times arrays - * if there are not at least two data points. - * - * @param ssInfo - * @param columnNumber - */ - public DataDisplay(ResultPage resultPage, int columnNumber) - { - - this.resultPage = resultPage; - this.columnNumber = columnNumber; - } - - /** - * Much of the stuff in this run() method was copied, without much - * understanding from Snippet245.java in the Eclipse examples. - */ - public void run() - { - - /* - * The data and times arrays are set to contain the data items to be displayed - * and the elapsed time (in milliseconds) at which each item was posted. - * The data is obtained from the appropriate column of the ssInfo items. - * For the Time column, the number of reports is graphed. - */ - - // The following method for getting the current display was - // copied without understanding from someplace or other. - - String title = getGraphTitle(columnNumber, resultPage); - - // We check if a shell exists with this title, and use it if - // it does. Otherwise, we get a new shell. - Display display = UIHelper.getCurrentDisplay(); - boolean shellExists = false; - Shell theShell = null; - Shell[] shells = display.getShells(); - for (int i = 0; i < shells.length; i++) - { - if (shells[i].getText().equals(title)) - { - theShell = shells[i]; - shellExists = true; - break; - } - } - if (!shellExists) - { - theShell = new Shell(display, SWT.SHELL_TRIM); - } - final Shell shell = theShell; - shell.setText(title); - shell.setActive(); // should cause it to pop up to the top. - if (shellExists) - { - shell.redraw(); - shell.update(); - } else - { - shell.addPaintListener(new PaintListener() { - public void paintControl(PaintEvent event) - { - StateSpaceInformationItem[] ssInfo = resultPage.getStateSpaceInformation(); - if (ssInfo.length < 2) - { - return; - } - - final long[] data = new long[ssInfo.length + 1]; - long[] times = new long[ssInfo.length + 1]; - data[0] = 0; - times[0] = 0; - - long startTime = resultPage.startTimestamp; - TLCUIActivator.getDefault().logDebug("first reported time - starttime = " - + (ssInfo[0].getTime().getTime() - startTime)); - if (startTime > ssInfo[0].getTime().getTime() - 1000) - { - startTime = ssInfo[0].getTime().getTime() - 1000; - } - for (int i = 1; i < data.length; i++) - { - switch (columnNumber) { - case StateSpaceLabelProvider.COL_TIME: - data[i] = i - 1; - break; - case StateSpaceLabelProvider.COL_DIAMETER: - data[i] = ssInfo[i - 1].getDiameter(); - break; - case StateSpaceLabelProvider.COL_FOUND: - data[i] = ssInfo[i - 1].getFoundStates(); - break; - case StateSpaceLabelProvider.COL_DISTINCT: - data[i] = ssInfo[i - 1].getDistinctStates(); - break; - case StateSpaceLabelProvider.COL_LEFT: - data[i] = ssInfo[i - 1].getLeftStates(); - break; - default: - return; - } - times[i] = ssInfo[i - 1].getTime().getTime() - startTime; - } - - Rectangle rect = shell.getClientArea(); - // Set maxData to the largest data value; - long maxData = 0; - for (int i = 0; i < data.length; i++) - { - if (data[i] > maxData) - { - maxData = data[i]; - } - } - long maxTime = times[times.length - 1]; - - // event.gc.drawOval(0, 0, rect.width - 1, rect.height - 1); - if (maxTime > 0) - { - // In case maxData equals 0, we use 1 instead for computing - // the coordinates of the points. - // (Added by LL on 6 July 2011 to fix division by zero bug.) - long maxDataVal = maxData ; - if (maxDataVal == 0) { - maxDataVal = 1; - } - int[] pointArray = new int[2 * data.length]; - for (int i = 0; i < data.length; i++) - { - pointArray[2 * i] = (int) ((times[i] * rect.width) / maxTime); - pointArray[(2 * i) + 1] = (int) (rect.height - ((data[i] * rect.height) / maxDataVal)); - } - event.gc.drawPolyline(pointArray); - } - String stringTime = "Time: "; - long unreportedTime = maxTime; - long days = maxTime / (1000 * 60 * 60 * 24); - if (days > 0) - { - unreportedTime = unreportedTime - days * (1000 * 60 * 60 * 24); - stringTime = stringTime + days + ((days == 1) ? (" day ") : (" days ")); - - } - long hours = unreportedTime / (1000 * 60 * 60); - if (hours > 0) - { - unreportedTime = unreportedTime - hours * (1000 * 60 * 60); - stringTime = stringTime + hours + ((hours == 1) ? (" hour ") : (" hours ")); - } - unreportedTime = (unreportedTime + (1000 * 26)) / (1000 * 60); - stringTime = stringTime + unreportedTime - + ((unreportedTime == 1) ? (" minute ") : (" minutes ")); - event.gc.drawString(stringTime, 0, 0); - event.gc.drawString("Current: " + data[data.length - 1], 0, 15); - if (maxData != data[data.length - 1]) - { - event.gc.drawString("Maximum: " + maxData, 0, 30); - } - } - }); - } - ; - if (!shellExists) - { - shell.setBounds(100 + 30 * columnNumber, 100 + 30 * columnNumber, 400, 300); - } - shell.open(); - // The following code from the Eclipse example was eliminated. - // It seems to cause the shell to survive after the Toolbox is - // killed. - // - // while (!shell.isDisposed()) { - // if (!display.readAndDispatch()) display.sleep(); - // } - - } - - } - - /** - * The title of a graph consists of two parts: the prefix, which - * identifies the column, and the suffix, which identifies the model. - * When we dispose of the ResultPage, we must dispose of all graph - * window (shells) for that model. - * - * @param resultPage - * @return - */ - private static String getGraphTitleSuffix(ResultPage resultPage) - { - return "(" + resultPage.getModel().getName() + ")"; - } - - private static String getGraphTitle(int columnNumber, ResultPage resultPage) - { - String title = StateSpaceLabelProvider.columnTitles[columnNumber]; - if (columnNumber == StateSpaceLabelProvider.COL_TIME) - { - title = "Number of Progress Reports"; - } - return title + " " + getGraphTitleSuffix(resultPage); - } - - public Set<Section> getSections(String ...sectionIDs) { - final Set<String> set = new HashSet<String>(Arrays.asList(sectionIDs)); - return this.sections.entrySet().stream().filter(e -> set.contains(e.getKey())).map(Map.Entry::getValue) - .collect(Collectors.toSet()); - } -} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/TLCConsumptionProfile.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/TLCConsumptionProfile.java new file mode 100644 index 0000000000000000000000000000000000000000..6c70731364331cc1e7b7eca1204741d86cc08e67 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/TLCConsumptionProfile.java @@ -0,0 +1,92 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page; + +import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; + +import util.TLCRuntime; + +/** + * This enum represents the profile types of TLC running. + */ +public enum TLCConsumptionProfile { + + LOCAL_MOST("Most", 0.7, 0.8, null, "local most"), + LOCAL_NORMAL("Medium", 0.5, 0.4, null, "local nomal"), + LOCAL_MINIMAL("Minimal", 0.2, ((double)TLCProcessJob.HEAP_SIZE_DEFAULT / 100.0), null, "local minimal"), + REMOTE_AD_HOC("Ad Hoc", 0, 0.3, "ad hoc", "ad hoc"), + REMOTE_AZURE("Azure", 0, 0, MainModelPage.CLOUD_CONFIGURATION_KEY, "Azure"), + REMOTE_AWS("Amazon", 0, 0, MainModelPage.CLOUD_CONFIGURATION_KEY, "aws-ec2"), + REMOTE_PACKET_NET("PacketNet", 0, 0, MainModelPage.CLOUD_CONFIGURATION_KEY, "PacketNet"); + + public static TLCConsumptionProfile getProfileWithPreferenceValue(final String value) { + for (final TLCConsumptionProfile profile : TLCConsumptionProfile.values()) { + if (value.equals(profile.getPreferenceValue())) { + return profile; + } + } + + return null; + } + + public static TLCConsumptionProfile getProfileWithDisplayName(final String displayName) { + for (final TLCConsumptionProfile profile : TLCConsumptionProfile.values()) { + if (displayName.equals(profile.getDisplayName())) { + return profile; + } + } + + return null; + } + + + private final double m_workerThreadPercentage; + private final double m_memoryPercentage; + private final String m_displayName; + + private final String m_configurationKey; + + private final String m_preferenceValue; + + private TLCConsumptionProfile(final String name, final double threadPercentage, final double memoryPercentage, + final String uiConfigurationKey, final String preferenceValue) { + m_displayName = name; + + m_workerThreadPercentage = threadPercentage; + m_memoryPercentage = memoryPercentage; + + m_configurationKey = uiConfigurationKey; + + m_preferenceValue = preferenceValue; + } + + public String getDisplayName() { + return m_displayName; + } + + public boolean profileIsForRemoteWorkers() { + return (m_configurationKey != null); + } + + public String getConfigurationKey() { + return m_configurationKey; + } + + public String getPreferenceValue() { + return m_preferenceValue; + } + + /** + * @return the 0-100 representation of percentage + */ + public int getMemoryPercentage() { + return (int)(100.0 * m_memoryPercentage); + } + + public long getMemory() { + return TLCRuntime.getInstance().getAbsolutePhysicalSystemMemory(m_memoryPercentage); + } + + public int getWorkerThreads() { + return (int)Math.ceil((float)Runtime.getRuntime().availableProcessors() * m_workerThreadPercentage); + } + +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java new file mode 100644 index 0000000000000000000000000000000000000000..61b10e5defeb1dd91e7bc9a307928b0ddebaae21 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java @@ -0,0 +1,490 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.IMessageManager; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.forms.widgets.TableWrapData; +import org.eclipse.ui.forms.widgets.TableWrapLayout; +import org.lamport.tla.toolbox.tool.ToolboxHandle; +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.model.Assignment; +import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableOverridesSectionPart; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; +import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; +import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper; +import org.lamport.tla.toolbox.util.IHelpConstants; +import org.lamport.tla.toolbox.util.UIHelper; + +import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.OpDefNode; + +/** + * Where we are sticking "advanced" model options, not including those related to TLC execution. + * + * @author Simon Zambrovski + */ +public class AdvancedModelPage extends BasicFormPage implements Closeable { + public static final String ID = "advancedModelPage"; + + + private SourceViewer constraintSource; + private SourceViewer actionConstraintSource; + private SourceViewer newDefinitionsSource; + private SourceViewer modelValuesSource; + + private TableViewer definitionsTable; + + /** + * Constructs the page + * + * @param editor + */ + public AdvancedModelPage(final FormEditor editor) { + super(editor, ID, "Spec Options", + "icons/full/advanced_model_options_" + IMAGE_TEMPLATE_TOKEN + ".png"); + helpId = IHelpConstants.ADVANCED_MODEL_PAGE; + } + + /** + * Loads data from the model + */ + @Override + protected void loadData() throws CoreException { + // definition overrides + List<String> definitions = getModel().getAttribute(MODEL_PARAMETER_DEFINITIONS, new Vector<String>()); + FormHelper.setSerializedInput(definitionsTable, definitions); + + // new definitions + String newDefinitions = getModel().getAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, EMPTY_STRING); + newDefinitionsSource.setDocument(new Document(newDefinitions)); + + // advanced model values + String modelValues = getModel().getAttribute(MODEL_PARAMETER_MODEL_VALUES, EMPTY_STRING); + modelValuesSource.setDocument(new Document(modelValues)); + + // constraint + String constraint = getModel().getAttribute(MODEL_PARAMETER_CONSTRAINT, EMPTY_STRING); + constraintSource.setDocument(new Document(constraint)); + + // action constraint + String actionConstraint = getModel().getAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, EMPTY_STRING); + actionConstraintSource.setDocument(new Document(actionConstraint)); + } + + /** + * Save data back to config + */ + @Override + public void commit(final boolean onSave) { + // definitions + List<String> definitions = FormHelper.getSerializedInput(definitionsTable); + getModel().setAttribute(MODEL_PARAMETER_DEFINITIONS, definitions); + + // new definitions + String newDefinitions = FormHelper.trimTrailingSpaces(newDefinitionsSource.getDocument().get()); + getModel().setAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, newDefinitions); + + // model values + String modelValues = FormHelper.trimTrailingSpaces(modelValuesSource.getDocument().get()); + TypedSet modelValuesSet = TypedSet.parseSet(modelValues); + getModel().setAttribute(MODEL_PARAMETER_MODEL_VALUES, modelValuesSet.toString()); + + // constraint formula + String constraintFormula = FormHelper.trimTrailingSpaces(constraintSource.getDocument().get()); + getModel().setAttribute(MODEL_PARAMETER_CONSTRAINT, constraintFormula); + + // action constraint formula + String actionConstraintFormula = FormHelper.trimTrailingSpaces(actionConstraintSource.getDocument().get()); + getModel().setAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, actionConstraintFormula); + + super.commit(onSave); + } + + /** + * Validate the page's state. + */ + @Override + public void validatePage(final boolean switchToErrorPage) { + if (getManagedForm() == null) + { + return; + } + IMessageManager mm = getManagedForm().getMessageManager(); + mm.setAutoUpdate(false); + + ModelEditor modelEditor = (ModelEditor) getEditor(); + + // clean old messages + // this is now done in validateRunnable of + // ModelEditor + // mm.removeAllMessages(); + // make the run possible + setComplete(true); + + // setup the names from the current page + getLookupHelper().resetModelNames(this); + + // get data binding manager + final DataBindingManager dm = getDataBindingManager(); + + // check the model values + final IDocument document = modelValuesSource.getDocument(); + if (document != null) { + final TypedSet modelValuesSet = TypedSet.parseSet(FormHelper.trimTrailingSpaces(document.get())); + if (modelValuesSet.getValueCount() > 0) + { + // there were values defined + + // check if those are numbers? + /* + * if (modelValuesSet.hasANumberOnlyValue()) { + * mm.addMessage("modelValues1", + * "A model value can not be an number", modelValuesSet, + * IMessageProvider.ERROR, modelValuesSource.getControl()); + * setComplete(false); } + */ + List<String> values = modelValuesSet.getValuesAsList(); + // check list of model values if these are already used + validateUsage(MODEL_PARAMETER_MODEL_VALUES, values, "modelValues2_", "A model value", + "Advanced Model Values", true); + // check whether the model values are valid ids + validateId(MODEL_PARAMETER_MODEL_VALUES, values, "modelValues2_", "A model value"); + + // get widget for model values + Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_MODEL_VALUES)); + + // check if model values are config file keywords + for (int j = 0; j < values.size(); j++) + { + String value = (String) values.get(j); + if (SemanticHelper.isConfigFileKeyword(value)) + { + modelEditor.addErrorMessage(value, "The toolbox cannot handle the model value " + value + ".", this + .getId(), IMessageProvider.ERROR, widget); + setComplete(false); + } +// else { +// // Call of removeErrorMessage added by LL on 21 Mar 2013 +// // However, it did nothing because the value argument is a string + // currently in the field, which is not going to be the one that + // caused any existing error message. +// modelEditor.removeErrorMessage(value, widget); +// } + } + + } + } + + // opDefNodes necessary for determining if a definition in definition + // overrides is still in the specification + SpecObj specObj = ToolboxHandle.getCurrentSpec().getValidRootModule(); + OpDefNode[] opDefNodes = null; + if (specObj != null) + { + opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs(); + } + Hashtable<String, OpDefNode> nodeTable = new Hashtable<String, OpDefNode>(); + + if (opDefNodes != null) + { + for (int j = 0; j < opDefNodes.length; j++) + { + String key = opDefNodes[j].getName().toString(); + nodeTable.put(key, opDefNodes[j]); + } + } + + // get widget for definition overrides + Control widget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_DEFINITIONS)); + mm.removeMessages(widget); + // check the definition overrides + @SuppressWarnings("unchecked") + List<Assignment> definitions = (List<Assignment>) definitionsTable.getInput(); + if (definitions != null) { + for (int i = 0; i < definitions.size(); i++) + { + Assignment definition = definitions.get(i); + List<String> values = Arrays.asList(definition.getParams()); + // check list of parameters + validateUsage(MODEL_PARAMETER_DEFINITIONS, values, "param1_", "A parameter name", "Definition Overrides", + false); + // check whether the parameters are valid ids + validateId(MODEL_PARAMETER_DEFINITIONS, values, "param1_", "A parameter name"); + + // The following if test was added by LL on 11 Nov 2009 to prevent an unparsed + // file from producing bogus error messages saying that overridden definitions + // have been removed from the spec. + if (opDefNodes != null) + { + // Note added by LL on 21 Mar 2013: We do not remove error messages + // for overridden definitions that are set by this code because doing so + // may remove error messages set for these definitions by checks elsewhere + // in the code. + + // check if definition still appears in root module + if (!nodeTable.containsKey(definition.getLabel())) + { + // the following would remove + // the definition override from the table + // right now, an error message appears instead + // definitions.remove(i); + // definitionsTable.setInput(definitions); + // dm.getSection(DEF_OVERRIDES_PART).markDirty(); + modelEditor.addErrorMessage(definition.getLabel(), "The defined symbol " + + definition.getLabel().substring(definition.getLabel().lastIndexOf("!") + 1) + + " has been removed from the specification." + + " It must be removed from the list of definition overrides.", this.getId(), + IMessageProvider.ERROR, widget); + setComplete(false); + } else + { + // add error message if the number of parameters has changed + OpDefNode opDefNode = (OpDefNode) nodeTable.get(definition.getLabel()); + if (opDefNode.getSource().getNumberOfArgs() != definition.getParams().length) + { + modelEditor.addErrorMessage(definition.getLabel(), "Edit the definition override for " + + opDefNode.getSource().getName() + " to match the correct number of arguments.", this + .getId(), IMessageProvider.ERROR, widget); + setComplete(false); + } + } + } + } + for (int j = 0; j < definitions.size(); j++) + { + Assignment definition = (Assignment) definitions.get(j); + String label = definition.getLabel(); + if (SemanticHelper.isConfigFileKeyword(label)) + { + modelEditor.addErrorMessage(label, "The toolbox cannot override the definition of " + label + + " because it is a configuration file keyword.", this.getId(), IMessageProvider.ERROR, widget); + setComplete(false); + } + } + } + + mm.setAutoUpdate(true); + + super.validatePage(switchToErrorPage); + } + + /** + * Creates the UI + * + * Its helpful to know what the standard SWT widgets look like. + * Pictures can be found at http://www.eclipse.org/swt/widgets/ + * + * Layouts are used throughout this method. + * A good explanation of layouts is given in the article + * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html + */ + @Override + protected void createBodyContent(final IManagedForm managedForm) { + final DataBindingManager dm = getDataBindingManager(); + final int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE | Section.EXPANDED; + + final FormToolkit toolkit = managedForm.getToolkit(); + final Composite body = managedForm.getForm().getBody(); + + GridLayout gl; + GridData gd; + TableWrapData twd; + + TableWrapLayout twl = new TableWrapLayout(); + twl.leftMargin = 0; + twl.rightMargin = 0; + twl.numColumns = 2; + body.setLayout(twl); + + // left + final Composite left = toolkit.createComposite(body); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + left.setLayout(gl); + twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.grabHorizontal = true; + left.setLayoutData(twd); + + // right + final Composite right = toolkit.createComposite(body); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + right.setLayout(gl); + twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.grabHorizontal = true; + right.setLayoutData(twd); + + Section section; + + // --------------------------------------------------------------- + // new definitions + + section = FormHelper.createSectionComposite(left, "Additional Definitions", + "Definitions required for the model checking, in addition to the definitions in the specification modules.", + toolkit, sectionFlags, getExpansionListener()); + ValidateableSectionPart newDefinitionsPart = new ValidateableSectionPart(section, this, SEC_NEW_DEFINITION); + managedForm.addPart(newDefinitionsPart); + DirtyMarkingListener newDefinitionsListener = new DirtyMarkingListener(newDefinitionsPart, true); + + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + section.setLayoutData(gd); + + Composite newDefinitionsArea = (Composite) section.getClient(); + newDefinitionsSource = FormHelper.createFormsSourceViewer(toolkit, newDefinitionsArea, SWT.V_SCROLL); + // layout of the source viewer + twd = new TableWrapData(TableWrapData.FILL); + twd.heightHint = 60; + twd.grabHorizontal = true; + newDefinitionsSource.getTextWidget().setLayoutData(twd); + newDefinitionsSource.addTextListener(newDefinitionsListener); + newDefinitionsSource.getTextWidget().addFocusListener(focusListener); + + dm.bindAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, newDefinitionsSource, newDefinitionsPart); + + // --------------------------------------------------------------- + // definition overwrite + // Change added by LL on 10 April 2011 to cause model page to be created with the + // definitions override section open iff there are overridden definitions. This is + // done so the user will be aware of automatically generated overrides. + // + int expand = 0; + try + { + List<String> definitions = getModel().getAttribute(MODEL_PARAMETER_DEFINITIONS, new Vector<String>()); + if ((definitions != null) && (definitions.size() != 0)) { + expand = Section.EXPANDED; + } + } catch (CoreException e) + { + // Just ignore this since I have no idea what an exception might mean. + } + + final ValidateableOverridesSectionPart definitionsPart = new ValidateableOverridesSectionPart(right, + "Definition Override", "Directs TLC to use alternate definitions for operators.", toolkit, + sectionFlags | expand, this); + + managedForm.addPart(definitionsPart); + // layout + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + definitionsPart.getSection().setLayoutData(gd); + definitionsTable = definitionsPart.getTableViewer(); + dm.bindAttribute(MODEL_PARAMETER_DEFINITIONS, definitionsTable, definitionsPart); + + // --------------------------------------------------------------- + // modelValues + section = FormHelper.createSectionComposite(left, "Model Values", "An additional set of model values.", + toolkit, sectionFlags, getExpansionListener()); + ValidateableSectionPart modelValuesPart = new ValidateableSectionPart(section, this, SEC_MODEL_VALUES); + managedForm.addPart(modelValuesPart); + DirtyMarkingListener modelValuesListener = new DirtyMarkingListener(modelValuesPart, true); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + section.setLayoutData(gd); + + Composite modelValueArea = (Composite) section.getClient(); + modelValuesSource = FormHelper.createFormsSourceViewer(toolkit, modelValueArea, SWT.V_SCROLL); + // layout of the source viewer + twd = new TableWrapData(TableWrapData.FILL); + twd.heightHint = 60; + twd.grabHorizontal = true; + modelValuesSource.getTextWidget().setLayoutData(twd); + modelValuesSource.addTextListener(modelValuesListener); + modelValuesSource.getTextWidget().addFocusListener(focusListener); + dm.bindAttribute(MODEL_PARAMETER_MODEL_VALUES, modelValuesSource, modelValuesPart); + + // --------------------------------------------------------------- + // action constraint + section = FormHelper.createSectionComposite(right, "Action Constraint", + "A formula restricting a transition if its evaluation is not satisfied.", toolkit, sectionFlags, + getExpansionListener()); + ValidateableSectionPart actionConstraintPart = new ValidateableSectionPart(section, this, SEC_ACTION_CONSTRAINT); + managedForm.addPart(actionConstraintPart); + DirtyMarkingListener actionConstraintListener = new DirtyMarkingListener(actionConstraintPart, true); + + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + section.setLayoutData(gd); + + Composite actionConstraintArea = (Composite) section.getClient(); + actionConstraintSource = FormHelper.createFormsSourceViewer(toolkit, actionConstraintArea, SWT.V_SCROLL); + // layout of the source viewer + twd = new TableWrapData(TableWrapData.FILL); + twd.heightHint = 60; + twd.grabHorizontal = true; + actionConstraintSource.getTextWidget().setLayoutData(twd); + actionConstraintSource.addTextListener(actionConstraintListener); + actionConstraintSource.getTextWidget().addFocusListener(focusListener); + dm.bindAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, actionConstraintSource, actionConstraintPart); + + // --------------------------------------------------------------- + // constraint + section = FormHelper.createSectionComposite(body, "State Constraint", + "A formula restricting the possible states by a state predicate.", toolkit, + sectionFlags, getExpansionListener()); + ValidateableSectionPart constraintPart = new ValidateableSectionPart(section, this, SEC_STATE_CONSTRAINT); + managedForm.addPart(constraintPart); + DirtyMarkingListener constraintListener = new DirtyMarkingListener(constraintPart, true); + + twd = new TableWrapData(); + twd.colspan = 2; + twd.grabHorizontal = true; + twd.align = TableWrapData.FILL; + section.setLayoutData(twd); + + Composite constraintArea = (Composite) section.getClient(); + constraintSource = FormHelper.createFormsSourceViewer(toolkit, constraintArea, SWT.V_SCROLL); + // layout of the source viewer + twd = new TableWrapData(TableWrapData.FILL); + twd.heightHint = 60; + twd.grabHorizontal = true; + constraintSource.getTextWidget().setLayoutData(twd); + constraintSource.addTextListener(constraintListener); + constraintSource.getTextWidget().addFocusListener(focusListener); + dm.bindAttribute(MODEL_PARAMETER_CONSTRAINT, constraintSource, constraintPart); + + // add section ignoring listeners + dirtyPartListeners.add(newDefinitionsListener); + dirtyPartListeners.add(actionConstraintListener); + dirtyPartListeners.add(modelValuesListener); + dirtyPartListeners.add(constraintListener); + } + + @Override + public void close() throws IOException { + final int openTabState = getModel().getOpenTabsValue(); + getModelEditor().updateOpenTabsState(openTabState & ~IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java new file mode 100644 index 0000000000000000000000000000000000000000..9373cfc697a771d5a6273dad578a6ecde4c56407 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java @@ -0,0 +1,1344 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Calendar; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Scale; +import org.eclipse.swt.widgets.Spinner; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.IMessageManager; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.forms.widgets.TableWrapData; +import org.eclipse.ui.forms.widgets.TableWrapLayout; +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.model.Model.Coverage; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.TLCConsumptionProfile; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; +import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; +import org.lamport.tla.toolbox.tool.tlc.ui.preference.TLCPreferenceInitializer; +import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; +import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper; +import org.lamport.tla.toolbox.util.HelpButton; +import org.lamport.tla.toolbox.util.IHelpConstants; +import org.lamport.tla.toolbox.util.ResourceHelper; +import org.lamport.tla.toolbox.util.UIHelper; + +import tlc2.TLCGlobals; +import tlc2.tool.fp.FPSet; +import tlc2.tool.fp.MultiFPSet; +import tlc2.util.FP64; +import util.TLCRuntime; + +public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable { + public static final String ID = "AdvancedTLCOptionsPage"; + + private static final String TITLE = "TLC Options"; + + + private Button saveDefaultConfigurationButton; + private Spinner workers; + private Scale maxHeapSize; + private Label maxHeapSizeFraction; + private AtomicBoolean programmaticallySettingWorkerParameters; + + private SourceViewer m_viewSource; + + private Button m_depthFirstOptionCheckbox; + private Button m_modelCheckModeOption; + private Button m_simulationModeOption; + private Button m_deferLivenessCheckbox; + private Button m_visualizeStateGraphCheckbox; + private Text m_depthText; + private Text m_simulationDepthText; + private Text m_simulationSeedText; + private Text m_simulationArilText; + + // The widgets to display the checkpoint size and the delete button. + private Button m_checkpointRecoverCheckbox; + private Text m_checkpointIdText; + private Label m_checkpointSizeLabel; + private Text m_checkpointSizeText; + private Button m_checkpointDeleteButton; + + // Widgets to enable/disable coverage + private ComboViewer m_collectCoverageCombo; + + /** + * Offset for the -fp parameter passed to TLC process to select the hash seed + */ + private Spinner m_fingerprintSeedIndex; + private Button m_randomFingerprintCheckbox; + /** + * -fpbits parameter designed to select how many fp bits are used for hash + * lookup + */ + private Spinner m_fingerprintBits; + /** + * -maxSetSize input to set the upper bound of the TLA set + * @see Bug #264 in general/bugzilla/index.html + */ + private Spinner m_maxSetSize; + /** + * Text box to pass additional/extra JVM arguments/system properties to + * nested TLC java process. + */ + private Text m_extraVMArgumentsText; + /** + * Text box to pass additional/extra parameters to nested process. + */ + private Text m_extraTLCParametersText; + + /** + * Used to interpolate y-values for memory scale + */ + private final Interpolator linearInterpolator; + + private MainModelPage mainModelPage; + + public AdvancedTLCOptionsPage(final FormEditor editor) { + super(editor, ID, TITLE, "icons/full/advanced_tlc_options_" + IMAGE_TEMPLATE_TOKEN + ".png"); + + helpId = IHelpConstants.ADVANCED_TLC_OPTIONS_PAGE; + + // available system memory + final long phySysMem = TLCRuntime.getInstance().getAbsolutePhysicalSystemMemory(1.0d); + + // 0.) Create LinearInterpolator with two additional points 0,0 and 1,0 which + int s = 0; + double[] x = new double[6]; + double[] y = new double[x.length]; + + // base point + y[s] = 0d; + x[s++] = 0d; + + // 1.) Minumum TLC requirements + // Use hard-coded minfpmemsize value * 4 * 10 regardless of how big the + // model is. *4 because .25 mem is used for FPs + double lowerLimit = ( (TLCRuntime.MinFpMemSize / 1024 / 1024 * 4d) / phySysMem) / 2; + x[s] = lowerLimit; + y[s++] = 0d; + + // a.) + // Current bloat in software is assumed to grow according to Moore's law => + // 2^((Year-1993)/ 2)+2) + // (1993 as base results from a statistic of windows OS memory requirements) + final int currentYear = Calendar.getInstance().get(Calendar.YEAR); + double estimateSoftwareBloatInMBytes = Math.pow(2, ((currentYear - 1993) / 3) + 3.5); + + // 2.) Optimal range + x[s] = lowerLimit * 2d; + y[s++] = 1.0d; + x[s] = 1.0d - (estimateSoftwareBloatInMBytes / phySysMem); + y[s++] = 1.0d; + + // 3.) Calculate OS reserve + double upperLimit = 1.0d - (estimateSoftwareBloatInMBytes / phySysMem) / 2; + x[s] = upperLimit; + y[s++] = 0d; + + // base point + x[s] = 1d; + y[s] = 0d; + + linearInterpolator = new Interpolator(x, y); + + programmaticallySettingWorkerParameters = new AtomicBoolean(false); + } + + /** + * On a refresh, the checkpoint information is re-read + */ + @Override + public void refresh() { + super.refresh(); + updateCheckpoints(); + } + + @Override + protected void createBodyContent(final IManagedForm managedForm) { + final DataBindingManager dm = getDataBindingManager(); + final FormToolkit toolkit = managedForm.getToolkit(); + final Composite formBody = managedForm.getForm().getBody(); + final int sectionFlags = Section.TITLE_BAR | Section.TREE_NODE; + + GridLayout gl; + GridData gd; + + final TableWrapLayout twl = new TableWrapLayout(); + twl.leftMargin = 0; + twl.rightMargin = 0; + twl.numColumns = 1; + formBody.setLayout(twl); + + mainModelPage = (MainModelPage)getEditor().findPage(MainModelPage.ID); + programmaticallySettingWorkerParameters.set(true); + + Section section = FormHelper.createSectionComposite(formBody, "Configuration", "", + toolkit, (sectionFlags | Section.EXPANDED), getExpansionListener()); + TableWrapData twd = new TableWrapData(); + twd.align = TableWrapData.FILL; + twd.grabHorizontal = true; + section.setLayoutData(twd); + + final ValidateableSectionPart configPart = new ValidateableSectionPart(section, this, SEC_TLCOPT_CONFIGURATION); + managedForm.addPart(configPart); + final DirtyMarkingListener configPartListener = new DirtyMarkingListener(configPart, true); + final Composite configBody = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginHeight = 2; + gl.marginWidth = 2; + configBody.setLayout(gl); + + /* + * Workers Spinner + */ + + // label workers + toolkit.createLabel(configBody, "Number of worker threads:"); + + final Composite workersLine = new Composite(configBody, SWT.NONE); + gd = new GridData(); + gd.horizontalIndent = 40; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + workersLine.setLayoutData(gd); + gl = new GridLayout(2, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + workersLine.setLayout(gl); + + // field workers + workers = new Spinner(workersLine, SWT.NONE); + workers.addFocusListener(focusListener); + workers.addListener(SWT.Verify, (e) -> { + if (!programmaticallySettingWorkerParameters.get()) { + mainModelPage.setWorkerCount(workers.getSelection()); + } + }); + gd = new GridData(); + gd.widthHint = 40; + workers.setLayoutData(gd); + + workers.setMinimum(1); + workers.setPageIncrement(1); + workers.setToolTipText("Determines how many threads will be spawned working on the next state relation."); + workers.setSelection(TLCConsumptionProfile.LOCAL_NORMAL.getWorkerThreads()); + workers.setEnabled(false); + + dm.bindAttribute(LAUNCH_NUMBER_OF_WORKERS, workers, configPart); + + saveDefaultConfigurationButton = new Button(workersLine, SWT.PUSH); + saveDefaultConfigurationButton.setText("Save as default"); + gd = new GridData(); + gd.horizontalAlignment = SWT.END; + gd.grabExcessHorizontalSpace = true; + saveDefaultConfigurationButton.setLayoutData(gd); + saveDefaultConfigurationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent se) { + final IPreferenceStore prefStore = TLCUIActivator.getDefault().getPreferenceStore(); + + prefStore.setValue(ITLCPreferenceConstants.I_TLC_DEFAULT_WORKERS_COUNT, workers.getSelection()); + prefStore.setValue(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT, maxHeapSize.getSelection()); + prefStore.setValue(ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT, m_fingerprintBits.getSelection()); + } + }); + + /* + * MapHeap Scale + */ + + // max heap size label + toolkit.createLabel(configBody, "Fraction of physical memory allocated to TLC:"); + + // Create a composite inside the right "cell" of the "how to run" + // section grid layout to fit the scale and the maxHeapSizeFraction + // label into a single row. + final Composite maxHeapScale = new Composite(configBody, SWT.NONE); + gl = new GridLayout(2, false); + maxHeapScale.setLayout(gl); + gd = new GridData(); + gd.horizontalIndent = 30; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + maxHeapScale.setLayoutData(gd); + + // field max heap size + final IPreferenceStore prefStore = TLCUIActivator.getDefault().getPreferenceStore(); + final int defaultMaxHeapSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); + maxHeapSize = new Scale(maxHeapScale, SWT.NONE); + maxHeapSize.addFocusListener(focusListener); + maxHeapSize.addListener(SWT.Selection, (e) -> { + if (!programmaticallySettingWorkerParameters.get()) { + mainModelPage.setHeapPercentage(maxHeapSize.getSelection()); + } + }); + gd = new GridData(); + gd.minimumWidth = 250; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + maxHeapSize.setLayoutData(gd); + maxHeapSize.setMaximum(99); + maxHeapSize.setMinimum(1); + maxHeapSize.setPageIncrement(5); + maxHeapSize.setSelection(defaultMaxHeapSize); + maxHeapSize.setToolTipText("Specifies the heap size of the Java VM that runs TLC."); + + dm.bindAttribute(LAUNCH_MAX_HEAP_SIZE, maxHeapSize, configPart); + + // label next to the scale showing the current fraction selected + final TLCRuntime instance = TLCRuntime.getInstance(); + final long memory = instance.getAbsolutePhysicalSystemMemory(defaultMaxHeapSize / 100d); + maxHeapSizeFraction = toolkit.createLabel(maxHeapScale, + MainModelPage.generateMemoryDisplayText(defaultMaxHeapSize, memory)); + maxHeapSize.addPaintListener((pe) -> { + maxHeapSizeFraction.setText(generateMemoryDisplayText()); + maxHeapScale.layout(); + }); + maxHeapSize.setEnabled(false); + + // fpbits label + Label l = toolkit.createLabel(configBody, "Log base 2 of number of disk storage files:"); + gd = new GridData(); + gd.verticalIndent = 6; + l.setLayoutData(gd); + + // fpbits spinner + m_fingerprintBits = new Spinner(configBody, SWT.NONE); + m_fingerprintBits.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); + m_fingerprintBits.addFocusListener(focusListener); + gd = new GridData(); + gd.verticalIndent = 6; + gd.horizontalIndent = 37; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_fingerprintBits.setLayoutData(gd); + + m_fingerprintBits.setMinimum(MultiFPSet.MIN_FPBITS); + m_fingerprintBits.setMaximum(MultiFPSet.MAX_FPBITS); + + final int defaultFPBits = prefStore.getInt(ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT); + m_fingerprintBits.setSelection(defaultFPBits); + + + // + // + // Checking Mode section + // + // + + + section = FormHelper.createSectionComposite(formBody, "Checking Mode", "", + toolkit, sectionFlags, getExpansionListener()); + final ValidateableSectionPart modePart = new ValidateableSectionPart(section, this, SEC_TLCOPT_CHECK_MODE); + managedForm.addPart(modePart); + final DirtyMarkingListener modePartListener = new DirtyMarkingListener(modePart, true); + final Composite modeBody = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginHeight = 2; + gl.marginWidth = 2; + modeBody.setLayout(gl); + + // Model checking mode + m_modelCheckModeOption = toolkit.createButton(modeBody, "Model-checking mode", SWT.RADIO); + gd = new GridData(); + gd.horizontalSpan = 2; + m_modelCheckModeOption.setLayoutData(gd); + m_modelCheckModeOption.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateEnabledStatesForAdvancedLaunchRadioSelection(); + } + }); + + // label view + final Label viewLabel = toolkit.createLabel(modeBody, "View:"); + gd = new GridData(); + gd.verticalAlignment = SWT.BEGINNING; + gd.horizontalIndent = 10; + viewLabel.setLayoutData(gd); + // field view + m_viewSource = FormHelper.createFormsSourceViewer(toolkit, modeBody, SWT.V_SCROLL); + // layout of the source viewer + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.heightHint = 60; + gd.minimumWidth = 200; + m_viewSource.getTextWidget().setLayoutData(gd); + m_viewSource.getTextWidget().setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + m_depthFirstOptionCheckbox = toolkit.createButton(modeBody, "Depth-first", SWT.CHECK); + gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalIndent = 10; + m_depthFirstOptionCheckbox.setLayoutData(gd); + m_depthFirstOptionCheckbox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + m_depthText.setEnabled(m_depthFirstOptionCheckbox.getSelection()); + } + }); + m_depthFirstOptionCheckbox.setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + // label depth + Label dfidDepthLabel = toolkit.createLabel(modeBody, "Depth:"); + gd = new GridData(); + gd.horizontalIndent = 36; + dfidDepthLabel.setLayoutData(gd); + // field depth + m_depthText = toolkit.createText(modeBody, "100"); + gd = new GridData(); + gd.minimumWidth = 100; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_depthText.setLayoutData(gd); + m_depthText.addFocusListener(focusListener); + m_depthText.setEnabled(false); + m_depthText.setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + m_simulationModeOption = toolkit.createButton(modeBody, "Simulation mode", SWT.RADIO); + gd = new GridData(); + gd.horizontalSpan = 2; + m_simulationModeOption.setLayoutData(gd); + m_simulationModeOption.addFocusListener(focusListener); + m_simulationModeOption.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateEnabledStatesForAdvancedLaunchRadioSelection(); + } + }); + + // label depth + final Label depthLabel = toolkit.createLabel(modeBody, "Maximum length of the trace:"); + gd = new GridData(); + gd.horizontalIndent = 10; + depthLabel.setLayoutData(gd); + // field depth + m_simulationDepthText = toolkit.createText(modeBody, "100"); + gd = new GridData(); + gd.minimumWidth = 100; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_simulationDepthText.setLayoutData(gd); + m_simulationDepthText.addFocusListener(focusListener); + m_simulationDepthText.setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + // label seed + final Label seedLabel = toolkit.createLabel(modeBody, "Seed:"); + gd = new GridData(); + gd.horizontalIndent = 10; + seedLabel.setLayoutData(gd); + + // field seed + m_simulationSeedText = toolkit.createText(modeBody, ""); + gd = new GridData(); + gd.minimumWidth = 200; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_simulationSeedText.setLayoutData(gd); + m_simulationSeedText.addFocusListener(focusListener); + m_simulationSeedText.setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + // label seed + final Label arilLabel = toolkit.createLabel(modeBody, "Aril:"); + gd = new GridData(); + gd.horizontalIndent = 10; + arilLabel.setLayoutData(gd); + + // field seed + m_simulationArilText = toolkit.createText(modeBody, ""); + gd = new GridData(); + gd.minimumWidth = 200; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_simulationArilText.setLayoutData(gd); + m_simulationArilText.addFocusListener(focusListener); + m_simulationArilText.setData(DataBindingManager.WIDGET_HAS_ENABLED_STATE_HANDLED_ELSEWHERE, new Object()); + + + // + // + // Features section + // + // + + + section = FormHelper.createSectionComposite(formBody, "Features", "", + toolkit, sectionFlags, getExpansionListener()); + final ValidateableSectionPart featuresPart = new ValidateableSectionPart(section, this, SEC_TLCOPT_FEATURES); + managedForm.addPart(featuresPart); + final DirtyMarkingListener featuresPartListener = new DirtyMarkingListener(featuresPart, true); + final Composite featuresBody = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginHeight = 2; + gl.marginWidth = 2; + + featuresBody.setLayout(gl); + + /* + * run from the checkpoint. Checkpoint help button added by LL on 17 Jan 2013 + */ + Composite checkpointComposite = new Composite(featuresBody, SWT.NONE) ; + gl = new GridLayout(2, false); + gl.marginWidth = 0; + gl.marginHeight = 0; + checkpointComposite.setLayout(gl); + + gd = new GridData(); + gd.horizontalSpan = 2; + gd.verticalIndent = 6; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.FILL; + checkpointComposite.setLayoutData(gd); + + m_checkpointRecoverCheckbox = toolkit.createButton(checkpointComposite, "Recover from checkpoint", SWT.CHECK); + m_checkpointRecoverCheckbox.addFocusListener(focusListener); + gd = new GridData(); + gd.horizontalAlignment = SWT.BEGINNING; + m_checkpointRecoverCheckbox.setLayoutData(gd); + + Button b = HelpButton.helpButton(checkpointComposite, "model/tlc-options-page.html#checkpoint") ; + gd = new GridData(); + gd.horizontalAlignment = SWT.END; + gd.grabExcessHorizontalSpace = true; + b.setLayoutData(gd); + + toolkit.createLabel(featuresBody, "Checkpoint ID:"); + + m_checkpointIdText = toolkit.createText(featuresBody, ""); + m_checkpointIdText.setEditable(false); + gd = new GridData(); + gd.minimumWidth = 100; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_checkpointIdText.setLayoutData(gd); + + m_checkpointSizeLabel = toolkit.createLabel(featuresBody, "Checkpoint size (kbytes):"); + m_checkpointSizeText = toolkit.createText(featuresBody, ""); + gd = new GridData(); + gd.minimumWidth = 100; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_checkpointSizeText.setLayoutData(gd); + m_checkpointDeleteButton = toolkit.createButton(featuresBody, "Delete Checkpoint", SWT.PUSH); + m_checkpointDeleteButton.addSelectionListener(new SelectionListener() { + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + public void widgetSelected(SelectionEvent e) { + final IResource[] checkpoints; + try { + checkpoints = getModel().getCheckpoints(false); + + if ((checkpoints != null) && checkpoints.length > 0) { + ResourcesPlugin.getWorkspace().run((monitor) -> { + checkpoints[0].delete(true, SubMonitor.convert(monitor, 1)); + }, null); + } + } catch (CoreException e1) { + return; + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) + */ + public void widgetDefaultSelected(SelectionEvent e) { } + }); + m_checkpointDeleteButton.addFocusListener(focusListener); + new Label(featuresBody, SWT.NONE); // use up last cell. + + // Collect Coverage + + final String collectCoverageHelp = "Profiling helps identify problems with the specification such as actions which are " + + "never enabled (Action enablement). Invocation and cost statistics allow to diagnose expensive expressions (to evaluate) and state space " + + "explosion (On). Profiling negatively impacts model checking performance and should thus be off while " + + "checking large models."; + final Label collectCoverageLabel = toolkit.createLabel(featuresBody, + "Profiling:"); + gd = new GridData(); + gd.verticalIndent = 9; + gd.grabExcessHorizontalSpace = true; + collectCoverageLabel.setLayoutData(gd); + collectCoverageLabel.setToolTipText(collectCoverageHelp); + + Composite coverageComposite = new Composite(featuresBody, SWT.NONE) ; + gl = new GridLayout(2, false); + gl.marginWidth = 0; + gl.marginHeight = 0; + coverageComposite.setLayout(gl); + + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + coverageComposite.setLayoutData(gd); + + m_collectCoverageCombo = new ComboViewer(new Combo(coverageComposite, SWT.READ_ONLY)); + gd = new GridData(); + gd.verticalIndent = 9; + gd.grabExcessHorizontalSpace = true; + m_collectCoverageCombo.getCombo().setLayoutData(gd); + m_collectCoverageCombo.getCombo().addFocusListener(focusListener); + m_collectCoverageCombo.getCombo().setToolTipText(collectCoverageHelp); + + m_collectCoverageCombo.setContentProvider(ArrayContentProvider.getInstance()); + m_collectCoverageCombo.setLabelProvider(new LabelProvider() { + @Override + public String getText(Object element) { + if (element instanceof Coverage) { + switch ((Coverage) element) { + case OFF: + return "Off"; + case ACTION: + return "Action enablement"; + case ON: + return "On"; + } + } + return "Off"; // make compiler happy + } + }); + m_collectCoverageCombo.setInput(Model.Coverage.values()); + + + b = HelpButton.helpButton(coverageComposite, "model/tlc-options-page.html#profiling") ; + gd = new GridData(); + gd.horizontalAlignment = SWT.END; + gd.verticalAlignment = SWT.BOTTOM; + gd.grabExcessHorizontalSpace = true; + b.setLayoutData(gd); + + + // Visualize State Graph with GraphViz (dot) + final String visualizeStateGraphHelp = "Draw the state graph after completion of model checking provided the " + + "state graph is sufficiently small (cannot handle more than a few dozen states and slows down model checking)."; + final Label visualizeStateGraphLabel = toolkit.createLabel(featuresBody, "Visualize state graph after completion of model checking:"); + gd = new GridData(); + gd.verticalIndent = 9; + gd.grabExcessHorizontalSpace = true; + visualizeStateGraphLabel.setLayoutData(gd); + visualizeStateGraphLabel.setToolTipText(visualizeStateGraphHelp); + + m_visualizeStateGraphCheckbox = toolkit.createButton(featuresBody, "", SWT.CHECK); + gd = new GridData(); + gd.verticalIndent = 9; + m_visualizeStateGraphCheckbox.setLayoutData(gd); + m_visualizeStateGraphCheckbox.addFocusListener(focusListener); + m_visualizeStateGraphCheckbox.setToolTipText(visualizeStateGraphHelp); + + + // + // + // Parameters section + // + // + + + section = FormHelper.createSectionComposite(formBody, "Parameters", "", + toolkit, sectionFlags, getExpansionListener()); + final ValidateableSectionPart parametersPart = new ValidateableSectionPart(section, this, SEC_TLCOPT_PARAMS); + managedForm.addPart(parametersPart); + final DirtyMarkingListener parametersPartListener = new DirtyMarkingListener(parametersPart, true); + final Composite parametersBody = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginHeight = 2; + gl.marginWidth = 2; + parametersBody.setLayout(gl); + + // label deferred liveness checking + final String deferLivenessHelp = "Defer verification of temporal properties (liveness) to the end of model checking" + + " to reduce overall model checking time. Liveness violations will be found late compared to invariant " + + "violations. In other words check liveness only once on the complete state space."; + final Label deferLivenessLabel = toolkit.createLabel(parametersBody, "Verify temporal properties upon termination only:"); + gd = new GridData(); + gd.verticalIndent = 6; + deferLivenessLabel.setLayoutData(gd); + deferLivenessLabel.setToolTipText(deferLivenessHelp); + + m_deferLivenessCheckbox = toolkit.createButton(parametersBody, "", SWT.CHECK); + m_deferLivenessCheckbox.addFocusListener(focusListener); + m_deferLivenessCheckbox.setToolTipText(deferLivenessHelp); + gd = new GridData(); + gd.verticalIndent = 6; + m_deferLivenessCheckbox.setLayoutData(gd); + + // label fp + toolkit.createLabel(parametersBody, "Fingerprint seed index:"); + + final Composite fpIndex = toolkit.createComposite(parametersBody); + gl = new GridLayout(2, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + fpIndex.setLayout(gl); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + fpIndex.setLayoutData(gd); + + m_randomFingerprintCheckbox = toolkit.createButton(fpIndex, "Select randomly", SWT.CHECK); + m_randomFingerprintCheckbox.setToolTipText( + "Let TLC randomly choose the irreducible polynomial at startup. The actual value will be shon in TLC's startup banner."); + m_randomFingerprintCheckbox.setSelection(true); + m_randomFingerprintCheckbox.addFocusListener(focusListener); + m_randomFingerprintCheckbox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + m_fingerprintSeedIndex.setEnabled(!m_randomFingerprintCheckbox.getSelection()); + } + }); + + // field fpIndex + m_fingerprintSeedIndex = new Spinner(fpIndex, SWT.NONE); + m_fingerprintSeedIndex.setEnabled(false); + m_fingerprintSeedIndex.setToolTipText( + "Index of irreducible polynominal used as a seed for fingerprint hashing (corresponds to \"-fp value\"). Set to the irreducible polynomial used for the previous run if \"Select randomly\" checked."); + gd = new GridData(); + gd.horizontalIndent = 15; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_fingerprintSeedIndex.setLayoutData(gd); + + // validation for fpIndex spinner + m_fingerprintSeedIndex.setMinimum(0); + m_fingerprintSeedIndex.setMaximum(FP64.Polys.length - 1); + + m_fingerprintSeedIndex.addFocusListener(focusListener); + + // maxSetSize label + toolkit.createLabel(parametersBody, "Cardinality of largest enumerable set:"); + + // maxSetSize spinner + m_maxSetSize = new Spinner(parametersBody, SWT.NONE); + m_maxSetSize.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); + m_maxSetSize.addFocusListener(focusListener); + gd = new GridData(); + gd.verticalIndent = 20; + gd.minimumWidth = 100; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_maxSetSize.setLayoutData(gd); + + m_maxSetSize.setMinimum(1); + m_maxSetSize.setMaximum(Integer.MAX_VALUE); + + final int defaultMaxSetSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXSETSIZE_DEFAULT); + m_maxSetSize.setSelection(defaultMaxSetSize); + + // Extra/Additional VM arguments and system properties + toolkit.createLabel(parametersBody, "JVM arguments:"); + + m_extraVMArgumentsText = toolkit.createText(parametersBody, "", SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + m_extraVMArgumentsText.setEditable(true); + m_extraVMArgumentsText.setToolTipText( + "Optionally pass additional JVM arguments to TLC process (e.g. -Djava.rmi.server.hostname=ThisHostName)"); + m_extraVMArgumentsText.addFocusListener(focusListener); + gd = new GridData(); + gd.verticalIndent = 20; + gd.heightHint = 40; + gd.minimumWidth = 300; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_extraVMArgumentsText.setLayoutData(gd); + + // Extra/Additional TLC arguments + toolkit.createLabel(parametersBody, "TLC command line parameters:"); + + m_extraTLCParametersText = toolkit.createText(parametersBody, "", SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + m_extraTLCParametersText.setEditable(true); + m_extraTLCParametersText + .setToolTipText("Optionally pass additional TLC process parameters (e.g. -Dcheckpoint 0)"); + m_extraTLCParametersText.addFocusListener(focusListener); + gd = new GridData(); + gd.verticalIndent = 20; + gd.heightHint = 40; + gd.minimumWidth = 300; + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + m_extraTLCParametersText.setLayoutData(gd); + + updateEnabledStatesForAdvancedLaunchRadioSelection(); + + dm.bindAttribute(MODEL_PARAMETER_VIEW, m_viewSource, modePart); + dm.bindAttribute(LAUNCH_RECOVER, m_checkpointRecoverCheckbox, featuresPart); + + // dirty listeners + workers.addSelectionListener(configPartListener); + maxHeapSize.addSelectionListener(configPartListener); + + m_modelCheckModeOption.addSelectionListener(modePartListener); + m_viewSource.addTextListener(modePartListener); + m_depthFirstOptionCheckbox.addSelectionListener(modePartListener); + m_depthText.addModifyListener(modePartListener); + m_simulationModeOption.addSelectionListener(modePartListener); + m_simulationDepthText.addModifyListener(modePartListener); + m_simulationSeedText.addModifyListener(modePartListener); + m_simulationArilText.addModifyListener(modePartListener); + + m_checkpointRecoverCheckbox.addSelectionListener(featuresPartListener); + m_collectCoverageCombo.getCombo().addSelectionListener(featuresPartListener); + m_visualizeStateGraphCheckbox.addSelectionListener(featuresPartListener); + + m_deferLivenessCheckbox.addSelectionListener(parametersPartListener); + m_fingerprintSeedIndex.addModifyListener(parametersPartListener); + m_randomFingerprintCheckbox.addSelectionListener(parametersPartListener); + m_fingerprintBits.addModifyListener(parametersPartListener); + m_maxSetSize.addModifyListener(parametersPartListener); + m_extraVMArgumentsText.addModifyListener(parametersPartListener); + m_extraTLCParametersText.addModifyListener(parametersPartListener); + + // add section ignoring listeners + dirtyPartListeners.add(configPartListener); + dirtyPartListeners.add(modePartListener); + dirtyPartListeners.add(featuresPartListener); + dirtyPartListeners.add(parametersPartListener); + } + + /** + * Loads data from the model + */ + @Override + protected void loadData() throws CoreException { + final Model model = getModel(); + + // view + final String view = model.getAttribute(LAUNCH_VIEW, EMPTY_STRING); + m_viewSource.setDocument(new Document(view)); + + // run mode mode + final boolean isMCMode = model.getAttribute(LAUNCH_MC_MODE, LAUNCH_MC_MODE_DEFAULT); + m_modelCheckModeOption.setSelection(isMCMode); + m_simulationModeOption.setSelection(!isMCMode); + + // DFID depth + final int dfidDepth = model.getAttribute(LAUNCH_DFID_DEPTH, LAUNCH_DFID_DEPTH_DEFAULT); + m_depthText.setText("" + dfidDepth); + + // DFID mode + final boolean isDFIDMode = model.getAttribute(LAUNCH_DFID_MODE, LAUNCH_DFID_MODE_DEFAULT); + m_depthFirstOptionCheckbox.setSelection(isDFIDMode); + m_depthText.setEnabled(isDFIDMode); + + // simulation depth + final int simuDepth = model.getAttribute(LAUNCH_SIMU_DEPTH, LAUNCH_SIMU_DEPTH_DEFAULT); + m_simulationDepthText.setText("" + simuDepth); + + // simulation aril + final int simuAril = model.getAttribute(LAUNCH_SIMU_SEED, LAUNCH_SIMU_ARIL_DEFAULT); + if (LAUNCH_SIMU_ARIL_DEFAULT != simuAril) { + m_simulationArilText.setText("" + simuAril); + } else { + m_simulationArilText.setText(""); + } + + // simulation seed + final int simuSeed = model.getAttribute(LAUNCH_SIMU_ARIL, LAUNCH_SIMU_SEED_DEFAULT); + if (LAUNCH_SIMU_SEED_DEFAULT != simuSeed) { + m_simulationSeedText.setText("" + simuSeed); + } else { + m_simulationSeedText.setText(""); + } + + // Defer Liveness + m_deferLivenessCheckbox.setSelection(model.getAttribute(LAUNCH_DEFER_LIVENESS, LAUNCH_DEFER_LIVENESS_DEFAULT)); + + // recover from the checkpoint + final boolean recover = model.getAttribute(LAUNCH_RECOVER, LAUNCH_RECOVER_DEFAULT); + m_checkpointRecoverCheckbox.setSelection(recover); + + // coverage + m_collectCoverageCombo.setSelection(new StructuredSelection(model.getCoverage()), true); + + // fp index + final boolean randomly = model.getAttribute(LAUNCH_FP_INDEX_RANDOM, LAUNCH_FP_INDEX_RANDOM_DEFAULT); + m_randomFingerprintCheckbox.setSelection(randomly); + final int fpIndex = model.getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); + m_fingerprintSeedIndex.setSelection(fpIndex); + m_fingerprintSeedIndex.setEnabled(!randomly); + + final IPreferenceStore prefStore = TLCUIActivator.getDefault().getPreferenceStore(); + + // fpBits + final int defaultFPBits = prefStore.getInt(ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT); + m_fingerprintBits.setSelection(model.getAttribute(LAUNCH_FPBITS, defaultFPBits)); + + // maxSetSize + final int defaultMaxSetSize = prefStore.getInt(ITLCPreferenceConstants.I_TLC_MAXSETSIZE_DEFAULT); + m_maxSetSize.setSelection(model.getAttribute(LAUNCH_MAXSETSIZE, defaultMaxSetSize)); + + // visualize state graph + m_visualizeStateGraphCheckbox.setSelection(model.getAttribute(LAUNCH_VISUALIZE_STATEGRAPH, LAUNCH_VISUALIZE_STATEGRAPH_DEFAULT)); + + // Extra JVM arguments and system properties + final String vmArgs = model.getAttribute(LAUNCH_JVM_ARGS, LAUNCH_JVM_ARGS_DEFAULT); + m_extraVMArgumentsText.setText(vmArgs); + + // Extra JVM arguments and system properties + final String tlcParameters = model.getAttribute(LAUNCH_TLC_PARAMETERS, LAUNCH_TLC_PARAMETERS_DEFAULT); + m_extraTLCParametersText.setText(tlcParameters); + + // it should still be true here from the body content creation invocation, but in case not: + programmaticallySettingWorkerParameters.set(true); + workers.setSelection(mainModelPage.getWorkerCount()); + maxHeapSize.setSelection(mainModelPage.getHeapPercentage()); + programmaticallySettingWorkerParameters.set(false); + setWorkerAndMemoryEnable(mainModelPage.workerCountCanBeModified(), mainModelPage.heapPercentageCanBeModified()); + + updateEnabledStatesForAdvancedLaunchRadioSelection(); + } + + /** + * Save data back to config + */ + @Override + public void commit(final boolean onSave) { + final Model model = getModel(); + + final boolean isMCMode = m_modelCheckModeOption.getSelection(); + model.setAttribute(LAUNCH_MC_MODE, isMCMode); + + // DFID mode + final boolean isDFIDMode = m_depthFirstOptionCheckbox.getSelection(); + model.setAttribute(LAUNCH_DFID_MODE, isDFIDMode); + final int dfidDepth = Integer.parseInt(m_simulationDepthText.getText()); + + final int simuDepth = Integer.parseInt(m_simulationDepthText.getText()); + int simuAril = LAUNCH_SIMU_ARIL_DEFAULT; + int simuSeed = LAUNCH_SIMU_SEED_DEFAULT; + + if (!"".equals(m_simulationArilText.getText())) { + simuAril = Integer.parseInt(m_simulationArilText.getText()); + } + if (!"".equals(m_simulationSeedText.getText())) { + simuSeed = Integer.parseInt(m_simulationSeedText.getText()); + } + + // DFID depth + model.setAttribute(LAUNCH_DFID_DEPTH, dfidDepth); + // simulation depth + model.setAttribute(LAUNCH_SIMU_DEPTH, simuDepth); + // simulation aril + model.setAttribute(LAUNCH_SIMU_SEED, simuSeed); + // simulation seed + model.setAttribute(LAUNCH_SIMU_ARIL, simuAril); + + // Defer Liveness + model.setAttribute(LAUNCH_DEFER_LIVENESS, m_deferLivenessCheckbox.getSelection()); + + // recover from deadlock + model.setAttribute(LAUNCH_RECOVER, m_checkpointRecoverCheckbox.getSelection()); + + // FP Seed choose randomly + model.setAttribute(LAUNCH_FP_INDEX_RANDOM, m_randomFingerprintCheckbox.getSelection()); + // FP Seed index + model.setAttribute(LAUNCH_FP_INDEX, m_fingerprintSeedIndex.getSelection()); + + // fpBits + model.setAttribute(LAUNCH_FPBITS, m_fingerprintBits.getSelection()); + + // fpBits + model.setAttribute(LAUNCH_MAXSETSIZE, m_maxSetSize.getSelection()); + + // Visualize State Graph + model.setAttribute(LAUNCH_VISUALIZE_STATEGRAPH, m_visualizeStateGraphCheckbox.getSelection()); + + // Collect Coverage + final Object coverage = m_collectCoverageCombo.getStructuredSelection().getFirstElement(); + if (coverage instanceof Coverage) { + model.setCoverage((Coverage) coverage); + } + + // view + String viewFormula = FormHelper.trimTrailingSpaces(m_viewSource.getDocument().get()); + model.setAttribute(LAUNCH_VIEW, viewFormula); + + // extra vm arguments (replace newlines which otherwise cause the + // process to ignore all args except the first one) + final String vmArgs = m_extraVMArgumentsText.getText().replace("\r\n", " ").replace("\n", " "); + model.setAttribute(LAUNCH_JVM_ARGS, vmArgs); + + // extra tlc parameters + final String tlcParameters = m_extraTLCParametersText.getText(); + model.setAttribute(LAUNCH_TLC_PARAMETERS, tlcParameters); + + super.commit(onSave); + } + + /** + * Validate the page's state. + */ + @Override + public void validatePage(final boolean switchToErrorPage) { + if (getManagedForm() == null) { + return; + } + + final DataBindingManager dm = getDataBindingManager(); + final IMessageManager mm = getManagedForm().getMessageManager(); + mm.setAutoUpdate(false); + + final ModelEditor modelEditor = (ModelEditor) getEditor(); + + // clean old messages + // this is now done in validateRunnable of + // ModelEditor + // mm.removeAllMessages(); + // make the run possible + setComplete(true); + + // setup the names from the current page + getLookupHelper().resetModelNames(this); + + // number of workers + int number = workers.getSelection(); + if (number > Runtime.getRuntime().availableProcessors()) + { + modelEditor.addErrorMessage("strangeNumber1", "Specified number of workers is " + number + + ". The number of processors available on the system is " + + Runtime.getRuntime().availableProcessors() + + ".\n The number of workers should not exceed the number of processors.", + this.getId(), IMessageProvider.WARNING, UIHelper.getWidget(dm + .getAttributeControl(LAUNCH_NUMBER_OF_WORKERS))); + expandSection(SEC_TLCOPT_CONFIGURATION); + } else { + modelEditor.removeErrorMessage("strangeNumber1", UIHelper.getWidget(dm + .getAttributeControl(LAUNCH_NUMBER_OF_WORKERS))); + } + + // legacy value? + // better handle legacy models + try { + final int defaultMaxHeapSize = TLCUIActivator + .getDefault() + .getPreferenceStore() + .getInt(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT); + final int legacyValue = getModel().getAttribute( + LAUNCH_MAX_HEAP_SIZE, defaultMaxHeapSize); + // old default, silently convert to new default + if (legacyValue == 500) { + getModel().setAttribute( + LAUNCH_MAX_HEAP_SIZE, TLCPreferenceInitializer.MAX_HEAP_SIZE_DEFAULT); + maxHeapSize.setSelection(TLCPreferenceInitializer.MAX_HEAP_SIZE_DEFAULT); + } else if (legacyValue >= 100) { + modelEditor + .addErrorMessage( + "strangeNumber1", + "Found legacy value for physically memory of (" + + legacyValue + + "mb) that needs manual conversion. 25% is a safe setting on most computers.", + this.getId(), IMessageProvider.WARNING, + maxHeapSize); + setComplete(false); + expandSection(SEC_TLCOPT_CONFIGURATION); + } + } catch (CoreException e) { + TLCUIActivator.getDefault().logWarning("Faild to read heap value", e); + } + + // max heap size + // color the scale according to OS and TLC requirements + int maxHeapSizeValue = maxHeapSize.getSelection(); + double x = maxHeapSizeValue / 100d; + float y = (float) linearInterpolator.interpolate(x); + maxHeapSize.setBackground(new Color(Display.getDefault(), new RGB(120 * y, 1 - y, 1f))); + + try { + int dfidDepth = Integer.parseInt(m_depthText.getText()); + if (dfidDepth <= 0) { + modelEditor.addErrorMessage("dfid1", "Depth of DFID launch must be a positive integer", this.getId(), + IMessageProvider.ERROR, m_depthText); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } else { + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("dfid1", m_depthText); + } + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("dfid2", m_depthText); + } catch (NumberFormatException e) { + modelEditor.addErrorMessage("dfid2", "Depth of DFID launch must be a positive integer", this.getId(), + IMessageProvider.ERROR, m_depthText); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } + try { + int simuDepth = Integer.parseInt(m_simulationDepthText.getText()); + if (simuDepth <= 0) { + modelEditor.addErrorMessage("simuDepth1", "Length of the simulation tracemust be a positive integer", + this.getId(), IMessageProvider.ERROR, m_simulationDepthText); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } else { + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("simuDepth1", m_simulationDepthText); + } + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("simuDepth2", m_simulationDepthText); + } catch (NumberFormatException e) { + modelEditor.addErrorMessage("simuDepth2", "Length of the simulation trace must be a positive integer", + this.getId(), IMessageProvider.ERROR, m_simulationDepthText); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } + if (!EMPTY_STRING.equals(m_simulationArilText.getText())) { + try { + long simuAril = Long.parseLong(m_simulationArilText.getText()); + if (simuAril <= 0) { + modelEditor.addErrorMessage("simuAril1", "The simulation aril must be a positive integer", + this.getId(), IMessageProvider.ERROR, m_simulationArilText); + setComplete(false); + } else { + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("simuAril1", m_simulationArilText); + } + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("simuAril2", m_simulationArilText); + } catch (NumberFormatException e) { + modelEditor.addErrorMessage("simuAril2", "The simulation aril must be a positive integer", this.getId(), + IMessageProvider.ERROR, m_simulationArilText); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } + } + if (!EMPTY_STRING.equals(m_simulationSeedText.getText())) { + try { + Long.parseLong(m_simulationSeedText.getText()); + // Call of removeErrorMessage added by LL on 21 Mar 2013 + modelEditor.removeErrorMessage("simuSeed1", m_simulationSeedText); + + } catch (NumberFormatException e) { + modelEditor.addErrorMessage("simuSeed1", "The simulation aril must be a positive integer", this.getId(), + IMessageProvider.ERROR, m_simulationSeedText); + expandSection(SEC_TLCOPT_CHECK_MODE); + setComplete(false); + } + } + + // fill the checkpoints + updateCheckpoints(); + + // recover from checkpoint + final Control checkpointRecover = UIHelper.getWidget(dm.getAttributeControl(LAUNCH_RECOVER)); + modelEditor.removeErrorMessage("noCheckpoint", checkpointRecover); + if (m_checkpointRecoverCheckbox.getSelection()) { + if (EMPTY_STRING.equals(m_checkpointIdText.getText())) { + modelEditor.addErrorMessage("noCheckpoint", "No checkpoint data found", this.getId(), + IMessageProvider.ERROR, checkpointRecover); + setComplete(false); + expandSection(SEC_TLCOPT_CHECK_MODE); + } + } + + // check if the view field contains a cfg file keyword + final Control viewWidget = UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_VIEW)); + final IDocument viewerDocument = m_viewSource.getDocument(); + if (viewerDocument != null) { + final String viewString = FormHelper.trimTrailingSpaces(viewerDocument.get()); + if (SemanticHelper.containsConfigFileKeyword(viewString)) { + modelEditor.addErrorMessage(viewString, + "The toolbox cannot handle the string " + viewString + + " because it contains a configuration file keyword.", + this.getId(), IMessageProvider.ERROR, viewWidget); + setComplete(false); + } + } + + mm.setAutoUpdate(true); + + + // fpBits + if (!FPSet.isValid(m_fingerprintBits.getSelection())) + { + modelEditor.addErrorMessage("wrongNumber3", "fpbits must be a positive integer number smaller than 31", this + .getId(), IMessageProvider.ERROR, UIHelper.getWidget(dm.getAttributeControl(LAUNCH_FPBITS))); + setComplete(false); + expandSection(SEC_TLCOPT_CONFIGURATION); + } +// else { +// // Call of removeErrorMessage added by LL on 21 Mar 2013 +// // However, it seems to be a no-op because you can't enter an illegal +// // value into the widget. I've commented this out in case it has some +// // unknown evil side effects. +// modelEditor.removeErrorMessage("wrongNumber3", +// UIHelper.getWidget(dm.getAttributeControl(LAUNCH_FPBITS))); +// } + + // maxSetSize + if (!TLCGlobals.isValidSetSize(m_maxSetSize.getSelection())) + { + modelEditor.addErrorMessage("wrongNumber3", "maxSetSize must be a positive integer number", this.getId(), + IMessageProvider.ERROR, UIHelper.getWidget(dm.getAttributeControl(LAUNCH_MAXSETSIZE))); + setComplete(false); + expandSection(SEC_TLCOPT_PARAMS); + } +// else { +// // Call of removeErrorMessage added by LL on 21 Mar 2013 +// // However, it seems to be a no-op because you can't enter an illegal +// // value into the widget, so this was all commented out. +// modelEditor.removeErrorMessage("wrongNumber3", +// UIHelper.getWidget(dm.getAttributeControl(LAUNCH_MAXSETSIZE))); +// } + + super.validatePage(switchToErrorPage); + } + + /** + * Checks if checkpoint information changed + */ + private void updateCheckpoints() { + IResource[] checkpoints = null; + try { + // checkpoint id + checkpoints = getModel().getCheckpoints(false); + } catch (CoreException e) { + TLCUIActivator.getDefault().logError("Error checking chekpoint data", e); + } + + if (checkpoints != null && checkpoints.length > 0) { + m_checkpointIdText.setText(checkpoints[0].getName()); + } else { + m_checkpointIdText.setText(EMPTY_STRING); + } + + if ((checkpoints == null) || (checkpoints.length == 0)) { + m_checkpointSizeText.setVisible(false); + m_checkpointSizeLabel.setVisible(false); + m_checkpointDeleteButton.setVisible(false); + } else { + m_checkpointSizeText.setText(String.valueOf(ResourceHelper.getSizeOfJavaFileResource(checkpoints[0]) / 1000)); + m_checkpointSizeText.setVisible(true); + m_checkpointSizeLabel.setVisible(true); + m_checkpointDeleteButton.setVisible(true); + } + } + + private void updateEnabledStatesForAdvancedLaunchRadioSelection () { + final boolean simulationMode = m_simulationModeOption.getSelection(); + + m_viewSource.getTextWidget().setEnabled(!simulationMode); + m_depthFirstOptionCheckbox.setEnabled(!simulationMode); + if (simulationMode) { + m_depthText.setEnabled(false); + } else { + m_depthText.setEnabled(m_depthFirstOptionCheckbox.getSelection()); + } + + m_simulationDepthText.setEnabled(simulationMode); + m_simulationSeedText.setEnabled(simulationMode); + m_simulationArilText.setEnabled(simulationMode); + } + + public void updateWorkersAndMemory(final int workerCount, final int memoryPercentage) { + programmaticallySettingWorkerParameters.set(true); + + workers.setSelection(workerCount); + maxHeapSize.setSelection(memoryPercentage); + + programmaticallySettingWorkerParameters.set(false); + } + + public void setWorkerAndMemoryEnable(final boolean enableWorker, final boolean enableMaxHeap) { + workers.getDisplay().asyncExec(() -> { + saveDefaultConfigurationButton.setEnabled(enableWorker); + workers.setEnabled(enableWorker); + maxHeapSize.setEnabled(enableMaxHeap); + }); + } + + public void setFpIndex(final int fpIndex) { + if (m_fingerprintSeedIndex.getSelection() == fpIndex) { + return; + } + // Temporarily disable all modify listeners to prevent the model from becoming + // dirty. We don't want the model to become dirty as a result of model checking. + final Listener[] listeners = this.m_fingerprintSeedIndex.getListeners(SWT.Modify); + for (Listener listener : listeners) { + m_fingerprintSeedIndex.removeListener(SWT.Modify, listener); + } + + m_fingerprintSeedIndex.setSelection(fpIndex); + + for (Listener listener : listeners) { + m_fingerprintSeedIndex.addListener(SWT.Modify, listener); + } + } + + @Override + public void close() throws IOException { + final int openTabState = getModel().getOpenTabsValue(); + getModelEditor().updateOpenTabsState(openTabState & ~IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC); + } + + private String generateMemoryDisplayText () { + final int percentage = maxHeapSize.getSelection(); + final long megabytes = TLCRuntime.getInstance().getAbsolutePhysicalSystemMemory(percentage / 100d); + + return MainModelPage.generateMemoryDisplayText(percentage, megabytes); + } + + + /** + * Interpolates based on LinearInterpolation + */ + private class Interpolator { + + private final double[] yCoords, xCoords; + + public Interpolator(double[] x, double[] y) { + this.xCoords = x; + this.yCoords = y; + } + + public double interpolate(double x) { + for (int i = 1; i < xCoords.length; i++) { + if (x < xCoords[i]) { + return yCoords[i] - (yCoords[i] - yCoords[i - 1]) + * (xCoords[i] - x) / (xCoords[i] - xCoords[i - 1]); + } + } + return 0d; + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..0f159e746666bdf54c8d2f66475ab3abc4e34841 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java @@ -0,0 +1,169 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.util.Comparator; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.util.AbstractTableLabelProvider; + +import tlc2.output.MP; + +/** + * This is the <code>LabelProvider</code> for the coverage statistics table found on the Results page. + * + * @see org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.ResultPage + */ +@SuppressWarnings("unchecked") +class CoverageLabelProvider extends AbstractTableLabelProvider { + static final String COVERAGE_COMPARATOR = "COVERAGE_COMPARATOR"; + + static final int COL_MODULE = 0; + static final int COL_ACTION = 1; + static final int COL_LOCATION = 2; + static final int COL_STATES = 3; + static final int COL_DISTSTATES = 4; + + static final String TOOLTIP = "Click on a row to go to action."; + + private static final String[] COLUMN_TITLES = new String[] { "Module", "Action", "Location", "States Found", "Distinct States" }; + private static final int[] COLUMN_WIDTHS; + private static final Comparator<ActionInformationItem>[] COLUMN_COMP; + private static final double[] COLUMN_WIDTH_PERCENTAGES; + private static final int MIN_WIDTH; + + static { + final double scale = 1.0; // future functionality: UIHelper.getDisplayScaleFactor(); + + int i = 0; + COLUMN_WIDTHS = new int[COLUMN_TITLES.length]; + COLUMN_WIDTHS[i++] = (int)(30.0 * scale); + COLUMN_WIDTHS[i++] = (int)(30.0 * scale); + COLUMN_WIDTHS[i++] = (int)(50.0 * scale); + COLUMN_WIDTHS[i++] = (int)(30.0 * scale); + COLUMN_WIDTHS[i++] = (int)(30.0 * scale); + + int sum = 0; + for (i = 0; i < COLUMN_WIDTHS.length; i++) { + sum += COLUMN_WIDTHS[i]; + } + MIN_WIDTH = sum; + + COLUMN_WIDTH_PERCENTAGES = new double[COLUMN_WIDTHS.length]; + for (i = 0; i < COLUMN_WIDTHS.length; i++) { + COLUMN_WIDTH_PERCENTAGES[i] = ((double)COLUMN_WIDTHS[i] / (double)MIN_WIDTH); + } + + i = 0; + COLUMN_COMP = new Comparator[COLUMN_TITLES.length]; + COLUMN_COMP[i++] = new Comparator<ActionInformationItem>() { + @Override + public int compare(ActionInformationItem o1, ActionInformationItem o2) { + return o1.getModule().compareTo(o2.getModule()); + } + }; + COLUMN_COMP[i++] = new Comparator<ActionInformationItem>() { + @Override + public int compare(ActionInformationItem o1, ActionInformationItem o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + COLUMN_COMP[i++] = new Comparator<ActionInformationItem>() { + @Override + public int compare(ActionInformationItem o1, ActionInformationItem o2) { + return o1.getModuleLocation().compareTo(o2.getModuleLocation()); + } + }; + COLUMN_COMP[i++] = new Comparator<ActionInformationItem>() { + @Override + public int compare(ActionInformationItem o1, ActionInformationItem o2) { + return Long.compare(o1.getCount(), o2.getCount()); + } + }; + COLUMN_COMP[i++] = new Comparator<ActionInformationItem>() { + @Override + public int compare(ActionInformationItem o1, ActionInformationItem o2) { + return Long.compare(o1.getUnseen(), o2.getUnseen()); + } + }; + } + + + CoverageLabelProvider() { + super(MIN_WIDTH, COLUMN_TITLES, COLUMN_WIDTH_PERCENTAGES); + } + + /** + * @param stateTable + */ + void createTableColumns(final Table stateTable, final TableColumnLayout layout) { + for (int i = 0; i < COLUMN_TITLES.length; i++) { + final TableColumn column = new TableColumn(stateTable, SWT.NULL); + column.setWidth(COLUMN_WIDTHS[i]); + column.setText(COLUMN_TITLES[i]); + column.setToolTipText(TOOLTIP); + column.setData(COVERAGE_COMPARATOR, COLUMN_COMP[i]); + + final int weight = (int)(100.0 * COLUMN_WIDTH_PERCENTAGES[i]); + layout.setColumnData(column, new ColumnWeightData(weight, COLUMN_WIDTHS[i], true)); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) + */ + @Override + public Image getColumnImage(final Object element, final int columnIndex) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) + */ + public String getColumnText(final Object element, final int columnIndex) { + if (element instanceof ActionInformationItem) { + final ActionInformationItem item = (ActionInformationItem) element; + + switch (columnIndex) { + case COL_MODULE: + return item.getModule(); + case COL_ACTION: + return item.getName(); + case COL_LOCATION: + if (item.hasDefinition()) { + return item.getDefinition().linesAndColumns(); + } + return item.getLocation(); + case COL_STATES: + return MP.format(item.getCount()); + case COL_DISTSTATES: + return MP.format(item.getUnseen()); + } + } + return null; + } + + public Color getForeground(final Object element, final int columnIndex) { + return null; // Use default color + } + + public Color getBackground(final Object element, final int columnIndex) { + if (element instanceof ActionInformationItem) { + final ActionInformationItem aii = (ActionInformationItem) element; + if (aii.getCount() == 0 && aii.getUnseen() == 0) { + return TLCUIActivator.getColor(SWT.COLOR_YELLOW); + } + } + return null; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageViewerComparator.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageViewerComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..ce7c65d12dd67d92a731c3862c961e6fad15bf31 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageViewerComparator.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of c1 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 c1 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 c2 LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR c2WISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR c2 DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.util.Comparator; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem; + +public class CoverageViewerComparator extends ViewerComparator { + + @Override + public int compare(final Viewer viewer, final Object e1, final Object e2) { + final ActionInformationItem a1 = (ActionInformationItem) e1; + final ActionInformationItem a2 = (ActionInformationItem) e2; + + final Table table = (Table) viewer.getControl(); + final TableColumn sortColumn = table.getSortColumn(); + if (sortColumn == null) { + // a) Compare by distinct states first (we want actions with zero distinct states + // to appear at the top). + if (Long.compare(a1.getUnseen(), a2.getUnseen()) == 0L) { + // b) Compare by location + return a1.getModuleLocation().compareTo(a2.getModuleLocation()); + } else { + return Long.compare(a1.getUnseen(), a2.getUnseen()); + } + } else { + // User requested to sort a specific column up or down. + @SuppressWarnings("unchecked") + final Comparator<ActionInformationItem> comp = (Comparator<ActionInformationItem>) sortColumn + .getData(CoverageLabelProvider.COVERAGE_COMPARATOR); + if (table.getSortDirection() == SWT.UP) { + return comp.compare(a2, a1); + } else { + return comp.compare(a1, a2); + } + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/DataDisplay.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/DataDisplay.java new file mode 100644 index 0000000000000000000000000000000000000000..7561d463e53321807441f5f01c26ac786e5b16d0 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/DataDisplay.java @@ -0,0 +1,198 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.util.UIHelper; + +/** + * The run method of this class creates a shell (a window) to display a graph of + * the appropriate State Space Progress information when the user clicks on a + * column heading. It then adds a PaintListener to that shell, and that listener + * draws the graph initially and whenever the window is resized or some other + * event requires it to be redrawn. + * + * The constructor is used to pass the arguments needed by the run method to + * display the data. + * + * Note: The location at which the shells are displayed is fixed in code buried + * deeply. There should probably be some thought given to where to pop up the + * window, and perhaps a window should be popped up in the same place as the + * last such window was popped--perhaps with a bit of random variation to + * prevent them all from piling up. + * + * @author lamport + */ +class DataDisplay implements Runnable { + private final int m_columnNumber; + private final ResultPage m_resultPage; + private final String m_graphTitle; + + /** + * The constructor returns an object with null data and times arrays if there + * are not at least two data points. + * + * @param ssInfo + * @param columnNumber + */ + public DataDisplay(final int columnNumber, final ResultPage resultPage) { + m_columnNumber = columnNumber; + m_resultPage = resultPage; + + final StateSpaceLabelProvider sslp + = (StateSpaceLabelProvider)resultPage.getStateSpaceTableViewer().getLabelProvider(); + m_graphTitle = ((columnNumber == StateSpaceLabelProvider.COL_TIME) ? "Number of Progress Reports" + : sslp.getColumnTitle(columnNumber)) + + " " + ResultPage.getGraphTitleSuffix(resultPage); + } + + /** + * Much of the stuff in this run() method was copied, without much understanding + * from Snippet245.java in the Eclipse examples. + */ + public void run() { + /* + * The data and times arrays are set to contain the data items to be displayed + * and the elapsed time (in milliseconds) at which each item was posted. The + * data is obtained from the appropriate column of the ssInfo items. For the + * Time column, the number of reports is graphed. + */ + + // We check if a shell exists with this title, and use it if + // it does. Otherwise, we get a new shell. + final Display display = UIHelper.getCurrentDisplay(); + boolean shellExists = false; + Shell theShell = null; + for (final Shell shell : display.getShells()) { + if (shell.getText().equals(m_graphTitle)) { + theShell = shell; + shellExists = true; + break; + } + } + if (!shellExists) { + theShell = new Shell(display, SWT.SHELL_TRIM); + } + + final Shell shell = theShell; + shell.setText(m_graphTitle); + shell.setActive(); // should cause it to pop up to the top. + if (shellExists) { + shell.redraw(); + shell.update(); + } else { + shell.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent event) { + final StateSpaceInformationItem[] ssInfo = m_resultPage.getStateSpaceInformation(); + if (ssInfo.length < 2) { + return; + } + + final long[] data = new long[ssInfo.length + 1]; + final long[] times = new long[ssInfo.length + 1]; + data[0] = 0; + times[0] = 0; + + long startTime = m_resultPage.getStartTimestamp(); + TLCUIActivator.getDefault().logDebug( + "first reported time - starttime = " + (ssInfo[0].getTime().getTime() - startTime)); + if (startTime > ssInfo[0].getTime().getTime() - 1000) { + startTime = ssInfo[0].getTime().getTime() - 1000; + } + for (int i = 1; i < data.length; i++) { + switch (m_columnNumber) { + case StateSpaceLabelProvider.COL_TIME: + data[i] = i - 1; + break; + case StateSpaceLabelProvider.COL_DIAMETER: + data[i] = ssInfo[i - 1].getDiameter(); + break; + case StateSpaceLabelProvider.COL_FOUND: + data[i] = ssInfo[i - 1].getFoundStates(); + break; + case StateSpaceLabelProvider.COL_DISTINCT: + data[i] = ssInfo[i - 1].getDistinctStates(); + break; + case StateSpaceLabelProvider.COL_LEFT: + data[i] = ssInfo[i - 1].getLeftStates(); + break; + default: + return; + } + times[i] = ssInfo[i - 1].getTime().getTime() - startTime; + } + + final Rectangle rect = shell.getClientArea(); + // Set maxData to the largest data value; + long maxData = 0; + for (int i = 0; i < data.length; i++) { + if (data[i] > maxData) { + maxData = data[i]; + } + } + + final long maxTime = times[times.length - 1]; + // event.gc.drawOval(0, 0, rect.width - 1, rect.height - 1); + if (maxTime > 0) { + final double maxTimeD = (double) maxTime; + // In case maxData equals 0, we use 1 instead for computing + // the coordinates of the points. + // (Added by LL on 6 July 2011 to fix division by zero bug.) + final double maxDataVal = (maxData == 0) ? 1 : maxData; + final double width = (double) (rect.width - 6); + final double height = (double) (rect.height - 6); + final int[] pointArray = new int[2 * data.length]; + for (int i = 0; i < data.length; i++) { + final double tFraction = (double) times[i] / maxTimeD; + final double dFraction = (double) data[i] / maxDataVal; + + pointArray[2 * i] = (int) (tFraction * width) + 2; + pointArray[(2 * i) + 1] = rect.height - (int) (dFraction * height) + 2; + } + event.gc.drawPolyline(pointArray); + } + String stringTime = "Time: "; + long unreportedTime = maxTime; + final long days = TimeUnit.MILLISECONDS.toDays(maxTime); + if (days > 0) { + unreportedTime = unreportedTime - TimeUnit.DAYS.toMillis(days); + stringTime = stringTime + days + ((days == 1) ? (" day ") : (" days ")); + + } + final long hours = TimeUnit.MILLISECONDS.toHours(unreportedTime); + if (hours > 0) { + unreportedTime = unreportedTime - TimeUnit.HOURS.toMillis(hours); + stringTime = stringTime + hours + ((hours == 1) ? (" hour ") : (" hours ")); + } + unreportedTime = (unreportedTime + (1000 * 26)) / (1000 * 60); + stringTime = stringTime + unreportedTime + ((unreportedTime == 1) ? (" minute ") : (" minutes ")); + event.gc.drawString(stringTime, 0, 0); + event.gc.drawString("Current: " + data[data.length - 1], 0, 15); + if (maxData != data[data.length - 1]) { + event.gc.drawString("Maximum: " + maxData, 0, 30); + } + } + }); + } + + if (!shellExists) { + shell.setBounds(100 + 30 * m_columnNumber, 100 + 30 * m_columnNumber, 400, 300); + } + + shell.open(); + // The following code from the Eclipse example was eliminated. + // It seems to cause the shell to survive after the Toolbox is + // killed. + // + // while (!shell.isDisposed()) { + // if (!display.readAndDispatch()) display.sleep(); + // } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java new file mode 100644 index 0000000000000000000000000000000000000000..e6eee6e65dcc9150452aa999c8f30f769b65cc1f --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java @@ -0,0 +1,437 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.events.IExpansionListener; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; +import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner; +import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner; +import org.lamport.tla.toolbox.editor.basic.TLASourceViewerConfiguration; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; +import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; +import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; +import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.util.IHelpConstants; +import org.lamport.tla.toolbox.util.UIHelper; + +/** + * This class is in this package as part of historical situation in which its UI + * facets were originally part of the 'Results' page; in some future world, this + * class should probably be moved out of this package. + */ +public class EvaluateConstantExpressionPage extends BasicFormPage implements ITLCModelLaunchDataPresenter { + public static final String ID = "evaluateConstantExpressionPage"; + + /** Exists for making RCPTT tests nicer, hopefully **/ + public static String getTabTitle() { + return "Constant Expressions"; + } + + static BodyContentAssets createBodyContent(final Composite body, final FormToolkit toolkit, final int sectionFlags, + final int textFieldFlags, final IExpansionListener expansionListener, final ModelEditor modelEditor) { + // There is no description line for this section, so it is necessary to eliminate that bit in the style flags that + // are passed in. If the bit were not changed to 0, an extra empty line would appear below the title. + final Section section = FormHelper.createSpaceGrabbingSectionComposite(body, "Evaluate Constant Expression", "", + toolkit, sectionFlags & ~Section.DESCRIPTION, expansionListener); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + section.setLayoutData(gd); + + Composite resultArea = (Composite) section.getClient(); + GridLayout gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + resultArea.setLayout(gl); + + final Composite expressionComposite = toolkit.createComposite(resultArea); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + gd.minimumWidth = 360; + expressionComposite.setLayoutData(gd); + gl = new GridLayout(1, false); + expressionComposite.setLayout(gl); + + final Composite labelToggleLine = toolkit.createComposite(expressionComposite); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + gd.minimumWidth = 360; + labelToggleLine.setLayoutData(gd); + gl = new GridLayout(2, false); + labelToggleLine.setLayout(gl); + + Label l = toolkit.createLabel(labelToggleLine, "Expression: "); + gd = new GridData(); + gd.horizontalAlignment = SWT.LEFT; + gd.heightHint = l.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + l.setLayoutData(gd); + + final Button b = new Button(labelToggleLine, SWT.CHECK); + b.setText("No Behavior Spec"); + gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + gd.heightHint = b.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + gd.grabExcessHorizontalSpace = true; + b.setLayoutData(gd); + b.setSelection(modelEditor.modelIsConfiguredWithNoBehaviorSpec()); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent e) { + final MainModelPage mmp = (MainModelPage)modelEditor.findPage(MainModelPage.ID); + + mmp.setNoBehaviorSpec(b.getSelection()); + } + }); + + + final SourceViewer input = FormHelper.createFormsSourceViewer(toolkit, expressionComposite, textFieldFlags, + new TLASourceViewerConfiguration()); + input.getTextWidget().addKeyListener(new KeyListener() { + @Override + public void keyPressed(KeyEvent e) { + if (isUndoKeyPress(e)) { + input.doOperation(ITextOperationTarget.UNDO); + } else if (isRedoKeyPress(e)) { + input.doOperation(ITextOperationTarget.REDO); + } + } + + private boolean isRedoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'y') || (e.keyCode == 'Y')); + } + + private boolean isUndoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'z') || (e.keyCode =='Z')); + } + + @Override + public void keyReleased(KeyEvent e) { } + }); + + // Reminder that this layout data is for this text area within the expression composite within the result area + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.minimumWidth = 360; + gd.minimumHeight = 80; + input.getTextWidget().setLayoutData(gd); + + + + l = toolkit.createLabel(expressionComposite, "Value: "); + gd = new GridData(); + gd.horizontalAlignment = SWT.LEFT; + gd.heightHint = l.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + l.setLayoutData(gd); + final SourceViewer output = FormHelper.createFormsOutputViewer(toolkit, expressionComposite, textFieldFlags); + // Reminder that this layout data is for this text area within the value composite within the result area + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.minimumWidth = 360; + gd.minimumHeight = 80; + output.getTextWidget().setLayoutData(gd); + + // We want this font to be the same as the input. If it was not set it would be the same as the font + // in the module editor. + input.getTextWidget().setFont(JFaceResources.getTextFont()); + output.getTextWidget().setFont(JFaceResources.getTextFont()); + // This is required to paint the borders of the text boxes it must be called on the direct parent of the widget + // with a border. There is a call of this method in FormHelper.createSectionComposite, but that is called + // on the section which is not a direct parent of the text box widget. + toolkit.paintBordersFor(expressionComposite); + + return new BodyContentAssets(section, input, output, b); + } + + + private SourceViewer m_expressionInput; + private SourceViewer m_expressionOutput; + private ValidateableSectionPart m_validateableCalculatorSection; + + private Button m_toggleButton; + + private final Lock disposeLock = new ReentrantLock(true); + + /** + * Constructs the page + * + * @param editor + */ + public EvaluateConstantExpressionPage(final FormEditor editor) { + super(editor, ID, getTabTitle(), "icons/full/ece_page_" + IMAGE_TEMPLATE_TOKEN + ".png"); + helpId = IHelpConstants.EVALUATE_CON_EX_PAGE; + } + + @Override + protected void createBodyContent(IManagedForm managedForm) { + final int sectionFlags = Section.TITLE_BAR | Section.TREE_NODE | Section.EXPANDED | SWT.WRAP; + final int textFieldFlags = SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.FULL_SELECTION | SWT.WRAP; + + final FormToolkit toolkit = managedForm.getToolkit(); + final Composite body = managedForm.getForm().getBody(); + final GridLayout gl = new GridLayout(); + gl.marginHeight = 0; + gl.marginWidth = 0; + body.setLayout(gl); + + final BodyContentAssets bca = createBodyContent(body, toolkit, sectionFlags, textFieldFlags, + getExpansionListener(), (ModelEditor)getEditor()); + m_expressionInput = bca.getExpressionInput(); + m_expressionOutput = bca.getExpressionOutput(); + m_toggleButton = bca.m_toggleButton; + + m_validateableCalculatorSection = new ValidateableSectionPart(bca.getSection(), this, SEC_EXPRESSION); + // This ensures that when the part is made dirty, the model appears unsaved. + managedForm.addPart(m_validateableCalculatorSection); + + // This makes the widget unsaved when text is entered. + m_expressionInput.getTextWidget().addModifyListener(new DirtyMarkingListener(m_validateableCalculatorSection, false)); + + getDataBindingManager().bindSection(m_validateableCalculatorSection, SEC_EXPRESSION, getId()); + getDataBindingManager().bindAttribute(Model.MODEL_EXPRESSION_EVAL, m_expressionInput, m_validateableCalculatorSection); + } + + public void setNoBehaviorSpecToggleState(final boolean selected) { + m_toggleButton.setSelection(selected); + } + + public State getECEContent() { + if (m_expressionInput != null) { + return new State(m_expressionInput.getDocument(), m_expressionOutput.getTextWidget().getText(), + m_toggleButton.getSelection()); + } + + return null; + } + + public void setECEContent(final State state) { + if (m_expressionInput == null) { + TLCUIActivator.getDefault().logError("Can't set ECE content on null objects."); + } else { + m_expressionInput.setDocument(state.getInputDocument()); + m_expressionOutput.getTextWidget().setText(state.getOutputText()); + m_toggleButton.setSelection(state.getToggleState()); + } + } + + /** + * Gets the data provider for the current page + */ + @Override + public void loadData() throws CoreException { + final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry.getModelCheckSourceRegistry(); + final TLCModelLaunchDataProvider provider = modelCheckSourceRegistry.getProvider(getModel()); + if (provider != null) { + provider.addDataPresenter(this); + } else { + // no data provider + m_expressionOutput.getTextWidget().setText(""); + } + + final Document document = new Document(getModel().getEvalExpression()); + final IDocumentPartitioner partitioner = new TLAFastPartitioner( + TLAEditorActivator.getDefault().getTLAPartitionScanner(), TLAPartitionScanner.TLA_PARTITION_TYPES); + document.setDocumentPartitioner(TLAPartitionScanner.TLA_PARTITIONING, partitioner); + partitioner.connect(document); + m_expressionInput.setDocument(document); + } + + /** + * Save data back to model + */ + public void commit(boolean onSave) { + final String expression = m_expressionInput.getDocument().get(); + getModel().unsavedSetEvalExpression(expression); + + super.commit(onSave); + } + + /** + * Dispose the page + */ + public void dispose() { + disposeLock.lock(); + try { + final IManagedForm managedForm = getManagedForm(); + + managedForm.removePart(m_validateableCalculatorSection); + + getDataBindingManager().unbindSectionFromPage(SEC_EXPRESSION, getId()); + + final Model model = getModel(); + final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry.getModelCheckSourceRegistry(); + // Do not initialize provider in dispose if it hasn't been initialized yet. + if (modelCheckSourceRegistry.hasProvider(model)) { + final TLCModelLaunchDataProvider provider = modelCheckSourceRegistry.getProvider(model); + if (provider != null) { + provider.removeDataPresenter(this); + } + } + + super.dispose(); + } finally { + disposeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setFocus() { + if ((m_expressionInput != null) && !m_expressionInput.getTextWidget().isDisposed() + && !m_expressionInput.getTextWidget().isFocusControl()) { + final StyledText st = m_expressionInput.getTextWidget(); + final int caretOffset = st.getText().length(); + + st.setFocus(); + + /* + * We get a focus notification at least 3 times after TLC execution finishes, in which none of those times + * does the text widget believe itself focused. Further, the text widget gaining focus resets its caret + * offset to 0; so, nearly ubiquitously we end up with the caret offset position set invocation never + * sticking. We resort to this waiting-out-the-notification-storm ugly hack to get the caret set + * to stick; were we getting more than 3 notifications, i would use a thread pool to gate proliferation + * here. + */ + final Runnable ohSWT = () -> { + try { + Thread.sleep(75); + } catch (Exception e) { } + + if (!st.isDisposed()) { + st.getDisplay().asyncExec(() -> { + if (!st.isDisposed()) { + st.setCaretOffset(caretOffset); + } + }); + } + }; + (new Thread(ohSWT)).start(); + } + } + + /** + * Will be called by the provider on data changes + */ + public void modelChanged(final TLCModelLaunchDataProvider dataProvider, final int fieldId) { + UIHelper.runUIAsync(() -> { + // Acquire dispose lock prior to widget access. Using a single + // lock just to serialize dispose and modelChange seems + // overkill, but the wait-for graph becomes tricky with all the + // background jobs going on (at least too tricky to get it + // solved within an hour). + disposeLock.lock(); + try { + if (getPartControl().isDisposed()) { + return; + } + if (fieldId == CONST_EXPR_EVAL_OUTPUT) { + m_expressionOutput.getTextWidget().setText(dataProvider.getCalcOutput()); + } + } finally { + disposeLock.unlock(); + } + }); + } + + + static class BodyContentAssets { + private final Section m_section; + private final SourceViewer m_expressionInput; + private final SourceViewer m_expressionOutput; + private final Button m_toggleButton; + + BodyContentAssets(final Section s, final SourceViewer input, final SourceViewer output, final Button toggle) { + m_section = s; + m_expressionInput = input; + m_expressionOutput = output; + m_toggleButton = toggle; + } + + Section getSection() { + return m_section; + } + + SourceViewer getExpressionInput() { + return m_expressionInput; + } + + SourceViewer getExpressionOutput() { + return m_expressionOutput; + } + + Button getToggleButton() { + return m_toggleButton; + } + } + + static public class State { + private final IDocument m_inputDocument; + private final String m_outputText; + private final boolean m_toggleState; + + State (final IDocument document, final String text, final boolean toggleState) { + m_inputDocument = document; + m_outputText = text; + m_toggleState = toggleState; + } + + public IDocument getInputDocument() { + return m_inputDocument; + } + + public String getOutputText() { + return m_outputText; + } + + public boolean getToggleState() { + return m_toggleState; + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java new file mode 100644 index 0000000000000000000000000000000000000000..084497ae2d4943423bedb8a6baa8c357905fbb58 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java @@ -0,0 +1,1514 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.time.DurationFormatUtils; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.mylyn.commons.notifications.core.INotificationService; +import org.eclipse.mylyn.commons.notifications.ui.NotificationsUi; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.FormEditor; +import org.eclipse.ui.forms.editor.IFormPage; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.events.HyperlinkAdapter; +import org.eclipse.ui.forms.events.HyperlinkEvent; +import org.eclipse.ui.forms.events.IHyperlinkListener; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Hyperlink; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.progress.UIJob; +import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner; +import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner; +import org.lamport.tla.toolbox.spec.Module; +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.model.Assignment; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformation; +import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageUINotification; +import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter; +import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; +import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.contribution.DynamicContributionItem; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ISectionConstants; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.TLACoverageEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.ErrorMessage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedTLCOptionsPage; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart; +import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; +import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler; +import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener; +import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView; +import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; +import org.lamport.tla.toolbox.util.FontPreferenceChangeListener; +import org.lamport.tla.toolbox.util.IHelpConstants; +import org.lamport.tla.toolbox.util.UIHelper; + +/** + * A page to display results of model checking. + * @author Simon Zambrovski + */ +@SuppressWarnings("restriction") +public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPresenter { + public static final String RESULT_PAGE_PROBLEM = "ResultPageProblem"; + + public static final String ID = "resultPage"; + + /** + * The title of a graph consists of two parts: the prefix, which + * identifies the column, and the suffix, which identifies the model. + * When we dispose of the ResultPage, we must dispose of all graph + * window (shells) for that model. + * + * @param resultPage + * @return the graph title suffix + */ + static String getGraphTitleSuffix(ResultPage resultPage) { + return "(" + resultPage.getModel().getName() + ")"; + } + + private static final Color ERROR_PANE_BACKGROUND = new Color(PlatformUI.getWorkbench().getDisplay(), 255, 241, 237); + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("HH:mm:ss '('MMM d')'"); + private static final String ZERO_COVERAGE_WARNING = "Disabled actions for one or more modules."; + + + /** + * UI elements + */ + private SourceViewer userOutput; + private SourceViewer progressOutput; + + private Composite m_calculatorSection; + private SourceViewer expressionEvalResult; + private SourceViewer expressionEvalInput; + private ValidateableSectionPart m_validateableCalculatorSection; + private Button m_noBehaviorModeToggleButton; + + private Section m_generalSection; + private int m_collapsedSectionHeight = 20; // We should be able to calculate this before we need; this is the 'just in case' value + private long m_startTimestamp; + private Composite m_generalTopPane; + private Label m_startLabel; + private Label m_lastCheckpointLabel; + private Label m_finishLabel; + private Label m_tlcSimulationLabel; + private Label m_tlcSearchModeLabel; + private Label m_tlcStatusLabel; + + private Composite m_generalErrorPane; + private Hyperlink m_errorStatusHyperLink; + private Label m_fingerprintCollisionLabel; + private Label m_zeroCoverageLabel; + + private Text coverageTimestampText; + private TableViewer coverage; + private TableViewer stateSpace; + private final Map<String, Section> sections = new HashMap<String, Section>(); + private final Lock disposeLock = new ReentrantLock(true); + + // listener on changes to the tlc output font preference + private FontPreferenceChangeListener fontChangeListener; + + // hyper link listener activated in case of errors + private final IHyperlinkListener m_errorHyperLinkListener = new HyperlinkAdapter() { + public void linkActivated(HyperlinkEvent e) + { + if (getModel() != null) + { + getModel().setOriginalTraceShown(true); + TLCErrorView.updateErrorView(getModel()); + } + } + }; + + private IMarker incompleteStateExploration; + private IMarker zeroCoverage; + + private final INotificationService ns; + + private final ErrorPaneViewState m_errorPaneViewState; + + /** + * Constructor for the page + * @param editor + */ + public ResultPage(final FormEditor editor) { + super(editor, ID, "Model Checking Results", "icons/full/results_page_" + IMAGE_TEMPLATE_TOKEN + ".png"); + this.helpId = IHelpConstants.RESULT_MODEL_PAGE; + + this.ns = NotificationsUi.getService(); + + m_errorPaneViewState = new ErrorPaneViewState(); + } + + @Override + public void modelCheckingHasBegun() { + m_errorPaneViewState.clearState(); + PlatformUI.getWorkbench().getDisplay().asyncExec(() -> { + m_tlcStatusLabel.setText("Starting..."); + m_errorStatusHyperLink.setVisible(m_errorPaneViewState.errorLinkIsDisplayed()); + m_fingerprintCollisionLabel.setVisible(m_errorPaneViewState.fingerprintIsDisplayed()); + m_zeroCoverageLabel.setVisible(m_errorPaneViewState.zeroCountIsDisplayed()); + setErrorPaneVisible(m_errorPaneViewState.shouldDisplay()); + }); + } + + /** + * Will be called by the provider on data changes + */ + public void modelChanged(final TLCModelLaunchDataProvider dataProvider, final int fieldId) { + UIHelper.runUIAsync(() -> { + // Acquire dispose lock prior to widget access. Using a single + // lock just to serialize dispose and modelChange seems + // overkill, but the wait-for graph becomes tricky with all the + // background jobs going on (at least too tricky to get it + // solved within an hour). + disposeLock.lock(); + try { + if (getPartControl().isDisposed()) { + // Don't update the widgets if the underlying SWT control has + // already been disposed. Otherwise it results in an + // "SWTException: Widget is disposed". + return; + } + switch (fieldId) { + case USER_OUTPUT: + userOutput.setDocument(dataProvider.getUserOutput()); + break; + case PROGRESS_OUTPUT: + progressOutput.setDocument(dataProvider.getProgressOutput()); + break; + case CONST_EXPR_EVAL_OUTPUT: + if (expressionEvalResult != null) { + expressionEvalResult.getTextWidget().setText(dataProvider.getCalcOutput()); + } + break; + case START_TIME: + setStartTime(dataProvider.getStartTimestamp()); + break; + case END_TIME: + setEndTime(dataProvider.getFinishTimestamp()); + + final long delta = dataProvider.getFinishTimestamp() - dataProvider.getStartTimestamp(); + final String duration = DurationFormatUtils.formatDuration(delta, "HH'hrs' mm'mins' ss'sec'"); + m_startLabel.setToolTipText(duration); + m_finishLabel.setToolTipText(duration); + break; + case TLC_MODE: + setSearchMode(dataProvider.getTLCMode()); + + final IFormPage iep = getEditor().findPage(AdvancedTLCOptionsPage.ID); + if (iep != null) { + ((AdvancedTLCOptionsPage)iep).setFpIndex(dataProvider.getFPIndex()); + } else { + // The tab isn't open so set the value into the model and the tab, should it open, will + // load it out of the model. + getModel().setAttribute(LAUNCH_FP_INDEX, dataProvider.getFPIndex()); + getModelEditor().saveModel(); + } + case LAST_CHECKPOINT_TIME: + setCheckpoint(dataProvider.getLastCheckpointTimeStamp()); + break; + case CURRENT_STATUS: + m_tlcStatusLabel.setText(dataProvider.getCurrentStatus()); + m_generalTopPane.layout(true, true); + break; + case FINGERPRINT_COLLISION_PROBABILITY: + final String collisionText = dataProvider.getFingerprintCollisionProbability().trim(); + + if (collisionText.length() == 0) { + m_fingerprintCollisionLabel.setVisible(false); + m_errorPaneViewState.setFingerprintDisplay(false); + setErrorPaneVisible(m_errorPaneViewState.shouldDisplay()); + } else { + m_fingerprintCollisionLabel.setText("Fingerprint collision probability: " + collisionText); + m_fingerprintCollisionLabel.setVisible(true); + m_errorPaneViewState.setFingerprintDisplay(true); + setErrorPaneVisible(true); + } + break; + case COVERAGE_TIME: + final String coverageTimestamp = dataProvider.getCoverageTimestamp(); + if ("".equals(coverageTimestamp)) { + // Reset + ResultPage.this.coverageTimestampText.setText(""); + } else { + // Print statistics timestamp relative to TLC startup. + final Date date = TLCModelLaunchDataProvider.parseDate(coverageTimestamp); + final String interval = TLCModelLaunchDataProvider.formatInterval(getStartTimestamp(), date.getTime()); + ResultPage.this.coverageTimestampText.setText(interval); + } + break; + case COVERAGE: + final CoverageInformation coverageInfo = dataProvider.getCoverageInfo(); + coverage.setInput(coverageInfo); + if (dataProvider.isDone() && !coverageInfo.isEmpty()) { +// mku: uncomment the following line; run Dijkstra with no zero coverage; then with zero coverage; then no zero coverage +//Logger.getAnonymousLogger().severe("COVERAGE - dp hasZeroCoverage? " + dataProvider.hasZeroCoverage()); + if (dataProvider.hasZeroCoverage()) { + if (zeroCoverage == null) { + final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription( + ZERO_COVERAGE_WARNING, IMarker.SEVERITY_WARNING); + marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2); + zeroCoverage = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC); + } + if (coverageInfo.hasDisabledSpecActions()) { + m_zeroCoverageLabel.setVisible(true); + m_errorPaneViewState.setZeroCountDisplay(true); + setErrorPaneVisible(true); + } + } else if (zeroCoverage != null) { + try { + zeroCoverage.delete(); + resetMessage(RESULT_PAGE_PROBLEM); + zeroCoverage = null; + } catch (CoreException e) { + TLCUIActivator.getDefault().logError(e.getMessage(), e); + } finally { + m_zeroCoverageLabel.setVisible(false); + m_errorPaneViewState.setZeroCountDisplay(false); + setErrorPaneVisible(m_errorPaneViewState.shouldDisplay()); + } + } + } + break; + case COVERAGE_END_OVERHEAD: + ns.notify(Collections.singletonList(new CoverageUINotification(getModelEditor()))); + // Continue with COVERAGE_END... + case COVERAGE_END: + final CoverageInformation ci = dataProvider.getCoverageInfo(); + if (ci.isEmpty() || ci.isLegacy()) { + // Cannot show coverage information without (non-legacy) coverage data. + break; + } + + final List<ActionInformationItem> zeroCoverageInformation = ci.getDisabledSpecActions(); + for (ActionInformationItem item : zeroCoverageInformation) { + final Module m = getModel().getSpec().getModule(item.getModule()); + if (m == null) { + // With the Toolbox better be safe than sorry. + continue; + } + try { + final IMarker createMarker = m.getResource() + .createMarker(ModelEditor.ZERO_COVERAGE_ACTION_MARKER); + + createMarker.setAttribute(IMarker.MESSAGE, + String.format("%s is never enabled.", item.getName())); + createMarker.setAttribute(IMarker.LINE_NUMBER, item.getModuleLocation().beginLine()); + + // In order to color/highlight the token itself, set char_start and char_end + // too. At this point we decided it is too intrusive though. +// final org.eclipse.jface.text.IRegion region = org.lamport.tla.toolbox.util.AdapterFactory +// .locationToRegion(item.getModuleLocation()); +// createMarker.setAttribute(IMarker.CHAR_START, region.getOffset()); +// createMarker.setAttribute(IMarker.CHAR_END, region.getOffset() + region.getLength()); + } catch (CoreException e) { + TLCUIActivator.getDefault().logError(e.getMessage(), e); + } + } + + // Do not open the dedicated coverage editor below if the user only requested + // action-only coverage. + if (Model.Coverage.ACTION == getModel().getCoverage()) { + break; + } + + + final ModelEditor modelEditor = (ModelEditor) ResultPage.this.getEditor(); + + final List<IFile> savedTLAFiles = modelEditor.getModel().getSavedTLAFiles(); + for (IFile iFile : savedTLAFiles) { + if (!ci.has(iFile)) { + continue; + } + // Open the files as pages of the current model editor. + final FileEditorInput input = new FileEditorInput(iFile); + final IEditorPart[] findEditors = modelEditor.findEditors(input); + try { + if (findEditors.length == 0) { + modelEditor.addPage(new TLACoverageEditor(ci.projectionFor(iFile)), input); + } else { + if (findEditors[0] instanceof TLACoverageEditor) { + final TLACoverageEditor coverageEditor = (TLACoverageEditor) findEditors[0]; + coverageEditor.resetInput(ci.projectionFor(iFile)); + } + } + } catch (PartInitException e) { + TLCUIActivator.getDefault().logError(e.getMessage(), e); + } + } + break; + case PROGRESS: + ResultPage.this.stateSpace.setInput(dataProvider.getProgressInformation()); + + // The following code finds all the graph windows (shells) for this + // model and calls redraw() and update() on them, which apparently is the + // magic incantation to cause its listener to be called to issue the + // necessary commands to redraw the data and then displays the result. + String suffix = getGraphTitleSuffix(ResultPage.this); + Shell[] shells = UIHelper.getCurrentDisplay().getShells(); + for (int i = 0; i < shells.length; i++) + { + if (shells[i].getText().endsWith(suffix)) + { + shells[i].redraw(); + shells[i].update(); + // The following was commented out by LL on 6 Jul 2012 because it was filling + // up the Console log with useless stuff. + // TLCUIActivator.getDefault().logDebug("Called redraw/update on shell number" + i); + } + } + break; + case WARNINGS: + if (dataProvider.isSymmetryWithLiveness()) { + final MainModelPage mmp = (MainModelPage) getModelEditor().getFormPage(MainModelPage.ID); + final Optional<Assignment> possibleSymmetrySet = mmp.getConstants().stream() + .filter(c -> c.isSymmetricalSet()).findFirst(); + if (possibleSymmetrySet.isPresent()) { + final Assignment symmetrySet = possibleSymmetrySet.get(); + getModelEditor().addErrorMessage(new ErrorMessage(String.format("%s %s", + symmetrySet.getLabel(), + "declared to be symmetric. Liveness checking under symmetry might fail to find a violation."), + symmetrySet.getLabel(), MainModelPage.ID, + Arrays.asList(ISectionConstants.SEC_WHAT_IS_THE_MODEL, + ISectionConstants.SEC_WHAT_TO_CHECK_PROPERTIES), + IModelConfigurationConstants.MODEL_PARAMETER_CONSTANTS)); + } + } + break; + case ERRORS: + final String text; + final Color color; + final boolean visible; + final int errorCount = dataProvider.getErrors().size(); + switch (errorCount) { + case 0: + text = TLCModelLaunchDataProvider.NO_ERRORS; + color = TLCUIActivator.getColor(SWT.COLOR_BLACK); + m_errorStatusHyperLink.removeHyperlinkListener(m_errorHyperLinkListener); + visible = false; + break; + case 1: + text = "1 Error"; + m_errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener); + color = TLCUIActivator.getColor(SWT.COLOR_RED); + visible = true; + break; + default: + text = String.valueOf(errorCount) + " Errors"; + m_errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener); + color = TLCUIActivator.getColor(SWT.COLOR_RED); + visible = true; + break; + } + + m_errorStatusHyperLink.setText(text); + m_errorStatusHyperLink.setForeground(color); + m_errorStatusHyperLink.setVisible(visible); + m_errorPaneViewState.setErrorLinkDisplay(visible); + setErrorPaneVisible(m_errorPaneViewState.shouldDisplay()); + + // update the error view + TLCErrorView.updateErrorView(dataProvider.getModel()); + break; + default: + break; + } + + // Set label provider to highlight unexplored states if + // TLC is done but not all states are explored. + if (ResultPage.this.stateSpace.getLabelProvider() instanceof StateSpaceLabelProvider) { + final StateSpaceLabelProvider sslp = (StateSpaceLabelProvider) ResultPage.this.stateSpace + .getLabelProvider(); + if (dataProvider.isDone() && dataProvider.getProgressInformation().size() > 0) { + final long statesLeft = dataProvider.getProgressInformation().get(0).getLeftStates(); + if (statesLeft > 0) { + sslp.setHighlightUnexplored(); + // Create a problem marker which gets displayed by + // BasicFormPage/ModelEditor as a warning on the + // result page. + if (incompleteStateExploration == null) { + final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription( + "State space exploration incomplete", IMarker.SEVERITY_WARNING); + marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2); + incompleteStateExploration = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC); + } + } else { + if (incompleteStateExploration != null) { + try { + incompleteStateExploration.delete(); + ResultPage.this.resetMessage(RESULT_PAGE_PROBLEM); + incompleteStateExploration = null; + } catch (CoreException e) { + TLCUIActivator.getDefault().logError(e.getMessage(), e); + } + } + sslp.unsetHighlightUnexplored(); + } + } + ResultPage.this.stateSpace.refresh(); + } + } finally { + disposeLock.unlock(); + } + }); + + } + + /** + * {@inheritDoc} + */ + @Override + public void setFocus() { + if ((expressionEvalInput != null) && !expressionEvalInput.getTextWidget().isDisposed() + && !expressionEvalInput.getTextWidget().isFocusControl()) { + final StyledText st = expressionEvalInput.getTextWidget(); + final int caretOffset = st.getText().length(); + + st.setFocus(); + + /* + * We get a focus notification at least 3 times after TLC execution finishes, in which none of those times + * does the text widget believe itself focused. Further, the text widget gaining focus resets its caret + * offset to 0; so, nearly ubiquitously we end up with the caret offset position set invocation never + * sticking. We resort to this waiting-out-the-notification-storm ugly hack to get the caret set + * to stick; were we getting more than 3 notifications, i would use a thread pool to gate proliferation + * here. + */ + final Runnable ohSWT = () -> { + try { + Thread.sleep(75); + } catch (Exception e) { } + + if (!st.isDisposed()) { + st.getDisplay().asyncExec(() -> { + if (!st.isDisposed()) { + st.setCaretOffset(caretOffset); + } + }); + } + }; + (new Thread(ohSWT)).start(); + } + } + + /** + * Gets the data provider for the current page + */ + @Override + public void loadData() throws CoreException { + final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry.getModelCheckSourceRegistry(); + final TLCModelLaunchDataProvider provider = modelCheckSourceRegistry.getProvider(getModel()); + if (provider != null) { + provider.addDataPresenter(this); + } else { + // no data provider + reinit(); + } + + // constant expression + final Document document = new Document(getModel().getEvalExpression()); + final IDocumentPartitioner partitioner = new TLAFastPartitioner( + TLAEditorActivator.getDefault().getTLAPartitionScanner(), TLAPartitionScanner.TLA_PARTITION_TYPES); + document.setDocumentPartitioner(TLAPartitionScanner.TLA_PARTITIONING, partitioner); + partitioner.connect(document); + if (expressionEvalInput != null) { + expressionEvalInput.setDocument(document); + } + } + + /** + * Reinitialize the fields + * has to be run in the UI thread + */ + private synchronized void reinit() + { + // TLCUIActivator.getDefault().logDebug("Entering reinit()"); + disposeLock.lock(); + try { + if (getPartControl().isDisposed()) { + return; + } + + m_startTimestamp = 0; + m_startLabel.setText(""); + m_lastCheckpointLabel.setText(""); + m_finishLabel.setText(""); + m_tlcSimulationLabel.setVisible(false); + m_tlcSearchModeLabel.setText(""); + m_tlcStatusLabel.setText(TLCModelLaunchDataProvider.NOT_RUNNING); + m_errorStatusHyperLink.setText(TLCModelLaunchDataProvider.NO_ERRORS); + m_errorStatusHyperLink.setVisible(false); + m_fingerprintCollisionLabel.setText(""); + m_fingerprintCollisionLabel.setVisible(false); + m_zeroCoverageLabel.setVisible(false); + coverage.setInput(new Vector<CoverageInformationItem>()); + stateSpace.setInput(new Vector<StateSpaceInformationItem>()); + progressOutput.setDocument(new Document(TLCModelLaunchDataProvider.NO_OUTPUT_AVAILABLE)); + userOutput.setDocument(new Document(TLCModelLaunchDataProvider.NO_OUTPUT_AVAILABLE)); + + setErrorPaneVisible(false); + + m_generalTopPane.layout(true, true); + } finally { + disposeLock.unlock(); + } + // TLCUIActivator.getDefault().logDebug("Exiting reinit()"); + } + + /** + * Dispose the page + */ + public void dispose() + { + disposeLock.lock(); + try { + /* + * Remove graph windows raised for the page. + */ + String suffix = getGraphTitleSuffix(this); + Shell[] shells = UIHelper.getCurrentDisplay().getShells(); + for (int i = 0; i < shells.length; i++) { + if (shells[i].getText().endsWith(suffix)) { + shells[i].dispose(); + } + } + + if (incompleteStateExploration != null) { + incompleteStateExploration.delete(); + incompleteStateExploration = null; + } + + if (zeroCoverage != null) { + zeroCoverage.delete(); + zeroCoverage = null; + } + + JFaceResources.getFontRegistry().removeListener(fontChangeListener); + + final Model model = getModel(); + final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry.getModelCheckSourceRegistry(); + // Do not initialize provider in dispose if it hasn't been initialized yet. + if (modelCheckSourceRegistry.hasProvider(model)) { + final TLCModelLaunchDataProvider provider = modelCheckSourceRegistry.getProvider(model); + if (provider != null) { + provider.removeDataPresenter(this); + } + } + super.dispose(); + } catch (CoreException e) { + e.printStackTrace(); + } finally { + disposeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Layout getBodyLayout() { + return FormHelper.createFormTableWrapLayout(true, 1); + } + + /** + * Draw the fields + * + * Its helpful to know what the standard SWT widgets look like. + * Pictures can be found at http://www.eclipse.org/swt/widgets/ + * + * Layouts are used throughout this method. + * A good explanation of layouts is given in the article + * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html + */ + protected void createBodyContent(IManagedForm managedForm) { + final int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE | Section.EXPANDED | SWT.WRAP; + final int textFieldFlags = SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.WRAP | SWT.FULL_SELECTION; + + final FormToolkit toolkit = managedForm.getToolkit(); + final Composite body = managedForm.getForm().getBody(); + + Section section; + GridLayout gl; + GridData gd; + + gl = new GridLayout(); + gl.marginHeight = 0; + gl.marginWidth = 0; + body.setLayout(gl); + + // ------------------------------------------------------------------- + // general section + // There is no description line for this section, so it is + // necessary to eliminate that bit in the style flags that + // are passed in. If the bit were not changed to 0, an + // extra empty line would appear below the title. + m_generalSection = FormHelper.createSectionComposite(body, "General", "", toolkit, sectionFlags & ~Section.DESCRIPTION, + null); //getExpansionListener()); + sections.put(SEC_GENERAL, m_generalSection); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.TOP; + m_generalSection.setLayoutData(gd); + final GeneralSectionExpansionHoopJumper absurdListener = new GeneralSectionExpansionHoopJumper(); + m_generalSection.addExpansionListener(absurdListener); + m_generalSection.setData(SECTION_EXPANSION_LISTENER, absurdListener); + + final Composite generalArea = (Composite) m_generalSection.getClient(); + gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + gl.marginBottom = 6; + generalArea.setLayout(gl); + + m_generalTopPane = new Composite(generalArea, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.TOP; + m_generalTopPane.setLayoutData(gd); + gl = new GridLayout(6, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + gl.horizontalSpacing = 12; + m_generalTopPane.setLayout(gl); + + m_startLabel = new Label(m_generalTopPane, SWT.NONE); + m_startLabel.setLayoutData(new GridData()); + m_startLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + m_lastCheckpointLabel = new Label(m_generalTopPane, SWT.NONE); + m_lastCheckpointLabel.setLayoutData(new GridData()); + m_finishLabel = new Label(m_generalTopPane, SWT.NONE); + m_finishLabel.setLayoutData(new GridData()); + m_finishLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + m_tlcSimulationLabel = new Label(m_generalTopPane, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.CENTER; + m_tlcSimulationLabel.setLayoutData(gd); + m_tlcSimulationLabel.setText("Simulation mode"); + m_tlcSimulationLabel.setVisible(false); + m_tlcSimulationLabel.setFont(JFaceResources.getFontRegistry().getItalic(JFaceResources.DIALOG_FONT)); + m_tlcSearchModeLabel = new Label(m_generalTopPane, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + gd.grabExcessHorizontalSpace = true; + m_tlcSearchModeLabel.setLayoutData(gd); + m_tlcStatusLabel = new Label(m_generalTopPane, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 18; + m_tlcStatusLabel.setLayoutData(gd); + m_tlcStatusLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + + m_generalErrorPane = new Composite(generalArea, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalIndent = 9; + gd.verticalAlignment = SWT.TOP; + m_generalErrorPane.setLayoutData(gd); + gl = new GridLayout(3, false); + gl.marginHeight = 6; + gl.marginWidth = 0; + gl.horizontalSpacing = 6; + m_generalErrorPane.setLayout(gl); + m_generalErrorPane.setBackground(ERROR_PANE_BACKGROUND); + + // errors + // Label createLabel = + // toolkit.createLabel(statusComposite, "Errors detected:"); + // this.errorStatusHyperLink = toolkit.createHyperlink(statusComposite, "", SWT.RIGHT); + m_errorStatusHyperLink = toolkit.createHyperlink(m_generalErrorPane, "", SWT.NONE); + m_errorStatusHyperLink.setBackground(m_generalErrorPane.getBackground()); + m_errorStatusHyperLink.setVisible(false); + + // fingerprint collision probability + m_fingerprintCollisionLabel = new Label(m_generalErrorPane, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.CENTER; + m_fingerprintCollisionLabel.setLayoutData(gd); + m_fingerprintCollisionLabel.setVisible(false); + + // zero coverage label + m_zeroCoverageLabel = new Label(m_generalErrorPane, SWT.NONE); + m_zeroCoverageLabel.setText(ZERO_COVERAGE_WARNING); + m_zeroCoverageLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + m_zeroCoverageLabel.setVisible(false); + gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.BOTTOM; + m_zeroCoverageLabel.setLayoutData(gd); + + setErrorPaneVisible(false); + + + // ------------------------------------------------------------------- + // statistics section + // There is no description line for this section, so it is + // necessary to eliminate that bit in the style flags that + // are passed in. If the bit were not changed to 0, an + // extra empty line would appear below the title. + section = FormHelper.createSpaceGrabbingSectionComposite(body, "Statistics", "", toolkit, + (sectionFlags | Section.COMPACT) & ~Section.DESCRIPTION, getExpansionListener()); + sections.put(SEC_STATISTICS, section); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + section.setLayoutData(gd); + + final Composite statArea = (Composite) section.getClient(); + gl = new GridLayout(2, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + statArea.setLayout(gl); + + final int heightGuidance = getHeightGuidanceForLabelTextFieldLine(statArea, toolkit); + + // progress stats + createAndSetupStateSpace(statArea, toolkit, heightGuidance); + + // coverage stats + createAndSetupCoverage(statArea, toolkit, heightGuidance); + + + // ------------------------------------------------------------------- + // Calculator section + final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore(); + final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB); + + m_calculatorSection = new Composite(body, SWT.NONE); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = !eceInItsOwnTab; + m_calculatorSection.setLayoutData(gd); + gl = new GridLayout(); + gl.marginHeight = 0; + gl.marginWidth = 0; + m_calculatorSection.setLayout(gl); + m_calculatorSection.setBackground(m_calculatorSection.getDisplay().getSystemColor(SWT.COLOR_WHITE)); + + if (!eceInItsOwnTab) { + pageShouldDisplayEvaluateConstantUI(true); + } + + // ------------------------------------------------------------------- + // output section + section = FormHelper.createSpaceGrabbingSectionComposite(body, "User Output", + "TLC output generated by evaluating Print and PrintT expressions.", toolkit, sectionFlags, + getExpansionListener()); + sections.put(SEC_OUTPUT, section); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + section.setLayoutData(gd); + final Composite outputArea = (Composite) section.getClient(); + outputArea.setLayout(new GridLayout(1, false)); + // output viewer -- see progressOutput comment complaints concerning SWT.WRAP included in the text field flags + userOutput = FormHelper.createFormsOutputViewer(toolkit, outputArea, textFieldFlags); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.minimumWidth = 360; + gd.minimumHeight = 120; + // while the rational person would say this width hint is pointless and gets ignored, the Eclipse architect + // would say "hey - no, we use this behind the scenes to influence word wrap on the text component, + // of course" + gd.widthHint = 400; + userOutput.getTextWidget().setLayoutData(gd); + userOutput.getTextWidget().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); + + // ------------------------------------------------------------------- + // progress section + // There is no description line for this section, so it is + // necessary to eliminate that bit in the style flags that + // are passed in. If the bit were not changed to 0, an + // extra empty line would appear below the title. + section = FormHelper.createSpaceGrabbingSectionComposite(body, "Progress Output", " ", toolkit, + (sectionFlags & ~Section.EXPANDED), getExpansionListener()); + sections.put(SEC_PROGRESS, section); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + // we don't want to set gd.grabExcessVerticalSpace = true; because we are initially collapsed + section.setLayoutData(gd); + final Composite progressArea = (Composite) section.getClient(); + progressArea.setLayout(new GridLayout(1, false)); + + // I am regularly stunned by how crappy and quirky SWT is... in this case, if we don't have SWT.WRAP in the, + // flags mask, the below maxWidth is observed on expansion of the text area (which we really don't want) + // but if we turn on WRAP, then the text area expands to fill the entire width but observes width shrinking + // of its parent editor. If we instead use GridLayout (with or without WRAP), width shrinking is + // completely ignored and the width of the text area is the longest line of text... + progressOutput = FormHelper.createFormsOutputViewer(toolkit, progressArea, textFieldFlags); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.minimumWidth = 360; + gd.minimumHeight = 120; + // while the rational person would say this width hint is pointless and gets ignored, the Eclipse architect + // would say "hey - no, we use this behind the scenes to influence word wrap on the text component, + // of course" + gd.widthHint = 400; + progressOutput.getTextWidget().setLayoutData(gd); + progressOutput.getTextWidget().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); + + Vector<Control> controls = new Vector<Control>(); + controls.add(userOutput.getControl()); + controls.add(progressOutput.getControl()); + fontChangeListener = new FontPreferenceChangeListener(controls, ITLCPreferenceConstants.I_TLC_OUTPUT_FONT); + + JFaceResources.getFontRegistry().addListener(fontChangeListener); + + headClientTBM.add(new DynamicContributionItem(new LoadOutputAction())); + } + + class LoadOutputAction extends Action { + public LoadOutputAction() { + super("Load output", TLCUIActivator.imageDescriptorFromPlugin( + TLCUIActivator.PLUGIN_ID, + "icons/full/copy_edit.gif")); + setDescription("Loads the output from an external model run (requires \"-tool\" parameter) corresponding to this model."); + setToolTipText( + "Loads an existing output (e.g. from a standlone TLC run that corresponds to this model). Output has to contain tool markers. Run TLC with \"-tool\" command line parameter. "); + } + + public void run() { + // Get the user input (the path to the TLC output file). + final FileDialog fileDialog = new FileDialog(new Shell()); + final String path = fileDialog.open(); + if (path == null) { + // User cancelled the dialog + return; + } + + // I/O operations should never run inside the UI thread. + final Job j = new WorkspaceJob("Loading output file...") { + public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { + try { + // Import the file into the Toolbox on the file/resource layer. + final TLCOutputSourceRegistry modelCheckSourceRegistry = TLCOutputSourceRegistry + .getModelCheckSourceRegistry(); + modelCheckSourceRegistry + .removeTLCStatusSource(new Model[] { getModel() }); + getModel().createModelOutputLogFile(new FileInputStream(new File(path)), monitor); + + // Once the output has been imported on the + // file/resource layer, update the UI. + final Job job = new UIJob("Updating results page with loaded output...") { + public IStatus runInUIThread(IProgressMonitor monitor) { + try { + ResultPage.this.loadData(); + } catch (CoreException e) { + return new Status(IStatus.ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e); + } + return Status.OK_STATUS; + } + }; + job.schedule(); + + } catch (FileNotFoundException e) { + return new Status(IStatus.ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e); + } + return Status.OK_STATUS; + } + }; + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + j.setRule(workspace.getRuleFactory().buildRule()); + j.schedule(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.action.Action#isEnabled() + */ + public boolean isEnabled() { + if (getModel().isRunning()) { + return false; + } + return super.isEnabled(); + } + } + + /** + * Save data back to model + */ + public void commit(boolean onSave) { + if (expressionEvalInput != null) { + final String expression = expressionEvalInput.getDocument().get(); + getModel().unsavedSetEvalExpression(expression); + } + + super.commit(onSave); + } + + private void setStartTime(final long msTime) { + m_startTimestamp = msTime; + + if (msTime < 0) { + // Leave the starttime text empty on a negative timestamp. A negative one indicates that the + // model has never been checked + // See Long.MIN_VALUE in org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider.initialize() + m_startLabel.setText("Awaiting first run..."); + } else { + m_startLabel.setText("Start: " + DATE_FORMATTER.format(new Date(msTime))); + } + + m_generalTopPane.layout(true, true); + } + + private void setEndTime(final long msTime) { + if (msTime < 0) { + m_finishLabel.setVisible(false); + } else { + m_finishLabel.setText("End: " + DATE_FORMATTER.format(new Date(msTime))); + m_finishLabel.setVisible(true); + } + + m_generalTopPane.layout(true, true); + } + + private void setCheckpoint(final long msTime) { + if (msTime < 0) { + m_lastCheckpointLabel.setVisible(false); + } else { + m_lastCheckpointLabel.setText("Last checkpoint: " + DATE_FORMATTER.format(new Date(msTime))); + m_lastCheckpointLabel.setVisible(true); + } + + m_generalTopPane.layout(true, true); + } + + private void setSearchMode(final String mode) { + if (TLCModelLaunchDataProvider.DEPTH_FIRST_SEARCH.equals(mode)) { + m_tlcSearchModeLabel.setText(TLCModelLaunchDataProvider.DEPTH_FIRST_SEARCH); + m_tlcSearchModeLabel.setVisible(true); + m_tlcSimulationLabel.setVisible(false); + } else { + m_tlcSearchModeLabel.setVisible(false); + m_tlcSimulationLabel.setVisible(TLCModelLaunchDataProvider.SIMULATION_MODE.equals(mode)); + } + + m_generalTopPane.layout(true, true); + } + + private void setErrorPaneVisible(final boolean visible) { + final GridData gd = (GridData)m_generalErrorPane.getLayoutData(); + + gd.exclude = !visible; + m_generalErrorPane.setLayoutData(gd); + + m_generalErrorPane.setVisible(visible); + } + + private int getHeightGuidanceForLabelTextFieldLine(final Composite parent, final FormToolkit toolkit) { + final Label l = toolkit.createLabel(parent, "Just Some Concerned Text you get"); + final Text t = toolkit.createText(parent, "More time text 12345:67890", SWT.FLAT); + + final int height = Math.max(t.computeSize(SWT.DEFAULT, SWT.DEFAULT).y, l.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); + + l.dispose(); + t.dispose(); + + return height; + } + + /** + * Creates the state space table (initializes the {@link stateSpace} variable) + * + * TODO there's definite commonality between this and createAndSetupCoverage - abstract + * + * @param parent + * @param toolkit + * @return the constructed composite + */ + private Composite createAndSetupStateSpace(final Composite parent, final FormToolkit toolkit, final int headerHeight) { + final Composite statespaceComposite = toolkit.createComposite(parent, SWT.WRAP); + GridLayout gl = new GridLayout(1, false); + gl.marginTop = 0; + gl.marginBottom = 3; + gl.marginWidth = 0; + statespaceComposite.setLayout(gl); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + statespaceComposite.setLayoutData(gd); + + + final Label title + = toolkit.createLabel(statespaceComposite, "State space progress (click column header for graph)"); + gd = new GridData(); + gd.heightHint = headerHeight + 2; + gd.horizontalAlignment = SWT.BEGINNING; + gd.horizontalIndent = 0; + gd.verticalIndent = 6; + title.setLayoutData(gd); + + final Composite tableComposite = new Composite(statespaceComposite, SWT.NONE); + final TableColumnLayout tableColumnLayout = new TableColumnLayout(); + tableComposite.setLayout(tableColumnLayout); + final Table stateTable + = toolkit.createTable(tableComposite, (SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.BORDER)); + final StateSpaceLabelProvider sslp = new StateSpaceLabelProvider(this); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + gd.minimumWidth = sslp.getMinimumTotalWidth(); + gd.minimumHeight = 100; + tableComposite.setLayoutData(gd); + + stateTable.setHeaderVisible(true); + stateTable.setLinesVisible(true); + + sslp.createTableColumns(stateTable, this, tableColumnLayout); + + // create the viewer + stateSpace = new TableViewer(stateTable); + + // create list-based content provider + stateSpace.setContentProvider(new IStructuredContentProvider() { + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } + + public void dispose() { } + + public Object[] getElements(Object inputElement) { + if ((inputElement != null) && (inputElement instanceof List)) { + return ((List<?>) inputElement).toArray(new Object[((List<?>) inputElement).size()]); + } + return null; + } + }); + + stateSpace.setLabelProvider(sslp); + getSite().setSelectionProvider(stateSpace); + + return statespaceComposite; + } + + /** + * Creates the coverage table (initializes the {@link coverageTimestamp} and {@link coverage} variables) + * + * TODO there's definite commonality between this and createAndSetupStateSpace - abstract + * + * @param parent + * @param toolkit + * @return returns the containing composite + */ + private Composite createAndSetupCoverage(final Composite parent, final FormToolkit toolkit, final int headerHeight) { + final Composite coverageComposite = toolkit.createComposite(parent, SWT.WRAP); + GridLayout gl = new GridLayout(1, false); + gl.marginTop = 0; + gl.marginBottom = 3; + gl.marginWidth = 0; + coverageComposite.setLayout(gl); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + coverageComposite.setLayoutData(gd); + + + final Composite headerLine = toolkit.createComposite(coverageComposite, SWT.WRAP); + gl = new GridLayout(2, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + headerLine.setLayout(gl); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + headerLine.setLayoutData(gd); + + final Label title = toolkit.createLabel(headerLine, "Actions at"); + gd = new GridData(); + gd.horizontalIndent = 0; + gd.verticalIndent = 6; + gd.heightHint = headerHeight + 2; + gd.horizontalAlignment = SWT.BEGINNING; + gd.verticalAlignment = SWT.BOTTOM; + title.setLayoutData(gd); + + this.coverageTimestampText = toolkit.createText(headerLine, "", SWT.FLAT); + this.coverageTimestampText.setEditable(false); + this.coverageTimestampText.setMessage("No information collected yet. Has coverage been enabled?"); + gd = new GridData(); + gd.horizontalIndent = 6; + gd.verticalIndent = 0; + gd.minimumWidth = 150; + gd.grabExcessHorizontalSpace = true; + gd.horizontalAlignment = SWT.FILL; + this.coverageTimestampText.setLayoutData(gd); + + + final Composite tableComposite = new Composite(coverageComposite, SWT.NONE); + final TableColumnLayout tableColumnLayout = new TableColumnLayout(); + tableComposite.setLayout(tableColumnLayout); + final Table coverageTable + = toolkit.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.BORDER); + final CoverageLabelProvider clp = new CoverageLabelProvider(); + gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + gd.horizontalIndent = 0; + gd.verticalIndent = 0; + gd.minimumWidth = clp.getMinimumTotalWidth(); + gd.heightHint = 100; + tableComposite.setLayoutData(gd); + + coverageTable.setHeaderVisible(true); + coverageTable.setLinesVisible(true); + coverageTable.setToolTipText(CoverageLabelProvider.TOOLTIP); + + clp.createTableColumns(coverageTable, tableColumnLayout); + + // create the viewer + coverage = new TableViewer(coverageTable); + + coverage.getTable().addMouseListener(new RecordToSourceCoupler(coverage)); + + // create list-based content provider + coverage.setContentProvider(new IStructuredContentProvider() { + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } + + public void dispose() { } + + public Object[] getElements(Object inputElement) { + if ((inputElement != null) && (inputElement instanceof List)) { + return ((List<?>) inputElement).toArray(new Object[((List<?>) inputElement).size()]); + } else if (inputElement instanceof CoverageInformation) { + return ((CoverageInformation) inputElement).getSpecActions().toArray(); + } + return null; + } + }); + + coverage.setLabelProvider(clp); + + coverage.setComparator(new CoverageViewerComparator()); + for (TableColumn column : coverage.getTable().getColumns()) { + column.addListener(SWT.Selection, e -> { + final Item sortColumn = coverage.getTable().getSortColumn(); + int direction = coverage.getTable().getSortDirection(); + + if (column.equals(sortColumn)) { + direction = direction == SWT.UP ? SWT.DOWN : SWT.UP; + } else { + coverage.getTable().setSortColumn(column); + direction = SWT.UP; + } + coverage.getTable().setSortDirection(direction); + coverage.refresh(); + }); + } + + getSite().setSelectionProvider(coverage); + + return coverageComposite; + } + + long getStartTimestamp() { + return m_startTimestamp; + } + + TableViewer getStateSpaceTableViewer() { + return stateSpace; + } + + /** + * Returns the StateSpaceInformationItem objects currently being displayed in + * the "State space progress" area, except in temporal order--that is, in the + * opposite order from which they are displayed. + * + * @return + */ + @SuppressWarnings("unchecked") // generics cast + public StateSpaceInformationItem[] getStateSpaceInformation() + { + List<StateSpaceInformationItem> infoList = (List<StateSpaceInformationItem>) stateSpace.getInput(); + StateSpaceInformationItem[] result = new StateSpaceInformationItem[infoList.size()]; + for (int i = 0; i < result.length; i++) + { + result[i] = infoList.get(result.length - i - 1); + } + return result; + + } + + // this is only ever used to fetch ids SEC_GENERAL and SEC_STATISTICS + public Set<Section> getSections(String ...sectionIDs) { + final Set<String> set = new HashSet<String>(Arrays.asList(sectionIDs)); + return sections.entrySet().stream().filter(e -> set.contains(e.getKey())).map(Map.Entry::getValue) + .collect(Collectors.toSet()); + } + + public EvaluateConstantExpressionPage.State getECEContent() { + if (expressionEvalInput != null) { + return new EvaluateConstantExpressionPage.State(expressionEvalInput.getDocument(), + expressionEvalResult.getTextWidget().getText(), m_noBehaviorModeToggleButton.getSelection()); + } + + return null; + } + + public void setECEContent(final EvaluateConstantExpressionPage.State state) { + if (expressionEvalInput == null) { + TLCUIActivator.getDefault().logError("Can't set ECE content on null objects."); + } else { + expressionEvalInput.setDocument(state.getInputDocument()); + expressionEvalResult.getTextWidget().setText(state.getOutputText()); + m_noBehaviorModeToggleButton.setSelection(state.getToggleState()); + } + } + + public void setNoBehaviorSpecToggleState(final boolean selected) { + if (m_noBehaviorModeToggleButton != null) { + m_noBehaviorModeToggleButton.setSelection(selected); + } + } + + public void pageShouldDisplayEvaluateConstantUI(final boolean shouldShow) { + final IManagedForm managedForm = getManagedForm(); + + if (shouldShow) { + final FormToolkit toolkit = managedForm.getToolkit(); + final int sectionFlags = Section.TITLE_BAR | Section.TREE_NODE | Section.EXPANDED | SWT.WRAP; + final int textFieldFlags = SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.FULL_SELECTION | SWT.WRAP; + final EvaluateConstantExpressionPage.BodyContentAssets assets = EvaluateConstantExpressionPage + .createBodyContent(m_calculatorSection, toolkit, sectionFlags, textFieldFlags, + getExpansionListener(), (ModelEditor)getEditor()); + final Section section = assets.getSection(); + + sections.put(SEC_EXPRESSION, section); + + expressionEvalInput = assets.getExpressionInput(); + expressionEvalResult = assets.getExpressionOutput(); + m_noBehaviorModeToggleButton = assets.getToggleButton(); + + m_validateableCalculatorSection = new ValidateableSectionPart(section, this, SEC_EXPRESSION); + // This ensures that when the part is made dirty, the model appears unsaved. + managedForm.addPart(m_validateableCalculatorSection); + + // This makes the widget unsaved when text is entered. + expressionEvalInput.getTextWidget().addModifyListener(new DirtyMarkingListener(m_validateableCalculatorSection, false)); + + getDataBindingManager().bindSection(m_validateableCalculatorSection, SEC_EXPRESSION, getId()); + getDataBindingManager().bindAttribute(Model.MODEL_EXPRESSION_EVAL, expressionEvalInput, m_validateableCalculatorSection); + + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(final ExpansionEvent e) { + if (e.getState()) { + final GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + m_calculatorSection.setLayoutData(gd); + } else { + final GridData gd = (GridData)m_calculatorSection.getLayoutData(); + final Point size = section.computeSize(SWT.DEFAULT, SWT.DEFAULT); + + gd.grabExcessVerticalSpace = e.getState(); + gd.heightHint = size.y; + + m_calculatorSection.setLayoutData(gd); + } + } + }); + } else if (m_validateableCalculatorSection != null) { + sections.remove(SEC_EXPRESSION); + + managedForm.removePart(m_validateableCalculatorSection); + + m_validateableCalculatorSection = null; + expressionEvalInput = null; + expressionEvalResult = null; + m_noBehaviorModeToggleButton = null; + + for (final Control control : m_calculatorSection.getChildren()) { + control.dispose(); + } + + getDataBindingManager().unbindSectionFromPage(SEC_EXPRESSION, getId()); + } + + final GridData gd = (GridData)m_calculatorSection.getLayoutData(); + gd.grabExcessVerticalSpace = shouldShow; + m_calculatorSection.setLayoutData(gd); + + getManagedForm().reflow(true); + } + + + private class GeneralSectionExpansionHoopJumper extends ExpansionAdapter implements Consumer<Boolean> { + public void expansionStateChanged(final ExpansionEvent e) { + accept(Boolean.valueOf(e.getState())); + } + + public void accept(final Boolean expand) { + if (expand.booleanValue()) { + final Composite c = (Composite)m_generalSection.getClient(); + final GridData gd = (GridData)m_generalSection.getLayoutData(); + + gd.heightHint = m_collapsedSectionHeight + c.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + + m_generalSection.setLayoutData(gd); + m_generalSection.getParent().layout(true, true); + } else { + final GridData gd = new GridData(); + gd.horizontalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = SWT.TOP; + m_generalSection.setLayoutData(gd); + + m_collapsedSectionHeight = m_generalSection.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + } + } + } + + + /** + * In an ideal world, we rely upon the associated SWT widgets being able to return a set value for visible and then + * just base our view state on those, except we experience load data in situations in which the "actual" visible + * value does not match what has been set. + */ + static class ErrorPaneViewState { + private final AtomicBoolean m_displayErrorLink; + private final AtomicBoolean m_displayFingerprint; + private final AtomicBoolean m_displayZeroCount; + + ErrorPaneViewState() { + m_displayErrorLink = new AtomicBoolean(false); + m_displayFingerprint = new AtomicBoolean(false); + m_displayZeroCount = new AtomicBoolean(false); + } + + void setErrorLinkDisplay(final boolean display) { + m_displayErrorLink.set(display); + } + + boolean errorLinkIsDisplayed() { + return m_displayErrorLink.get(); + } + + void setFingerprintDisplay(final boolean display) { + m_displayFingerprint.set(display); + } + + boolean fingerprintIsDisplayed() { + return m_displayFingerprint.get(); + } + + void setZeroCountDisplay(final boolean display) { + m_displayZeroCount.set(display); + } + + boolean zeroCountIsDisplayed() { + return m_displayZeroCount.get(); + } + + void clearState() { + m_displayErrorLink.set(false); + m_displayFingerprint.set(false); + m_displayZeroCount.set(false); + } + + boolean shouldDisplay() { + return m_displayErrorLink.get() || m_displayFingerprint.get() || m_displayZeroCount.get(); + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPageColumnListener.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPageColumnListener.java new file mode 100644 index 0000000000000000000000000000000000000000..386c441b7ee0469db9e9564f63e35c73202f35e2 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPageColumnListener.java @@ -0,0 +1,44 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.lamport.tla.toolbox.util.UIHelper; + +/** + * A ResultPageColumnListener is a listener that handles clicks on + * the column headers of the "State space progress" region of the + * Result Page. The same class is used for all the column + * headers, with the column number indicating which column header + * was clicked on. + * + * @author lamport + */ +class ResultPageColumnListener implements SelectionListener { + private final int m_columnNumber; + private final ResultPage m_resultPage; + + public ResultPageColumnListener(final int columnNumber, final ResultPage resultPage) { + m_columnNumber = columnNumber; + m_resultPage = resultPage; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse. + * swt.events.SelectionEvent) + */ + @Override + public void widgetDefaultSelected(final SelectionEvent se) { } + + /** + * This is called when the user clicks on the header of a column of the "State + * space progress" region of the ResultsPage. It raises a window with a graph of + * the specified column. + */ + @Override + public void widgetSelected(final SelectionEvent se) { + UIHelper.runUIAsync(new DataDisplay(m_columnNumber, m_resultPage)); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/StateSpaceLabelProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/StateSpaceLabelProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..fdcb6d9114164d5b16204b996e5fa552dfa6356e --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/StateSpaceLabelProvider.java @@ -0,0 +1,161 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results; + +import java.text.NumberFormat; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.util.AbstractTableLabelProvider; + +/** + * This is the <code>LabelProvider</code> for the state space statistics table found on the Results page. + * + * @see org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.ResultPage + */ +class StateSpaceLabelProvider extends AbstractTableLabelProvider { + static final int COL_TIME = 0; + static final int COL_DIAMETER = 1; + static final int COL_FOUND = 2; + static final int COL_DISTINCT = 3; + static final int COL_LEFT = 4; + + private static final String[] COLUMN_TITLES + = new String[] { "Time", "Diameter", "States Found", "Distinct States", "Queue Size" }; + private static final String NO_DATA_TEXT = "--"; + private static final int[] COLUMN_WIDTHS; + private static final double[] COLUMN_WIDTH_PERCENTAGES; + private static final int MIN_WIDTH; + + static { + final double scale = 1.0; // future functionality: UIHelper.getDisplayScaleFactor(); + + COLUMN_WIDTHS = new int[5]; + COLUMN_WIDTHS[0] = (int) (60.0 * scale); + COLUMN_WIDTHS[1] = (int) (30.0 * scale); + COLUMN_WIDTHS[2] = (int) (40.0 * scale); + COLUMN_WIDTHS[3] = (int) (50.0 * scale); + COLUMN_WIDTHS[4] = (int) (40.0 * scale); + + MIN_WIDTH = COLUMN_WIDTHS[0] + COLUMN_WIDTHS[1] + COLUMN_WIDTHS[2] + COLUMN_WIDTHS[3] + COLUMN_WIDTHS[4]; + + COLUMN_WIDTH_PERCENTAGES = new double[5]; + for (int i = 0; i < 5; i++) { + COLUMN_WIDTH_PERCENTAGES[i] = ((double)COLUMN_WIDTHS[i] / (double)MIN_WIDTH); + } + } + + private boolean m_doHighlight; + private final ResultPage m_resultPage; + + StateSpaceLabelProvider(final ResultPage resultPage) { + super(MIN_WIDTH, COLUMN_TITLES, COLUMN_WIDTH_PERCENTAGES); + + m_doHighlight = false; + m_resultPage = resultPage; + } + + /** + * @param stateTable + */ + void createTableColumns(final Table stateTable, final ResultPage page, final TableColumnLayout layout) { + for (int i = 0; i < COLUMN_TITLES.length; i++) { + final TableColumn column = new TableColumn(stateTable, SWT.NULL); + column.setWidth(COLUMN_WIDTHS[i]); + column.setText(COLUMN_TITLES[i]); + + final int weight = (int)(100.0 * COLUMN_WIDTH_PERCENTAGES[i]); + layout.setColumnData(column, new ColumnWeightData(weight, COLUMN_WIDTHS[i], true)); + + // The following statement attaches a listener to the column header. + // See the ResultPageColumnListener comments. + column.addSelectionListener(new ResultPageColumnListener(i, page)); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) + */ + @Override + public Image getColumnImage(final Object element, final int columnIndex) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) + */ + @Override + public String getColumnText(final Object element, final int columnIndex) { + if (element instanceof StateSpaceInformationItem) { + // the "N/A" values are used for simulation mode + final NumberFormat nf = NumberFormat.getIntegerInstance(); + final StateSpaceInformationItem item = (StateSpaceInformationItem) element; + + switch (columnIndex) { + case COL_TIME: + return TLCModelLaunchDataProvider.formatInterval(m_resultPage.getStartTimestamp(), item.getTime().getTime()); + case COL_DIAMETER: + if (item.getDiameter() >= 0) { + return nf.format(item.getDiameter()); + } else { + return NO_DATA_TEXT; + } + case COL_FOUND: + return nf.format(item.getFoundStates()); + case COL_DISTINCT: + if (item.getDistinctStates() >= 0) { + return nf.format(item.getDistinctStates()); + } else { + return NO_DATA_TEXT; + } + + case COL_LEFT: + if (item.getLeftStates() >= 0) { + return nf.format(item.getLeftStates()); + } else { + return NO_DATA_TEXT; + } + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Color getForeground(final Object element, final int columnIndex) { + return null; // Use default color + } + + /** + * {@inheritDoc} + */ + @Override + public Color getBackground(final Object element, final int columnIndex) { + final StateSpaceInformationItem ssii = (StateSpaceInformationItem) element; + if (m_doHighlight && (columnIndex == COL_LEFT) && ssii.isMostRecent()) { + return TLCUIActivator.getColor(SWT.COLOR_RED); + } + return null; + } + + void setHighlightUnexplored() { + m_doHighlight = true; + } + + void unsetHighlightUnexplored() { + m_doHighlight = false; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java index 433793ca9c9bd8bba67a1a5769827d4f2a5eb69a..c08219885105fbb9c72657ad0757873cd1369e13 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java @@ -155,7 +155,7 @@ public class ValidateableOverridesSectionPart extends ValidateableConstantSectio // if the label is M!N!Foo, this will return Foo as the label. If ! is not used, // it will do nothing. If the definition override is a model value // then the right side will be equal to the label without any !. - // For example if M!N!Foo is overriden as a model value, + // For example if M!N!Foo is overridden as a model value, // the right side of the assignment used to generate the string // in this method will be Foo. tableViewer.setLabelProvider(new LabelProvider() { @@ -166,6 +166,17 @@ public class ValidateableOverridesSectionPart extends ValidateableConstantSectio Assignment assign = (Assignment) element; String label = assign.getLabel(); String noBangLabel = label.substring(label.lastIndexOf("!") + 1); + + // This is upside-down because early in the call stack we had the node instance + // but dropped it and instead serialized parts of it into Assignment. Now we + // have to reconstruct the actual OpDefNode because need to know its module. + // Since this is the standard idiom throughout this part of the model editor, + // I'm not going to rewrite it. + OpDefNode node = ModelHelper.getOpDefNode(label); + if (node != null && node.getSource() != node) { + noBangLabel += " [" + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]"; + } + String rightSide = null; if (assign.isModelValue()) { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java index fd76feeb7578fa47a37e47fcff347351fbb98de7..70a53ce73581ab2708bd21ef998972e1ff749f94 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java @@ -246,7 +246,7 @@ public class ValidateableTableSectionPart extends SectionPart implements IValida buttonAdd.addSelectionListener(fSelectionListener); gd = new GridData(); gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; + gd.horizontalAlignment = SWT.FILL; buttonAdd.setLayoutData(gd); added++; } @@ -258,7 +258,7 @@ public class ValidateableTableSectionPart extends SectionPart implements IValida buttonEdit.addSelectionListener(fSelectionListener); gd = new GridData(); gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; + gd.horizontalAlignment = SWT.FILL; buttonEdit.setLayoutData(gd); added++; } @@ -270,7 +270,7 @@ public class ValidateableTableSectionPart extends SectionPart implements IValida buttonRemove.addSelectionListener(fSelectionListener); gd = new GridData(); gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; + gd.horizontalAlignment = SWT.FILL; buttonRemove.setLayoutData(gd); added++; } @@ -281,7 +281,7 @@ public class ValidateableTableSectionPart extends SectionPart implements IValida gd = new GridData(); gd.verticalSpan = 3 - added; gd.verticalAlignment = SWT.TOP; - gd.widthHint = 70; + gd.horizontalAlignment = SWT.FILL; span.setLayoutData(gd); } } @@ -386,7 +386,9 @@ public class ValidateableTableSectionPart extends SectionPart implements IValida // Create the wizard dialog WizardDialog dialog = new WizardDialog(getTableViewer().getTable().getShell(), wizard); - dialog.setHelpAvailable(true); + // MAK 04/2019: Commented, because setting to true doesn't magically create help + // content. Thus, don't show a no-op help button. + //dialog.setHelpAvailable(true); // Open the wizard dialog if (Window.OK == dialog.open()) diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/CloneModelContributionItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/CloneModelContributionItem.java index 0dac565c4fef51adedf83a6fd85ee6ee251df20c..6f89f7c4d61daa339d75a4cf0d928ee915cc1704 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/CloneModelContributionItem.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/CloneModelContributionItem.java @@ -16,6 +16,7 @@ import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.CommandContributionItemParameter; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.ToolboxHandle; +import org.lamport.tla.toolbox.tool.tlc.handlers.CloneForeignModelHandler; import org.lamport.tla.toolbox.tool.tlc.handlers.CloneModelHandlerDelegate; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; @@ -25,7 +26,6 @@ import org.lamport.tla.toolbox.util.UIHelper; * Contributes a list of models for cloning. * * @author Daniel Ricketts - * */ public class CloneModelContributionItem extends CompoundContributionItem { @@ -36,18 +36,16 @@ public class CloneModelContributionItem extends CompoundContributionItem private ImageDescriptor modelIcon = TLCUIActivator.getImageDescriptor("icons/full/choice_sc_obj.gif"); - protected IContributionItem[] getContributionItems() - { + protected IContributionItem[] getContributionItems() { final Vector<CommandContributionItem> modelContributions = new Vector<CommandContributionItem>(); - Spec currentSpec = ToolboxHandle.getCurrentSpec(); + final Spec currentSpec = ToolboxHandle.getCurrentSpec(); if (currentSpec == null) { return new IContributionItem[0]; } - IProject specProject = currentSpec.getProject(); - - try - { + + final IProject specProject = currentSpec.getProject(); + try { // refresh local to pick up any models that have been added // to the file system but not recognized by the toolbox's resource // framework. @@ -55,23 +53,22 @@ public class CloneModelContributionItem extends CompoundContributionItem // here. Meaning, why doesn't the resource fw handle this case // already? specProject.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor()); - } catch (CoreException e) - { - e.printStackTrace(); + } catch (CoreException e) { + TLCUIActivator.getDefault().logError("Exception encountered refreshing the project.", e); } // First, search for all models for the given spec. final Set<String> modelNames = currentSpec.getAdapter(TLCSpec.class).getModels().keySet(); - for (String modelName : modelNames) { + for (final String modelName : modelNames) { // Next, set the command and the parameters for the command // that will be called when the user selects this item. - Map<String, String> parameters = new HashMap<String, String>(); + final Map<String, String> parameters = new HashMap<String, String>(); // fill the model name for the handler parameters.put(CloneModelHandlerDelegate.PARAM_MODEL_NAME, modelName); // create the contribution item - CommandContributionItemParameter param = new CommandContributionItemParameter(UIHelper + final CommandContributionItemParameter param = new CommandContributionItemParameter(UIHelper .getActiveWindow(), "toolbox.command.model.clone." + modelName, COMMAND_ID_ALWAYS_ENABLED, parameters, modelIcon, null, null, modelName, null, "Clones " + modelName, CommandContributionItem.STYLE_PUSH, null, true); @@ -79,6 +76,12 @@ public class CloneModelContributionItem extends CompoundContributionItem // add contribution item to the list modelContributions.add(new CommandContributionItem(param)); } + final CommandContributionItemParameter param + = new CommandContributionItemParameter(UIHelper.getActiveWindow(), + "toolbox.command.model.cloneforeign", CloneForeignModelHandler.COMMAND_ID, null, null, null, null, + "Foreign Model...", null, "Shows a chooser dialog to select a foreign model.", + CommandContributionItem.STYLE_PUSH, null, true); + modelContributions.add(new CommandContributionItem(param)); return (IContributionItem[]) modelContributions.toArray(new IContributionItem[modelContributions.size()]); } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java index 220185b5b96e6226c82d4d69f91325f4adcbdfc5..c41458c27be49db984d095661985c15cb7e61465 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java @@ -60,7 +60,12 @@ public class ModelContentProvider implements ITreeContentProvider { @Override public void run() { final Model model = event.getModel(); - final TLCSpec parent = model.getSpec(); + // getViewer().remove(...) internally (see + // org.eclipse.jface.viewers.StructuredViewer.findItems(Object)) tries to find + // the TreeItem corresponding to Spec (not TLCSpec). TLCSpec just wraps Spec but + // does not exist in the SpecExplorers content tree. With TLCSpec setSelection + // and remove are actually (silent) no-ops. + final Spec parent = model.getSpec().toSpec(); // The CommonViewer is stupid in that it accesses an element (model) even // after it has been removed in order to update the viewer's current selection. // Since we have to prevent this access to avoid a null pointer, we explicitly diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelSnapshotSorter.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelSnapshotSorter.java index 43a37fa19abbb92afac9948249b30ecd38d79aca..58bffa73e40655ecbb454f9c0c09f94fbfb191e0 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelSnapshotSorter.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelSnapshotSorter.java @@ -2,7 +2,6 @@ package org.lamport.tla.toolbox.tool.tlc.ui.modelexplorer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; - import org.lamport.tla.toolbox.tool.tlc.model.Model; /** diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java index bb4fe333c10a20440991af7e7f2605a8d99ab432..477698bff5cd293d179f4ffde27fc8458cfc80be 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java @@ -8,46 +8,76 @@ import tlc2.tool.fp.FPSet; * TLC preferences * @author Simon Zambrovski */ -public interface ITLCPreferenceConstants -{ - /** - * Maximum number of states to show in {@link TLCErrorView} - */ - public static final String I_TLC_TRACE_MAX_SHOW_ERRORS = "traceMaxShowErrors"; +public interface ITLCPreferenceConstants { /** + * TODO this is not TLC - this is model editor + * * Popup on TLC errors */ public static final String I_TLC_POPUP_ERRORS = "popupOnMCErrors"; /** + * TODO this is not TLC - this is model editor + * * Re-validate model on save */ public static final String I_TLC_REVALIDATE_ON_MODIFY = "revalidateOnModify"; + /** + * TODO this is not TLC - this is model editor + * + * Font used for text in the error viewer at the top of the TLC error view, the + * User Output field on the results page, and the Progress Output on the results + * page. + * + * Note: this preference appears in the preference page General > Appearance > + * Colors and Fonts It is put there by registering an extension to the extension + * point org.eclipse.ui.themes + */ + public static final String I_TLC_OUTPUT_FONT = "org.lamport.tla.toolbox.tool.tlc.ui.tlcOutputFont"; + /** + * TODO this is not TLC - this is model editor + * + * Font used for text in the error trace viewer in the TLC error view. + * + * Note: this preference appears in the preference page General > Appearance > + * Colors and Fonts It is put there by registering an extension to the extension + * point org.eclipse.ui.themes + */ + public static final String I_TLC_ERROR_TRACE_FONT = "org.lamport.tla.toolbox.tool.tlc.ui.tlcErrorTraceFont"; + /** + * TODO this is not TLC - this is model editor + * + * If set, the Toolbox will open a modal progress dialog to indicate TLC + * startup. A user can opt to subsequently suppress the dialog. This returns the + * old behavior prior to the change in https://bugs.eclipse.org/146205#c10. + */ + public static final String I_TLC_SHOW_MODAL_PROGRESS = "showModalProgress"; + /** + * TODO this is not TLC - this is model editor + * + * If set, the Evaluate Constant Expressions section of the Results page will be shown in its own model editor tab. + */ + public static final String I_TLC_SHOW_ECE_AS_TAB = "showECEAsTab"; // /** // * Delete data (.st files and unused checkpoints) from the previous run) // */ // public static final String I_TLC_DELETE_PREVIOUS_FILES = "deleteUnusedMCData"; + + + /** + * Maximum number of states to show in {@link TLCErrorView} + */ + public static final String I_TLC_TRACE_MAX_SHOW_ERRORS = "traceMaxShowErrors"; + + public static final String I_TLC_DEFAULT_WORKERS_COUNT = "tlcWorkersCountDefault"; + public static final String I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT = "maxHeapSizeDefault"; public static final String I_TLC_FPBITS_DEFAULT = "fpBitsDefault"; public static final String I_TLC_MAXSETSIZE_DEFAULT = "maxSetSizeDefault"; - /** - * font used for text in the error viewer at the top of the TLC error - * view, the User Output field on the results page, and the Progress - * Output on the results page. - * - * Note: this preference appears in the preference page General > Appearance > Colors and Fonts - * It is put there by registering an extension to the extension point org.eclipse.ui.themes - */ - public static final String I_TLC_OUTPUT_FONT = "org.lamport.tla.toolbox.tool.tlc.ui.tlcOutputFont"; + /** * Implementation of {@link FPSet} to use during model checking */ public static final String I_TLC_FPSETIMPL_DEFAULT = "fpSetImpl"; - /** - * If set, the Toolbox will open a modal progress dialog to indicate TLC - * startup. A user can opt to subsequently suppress the dialog. This returns the - * old behavior prior to the change in https://bugs.eclipse.org/146205#c10. - */ - public static final String I_TLC_SHOW_MODAL_PROGRESS = "showModalProgress"; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java index 69d260e308408580c1b60725fd385cd1c5eaba1b..69ef319b9946bb404dd0bd40d093d4acee94c539 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java @@ -9,6 +9,7 @@ import org.eclipse.ui.internal.WorkbenchPlugin; import org.lamport.tla.toolbox.tool.tlc.TLCActivator; import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.TLCConsumptionProfile; import org.osgi.service.prefs.BackingStoreException; import tlc2.TLCGlobals; @@ -40,6 +41,9 @@ public class TLCPreferenceInitializer extends AbstractPreferenceInitializer uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS, 10000); uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_POPUP_ERRORS, true); uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_REVALIDATE_ON_MODIFY, true); + uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB, false); + uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_DEFAULT_WORKERS_COUNT, + TLCConsumptionProfile.LOCAL_NORMAL.getWorkerThreads()); uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT, MAX_HEAP_SIZE_DEFAULT); uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_MAXSETSIZE_DEFAULT, TLCGlobals.setBound); uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_FPBITS_DEFAULT, 1); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java index db5554a4821f92befc409f7c7e6b2734e8fe824b..7e2d1f99b337836032222f8246a455cdd8bbb56b 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java @@ -60,6 +60,9 @@ public class TLCPreferencePage extends FieldEditorPreferencePage implements IWor addField(new BooleanFieldEditor(ITLCPreferenceConstants.I_TLC_REVALIDATE_ON_MODIFY, "&Re-validate model on save", getFieldEditorParent())); + addField(new BooleanFieldEditor(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB, + "Show Evaluate Constant Expression in its own tab", getFieldEditorParent())); + IntegerFieldEditor integerFieldEditor = new IntegerFieldEditor(TLCActivator.I_TLC_SNAPSHOT_KEEP_COUNT, "Number of model &snapshots to keep", getFieldEditorParent()); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/AbstractTableLabelProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/AbstractTableLabelProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..1d865d27e36b411045f5d8ccaab9a95b111e3fa4 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/AbstractTableLabelProvider.java @@ -0,0 +1,65 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.util; + +import org.eclipse.jface.viewers.ITableColorProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +/** + * An abstract superclass for label providers. + */ +public abstract class AbstractTableLabelProvider + extends LabelProvider + implements ITableLabelProvider, ITableColorProvider { + private final int m_minimumWidth; + private final String[] m_columnTitles; + private final double[] m_columnWidthPercentages; + + protected AbstractTableLabelProvider(final int minWidth, final String[] titles, final double[] percentages) { + m_minimumWidth = minWidth; + m_columnTitles = titles; + m_columnWidthPercentages = percentages; + } + + /** + * @return the minimum required width of all columns provided + */ + public int getMinimumTotalWidth() { + return m_minimumWidth; + } + + /** + * @param columnIndex the index of the column for which the title is desired + * @return the title for the column at the specified index, or null if the index is out of bounds + */ + public String getColumnTitle(final int columnIndex) { + if ((columnIndex >= 0) && (columnIndex < m_columnTitles.length)) { + return m_columnTitles[columnIndex]; + } + + return null; + } + + /** + * This method will be invoked when the table's size is changing; the provider should size the columns + * appropriately. + * + * @param newTableWidth the new size for the table + */ + public void resizeColumns(final int newTableWidth, final Table table) { + double tableWidth = (double)newTableWidth; + int currentWidthSum = 0; + + for (int i = 0; i < (m_columnWidthPercentages.length - 1); i++) { + final TableColumn column = table.getColumn(i); + final int newWidth = (int)(m_columnWidthPercentages[i] * tableWidth); + + column.setWidth(newWidth); + currentWidthSum += newWidth; + } + + final TableColumn column = table.getColumn(m_columnWidthPercentages.length - 1); + column.setWidth(newTableWidth - currentWidthSum); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..69abb7951836d7037432f3b30e1aa460d0b32ee8 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.util; + +import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; + +import util.ExecutionStatisticsCollector; +import util.ExecutionStatisticsCollector.Selection; + +public class ExecutionStatisticsDialog extends MessageDialog { + + private static final String KEY = "BUTTON_KEY"; + + private final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(); + + public ExecutionStatisticsDialog(final Shell parentShell) { + super(parentShell, "TLA+ execution statistics", (Image) null, "The TLA+ project needs your help!", + MessageDialog.QUESTION, new String[0], 0); + + // Do not block the Toolbox's main window. + setShellStyle(getShellStyle() ^ SWT.APPLICATION_MODAL | SWT.MODELESS); + setBlockOnOpen(false); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.MessageDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(final Composite parent) { + final Button[] buttons = new Button[3]; + buttons[0] = createButton(parent, 0, "&Always Share\nExecution Statistics", false); + buttons[0].setData(KEY, ExecutionStatisticsCollector.Selection.ON); + buttons[1] = createButton(parent, 1, "Share Without\n&Installation Identifier", false); + buttons[1].setData(KEY, ExecutionStatisticsCollector.Selection.RANDOM_IDENTIFIER); + buttons[2] = createButton(parent, 2, "&Never Share\nExecution Statistics", false); + buttons[2].setData(KEY, ExecutionStatisticsCollector.Selection.NO_ESC); + + // Disable the button for the currently active selection. + final Selection selection = esc.get(); + switch (selection) { + case ON: + buttons[0].setEnabled(false); + break; + case RANDOM_IDENTIFIER: + buttons[1].setEnabled(false); + break; + case NO_ESC: + buttons[2].setEnabled(false); + } + + setButtons(buttons); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.MessageDialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String, boolean) + */ + protected Button createButton(Composite parent, int id, String label, boolean defaultButton) { + // increment the number of columns in the button bar + ((GridLayout) parent.getLayout()).numColumns++; + Button button = new Button(parent, SWT.PUSH | SWT.WRAP); // Need wrap here contrary to Dialog#createButton to wrap button label on Windows and macOS(?). + button.setText(label); + button.setFont(JFaceResources.getDialogFont()); + button.setData(Integer.valueOf(id)); + button.addSelectionListener(widgetSelectedAdapter(event -> buttonPressed(((Integer) event.widget.getData()).intValue()))); + if (defaultButton) { + Shell shell = parent.getShell(); + if (shell != null) { + shell.setDefaultButton(button); + } + } + setButtonLayoutData(button); + return button; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.MessageDialog#createCustomArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createCustomArea(Composite parent) { + final Composite c = new Composite(parent, SWT.BORDER); + c.setLayout(new GridLayout()); + c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + final String txt = String.format("%s" + + "* Total number of cores and cores assigned to TLC\n" + + "* Heap and off-heap memory allocated to TLC\n" + + "* TLC's version (git commit SHA)\n" + + "* If breadth-first search, depth-first search or simulation mode is active\n" + + "* TLC's implementation for the sets of seen and unseen states\n" + + "* If TLC has been launched from the TLA Toolbox\n" + + "* Name, version, and architecture of your operating system\n" + + "* Vendor, version, and architecture of your Java virtual machine\n" + + "* The current date and time\n" + + "* An installation identifier which allows us to group execution statistics\n\n" + + "The execution statistics do not contain personal information. If you wish to revoke\n" + + "your consent to share execution statistics at a later point, please chose \n" + + "\"Never Share Execution Statistics\" below by re-opening this dialog via\n" + + "Help > Opt In/Out Execution Statistics accessible from the Toolbox's main menu.", prettyPrintSelection2(esc)); + + final StyledText st = new StyledText(c, SWT.SHADOW_NONE | SWT.WRAP); + st.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + st.setEnabled(true); + st.setEditable(false); + st.setText(txt); + + final StyleRange[] ranges = new StyleRange[2]; + ranges[0] = new StyleRange(txt.indexOf("(TLC) execution statistics"), "(TLC) execution statistics".length(), null, null); + ranges[0].underline = true; + ranges[0].underlineStyle = SWT.UNDERLINE_LINK; + ranges[0].data = "https://exec-stats.tlapl.us"; + + ranges[1] = new StyleRange(txt.indexOf("git commit SHA"), "git commit SHA".length(), null, null); + ranges[1].underline = true; + ranges[1].underlineStyle = SWT.UNDERLINE_LINK; + ranges[1].data = "https://git-scm.com/book/en/v2/Git-Internals-Git-Objects"; + + st.setStyleRanges(ranges); + st.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(final MouseEvent event) { + final int offset = st.getOffsetAtPoint(new Point(event.x, event.y)); + if (offset < 0 || offset >= st.getCharCount()) { + return; + } + final StyleRange style = st.getStyleRangeAtOffset(offset); + if (style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK && style.data instanceof String) { + try { + PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL((String) style.data)); + } catch (PartInitException | MalformedURLException notExpectedToHappen) { + notExpectedToHappen.printStackTrace(); + } + } + } + }); + + return c; + } + + private static String prettyPrintSelection2(final ExecutionStatisticsCollector esc) { + switch (esc.get()) { + case ON: + return String.format( + "Thank you for sharing (TLC) execution statistics with installation identifier\n%s.\n\nExecution Statistics help us make informed decisions about future research and\ndevelopment directions. Execution statistics contain the following information:\n\n", + esc.getIdentifier()); + case RANDOM_IDENTIFIER: + return "Thank you for sharing (TLC) execution statistics. Execution Statistics help us\nmake informed decisions about future research anddevelopment directions.\nExecution statistics contain the following information:\n\n"; + } + return "Please opt-in and share (TLC) execution statistics. Execution statistics contain\nthe following information:\n\n"; + } + + @Override + protected void buttonPressed(final int buttonId) { + final ExecutionStatisticsCollector.Selection col = (Selection) getButton(buttonId).getData(KEY); + final Job j = new Job("Write Execution Statistics Preference.") { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + esc.set(col); + } catch (IOException e) { + return new Status(ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e); + } + return Status.OK_STATUS; + } + }; + j.schedule(); + + super.buttonPressed(buttonId); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..7341fe4de9ac1e0aed44a46b4e9e8d7621c9b717 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.util; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +public class ExecutionStatisticsHandler extends AbstractHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + new ExecutionStatisticsDialog(HandlerUtil.getActiveShellChecked(event)).open(); + return null; + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExpandableSpaceReclaimer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExpandableSpaceReclaimer.java new file mode 100644 index 0000000000000000000000000000000000000000..070a193f9700f57790f0a8eb82d964c96a97b217 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExpandableSpaceReclaimer.java @@ -0,0 +1,157 @@ +package org.lamport.tla.toolbox.tool.tlc.ui.util; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.events.IExpansionListener; +import org.eclipse.ui.forms.widgets.Section; + +/** + * There are a few scenarios in which we want the collapse of a section to force a neighboring component to expand into + * that space. This class begins to address that. + * + * <b>Note</b> this class presently only handles N-child SashForms and is only coded to handle those with vertical + * layout. + */ +public class ExpandableSpaceReclaimer implements IExpansionListener { + private static final double MINIMUM_SASH_PART_PERCENTAGE = 0.1; + + + private final Section m_section; + private final SashForm m_sashForm; + + private final int m_sectionIndex; + private final int m_otherChildrenCount; + + private Point m_lastSectionSizeOnCollapse; + + /** + * An instance should be constructed only after all children have been added to the sash form. + * + * @param s the section which we will listen for collapse and expansion on + * @param sf the sash form in which the section sits + * @throws IllegalArgumentException if the section is not one of the sash form's children + */ + public ExpandableSpaceReclaimer(final Section s, final SashForm sf) { + m_section = s; + m_sashForm = sf; + + final Control[] children = m_sashForm.getChildren(); + int index = -1; + for (int i = 0; i < children.length; i++) { + if (s == children[i]) { + index = i; + + break; + } + } + + if (index == -1) { + throw new IllegalArgumentException("Section could not be found in the sash form."); + } + + m_sectionIndex = index; + m_otherChildrenCount = children.length - 1; + m_section.addExpansionListener(this); + + m_lastSectionSizeOnCollapse = null; + } + + @Override + public void expansionStateChanging(final ExpansionEvent ee) { + if (!ee.getState()) { + m_lastSectionSizeOnCollapse = m_section.getSize(); + } + } + + @Override + public void expansionStateChanged(final ExpansionEvent ee) { + final Point sashFormSize = m_sashForm.getSize(); + final int totalSashConsumption = m_sashForm.getSashWidth() * m_otherChildrenCount; + + if (ee.getState()) { // => now expanded + final Point desiredSize = (m_lastSectionSizeOnCollapse != null) + ? m_lastSectionSizeOnCollapse + : m_section.computeSize(SWT.DEFAULT, SWT.DEFAULT, false); + + if (m_sashForm.getOrientation() == SWT.VERTICAL) { + final int minimumHeight = (int)(MINIMUM_SASH_PART_PERCENTAGE * (double)sashFormSize.y); + final int totalMinimumHeight = (minimumHeight * m_otherChildrenCount) + totalSashConsumption; + final double usableSashFormHeight = sashFormSize.y - totalSashConsumption; + + if (desiredSize.y < (sashFormSize.y - totalMinimumHeight)) { + final double remainingHeight = usableSashFormHeight - desiredSize.y; + final int[] weights = m_sashForm.getWeights(); + double sumOfOtherWeights = 0; + + for (int i = 0; i < weights.length; i++) { + if (i != m_sectionIndex) { + sumOfOtherWeights += weights[i]; + } + } + + final double[] newHeights = new double[weights.length]; + int heightSum = 0; + for (int i = 0; i < weights.length; i++) { + if (i != m_sectionIndex) { + final double percentage = (double)weights[i] / sumOfOtherWeights; + newHeights[i] = (int)(percentage * remainingHeight); + heightSum += newHeights[i]; + } + } + newHeights[m_sectionIndex] = usableSashFormHeight - heightSum; + + final int[] newWeights = new int[weights.length]; + for (int i = 0; i < weights.length; i++) { + newWeights[i] = (int)(newHeights[i] * 100.0 / usableSashFormHeight); + } + + m_sashForm.setWeights(newWeights); + } // else let the user fend for themselves + } else { + final int minimumWidth = (int)(MINIMUM_SASH_PART_PERCENTAGE * (double)sashFormSize.x); + final int totalMinimumWidth = (minimumWidth + m_sashForm.getSashWidth()) * m_otherChildrenCount; + + if (desiredSize.x < (sashFormSize.x - totalMinimumWidth)) { + + } // else let the user fend for themselves + } + } else { + final Point sectionSize = m_section.getSize(); + final Point sectionClientSize = m_section.getClient().getSize(); + + if (m_sashForm.getOrientation() == SWT.VERTICAL) { + final double titleBarHeight = sectionSize.y - sectionClientSize.y; + final double usableSashFormHeight = sashFormSize.y - (totalSashConsumption + titleBarHeight); + final int[] weights = m_sashForm.getWeights(); + double sumOfOtherWeights = 0; + + for (int i = 0; i < weights.length; i++) { + if (i != m_sectionIndex) { + sumOfOtherWeights += weights[i]; + } + } + + final double[] newHeights = new double[weights.length]; + for (int i = 0; i < weights.length; i++) { + if (i != m_sectionIndex) { + final double percentage = (double)weights[i] / sumOfOtherWeights; + newHeights[i] = (int)(percentage * usableSashFormHeight); + } + } + newHeights[m_sectionIndex] = (int)titleBarHeight; + + final int[] newWeights = new int[weights.length]; + for (int i = 0; i < weights.length; i++) { + newWeights[i] = (int)(newHeights[i] * 100.0 / usableSashFormHeight); + } + + m_sashForm.setWeights(newWeights); + } else { + + } + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java index 69d600ce1402750d8ea7c31bf8c31ed5a8baff78..6c6a8f58eecfd869816b7ab5c163a9fd4a042982 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java @@ -1,6 +1,6 @@ package org.lamport.tla.toolbox.tool.tlc.ui.util; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -17,13 +17,15 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; import org.eclipse.ui.forms.events.IExpansionListener; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Hyperlink; import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.forms.widgets.TableWrapLayout; import org.lamport.tla.toolbox.tool.tlc.model.Assignment; import org.lamport.tla.toolbox.tool.tlc.model.Formula; @@ -43,6 +45,9 @@ public class FormHelper public static final int FORM_BODY_MARGIN_RIGHT = 6; public static final int FORM_BODY_HORIZONTAL_SPACING = 20; public static final int FORM_BODY_VERTICAL_SPACING = 17; + + /** Sections created by this class will have this data key if they should not be altered on collapse expand for resizing. **/ + public static final String SECTION_IS_NOT_SPACE_GRABBING = "_no_space_grab"; /** * Create TableWrapLayout for the whole page @@ -109,11 +114,9 @@ public class FormHelper public static Section createSectionComposite(Composite parent, String title, String description, FormToolkit toolkit, int sectionFlags, IExpansionListener expansionListener) { - Section section = toolkit.createSection(parent, sectionFlags); + final Section section = toolkit.createSection(parent, sectionFlags); - TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB); - td.grabHorizontal = true; - section.setLayoutData(td); + section.setData(SECTION_IS_NOT_SPACE_GRABBING, new Object()); section.setText(title); section.setDescription(description); @@ -133,6 +136,56 @@ public class FormHelper toolkit.paintBordersFor(sectionClient); return section; } + + /** + * This creates a section composite which does its best to result in neighboring sections grabbing available + * space when the section collapses. + * + * @param parent + * @param title + * @param description + * @param toolkit + * @param sectionFlags + * @param expansionListener + * @return + */ + public static Section createSpaceGrabbingSectionComposite(final Composite parent, final String title, final String description, + final FormToolkit toolkit, final int sectionFlags, final IExpansionListener expansionListener) { + final Section section = toolkit.createSection(parent, sectionFlags); + + section.setText(title); + section.setDescription(description); + + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(final ExpansionEvent e) { + final GridData gd = (GridData)section.getLayoutData(); + + gd.grabExcessVerticalSpace = e.getState(); + + section.setLayoutData(gd); + + if (e.getState()) { + ((Composite)section.getClient()).layout(true, true); + } + } + }); + + if (expansionListener != null) { + section.addExpansionListener(expansionListener); + } + + // create section client + final Composite sectionClient = toolkit.createComposite(section); + final TableWrapLayout layout = new TableWrapLayout(); + layout.numColumns = 1; + sectionClient.setLayout(layout); + section.setClient(sectionClient); + + // draw flat borders + toolkit.paintBordersFor(sectionClient); + + return section; + } /** * @see {@link FormHelper#createSectionComposite(String, String, FormToolkit, Composite, int)} @@ -159,7 +212,7 @@ public class FormHelper SourceViewer sourceViewer = createSourceViewer(parent, flags, config); sourceViewer.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); - sourceViewer.getTextWidget().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); + sourceViewer.getTextWidget().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); toolkit.adapt(sourceViewer.getTextWidget(), true, true); return sourceViewer; @@ -177,7 +230,7 @@ public class FormHelper SourceViewer sourceViewer = createOutputViewer(parent, flags); sourceViewer.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); - sourceViewer.getTextWidget().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); + sourceViewer.getTextWidget().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); toolkit.adapt(sourceViewer.getTextWidget(), true, true); return sourceViewer; @@ -230,49 +283,28 @@ public class FormHelper * @param source - viewer containing the formulas/assignments * @return */ - public static List<String> getSerializedInput(TableViewer table) - { - if (table instanceof CheckboxTableViewer) - { - CheckboxTableViewer source = (CheckboxTableViewer) table; - @SuppressWarnings("unchecked") - List<Formula> formulas = (List<Formula>) source.getInput(); - Object[] checkedArray = source.getCheckedElements(); - - if (formulas == null) - { - return null; - } - - Vector<String> result = new Vector<String>(formulas.size()); - List<Object> checked = Arrays.asList(checkedArray); - - Iterator<Formula> formulaIterator = formulas.iterator(); - - Formula formula; - String entry; - while (formulaIterator.hasNext()) - { - formula = formulaIterator.next(); - entry = ((checked.contains(formula)) ? "1" : "0") + formula.toString(); - result.add(entry); - } + public static List<String> getSerializedInput(final TableViewer tableViewer) { + if (tableViewer instanceof CheckboxTableViewer) { + final ArrayList<String> result = new ArrayList<>(); + final TableItem[] tableItems = tableViewer.getTable().getItems(); + final int itemCount = tableItems.length; + for (int i = 0; i < itemCount; i++) { + final TableItem item = tableItems[i]; + final String serialized = (item.getChecked() ? "1" : "0") + item.getText(); + + result.add(serialized); + } return result; - - } else - { + } else { @SuppressWarnings("unchecked") - List<Assignment> assignments = (List<Assignment>) table.getInput(); - if (assignments == null) - { - return null; - } + List<Assignment> assignments = (List<Assignment>) tableViewer.getInput(); + if (assignments == null) { + return null; + } return ModelHelper.serializeAssignmentList(assignments); - } - } /** @@ -369,16 +401,14 @@ public class FormHelper */ public static Hyperlink createHyperlinkLeft(String title, Composite parent, FormToolkit toolkit) { - Label createLabel = toolkit.createLabel(parent, title); + final Label createLabel = toolkit.createLabel(parent, title); GridData gd = new GridData(); - createLabel.setLayoutData(gd); gd.verticalAlignment = SWT.TOP; + createLabel.setLayoutData(gd); - Hyperlink hyperlink = toolkit.createHyperlink(parent, "", SWT.RIGHT); - gd = new GridData(SWT.FILL, SWT.LEFT, true, false); + final Hyperlink hyperlink = toolkit.createHyperlink(parent, "", SWT.RIGHT); + gd = new GridData(SWT.FILL, SWT.TOP, true, false); gd.horizontalIndent = 30; - gd.verticalAlignment = SWT.TOP; - gd.horizontalAlignment = SWT.RIGHT; gd.minimumWidth = 300; hyperlink.setLayoutData(gd); @@ -394,16 +424,14 @@ public class FormHelper */ public static Text createTextLeft(String title, Composite parent, FormToolkit toolkit) { - Label createLabel = toolkit.createLabel(parent, title); + final Label createLabel = toolkit.createLabel(parent, title); GridData gd = new GridData(); - createLabel.setLayoutData(gd); gd.verticalAlignment = SWT.TOP; + createLabel.setLayoutData(gd); - Text text = toolkit.createText(parent, ""); - gd = new GridData(SWT.FILL, SWT.LEFT, true, false); + final Text text = toolkit.createText(parent, ""); + gd = new GridData(SWT.FILL, SWT.TOP, true, false); gd.horizontalIndent = 30; - gd.verticalAlignment = SWT.TOP; - gd.horizontalAlignment = SWT.RIGHT; gd.minimumWidth = 400; text.setLayoutData(gd); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ActionClickListener.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java similarity index 51% rename from org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ActionClickListener.java rename to org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java index 8654c0a616ed3fdd8a2de275222acb757941b5da..cbf422d309bc5b20a7ded45775954e7bbdb84993 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ActionClickListener.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java @@ -1,5 +1,9 @@ package org.lamport.tla.toolbox.tool.tlc.ui.util; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + import org.eclipse.core.runtime.Platform; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; @@ -12,6 +16,8 @@ import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.texteditor.ITextEditor; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; @@ -24,8 +30,8 @@ import tla2sany.st.Location; /** * A listener that will respond to the user double clicking or selecting an * action by opening the module containing that action and highlighting the - * action. Can jump to the location in a saved module editor if such an editor - * is already open. + * action; this also supports a jump to the location in a saved module editor if + * such an editor is already open. * * Currently, double clicking or selecting something in a viewer with this as a * listener will only do something if the selection is an instance of @@ -35,51 +41,112 @@ import tla2sany.st.Location; * implement that interface. * * @author Daniel Ricketts - * */ -public class ActionClickListener implements MouseListener, KeyListener { +public class RecordToSourceCoupler implements MouseListener, KeyListener { + /** + * @see RecordToSourceCoupler#RecordToSourceCoupler(Viewer, Set, IWorkbenchPart, FocusRetentionPolicy) + */ + public enum FocusRetentionPolicy { + /** All actions that are responded to keep focus in the defined workbench part **/ + ALWAYS, + /** Only actions that are triggered by arrow key traversals keep focus in the defined workbench part **/ + ARROW_KEY_TRAVERSAL; + } + + /** + * @see #setNonDefaultObservables(int) + */ + public static final int OBSERVE_DEFAULT = 0; + public static final int OBSERVE_ARROW_KEY = 1 << 1; + public static final int OBSERVE_SINGLE_CLICK = 1 << 2; + private final Viewer viewer; + private final Set<Class<? extends ITextEditor>> blacklist; + private final IWorkbenchPart partToRefocus; + + private final AtomicBoolean observeArrowKeyEvents; + private final AtomicBoolean observeSingleClickEvents; + + private final FocusRetentionPolicy focusRetentionPolicy; + + public RecordToSourceCoupler(final Viewer viewer) { + this(viewer, new HashSet<Class<? extends ITextEditor>>()); + } - public ActionClickListener(final Viewer viewer) { - this.viewer = viewer; + public RecordToSourceCoupler(final Viewer variableViewer, final Set<Class<? extends ITextEditor>> editorBlacklist) { + this(variableViewer, editorBlacklist, null, null); + } + + /** + * @param workbenchPart if this is non-null, then the potential part focus change which may occur due to Location-based + * viewing will be followed with first a focus on to this, followed by a focus to the + * <code>variableViewer</code>'s control. + * @param focusPolicy under what conditions focus retention on the above workbench part is preserved + */ + public RecordToSourceCoupler(final Viewer variableViewer, final Set<Class<? extends ITextEditor>> editorBlacklist, + final IWorkbenchPart workbenchPart, final FocusRetentionPolicy focusPolicy) { + viewer = variableViewer; + blacklist = editorBlacklist; + partToRefocus = workbenchPart; + observeArrowKeyEvents = new AtomicBoolean(false); + observeSingleClickEvents = new AtomicBoolean(false); + focusRetentionPolicy = focusPolicy; + } + + /** + * @param observablesMask either OBSERVE_DEFAULT (turning off any changes in + * default behavior or a bitwise-OR'd combination of the + * OBSERVE_* constants) + */ + public void setNonDefaultObservables(final int observablesMask) { + observeArrowKeyEvents.set((observablesMask & OBSERVE_ARROW_KEY) == OBSERVE_ARROW_KEY); + observeSingleClickEvents.set((observablesMask & OBSERVE_SINGLE_CLICK) == OBSERVE_SINGLE_CLICK); } /* (non-Javadoc) * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) */ - public void mouseDoubleClick(MouseEvent event) { - goToAction(viewer.getSelection(), (event.stateMask & SWT.CTRL) != 0); + public void mouseDoubleClick(final MouseEvent event) { + performSourceCoupling(viewer.getSelection(), ((event.stateMask & SWT.MOD1) != 0), false); } /* (non-Javadoc) * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) */ - public void mouseDown(MouseEvent e) {} + public void mouseDown(final MouseEvent event) {} /* (non-Javadoc) * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) */ - public void mouseUp(MouseEvent e) {} + public void mouseUp(final MouseEvent event) { + if (observeSingleClickEvents.get()) { + performSourceCoupling(viewer.getSelection(), ((event.stateMask & SWT.MOD1) != 0), false); + } + } /* (non-Javadoc) * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) */ - public void keyPressed(KeyEvent e) {} + public void keyPressed(final KeyEvent event) {} /* (non-Javadoc) * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) */ public void keyReleased(final KeyEvent event) { - if (event.keyCode == SWT.CR) { - goToAction(viewer.getSelection(), (event.stateMask & SWT.CTRL) != 0); - } else if (event.keyCode == SWT.KEYPAD_DIVIDE && (event.stateMask & SWT.ALT) != 0 - && this.viewer instanceof TreeViewer) { - ((TreeViewer) this.viewer).collapseAll(); + final int code = event.keyCode; + + if (code == SWT.CR) { + performSourceCoupling(viewer.getSelection(), ((event.stateMask & SWT.MOD1) != 0), false); + } else if ((code == SWT.KEYPAD_DIVIDE) && ((event.stateMask & SWT.ALT) != 0) && (viewer instanceof TreeViewer)) { + ((TreeViewer) viewer).collapseAll(); + } else if (observeArrowKeyEvents.get() && ((code == SWT.ARROW_UP) || (code == SWT.ARROW_DOWN)) + && (viewer instanceof TreeViewer)) { + performSourceCoupling(viewer.getSelection(), false, true); } } - private void goToAction(final ISelection selection, boolean jumpToPCal) { + private void performSourceCoupling(final ISelection selection, final boolean jumpToPCal, final boolean dueToArrowKeys) { if (selection != null && !selection.isEmpty()) { if (selection instanceof StructuredSelection) { final StructuredSelection structuredSelection = (StructuredSelection) selection; @@ -98,7 +165,7 @@ public class ActionClickListener implements MouseListener, KeyListener { }); } else if (firstElement instanceof IModuleLocatable) { final IModuleLocatable moduleLocatable = (IModuleLocatable) firstElement; - Location location = moduleLocatable.getModuleLocation(); + final Location location = moduleLocatable.getModuleLocation(); if (location != null) { /* * jumpToNested will be true if the location could be @@ -107,10 +174,20 @@ public class ActionClickListener implements MouseListener, KeyListener { */ Model model = ToolboxHandle.getCurrentSpec().getAdapter(TLCSpec.class).getModel(moduleLocatable .getModelName()); - final boolean jumpedToNested = TLCUIHelper - .jumpToSavedLocation(location, model); - if (!jumpedToNested) { - UIHelper.jumpToLocation(location, jumpToPCal); + if (!TLCUIHelper.jumpToSavedLocation(location, model, blacklist)) { + final IWorkbenchPart iwp; + if (dueToArrowKeys || FocusRetentionPolicy.ALWAYS.equals(focusRetentionPolicy)) { + iwp = partToRefocus; + } else { + iwp = null; + } + UIHelper.jumpToLocation(location, jumpToPCal, iwp); + + if (iwp != null) { + viewer.getControl().getDisplay().asyncExec(() -> { + viewer.getControl().forceFocus(); + }); + } } } } else if (!Platform.getWS().equals(Platform.WS_WIN32) && viewer instanceof TreeViewer) { @@ -126,8 +203,8 @@ public class ActionClickListener implements MouseListener, KeyListener { } } + public static class LoaderTLCState extends TLCState { - private final TLCError error; private final int numberOfStatesToShow; private final TreeViewer viewer; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/SemanticHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/SemanticHelper.java index d6b146686fd46471a9e191e118304985c83967ff..7eb89af902bc604ae5b06b1d01b4b08ea14394e8 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/SemanticHelper.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/SemanticHelper.java @@ -13,7 +13,7 @@ import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.Context; import tla2sany.semantic.ExternalModuleTable; import tla2sany.semantic.ModuleNode; -import tlc2.tool.ModelConfig; +import tlc2.tool.impl.ModelConfig; import util.UniqueString; /** @@ -35,9 +35,9 @@ public class SemanticHelper */ public static final String TLA_BUILTIN = "--TLA+ BUILTINS--"; - private static Set CONFIG_KEYWORDS = new HashSet(Arrays.asList(ModelConfig.ALL_KEYWORDS)); + private static Set<String> CONFIG_KEYWORDS = new HashSet<>(Arrays.asList(ModelConfig.ALL_KEYWORDS)); - private Hashtable pageStorage; + private Hashtable<Object, Hashtable<String, String>> pageStorage; private Context specContext; private Set<String> keywords = ITLAReserveredWords.ALL_WORDS_SET; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java index 27cbb891061321cbdb18522e02fffd26249da97c..31b2ccec4c371da286e4078d88a160f8cb19cacf 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java @@ -1,7 +1,9 @@ package org.lamport.tla.toolbox.tool.tlc.ui.util; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -75,8 +77,9 @@ public class TLCUIHelper } } - protected static List<StyleRange> setTLCLocationHyperlinks(String text) { + protected static List<StyleRange> setTLCLocationHyperlinks(final String text) { final List<StyleRange> result = new ArrayList<StyleRange>(); + String mutableText = text; /* * Will be set to the module name @@ -87,7 +90,7 @@ public class TLCUIHelper * the module, but it is the same as the module in the * error reported by TLC for the failed assertion. */ - String pcalModuleName = null; + String moduleName = null; /* * For each Pattern defined in the Location class, we find @@ -97,25 +100,24 @@ public class TLCUIHelper * to nullLoc, or point to the MC or TE modules. */ Matcher matcher; - for (int i = 0; i < Location.ALL_PATTERNS.length; i++) - { - matcher = Location.ALL_PATTERNS[i].matcher(text); - while (matcher.find()) - { + for (int i = 0; i < Location.ALL_PATTERNS.length; i++) { + matcher = Location.ALL_PATTERNS[i].matcher(mutableText); + while (matcher.find()) { final String locationString = matcher.group(); - - // "consume" location string to prevent pcal matcher from consuming the same text again - // @see Bug #269 in general/bugzilla/index.html - text = text.replace(locationString, ""); - - Location location = Location.parseLocation(locationString); - if (location != null && !location.equals(Location.nullLoc) + final Location location = Location.parseLocation(locationString); + if ((location != null) + && !location.equals(Location.nullLoc) && !location.source().equals(ModelHelper.MC_MODEL_NAME) - && !location.source().equals(ModelHelper.TE_MODEL_NAME)) - { - pcalModuleName = location.source(); + && !location.source().equals(ModelHelper.TE_MODEL_NAME)) { + moduleName = location.source(); result.add(getHyperlinkStyleRange(location, matcher.start(), matcher.end())); } + + // remove the matched location string to prevent PCAL_LOC_PATTERN's matcher from consuming + // the same text again in the below code; should there ever be multiple markers + // with the same location string, this would potentially cause problems. + // @see Bug #269 in general/bugzilla/index.html + mutableText = mutableText.replace(locationString, ""); } } @@ -124,25 +126,22 @@ public class TLCUIHelper * of assertion failure statements where the assertion was * written in PlusCal. */ - matcher = PCAL_LOC_PATTERN.matcher(text); - if (matcher.find()) - { - try - { - Assert - .isNotNull(pcalModuleName, + matcher = PCAL_LOC_PATTERN.matcher(mutableText); + if (matcher.find()) { + try { + Assert.isNotNull(moduleName, "Found a plus cal assertion failed location without a TLC error location with the module name."); - int beginLine = Integer.parseInt(matcher.group(1)); - int beginColumn = Integer.parseInt(matcher.group(2)); + final int beginLine = Integer.parseInt(matcher.group(1)); + final int beginColumn = Integer.parseInt(matcher.group(2)); + final Location l = new Location(UniqueString.uniqueStringOf(moduleName), beginLine, beginColumn, + beginLine, beginColumn); - result.add(getHyperlinkStyleRange(new Location(UniqueString - .uniqueStringOf(pcalModuleName), beginLine, beginColumn, beginLine, beginColumn), matcher - .start(), matcher.end())); - } catch (NumberFormatException e) - { + result.add(getHyperlinkStyleRange(l, matcher.start(), matcher.end())); + } catch (NumberFormatException e) { TLCUIActivator.getDefault().logError("Error parsing PlusCal assertion failed location.", e); } } + return result; } @@ -159,6 +158,11 @@ public class TLCUIHelper * @param model */ public static void openTLCLocationHyperlink(StyledText styledText, MouseEvent trigger, Model model) + { + openTLCLocationHyperlink(styledText, trigger, model, new HashSet<>()); + } + + public static void openTLCLocationHyperlink(StyledText styledText, MouseEvent trigger, Model model, Set<Class<? extends ITextEditor>> blacklist) { try { @@ -169,10 +173,10 @@ public class TLCUIHelper Object data = range.data; if (data instanceof Location) { - boolean jumpToSavedModule = jumpToSavedLocation((Location) data, model); + boolean jumpToSavedModule = jumpToSavedLocation((Location) data, model, blacklist); if (!jumpToSavedModule) { - UIHelper.jumpToLocation((Location) data, (trigger.stateMask & SWT.CTRL) != 0); + UIHelper.jumpToLocation((Location) data, (trigger.stateMask & SWT.MOD1) != 0, null); } } } @@ -231,6 +235,12 @@ public class TLCUIHelper * @return */ public static boolean jumpToSavedLocation(Location location, Model model) + { + return jumpToSavedLocation(location, model, new HashSet<>()); + } + + public static boolean jumpToSavedLocation(Location location, Model model, + Set<Class<? extends ITextEditor>> blacklist) { IEditorPart editor = model.getAdapter(ModelEditor.class); if (editor instanceof ModelEditor) @@ -239,7 +249,7 @@ public class TLCUIHelper ITextEditor moduleEditor = modelEditor.getSavedModuleEditor(location.source()); - if (moduleEditor != null) + if (moduleEditor != null && !blacklist.contains(moduleEditor.getClass())) { try { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUINotification.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUINotification.java new file mode 100644 index 0000000000000000000000000000000000000000..913cd87a1fdf52c071f9c00c452c8033c4a3c0cc --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUINotification.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.ui.util; + +import java.util.Date; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.mylyn.commons.notifications.ui.AbstractUiNotification; +import org.eclipse.swt.graphics.Image; + +@SuppressWarnings("restriction") +public class TLCUINotification extends AbstractUiNotification { + + private final String label; + private final String description; + private final Date date; + + private Image image; + private Image kindImage; + + public TLCUINotification(final String label, final String description, final Date date) { + super("org.lamport.tla.toolbox.tool.tlc.ui.notification.event"); + this.label = label; + this.description = description; + this.date = date; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @Override + public <T> T getAdapter(Class<T> adapter) { + return Platform.getAdapterManager().getAdapter(this, adapter); + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.core.AbstractNotification#getDate() + */ + @Override + public Date getDate() { + return date; + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.core.AbstractNotification#getDescription() + */ + @Override + public String getDescription() { + return description; + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.core.AbstractNotification#getLabel() + */ + @Override + public String getLabel() { + return label; + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.ui.AbstractUiNotification#getNotificationImage() + */ + @Override + public Image getNotificationImage() { + return image; + } + + public TLCUINotification setImage(Image image) { + return this; + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.ui.AbstractUiNotification#getNotificationKindImage() + */ + @Override + public Image getNotificationKindImage() { + return kindImage; + } + + public TLCUINotification setKindImage(Image image) { + this.kindImage = image; + return this; + } + + /* (non-Javadoc) + * @see org.eclipse.mylyn.commons.notifications.ui.AbstractUiNotification#open() + */ + @Override + public void open() { + // Do nothing + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java index 1cc678e03ae5f7aa28dea45b73263e694e2a8327..2bb06132121c8663aab2ff61f4bd0f03cb1eab8e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java @@ -1,1345 +1,1513 @@ -package org.lamport.tla.toolbox.tool.tlc.ui.view; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IDialogSettings; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.source.SourceViewer; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; -import org.eclipse.jface.viewers.ILazyTreeContentProvider; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.TreeViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.SashForm; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.ScrollBar; -import org.eclipse.swt.widgets.Scrollable; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.ui.forms.widgets.Form; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.part.ViewPart; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.tool.tlc.model.Formula; -import org.lamport.tla.toolbox.tool.tlc.model.Model; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFcnElementVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFunctionVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCMultiVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCNamedVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCRecordVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSequenceVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSetVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSimpleVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariable; -import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue; -import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; -import org.lamport.tla.toolbox.tool.tlc.traceexplorer.TraceExplorerComposite; -import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; -import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; -import org.lamport.tla.toolbox.tool.tlc.ui.util.ActionClickListener; -import org.lamport.tla.toolbox.tool.tlc.ui.util.ActionClickListener.LoaderTLCState; -import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; -import org.lamport.tla.toolbox.tool.tlc.ui.util.TLCUIHelper; -import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; -import org.lamport.tla.toolbox.util.FontPreferenceChangeListener; -import org.lamport.tla.toolbox.util.IHelpConstants; -import org.lamport.tla.toolbox.util.UIHelper; - -import tla2sany.st.Location; -import tlc2.output.MP; - -/** - * Error representation view containing the error description and the trace - * explorer. This is the view of the error description. - * - * @author Simon Zambrovski - */ -public class TLCErrorView extends ViewPart -{ - private static final SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss"); - - private static final String INNER_WEIGHTS_KEY = "INNER_WEIGHTS_KEY"; - private static final String OUTER_WEIGHTS_KEY = "OUTER_WEIGHTS_KEY"; - - public static final String ID = "toolbox.tool.tlc.view.TLCErrorView"; - - /** - * This is the pattern of an error message resulting from evaluating the constant - * expression entered in the expression field by the user. - */ - private static final Pattern CONSTANT_EXPRESSION_ERROR_PATTERN = Pattern.compile("Evaluating assumption PrintT\\(" - + TLCModelLaunchDataProvider.CONSTANT_EXPRESSION_OUTPUT_PATTERN.toString() + "\\)", Pattern.DOTALL); - - - private static final IDocument EMPTY_DOCUMENT() - { - return new Document("No error information"); - } - - private static final IDocument NO_VALUE_DOCUMENT() - { - return new Document("Select line in Error Trace to show its value here."); - } - - private int numberOfStatesToShow; - - private FormToolkit toolkit; - private Form form; - - private SourceViewer errorViewer; - private TreeViewer variableViewer; - private SourceViewer valueViewer; - private Model model; - private TraceExplorerComposite traceExplorerComposite; - - // listener on changes to the tlc output font preference - private FontPreferenceChangeListener fontChangeListener; - - public TLCErrorView() { - numberOfStatesToShow = TLCUIActivator.getDefault().getPreferenceStore() - .getInt(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS); - } - - /** - * Clears the view - */ - public void clear() - { - errorViewer.setDocument(EMPTY_DOCUMENT()); +package org.lamport.tla.toolbox.tool.tlc.ui.view; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.resource.FontRegistry; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.ILazyTreeContentProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Scrollable; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.ui.texteditor.ITextEditor; +import org.lamport.tla.toolbox.Activator; +import org.lamport.tla.toolbox.tool.tlc.model.Formula; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFcnElementVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFunctionVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCMultiVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCNamedVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCRecordVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSequenceVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSetVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSimpleVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariable; +import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue; +import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; +import org.lamport.tla.toolbox.tool.tlc.traceexplorer.TraceExplorerComposite; +import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.TLACoverageEditor; +import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants; +import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler; +import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler.LoaderTLCState; +import org.lamport.tla.toolbox.tool.tlc.ui.util.ExpandableSpaceReclaimer; +import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.tool.tlc.ui.util.TLCUIHelper; +import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; +import org.lamport.tla.toolbox.util.FontPreferenceChangeListener; +import org.lamport.tla.toolbox.util.IHelpConstants; +import org.lamport.tla.toolbox.util.UIHelper; + +import tla2sany.st.Location; +import tlc2.output.MP; + +/** + * Error representation view containing the error description and the trace + * explorer. This is the view of the error description. + * + * @author Simon Zambrovski + */ +public class TLCErrorView extends ViewPart +{ + public static final String ID = "toolbox.tool.tlc.view.TLCErrorView"; + + private static final SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss"); + + private static final String JFACE_ERROR_TRACE_ID = ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT + "_private"; + private static final String CELL_TEXT_PROTOTYPE = "{|qgyA!#93^<[?"; + + private static final String INNER_WEIGHTS_KEY = "INNER_WEIGHTS_KEY"; + private static final String OUTER_WEIGHTS_KEY = "OUTER_WEIGHTS_KEY"; + private static final String MID_WEIGHTS_KEY = "MID_WEIGHTS_KEY"; + + private static final String SYNCED_TRAVERSAL_KEY = "SYNCED_TRAVERSAL_KEY"; + + private static final String DEFAULT_TOOL_TIP + = "Click on a row to see in viewer below.\nDouble-click to go to corresponding action in spec \u2014 " + + "while holding\n down " + (Platform.getOS().equals(Platform.OS_MACOSX) ? "\u2318" : "CTRL") + + " to go to the original PlusCal code, if present."; + + /** + * This is the pattern of an error message resulting from evaluating the constant + * expression entered in the expression field by the user. + */ + private static final Pattern CONSTANT_EXPRESSION_ERROR_PATTERN = Pattern.compile("Evaluating assumption PrintT\\(" + + TLCModelLaunchDataProvider.CONSTANT_EXPRESSION_OUTPUT_PATTERN.toString() + "\\)", Pattern.DOTALL); + + private static final IDocument EMPTY_DOCUMENT() + { + return new Document("No error information"); + } + + private static final IDocument NO_VALUE_DOCUMENT() + { + return new Document("Select line in Error Trace to show its value here."); + } + + + private int numberOfStatesToShow; + + private FormToolkit toolkit; + private Form form; + + private SourceViewer errorViewer; + private TreeViewer variableViewer; + private RecordToSourceCoupler stackTraceActionListener; + private SyncStackTraversal syncStackTraversalAction; + private SourceViewer valueViewer; + private Model model; + private TraceExplorerComposite traceExplorerComposite; + + @SuppressWarnings("unused") // help onto for a nicer object graph + private ExpandableSpaceReclaimer spaceReclaimer; + + // listener on changes to the tlc output font preference + private FontPreferenceChangeListener outputFontChangeListener; + // listener on changes to the error trace font preference + private final IPropertyChangeListener errorTraceFontChangeListener; + + public TLCErrorView() { + numberOfStatesToShow = TLCUIActivator.getDefault().getPreferenceStore() + .getInt(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS); + + errorTraceFontChangeListener = (event) -> { + if ((event == null) || event.getProperty().equals(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT)) { + final Font f = JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT); + + JFaceResources.getFontRegistry().put(JFACE_ERROR_TRACE_ID, f.getFontData()); + + if (variableViewer != null) { + variableViewer.refresh(true); + } + } + }; + errorTraceFontChangeListener.propertyChange(null); + JFaceResources.getFontRegistry().addListener(errorTraceFontChangeListener); + } + + /** + * Clears the view + */ + public void clear() + { + errorViewer.setDocument(EMPTY_DOCUMENT()); setTraceInput(new TLCError()); - traceExplorerComposite.getTableViewer().setInput(new Vector<TLCState>()); - traceExplorerComposite.changeExploreEnablement(false); - valueViewer.setInput(EMPTY_DOCUMENT()); - } - - /** - * Fill data into the view - * - * This includes loading expressions into the trace explorer table. - * - * @param modelName - * name of the model displayed in the view title section - * @param problems - * a list of {@link TLCError} objects representing the errors. - */ - protected void fill(Model model, List<TLCError> problems, final List<String> serializedInput) - { - /* - * Fill the trace explorer expression table with expressions saved in - * the config. - * - * Setting the input of the trace explorer composite table viewer to an - * empty vector is done to avoid adding duplicates. - * - * FormHelper.setSerializedInput adds the elements from the config to - * the table viewer. - */ - traceExplorerComposite.getTableViewer().setInput(new Vector<Formula>()); - FormHelper.setSerializedInput(traceExplorerComposite.getTableViewer(), serializedInput); - - // if there are errors + traceExplorerComposite.getTableViewer().setInput(new Vector<Formula>()); + valueViewer.setInput(EMPTY_DOCUMENT()); + } + + /** + * Fill data into the view + * + * This includes loading expressions into the trace explorer table. + * + * @param modelName + * name of the model displayed in the view title section + * @param problems + * a list of {@link TLCError} objects representing the errors. + */ + protected void fill(Model model, List<TLCError> problems, final List<String> serializedInput) + { + /* + * Fill the trace explorer expression table with expressions saved in + * the config. + * + * Setting the input of the trace explorer composite table viewer to an + * empty vector is done to avoid adding duplicates. + * + * FormHelper.setSerializedInput adds the elements from the config to + * the table viewer. + */ + traceExplorerComposite.getTableViewer().setInput(new Vector<Formula>()); + FormHelper.setSerializedInput(traceExplorerComposite.getTableViewer(), serializedInput); + + // if there are errors TLCError trace = null; - if (problems != null && !problems.isEmpty()) - { - StringBuffer buffer = new StringBuffer(); - // iterate over the errors - for (int i = 0; i < problems.size(); i++) - { - TLCError error = problems.get(i); - - appendError(buffer, error); - - // read out the trace if any - if (error.hasTrace()) - { + if (problems != null && !problems.isEmpty()) + { + StringBuffer buffer = new StringBuffer(); + // iterate over the errors + for (int i = 0; i < problems.size(); i++) + { + TLCError error = problems.get(i); + + appendError(buffer, error); + + // read out the trace if any + if (error.hasTrace()) + { Assert.isTrue(trace == null, "Two traces are provided. Unexpected. This is a bug"); trace = error; - } - } + } + } if (trace == null) - { + { trace = new TLCError(); - } - - IDocument document = errorViewer.getDocument(); - try - { - document.replace(0, document.getLength(), buffer.toString()); - TLCUIHelper.setTLCLocationHyperlinks(errorViewer.getTextWidget()); - } catch (BadLocationException e) - { - TLCUIActivator.getDefault().logError("Error reporting the error " + buffer.toString(), e); - } - + } + + final IDocument document = errorViewer.getDocument(); + try + { + document.replace(0, document.getLength(), buffer.toString()); + TLCUIHelper.setTLCLocationHyperlinks(errorViewer.getTextWidget()); + } catch (BadLocationException e) + { + TLCUIActivator.getDefault().logError("Error reporting the error " + buffer.toString(), e); + } + /* * determine if trace has changed. this is important for really long * traces because resetting the trace input locks up the toolbox for a few - * seconds in these cases, so it is important to not reset the trace - * if it is not necessary + * seconds, so it is important to not reset the trace if it is not necessary. */ TLCError oldTrace = (TLCError) variableViewer.getInput(); boolean isNewTrace = trace != null && oldTrace != null && !(trace == oldTrace); - // update the trace information - if (isNewTrace) - { + // update the trace information + if (isNewTrace) + { this.setTraceInput(trace); - traceExplorerComposite.changeExploreEnablement(true); - } - if (model.isSnapshot()) { - final String date = sdf.format(model.getSnapshotTimeStamp()); - this.form.setText(model.getSnapshotFor().getName() + " (" + date + ")"); - } else { - this.form.setText(model.getName()); - } - - } else - { - clear(); - } - // TODO Check if a run of the trace explorer produced no errors. This would be a bug. - } - - /** - * Hides the current view - */ - public void hide() - { - getViewSite().getPage().hideView(TLCErrorView.this); - } - - /** - * Creates the layout and fill it with data - */ - public void createPartControl(Composite parent) - { - - // The following is not needed because the error viewer is no longer - // a section of anything as of 30 Aug 2009. - // - // int sectionFlags = Section.DESCRIPTION | Section.TITLE_BAR - // | Section.EXPANDED | Section.TWISTIE; - toolkit = new FormToolkit(parent.getDisplay()); - form = toolkit.createForm(parent); - form.setText(""); - toolkit.decorateFormHeading(form); - - GridLayout layout; - GridData gd; - Composite body = form.getBody(); - layout = new GridLayout(1, false); - body.setLayout(layout); - - /* - * The following added by LL 30 Aug 2009 to put the errorViewer and the - * trace viewer inside a SashForm to permit the user to adjust their - * heights. - */ - final SashForm outerSashForm = new SashForm(body, SWT.VERTICAL); - toolkit.adapt(outerSashForm); - gd = new GridData(SWT.FILL, SWT.FILL, true, true); - outerSashForm.setLayoutData(gd); - - // error section - - // On 30 Aug 2009 LL commented out the following code that put a "hider" - // around the error viewer. - // - // Section section = FormHelper.createSectionComposite(outerSashForm, - // "Error", "", toolkit, sectionFlags, null); - // // Section section = FormHelper.createSectionComposite(body, "Error", - // "", toolkit, sectionFlags, null); - // gd = new GridData(SWT.FILL, SWT.FILL, true, false); - // section.setLayoutData(gd); - // Composite clientArea = (Composite) section.getClient(); - // layout = new GridLayout(); - // clientArea.setLayout(layout); - // - // errorViewer = FormHelper.createFormsOutputViewer(toolkit, clientArea, - // SWT.V_SCROLL | SWT.MULTI); - errorViewer = FormHelper.createFormsOutputViewer(toolkit, outerSashForm, SWT.V_SCROLL | SWT.H_SCROLL - | SWT.MULTI | SWT.BORDER); - gd = new GridData(SWT.FILL, SWT.FILL, true, false); - gd.heightHint = 100; - errorViewer.getControl().setLayoutData(gd); - errorViewer.getControl().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); - - /* - * Add a listener to clicks in the error viewer. - * - * Currently, this listener just reacts to clicks - * on location hyperlinks. - */ - final StyledText text = errorViewer.getTextWidget(); - text.addMouseListener(new MouseListener() { - - public void mouseUp(MouseEvent e) - { - // TODO Auto-generated method stub - - } - - public void mouseDown(MouseEvent e) - { - TLCUIHelper.openTLCLocationHyperlink(text, e, model); - } - - public void mouseDoubleClick(MouseEvent e) - { - // TODO Auto-generated method stub - - } - }); - - /* - * We want the lower part of the outer sash form to contain - * the trace explorer expression table section and the inner sash form - * containing the trace tree and the variable viewer. - * Not putting the trace explorer expression table in the sash form - * allows the sash form to expand into the space left behind when the - * user contracts the trace explorer expression section. - * - * The lower part of the outer sash form contains the composite - * belowErrorViewerComposite which contains the trace explorer expression - * table section and the errorTraceSection which contains the inner sash form. - */ - Composite belowErrorViewerComposite = toolkit.createComposite(outerSashForm); - layout = new GridLayout(1, false); - /* - * There is already some margin around this composite - * when it is placed in the lower part of the outer sash form. It - * looks bad when the additional default margin (5 pixels) is placed - * around the left and right edges of widgets that are placed within the - * belowErrorViewerComposite. To eliminate this default margin, - * we set the margin width to 0. - */ - layout.marginWidth = 0; - belowErrorViewerComposite.setLayout(layout); - - traceExplorerComposite = new TraceExplorerComposite(belowErrorViewerComposite, "Error-Trace Exploration", - "Enter expressions to be evaluated at each state of the trace", toolkit, this); - - // A group can be used to organize and provide a title for the inner sash form - // but right now I think the section looks better because it looks the same - // as the trace explorer section - // Group lowerGroup = new Group(belowErrorViewerComposite, SWT.SHADOW_NONE); - // lowerGroup.setLayout(new GridLayout(1, true)); - // lowerGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - // lowerGroup.setText("Error-Trace"); - - /* - * This section contains the inner sash form which contains the error trace table - * and the variable value viewer. - * - * Putting these in a section gives a them a title and logically groups them together. - * - * There is no reason to make it possible to not have this in the expanded form, so the - * only style bit is for the title bar. - */ - Section errorTraceSection = toolkit.createSection(belowErrorViewerComposite, Section.TITLE_BAR); - errorTraceSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - errorTraceSection.setLayout(new GridLayout(1, true)); - errorTraceSection.setText("Error-Trace"); - - // must create the client area for the section - Composite errorTraceSectionClientArea = toolkit.createComposite(errorTraceSection); - errorTraceSectionClientArea.setLayout(new GridLayout(1, true)); - errorTraceSection.setClient(errorTraceSectionClientArea); - - // Modified on 30 Aug 2009 as part of putting error viewer inside a - // sash. - // SashForm sashForm = new SashForm(body, SWT.VERTICAL); // - final SashForm sashForm = new SashForm(errorTraceSectionClientArea/*belowErrorViewerComposite*/, SWT.VERTICAL); - toolkit.adapt(sashForm); - - gd = new GridData(SWT.FILL, SWT.FILL, true, true); - - sashForm.setLayoutData(gd); - - Tree tree = toolkit.createTree(sashForm, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE - | SWT.VIRTUAL); - tree.setHeaderVisible(true); - tree.setLinesVisible(true); - - gd = new GridData(SWT.LEFT, SWT.TOP, true, false); - gd.minimumHeight = 300; - // gd.minimumWidth = 300; - - // LL tried the following in attempting to fix the layout of the trace - // viewer, but it did nothing - // gd.grabExcessHorizontalSpace = true ; - - tree.setLayoutData(gd); - - // Initialize the trace display's resizer. - TraceDisplayResizer resizer = new TraceDisplayResizer(); - resizer.comp = sashForm; - resizer.tree = tree; - - tree.addControlListener(resizer); - - variableViewer = new TreeViewer(tree); + } + if (model.isSnapshot()) { + final String date = sdf.format(model.getSnapshotTimeStamp()); + this.form.setText(model.getSnapshotFor().getName() + " (" + date + ")"); + } else { + this.form.setText(model.getName()); + } + + } else + { + clear(); + } + // TODO Check if a run of the trace explorer produced no errors. This would be a bug. + + traceExplorerComposite.changeButtonEnablement(); + } + + /** + * Hides the current view + */ + public void hide() + { + getViewSite().getPage().hideView(TLCErrorView.this); + } + + /** + * Creates the layout and fill it with data + */ + public void createPartControl(Composite parent) + { + + // The following is not needed because the error viewer is no longer + // a section of anything as of 30 Aug 2009. + // + // int sectionFlags = Section.DESCRIPTION | Section.TITLE_BAR + // | Section.EXPANDED | Section.TWISTIE; + toolkit = new FormToolkit(parent.getDisplay()); + form = toolkit.createForm(parent); + form.setText(""); + toolkit.decorateFormHeading(form); + + GridLayout layout; + GridData gd; + Composite body = form.getBody(); + layout = new GridLayout(1, false); + body.setLayout(layout); + + /* + * The following added by LL 30 Aug 2009 to put the errorViewer and the + * trace viewer inside a SashForm to permit the user to adjust their + * heights. + */ + final SashForm outerSashForm = new SashForm(body, SWT.VERTICAL); + toolkit.adapt(outerSashForm); + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + outerSashForm.setLayoutData(gd); + + // error section + + // On 30 Aug 2009 LL commented out the following code that put a "hider" + // around the error viewer. + // + // Section section = FormHelper.createSectionComposite(outerSashForm, + // "Error", "", toolkit, sectionFlags, null); + // // Section section = FormHelper.createSectionComposite(body, "Error", + // "", toolkit, sectionFlags, null); + // gd = new GridData(SWT.FILL, SWT.FILL, true, false); + // section.setLayoutData(gd); + // Composite clientArea = (Composite) section.getClient(); + // layout = new GridLayout(); + // clientArea.setLayout(layout); + // + // errorViewer = FormHelper.createFormsOutputViewer(toolkit, clientArea, + // SWT.V_SCROLL | SWT.MULTI); + errorViewer = FormHelper.createFormsOutputViewer(toolkit, outerSashForm, SWT.V_SCROLL | SWT.H_SCROLL + | SWT.MULTI | SWT.BORDER); + gd = new GridData(SWT.FILL, SWT.FILL, true, false); + gd.heightHint = 100; + errorViewer.getControl().setLayoutData(gd); + errorViewer.getControl().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); + + /* + * Add a listener to clicks in the error viewer. + * + * Currently, this listener just reacts to clicks + * on location hyperlinks. + */ + final StyledText text = errorViewer.getTextWidget(); + text.addMouseListener(new MouseListener() { + + public void mouseUp(MouseEvent e) + { + // TODO Auto-generated method stub + + } + + public void mouseDown(MouseEvent e) + { + final Set<Class<? extends ITextEditor>> blacklist = new HashSet<>(); + blacklist.add(TLACoverageEditor.class); + TLCUIHelper.openTLCLocationHyperlink(text, e, model, blacklist); + } + + public void mouseDoubleClick(MouseEvent e) + { + // TODO Auto-generated method stub + + } + }); + + /* + * We want the lower part of the outer sash form to contain + * the trace explorer expression table section and the inner sash form + * containing the trace tree and the variable viewer. + * Not putting the trace explorer expression table in the sash form + * allows the sash form to expand into the space left behind when the + * user contracts the trace explorer expression section. + * + * The lower part of the outer sash form contains the composite + * belowErrorViewerComposite which contains the trace explorer expression + * table section and the errorTraceSection which contains the inner sash form. + */ + Composite belowErrorViewerComposite = toolkit.createComposite(outerSashForm); + layout = new GridLayout(1, false); + /* + * There is already some margin around this composite + * when it is placed in the lower part of the outer sash form. It + * looks bad when the additional default margin (5 pixels) is placed + * around the left and right edges of widgets that are placed within the + * belowErrorViewerComposite. To eliminate this default margin, + * we set the margin width to 0. + */ + layout.marginWidth = 0; + belowErrorViewerComposite.setLayout(layout); + + final SashForm middleSashForm = new SashForm(belowErrorViewerComposite, SWT.VERTICAL); + toolkit.adapt(middleSashForm); + + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + + middleSashForm.setLayoutData(gd); + + traceExplorerComposite = new TraceExplorerComposite(middleSashForm, "Error-Trace Exploration", + "Expressions to be evaluated at each state of the trace - drag to re-order.", toolkit, this); + + // A group can be used to organize and provide a title for the inner sash form + // but right now I think the section looks better because it looks the same + // as the trace explorer section + // Group lowerGroup = new Group(belowErrorViewerComposite, SWT.SHADOW_NONE); + // lowerGroup.setLayout(new GridLayout(1, true)); + // lowerGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + // lowerGroup.setText("Error-Trace"); + + /* + * This section contains the inner sash form which contains the error trace table + * and the variable value viewer. + * + * Putting these in a section gives a them a title and logically groups them together. + * + * There is no reason to make it possible to not have this in the expanded form, so the + * only style bit is for the title bar. + */ + Section errorTraceSection = toolkit.createSection(middleSashForm, Section.TITLE_BAR); + errorTraceSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + errorTraceSection.setLayout(new GridLayout(1, true)); + errorTraceSection.setText("Error-Trace"); + + // must create the client area for the section + Composite errorTraceSectionClientArea = toolkit.createComposite(errorTraceSection); + errorTraceSectionClientArea.setLayout(new GridLayout(1, true)); + errorTraceSection.setClient(errorTraceSectionClientArea); + + spaceReclaimer = new ExpandableSpaceReclaimer(traceExplorerComposite.getSection(), middleSashForm); + + final SashForm sashForm = new SashForm(errorTraceSectionClientArea, SWT.VERTICAL); + toolkit.adapt(sashForm); + + gd = new GridData(SWT.FILL, SWT.FILL, true, true); + + sashForm.setLayoutData(gd); + + Tree tree = toolkit.createTree(sashForm, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE + | SWT.VIRTUAL); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + gd = new GridData(SWT.LEFT, SWT.TOP, true, false); + gd.minimumHeight = 300; + // gd.minimumWidth = 300; + + // LL tried the following in attempting to fix the layout of the trace + // viewer, but it did nothing + // gd.grabExcessHorizontalSpace = true ; + + tree.setLayoutData(gd); + + // Initialize the trace display's resizer. + TraceDisplayResizer resizer = new TraceDisplayResizer(); + resizer.comp = sashForm; + resizer.tree = tree; + + tree.addControlListener(resizer); + tree.addListener(SWT.MeasureItem, (event) -> { + final Font originalFont = event.gc.getFont(); + + event.gc.setFont(JFaceResources.getFontRegistry().getBold(JFACE_ERROR_TRACE_ID)); + // we add 2 because SWT doesn't seem to calculate the height correctly, regardless of the prototype + final int height = event.gc.stringExtent(CELL_TEXT_PROTOTYPE).y + 2; + event.height = height; + + event.gc.setFont(originalFont); + }); + + variableViewer = new TreeViewer(tree); final StateContentProvider provider = new StateContentProvider(variableViewer); - variableViewer.setUseHashlookup(true); + variableViewer.setUseHashlookup(true); variableViewer.setContentProvider(provider); - ColumnViewerToolTipSupport.enableFor(variableViewer); - getSite().setSelectionProvider(variableViewer); - - final StateLabelProvider labelProvider = new StateLabelProvider(); - for (int i = 0; i < StateLabelProvider.COLUMN_TEXTS.length; i++) { - final TreeViewerColumn column = new TreeViewerColumn(variableViewer, i); - column.getColumn().setText(StateLabelProvider.COLUMN_TEXTS[i]); - column.getColumn().setWidth(StateLabelProvider.COLUMN_WIDTH[i]); - column.setLabelProvider(labelProvider); - resizer.column[i] = column.getColumn(); // set up the resizer. - column.getColumn().addSelectionListener(new SelectionAdapter() { - public void widgetSelected(final SelectionEvent e) { - // reverse the current trace - final TLCError error = (TLCError) variableViewer.getInput(); - error.reverseTrace(); - // Reset the viewer's selection to the empty selection. With empty - // selection, the subsequent refresh call does *not* invalidate the - // StateContentProvider's lazy policy. - // We know that the user clicked on the tree's column header - // and the real selection is of little importance. - variableViewer.setSelection(new ISelection() { - public boolean isEmpty() { - return true; - } - }); - variableViewer.refresh(false); - - // remember the order for next trace shown - final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); - dialogSettings.put(TLCModelLaunchDataProvider.STATESORTORDER, - !dialogSettings.getBoolean(TLCModelLaunchDataProvider.STATESORTORDER)); - } - }); - } - - // I need to add a listener for size changes to column[0] to - // detect when the user has tried to resize the individual columns. - // The following might work, if I can figure out the real event type - // to use. - int eventType = SWT.Resize; // (2^25) - 1 ; // 1023; // what should this - // be? - resizer.column[0].addListener(eventType, resizer); - - variableViewer.getTree().addMouseListener(new ActionClickListener(variableViewer)); - variableViewer.getTree().addKeyListener(new ActionClickListener(variableViewer)); - -// This is working but I'm not sure we need it. ActionClickListener -// has a keystroke to collapse the viewer. -// // Add a right click context menu to expand and collapse all variables. -// final MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$ -// contextMenu.setRemoveAllWhenShown(true); -// contextMenu.addMenuListener(new IMenuListener() { -// @Override -// public void menuAboutToShow(IMenuManager mgr) { -// mgr.add(new Action("&Collapse All") { -// public void run() { -// variableViewer.collapseAll(); -// } -// }); -// mgr.add(new Action("Expand to &default level") { -// public void run() { -// // expandAll() followed by expandToLevel(2) requires us -// // to collapse the viewer first. -// variableViewer.collapseAll(); -// variableViewer.expandToLevel(2); -// } -// }); -// mgr.add(new Action("&Expand All") { -// public void run() { -// variableViewer.expandAll(); -// } -// }); -// } -// }); -// final Menu menu = contextMenu.createContextMenu(variableViewer.getControl()); -// variableViewer.getControl().setMenu(menu); -// - variableViewer.addSelectionChangedListener(new ISelectionChangedListener() { - - public void selectionChanged(SelectionChangedEvent event) - { - if (!((IStructuredSelection) event.getSelection()).isEmpty()) - { - // Set selection to the selected element (or the - // first if there are multiple - // selections), and show its string representation - // in the value viewer - // (the lower sub-window). - Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement(); - if (selection instanceof TLCState) - { - TLCState state = (TLCState) selection; - valueViewer.setDocument(new Document(state.getDescriptionWithTraceExpressions())); - } else - { - valueViewer.setDocument(new Document(selection.toString())); - } - } else - { - valueViewer.setDocument(NO_VALUE_DOCUMENT()); - } - - } - }); - - /* Horizontal scroll bar added by LL on 26 Aug 2009 */ - valueViewer = FormHelper.createFormsSourceViewer(toolkit, sashForm, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI - | SWT.BORDER); - valueViewer.setEditable(false); - - gd = new GridData(SWT.LEFT, SWT.TOP, true, false); - valueViewer.getControl().setLayoutData(gd); - - - // Restore the sash ratio from the persistent disk storage. Unfortunately it - // doesn't support storing int[] directly, thus have to convert the string - // representation back to an int[] manually. - // It also sets the default ratio if the dialogsettings return null. - // This is the case with a fresh workspace or when the dialog settings - // have never been written before. - final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); - final String innerWeights = dialogSettings.get(INNER_WEIGHTS_KEY); - if (innerWeights != null) { - sashForm.setWeights(stringToIntArray(innerWeights)); - } else { - sashForm.setWeights(new int[] {1,1}); - } - final String outerWeights = dialogSettings.get(OUTER_WEIGHTS_KEY); - if (outerWeights != null) { - outerSashForm.setWeights(stringToIntArray(outerWeights)); - } else { - outerSashForm.setWeights(new int[] {1,4}); - } - - sashForm.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); - dialogSettings.put(INNER_WEIGHTS_KEY, Arrays.toString(sashForm.getWeights())); - } - }); - outerSashForm.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); - dialogSettings.put(OUTER_WEIGHTS_KEY, Arrays.toString(outerSashForm.getWeights())); - } - }); - - form.getToolBarManager().add(new HelpAction()); - form.getToolBarManager().update(true); - - // init - clear(); - - // add a listener to the preference store to react when the font is - // changed - - Vector<Control> controls = new Vector<Control>(); - controls.add(errorViewer.getControl()); - fontChangeListener = new FontPreferenceChangeListener(controls, ITLCPreferenceConstants.I_TLC_OUTPUT_FONT); - JFaceResources.getFontRegistry().addListener(fontChangeListener); - - TLCUIHelper.setHelp(parent, IHelpConstants.TLC_ERROR_VIEW); - - } - - private int[] stringToIntArray(final String str) { - final String[] strings = str.replace("[", "").replace("]", "").split(", "); - int result[] = new int[strings.length]; - for (int i = 0; i < result.length; i++) { - result[i] = Integer.parseInt(strings[i]); - } - return result; - } - - public void setFocus() - { - form.setFocus(); - } - - public void dispose() - { - JFaceResources.getFontRegistry().removeListener(fontChangeListener); - toolkit.dispose(); - super.dispose(); - } - - /** - * Appends the error description to the buffer. - * - * This method filters and replaces strings in TLC's - * output that we don't want the user to see. - * - * Currently, it filters out the starting and ending - * tags and replaces error messages resulting from - * evaluating the constant expression field with something - * more sensible. - * - * @param buffer - * string buffer to append the error description to - * @param error - * error object - */ - private static void appendError(StringBuffer buffer, TLCError error) - { - String message = error.getMessage(); - if (message != null && !message.equals("")) - { - // remove start and end tags from the message - String toAppend = message.replaceAll(MP.DELIM + MP.STARTMSG + "[0-9]{4}" + MP.COLON + "[0-9] " + MP.DELIM, - ""); - toAppend = toAppend.replaceAll(MP.DELIM + MP.ENDMSG + "[0-9]{4} " + MP.DELIM, ""); - // Replace error messages resulting from evaluating the constant - // expression field with something more sensible. - toAppend = CONSTANT_EXPRESSION_ERROR_PATTERN.matcher(toAppend).replaceAll( - "The `Evaluate Constant Expression� section�s evaluation"); - buffer.append(toAppend).append("\n"); - } - TLCError cause = error.getCause(); - // look for a cause that has a message - // that is not a substring of this error's - // message - // if one is found, append that error - while (cause != null) - { - if (message == null || !message.contains(cause.getMessage())) - { - appendError(buffer, cause); - break; - } else - { - cause = cause.getCause(); - } - } - } - - public void updateErrorView() { - updateErrorView(this.model); - } - - /** - * Display the errors in the view, or hides the view if no errors - * Displays data from the most recent trace explorer run for config - * iff {@link ModelHelper#isOriginalTraceShown(ILaunchConfiguration)} is false. - * - * @param errors - * a list of {@link TLCError} - */ - public static void updateErrorView(Model model) { - updateErrorView(model, true); - } - - public static void updateErrorView(Model model, boolean openErrorView) - { - if (model == null) - { - return; - } - boolean isTraceExplorerUpdate; - isTraceExplorerUpdate = !model.isOriginalTraceShown(); - - TLCModelLaunchDataProvider provider = null; - if (isTraceExplorerUpdate) - { - provider = TLCOutputSourceRegistry.getTraceExploreSourceRegistry().getProvider(model); - } else - { - provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model); - } - - if (provider == null) - { - return; - } - updateErrorView(provider, model, openErrorView); - } - - public static void updateErrorView(final TLCModelLaunchDataProvider provider, final Model model, - boolean openErrorView) { - TLCErrorView errorView; - if (provider.getErrors().size() > 0 && openErrorView == true) { - errorView = (TLCErrorView) UIHelper.openView(TLCErrorView.ID); + ColumnViewerToolTipSupport.enableFor(variableViewer); + getSite().setSelectionProvider(variableViewer); + + final StateLabelProvider labelProvider = new StateLabelProvider(); + for (int i = 0; i < StateLabelProvider.COLUMN_TEXTS.length; i++) { + final TreeViewerColumn column = new TreeViewerColumn(variableViewer, i); + column.getColumn().setText(StateLabelProvider.COLUMN_TEXTS[i]); + column.getColumn().setWidth(StateLabelProvider.COLUMN_WIDTH[i]); + column.setLabelProvider(labelProvider); + resizer.column[i] = column.getColumn(); // set up the resizer. + column.getColumn().addSelectionListener(new SelectionAdapter() { + public void widgetSelected(final SelectionEvent e) { + // reverse the current trace + final TLCError error = (TLCError) variableViewer.getInput(); + error.reverseTrace(); + // Reset the viewer's selection to the empty selection. With empty + // selection, the subsequent refresh call does *not* invalidate the + // StateContentProvider's lazy policy. + // We know that the user clicked on the tree's column header + // and the real selection is of little importance. + variableViewer.setSelection(new ISelection() { + public boolean isEmpty() { + return true; + } + }); + variableViewer.refresh(false); + + // remember the order for next trace shown + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + dialogSettings.put(TLCModelLaunchDataProvider.STATESORTORDER, + !dialogSettings.getBoolean(TLCModelLaunchDataProvider.STATESORTORDER)); + } + }); + } + + // I need to add a listener for size changes to column[0] to + // detect when the user has tried to resize the individual columns. + // The following might work, if I can figure out the real event type + // to use. + resizer.column[0].addListener(SWT.Resize, resizer); + + + final Set<Class<? extends ITextEditor>> blacklist = new HashSet<>(); + blacklist.add(TLACoverageEditor.class); + stackTraceActionListener = new RecordToSourceCoupler(variableViewer, blacklist, this, + RecordToSourceCoupler.FocusRetentionPolicy.ARROW_KEY_TRAVERSAL); + variableViewer.getTree().addMouseListener(stackTraceActionListener); + variableViewer.getTree().addKeyListener(stackTraceActionListener); + variableViewer.getTree().addDisposeListener((event) -> { + final IDialogSettings ids = Activator.getDefault().getDialogSettings(); + ids.put(SYNCED_TRAVERSAL_KEY, syncStackTraversalAction.isChecked()); + }); + + // Make it possible to expand and collapse the error trace with the push of a button. + final ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT); + final ToolBar toolbar = toolBarManager.createControl(errorTraceSection); + final ShiftClickAction action = new ShiftClickAction( + "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)", + TLCUIActivator.getImageDescriptor("icons/elcl16/toggle_expand_state.png")) { + @Override + void runWithKey(final boolean pressed) { + if (pressed) { + // expandAll() followed by expandToLevel(2) requires us + // to collapse the viewer first. + variableViewer.collapseAll(); + variableViewer.expandToLevel(2); + } else { + final Object[] expandedElements = variableViewer.getExpandedElements(); + if (expandedElements.length == 0) { + variableViewer.expandAll(); + } else { + variableViewer.collapseAll(); + } + } + } + }; + parent.getDisplay().addFilter(SWT.KeyDown, action); + parent.getDisplay().addFilter(SWT.KeyUp, action); + toolBarManager.add(action); + syncStackTraversalAction = new SyncStackTraversal(); + toolBarManager.add(syncStackTraversalAction); + toolBarManager.update(true); + errorTraceSection.setTextClient(toolbar); +// This is working but now redundant to the buttons on the section (see above). +// Also ActionClickListener has a keystroke to collapse the viewer. +// // Add a right click context menu to expand and collapse all variables. +// final MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$ +// contextMenu.setRemoveAllWhenShown(true); +// contextMenu.addMenuListener(new IMenuListener() { +// @Override +// public void menuAboutToShow(IMenuManager mgr) { +// mgr.add(new Action("&Collapse All") { +// public void run() { +// variableViewer.collapseAll(); +// } +// }); +// mgr.add(new Action("Expand to &default level") { +// public void run() { +// // expandAll() followed by expandToLevel(2) requires us +// // to collapse the viewer first. +// variableViewer.collapseAll(); +// variableViewer.expandToLevel(2); +// } +// }); +// mgr.add(new Action("&Expand All") { +// public void run() { +// variableViewer.expandAll(); +// } +// }); +// } +// }); +// final Menu menu = contextMenu.createContextMenu(variableViewer.getControl()); +// variableViewer.getControl().setMenu(menu); +// + variableViewer.addSelectionChangedListener(new ISelectionChangedListener() { + + public void selectionChanged(SelectionChangedEvent event) + { + if (!((IStructuredSelection) event.getSelection()).isEmpty()) + { + // Set selection to the selected element (or the + // first if there are multiple + // selections), and show its string representation + // in the value viewer + // (the lower sub-window). + Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement(); + if (selection instanceof TLCState) + { + TLCState state = (TLCState) selection; + valueViewer.setDocument(new Document(state.getDescriptionWithTraceExpressions())); + } else + { + valueViewer.setDocument(new Document(selection.toString())); + } + } else + { + valueViewer.setDocument(NO_VALUE_DOCUMENT()); + } + + } + }); + + /* Horizontal scroll bar added by LL on 26 Aug 2009 */ + valueViewer = FormHelper.createFormsSourceViewer(toolkit, sashForm, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI + | SWT.BORDER); + valueViewer.setEditable(false); + + gd = new GridData(SWT.LEFT, SWT.TOP, true, false); + valueViewer.getControl().setLayoutData(gd); + + + // Restore the sash ratio from the persistent disk storage. Unfortunately it + // doesn't support storing int[] directly, thus have to convert the string + // representation back to an int[] manually. + // It also sets the default ratio if the dialogsettings return null. + // This is the case with a fresh workspace or when the dialog settings + // have never been written before. + final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings(); + final String innerWeights = dialogSettings.get(INNER_WEIGHTS_KEY); + if (innerWeights != null) { + sashForm.setWeights(stringToIntArray(innerWeights)); + } else { + sashForm.setWeights(new int[] {1,1}); + } + final String outerWeights = dialogSettings.get(OUTER_WEIGHTS_KEY); + if (outerWeights != null) { + outerSashForm.setWeights(stringToIntArray(outerWeights)); + } else { + outerSashForm.setWeights(new int[] {1,4}); + } + final String midWeights = dialogSettings.get(MID_WEIGHTS_KEY); + if (midWeights != null) { + middleSashForm.setWeights(stringToIntArray(midWeights)); + } else { + final int[] weights; + + if (traceExplorerComposite.getSection().isExpanded()) { + weights = new int[] {3, 7}; + } else { + weights = new int[] {1, 9}; + } + + middleSashForm.setWeights(weights); + } + + sashForm.addDisposeListener((event) -> { + final IDialogSettings ids = Activator.getDefault().getDialogSettings(); + ids.put(INNER_WEIGHTS_KEY, Arrays.toString(sashForm.getWeights())); + }); + outerSashForm.addDisposeListener((event) -> { + final IDialogSettings ids = Activator.getDefault().getDialogSettings(); + ids.put(OUTER_WEIGHTS_KEY, Arrays.toString(outerSashForm.getWeights())); + }); + middleSashForm.addDisposeListener((event) -> { + final IDialogSettings ids = Activator.getDefault().getDialogSettings(); + ids.put(MID_WEIGHTS_KEY, Arrays.toString(middleSashForm.getWeights())); + }); + + form.getToolBarManager().add(new HelpAction()); + form.getToolBarManager().update(true); + + // init + clear(); + + // add listeners to the preference store to react when the fonts are changed + Vector<Control> controls = new Vector<>(); + controls.add(errorViewer.getControl()); + outputFontChangeListener = new FontPreferenceChangeListener(controls, ITLCPreferenceConstants.I_TLC_OUTPUT_FONT); + JFaceResources.getFontRegistry().addListener(outputFontChangeListener); + + TLCUIHelper.setHelp(parent, IHelpConstants.TLC_ERROR_VIEW); + } + + private int[] stringToIntArray(final String str) { + final String[] strings = str.replace("[", "").replace("]", "").split(", "); + int result[] = new int[strings.length]; + for (int i = 0; i < result.length; i++) { + result[i] = Integer.parseInt(strings[i]); + } + return result; + } + + public void setFocus() + { + form.setFocus(); + } + + public void dispose() { + final FontRegistry fr = JFaceResources.getFontRegistry(); + + fr.removeListener(outputFontChangeListener); + fr.removeListener(errorTraceFontChangeListener); + + toolkit.dispose(); + + super.dispose(); + } + + /** + * Appends the error description to the buffer. + * + * This method filters and replaces strings in TLC's + * output that we don't want the user to see. + * + * Currently, it filters out the starting and ending + * tags and replaces error messages resulting from + * evaluating the constant expression field with something + * more sensible. + * + * @param buffer + * string buffer to append the error description to + * @param error + * error object + */ + private static void appendError(StringBuffer buffer, TLCError error) + { + String message = error.getMessage(); + if (message != null && !message.equals("")) + { + // remove start and end tags from the message + String toAppend = message.replaceAll(MP.DELIM + MP.STARTMSG + "[0-9]{4}" + MP.COLON + "[0-9] " + MP.DELIM, + ""); + toAppend = toAppend.replaceAll(MP.DELIM + MP.ENDMSG + "[0-9]{4} " + MP.DELIM, ""); + // Replace error messages resulting from evaluating the constant + // expression field with something more sensible. + toAppend = CONSTANT_EXPRESSION_ERROR_PATTERN.matcher(toAppend).replaceAll( + "The `Evaluate Constant Expression� section�s evaluation"); + buffer.append(toAppend).append("\n"); + } + TLCError cause = error.getCause(); + // look for a cause that has a message + // that is not a substring of this error's + // message + // if one is found, append that error + while (cause != null) + { + if (message == null || !message.contains(cause.getMessage())) + { + appendError(buffer, cause); + break; + } else + { + cause = cause.getCause(); + } + } + } + + public void updateErrorView() { + updateErrorView(this.model); + } + + /** + * Display the errors in the view, or hides the view if no errors + * Displays data from the most recent trace explorer run for config + * iff {@link ModelHelper#isOriginalTraceShown(ILaunchConfiguration)} is false. + * + * @param errors + * a list of {@link TLCError} + */ + public static void updateErrorView(Model model) { + updateErrorView(model, true); + } + + public static void updateErrorView(Model model, boolean openErrorView) + { + if (model == null) + { + return; + } + boolean isTraceExplorerUpdate; + isTraceExplorerUpdate = !model.isOriginalTraceShown(); + + TLCModelLaunchDataProvider provider = null; + if (isTraceExplorerUpdate) + { + provider = TLCOutputSourceRegistry.getTraceExploreSourceRegistry().getProvider(model); + } else + { + provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model); + } + + if (provider == null) + { + return; + } + updateErrorView(provider, model, openErrorView); + } + + public static void updateErrorView(final TLCModelLaunchDataProvider provider, final Model model, + boolean openErrorView) { + TLCErrorView errorView; + if (provider.getErrors().size() > 0 && openErrorView == true) { + errorView = (TLCErrorView) UIHelper.openView(TLCErrorView.ID); } else { - errorView = (TLCErrorView) UIHelper.findView(TLCErrorView.ID); - } + errorView = (TLCErrorView) UIHelper.findView(TLCErrorView.ID); + } if (errorView != null) { - errorView.model= model; - - final List<String> serializedInput = model.getTraceExplorerExpressions(); - // fill the name and the errors - errorView.fill(provider.getModel(), provider.getErrors(), - serializedInput); - - if (provider.getErrors().size() == 0) { - errorView.hide(); - } - } - } - - /** - * A control listener for the Provides method for resizing the columns of - * the error trace viewer. This is to solve the problem of a bogus - * "third column" being displayed when the window is made wider than the two - * real columns. - * - * There are two listener methods in this class: controlResized - called - * when the tree is resized. handleEvent - called when column[0] is resized. - * The controlResized command can change the size of column[0], which - * triggers the calling of the handleEvent. Experimentation indicates that - * this call of handleEvent occurs in the middle of executing the call of - * controlResized. The boolean flag inControlResized is used to tell the - * handleEvent method whether it was called this way or by the user resizing - * the colulmn. - * - * Note: I am assuming that the call of handleEvent that happens when - * controlResized is resizing column[0] happens during the execution of - * column[0].setWidth, and no funny races are possible. - * - * Note that all the code here assumes that there are two columns. It needs - * to be modified if the number of columns is changed. - */ - static class TraceDisplayResizer extends ControlAdapter implements Listener - { - double firstColumnPercentageWidth = .5; - - // See comments above for meaning of the following flag. - boolean inControlResized = false; - Scrollable comp; // The component containing the trace display. - TreeColumn[] column = new TreeColumn[StateLabelProvider.COLUMN_TEXTS.length]; - Tree tree; - - public void controlResized(ControlEvent e) - { - inControlResized = true; - - int treeWidth = computeMaximumWidthOfAllColumns(); - int firstColWidth = Math.round(Math.round(firstColumnPercentageWidth * treeWidth)); - int secondColWidth = treeWidth - firstColWidth; - column[0].setWidth(firstColWidth); - column[1].setWidth(secondColWidth); - inControlResized = false; - } - - int count = 0; - - public void handleEvent(Event event) - { - if (inControlResized) - { - return; - } - - int treeWidth = computeMaximumWidthOfAllColumns(); - int firstColWidth = column[0].getWidth(); - - if (treeWidth == 0) - { - return; - } - - // the percentage that the first column will occupy - // until controlResized is called - // We do not want the width of either column - // to be less than 10% of the total width - // of the tree. Currently, the user - // can make a column smaller than 10%, but - // when controlResized is called, the column - // will be enlarged to 10%. It is not very nice - // to do the enlarging in this method. It creates - // very choppy performance. - double tentativefirstColPercentageWidth = (double) firstColWidth / (double) treeWidth; - if (tentativefirstColPercentageWidth > .1 && tentativefirstColPercentageWidth < .9) - { - firstColumnPercentageWidth = (double) firstColWidth / (double) treeWidth; - - } else if (tentativefirstColPercentageWidth <= .1) - { - firstColumnPercentageWidth = .1; - } else - { - firstColumnPercentageWidth = .9; - } - firstColWidth = Math.round(Math.round(tentativefirstColPercentageWidth * treeWidth)); - int secondColWidth = treeWidth - firstColWidth; - column[1].setWidth(secondColWidth); - } - - /* - * Computes the maximum width that columns of the tree can occupy - * without having a horizontal scrollbar. - * - * This is not equal to the sash form's client area. From the client - * area we must subtract the tree's border width. We must also subtract - * the width of the grid lines used in the tree times the number of - * columns because there is one grid line per column. We must subtract - * the width of the vertical scroll bar if it is visible. - */ - private int computeMaximumWidthOfAllColumns() - { - ScrollBar vBar = tree.getVerticalBar(); - boolean scrollBarShown = vBar.isVisible(); - return comp.getClientArea().width - tree.getBorderWidth() - tree.getColumnCount() * tree.getGridLineWidth() - - ((scrollBarShown) ? vBar.getSize().x : 0); - } - - } - - /** - * Content provider for the tree table - */ + errorView.model= model; + + final List<String> serializedInput = model.getTraceExplorerExpressions(); + // fill the name and the errors + errorView.fill(provider.getModel(), provider.getErrors(), + serializedInput); + + if (provider.getErrors().size() == 0) { + errorView.hide(); + } + } + } + + /** + * A control listener for the Provides method for resizing the columns of + * the error trace viewer. This is to solve the problem of a bogus + * "third column" being displayed when the window is made wider than the two + * real columns. + * + * There are two listener methods in this class: controlResized - called + * when the tree is resized. handleEvent - called when column[0] is resized. + * The controlResized command can change the size of column[0], which + * triggers the calling of the handleEvent. Experimentation indicates that + * this call of handleEvent occurs in the middle of executing the call of + * controlResized. The boolean flag inControlResized is used to tell the + * handleEvent method whether it was called this way or by the user resizing + * the colulmn. + * + * Note: I am assuming that the call of handleEvent that happens when + * controlResized is resizing column[0] happens during the execution of + * column[0].setWidth, and no funny races are possible. + * + * Note that all the code here assumes that there are two columns. It needs + * to be modified if the number of columns is changed. + */ + static class TraceDisplayResizer extends ControlAdapter implements Listener + { + double firstColumnPercentageWidth = .5; + + // See comments above for meaning of the following flag. + boolean inControlResized = false; + Scrollable comp; // The component containing the trace display. + TreeColumn[] column = new TreeColumn[StateLabelProvider.COLUMN_TEXTS.length]; + Tree tree; + + public void controlResized(ControlEvent e) + { + inControlResized = true; + + int treeWidth = computeMaximumWidthOfAllColumns(); + int firstColWidth = Math.round(Math.round(firstColumnPercentageWidth * treeWidth)); + int secondColWidth = treeWidth - firstColWidth; + column[0].setWidth(firstColWidth); + column[1].setWidth(secondColWidth); + inControlResized = false; + } + + int count = 0; + + public void handleEvent(Event event) + { + if (inControlResized) + { + return; + } + + int treeWidth = computeMaximumWidthOfAllColumns(); + int firstColWidth = column[0].getWidth(); + + if (treeWidth == 0) + { + return; + } + + // the percentage that the first column will occupy + // until controlResized is called + // We do not want the width of either column + // to be less than 10% of the total width + // of the tree. Currently, the user + // can make a column smaller than 10%, but + // when controlResized is called, the column + // will be enlarged to 10%. It is not very nice + // to do the enlarging in this method. It creates + // very choppy performance. + double tentativefirstColPercentageWidth = (double) firstColWidth / (double) treeWidth; + if (tentativefirstColPercentageWidth > .1 && tentativefirstColPercentageWidth < .9) + { + firstColumnPercentageWidth = (double) firstColWidth / (double) treeWidth; + + } else if (tentativefirstColPercentageWidth <= .1) + { + firstColumnPercentageWidth = .1; + } else + { + firstColumnPercentageWidth = .9; + } + firstColWidth = Math.round(Math.round(tentativefirstColPercentageWidth * treeWidth)); + int secondColWidth = treeWidth - firstColWidth; + column[1].setWidth(secondColWidth); + } + + /* + * Computes the maximum width that columns of the tree can occupy + * without having a horizontal scrollbar. + * + * This is not equal to the sash form's client area. From the client + * area we must subtract the tree's border width. We must also subtract + * the width of the grid lines used in the tree times the number of + * columns because there is one grid line per column. We must subtract + * the width of the vertical scroll bar if it is visible. + */ + private int computeMaximumWidthOfAllColumns() + { + ScrollBar vBar = tree.getVerticalBar(); + boolean scrollBarShown = vBar.isVisible(); + return comp.getClientArea().width - tree.getBorderWidth() - tree.getColumnCount() * tree.getGridLineWidth() + - ((scrollBarShown) ? vBar.getSize().x : 0); + } + + } + + /** + * Content provider for the tree table + */ private class StateContentProvider implements ILazyTreeContentProvider { - - private final TreeViewer viewer; - private List<TLCState> states = new ArrayList<TLCState>(0); - - public StateContentProvider(TreeViewer viewer) { - this.viewer = viewer; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IContentProvider#dispose() - */ - public void dispose() { - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) - */ - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // Eagerly cache the list of states as it can be a sublist of the - // complete trace. Getting the sublist in the updateElement method - // means we obtain it over and over again for each top-level tree - // item. - if (newInput instanceof TLCError) { - this.states = ((TLCError) newInput).getStates(); - } else if (newInput == null) { - this.states = new ArrayList<TLCState>(0); - } else { - throw new IllegalArgumentException(); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object, int) - */ - public void updateElement(Object parent, int viewerIndex) { - if (parent instanceof TLCError) { - final TLCError error = (TLCError) parent; - if (error.isTraceRestricted() && viewerIndex == 0) { - // If only a subset of the trace is shown, show a dummy item - // at the top which can be double-clicked to load more. - viewer.replace(parent, viewerIndex, new ActionClickListener.LoaderTLCState(viewer, - Math.min(numberOfStatesToShow, error.getNumberOfRestrictedTraceStates()), error)); - return; - } - // decrease index into states by one if the viewers first element is a dummy item - final int statesIndex = viewerIndex - (error.isTraceRestricted() ? 1 : 0); - final TLCState child = states.get(statesIndex); - // Diffing is supposed to be lazy and thus is done here when - // the state is first used by the viewer. The reason why it - // has to be lazy is to be able to efficiently handle traces - // with hundreds or thousands of states where it would be a - // waste to diff all state pairs even if the user is never - // going to look at all states anyway. - // TODO If ever comes up as a performance problem again, the - // nested TLCVariableValues could also be diffed lazily. - if (statesIndex > 0) { - final TLCState predecessor = states.get(statesIndex - 1); - predecessor.diff(child); - } - viewer.replace(parent, viewerIndex, child); - // Always setHashChildren even if child has no children: This is - // a virtual table here meaning that it reduces the number of - // table items at the OS level by recycling them (the OS only - // creates a many items that fit into the visible area). If an - // item showing a regular state, is later recycled by a "back to - // state" or "stuttering" indicator (neither has children), - // the OS still incorrectly assumes the item has children. This - // crashes hard on Linux and results in erratic behavior on - // Windows and Mac. - viewer.setHasChildren(child, child.getVariablesAsList().size() > 0); - // Lazily expand the children - if (child.isExpandable()){ - viewer.expandToLevel(child, 1); - } - } else if (parent instanceof TLCState) { - final TLCState state = (TLCState) parent; - if ((state.isStuttering() || state.isBackToState())) { - viewer.setChildCount(state, 0); - } else { - final List<TLCVariable> variablesAsList = state.getVariablesAsList(); - if (variablesAsList.size() > viewerIndex) { - final TLCVariable child = variablesAsList.get(viewerIndex); - viewer.replace(parent, viewerIndex, child); - viewer.setHasChildren(child, child.getChildCount() > 0); - } - } - } else if (parent instanceof TLCVariable - && ((TLCVariable) parent).getValue() instanceof TLCMultiVariableValue) { - final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariable) parent).getValue(); - final TLCVariableValue child = multiValue.asList().get(viewerIndex); - viewer.replace(parent, viewerIndex, child); - viewer.setHasChildren(child, child.getChildCount() > 0); - } else if (parent instanceof TLCVariable) { - final TLCVariable variable = (TLCVariable) parent; - final TLCVariableValue child = variable.getValue(); - viewer.replace(parent, viewerIndex, child); - viewer.setChildCount(child, child.getChildCount()); - } else if (parent instanceof TLCMultiVariableValue) { - final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) parent; - final TLCVariableValue child = multiValue.asList().get(viewerIndex); - viewer.replace(parent, viewerIndex, child); - viewer.setHasChildren(child, child.getChildCount() > 0); - } else if (parent instanceof TLCVariableValue - && ((TLCVariableValue) parent).getValue() instanceof TLCMultiVariableValue) { - final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariableValue) parent).getValue(); - final TLCVariableValue child = multiValue.asList().get(viewerIndex); - viewer.replace(parent, viewerIndex, child); - viewer.setHasChildren(child, child.getChildCount() > 0); - } else { - throw new IllegalArgumentException(); - } - } + + private final TreeViewer viewer; + private List<TLCState> states = new ArrayList<TLCState>(0); + + public StateContentProvider(TreeViewer viewer) { + this.viewer = viewer; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // Eagerly cache the list of states as it can be a sublist of the + // complete trace. Getting the sublist in the updateElement method + // means we obtain it over and over again for each top-level tree + // item. + if (newInput instanceof TLCError) { + this.states = ((TLCError) newInput).getStates(); + } else if (newInput == null) { + this.states = new ArrayList<TLCState>(0); + } else { + throw new IllegalArgumentException(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object, int) + */ + public void updateElement(Object parent, int viewerIndex) { + if (parent instanceof TLCError) { + final TLCError error = (TLCError) parent; + if (error.isTraceRestricted() && viewerIndex == 0) { + // If only a subset of the trace is shown, show a dummy item + // at the top which can be double-clicked to load more. + viewer.replace(parent, viewerIndex, new RecordToSourceCoupler.LoaderTLCState(viewer, + Math.min(numberOfStatesToShow, error.getNumberOfRestrictedTraceStates()), error)); + return; + } + // decrease index into states by one if the viewers first element is a dummy item + final int statesIndex = viewerIndex - (error.isTraceRestricted() ? 1 : 0); + final TLCState child = states.get(statesIndex); + // Diffing is supposed to be lazy and thus is done here when + // the state is first used by the viewer. The reason why it + // has to be lazy is to be able to efficiently handle traces + // with hundreds or thousands of states where it would be a + // waste to diff all state pairs even if the user is never + // going to look at all states anyway. + // TODO If ever comes up as a performance problem again, the + // nested TLCVariableValues could also be diffed lazily. + if (statesIndex > 0) { + final TLCState predecessor = states.get(statesIndex - 1); + predecessor.diff(child); + } + viewer.replace(parent, viewerIndex, child); + // Always setHashChildren even if child has no children: This is + // a virtual table here meaning that it reduces the number of + // table items at the OS level by recycling them (the OS only + // creates a many items that fit into the visible area). If an + // item showing a regular state, is later recycled by a "back to + // state" or "stuttering" indicator (neither has children), + // the OS still incorrectly assumes the item has children. This + // crashes hard on Linux and results in erratic behavior on + // Windows and Mac. + viewer.setHasChildren(child, child.getVariablesAsList().size() > 0); + // Lazily expand the children + if (child.isExpandable()){ + viewer.expandToLevel(child, 1); + } + } else if (parent instanceof TLCState) { + final TLCState state = (TLCState) parent; + if ((state.isStuttering() || state.isBackToState())) { + viewer.setChildCount(state, 0); + } else { + final List<TLCVariable> variablesAsList = state.getVariablesAsList(); + if (variablesAsList.size() > viewerIndex) { + final TLCVariable child = variablesAsList.get(viewerIndex); + viewer.replace(parent, viewerIndex, child); + viewer.setHasChildren(child, child.getChildCount() > 0); + } + } + } else if (parent instanceof TLCVariable + && ((TLCVariable) parent).getValue() instanceof TLCMultiVariableValue) { + final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariable) parent).getValue(); + final TLCVariableValue child = multiValue.asList().get(viewerIndex); + viewer.replace(parent, viewerIndex, child); + viewer.setHasChildren(child, child.getChildCount() > 0); + } else if (parent instanceof TLCVariable) { + final TLCVariable variable = (TLCVariable) parent; + final TLCVariableValue child = variable.getValue(); + viewer.replace(parent, viewerIndex, child); + viewer.setChildCount(child, child.getChildCount()); + } else if (parent instanceof TLCMultiVariableValue) { + final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) parent; + final TLCVariableValue child = multiValue.asList().get(viewerIndex); + viewer.replace(parent, viewerIndex, child); + viewer.setHasChildren(child, child.getChildCount() > 0); + } else if (parent instanceof TLCVariableValue + && ((TLCVariableValue) parent).getValue() instanceof TLCMultiVariableValue) { + final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariableValue) parent).getValue(); + final TLCVariableValue child = multiValue.asList().get(viewerIndex); + viewer.replace(parent, viewerIndex, child); + viewer.setHasChildren(child, child.getChildCount() > 0); + } else { + throw new IllegalArgumentException(); + } + } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateChildCount(java.lang.Object, int) */ - public void updateChildCount(Object element, int currentChildCount) { - if (element instanceof TLCError) { - final TLCError error = (TLCError) element; - int traceSize = error.getTraceSize(); - if (traceSize != currentChildCount) { - if (error.isTraceRestricted()) { - viewer.setChildCount(element, traceSize + 1); - } else { - viewer.setChildCount(element, traceSize); - } - } - } else if (element instanceof TLCState) { - final TLCState state = (TLCState) element; - if (((state.isStuttering() || state.isBackToState()) && currentChildCount != 0)) { - viewer.setChildCount(element, 0); - } else if (currentChildCount != state.getVariablesAsList().size()) { - viewer.setChildCount(element, state.getVariablesAsList().size()); - } - } else if (element instanceof TLCVariable) { - final TLCVariable variable = (TLCVariable) element; - if (currentChildCount != variable.getChildCount()) { - viewer.setChildCount(element, variable.getChildCount()); - } - } else if (element instanceof TLCVariableValue) { - final TLCVariableValue value = (TLCVariableValue) element; - if (currentChildCount != value.getChildCount()) { - viewer.setChildCount(element, value.getChildCount()); - } - } else { - throw new IllegalArgumentException(); - } - } + public void updateChildCount(Object element, int currentChildCount) { + if (element instanceof TLCError) { + final TLCError error = (TLCError) element; + int traceSize = error.getTraceSize(); + if (traceSize != currentChildCount) { + if (error.isTraceRestricted()) { + viewer.setChildCount(element, traceSize + 1); + } else { + viewer.setChildCount(element, traceSize); + } + } + } else if (element instanceof TLCState) { + final TLCState state = (TLCState) element; + if (((state.isStuttering() || state.isBackToState()) && currentChildCount != 0)) { + viewer.setChildCount(element, 0); + } else if (currentChildCount != state.getVariablesAsList().size()) { + viewer.setChildCount(element, state.getVariablesAsList().size()); + } + } else if (element instanceof TLCVariable) { + final TLCVariable variable = (TLCVariable) element; + if (currentChildCount != variable.getChildCount()) { + viewer.setChildCount(element, variable.getChildCount()); + } + } else if (element instanceof TLCVariableValue) { + final TLCVariableValue value = (TLCVariableValue) element; + if (currentChildCount != value.getChildCount()) { + viewer.setChildCount(element, value.getChildCount()); + } + } else { + throw new IllegalArgumentException(); + } + } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#getParent(java.lang.Object) */ public Object getParent(Object element) { return null; - } - } - - /** - * Label provider for the tree table. Modified on 30 Aug 2009 by LL to - * implement ITableColorProvider instead of IColorProvider. This allows - * coloring of individual columns, not just of entire rows. - */ - static class StateLabelProvider extends CellLabelProvider - { - public static final int NAME = 0; - public static final int VALUE = 1; - - public static final int[] COLUMN_WIDTH = { 200, 200 }; - public static final String[] COLUMN_TEXTS = { "Name", "Value" }; - - private final Image stateImage; - private final Image varImage; - private final Image recordImage; - private final Image setImage; - private final Image loadMoreImage; - - public StateLabelProvider() - { - stateImage = TLCUIActivator.getImageDescriptor("/icons/full/default_co.gif").createImage(); - varImage = TLCUIActivator.getImageDescriptor("/icons/full/private_co.gif").createImage(); - recordImage = TLCUIActivator.getImageDescriptor("/icons/full/brkpi_obj.gif").createImage(); - // setImage = TLCUIActivator.getImageDescriptor("/icons/full/over_co.gif").createImage(); - setImage = TLCUIActivator.getImageDescriptor("/icons/full/compare_method.gif").createImage(); - loadMoreImage = TLCUIActivator.getImageDescriptor("/icons/full/add.gif").createImage(); // other candidate is newstream_wiz.gif, nav_go.gif, debugt_obj.gif - } - - private Image getColumnImage(Object element, int columnIndex) - { - if (columnIndex == NAME) - { - if (element instanceof LoaderTLCState) { - return loadMoreImage; - } - if (element instanceof TLCState) - { - return stateImage; - } else if (element instanceof TLCVariable) - { - return varImage; - } else if (element instanceof TLCNamedVariableValue) - { - return recordImage; - } else if (element instanceof TLCFcnElementVariableValue) - { - return recordImage; - } - return setImage; // other things appear in unordered collections - } - return null; - } - - private String getColumnText(Object element, int columnIndex) - { - if (element instanceof TLCState) - { - TLCState state = (TLCState) element; - - switch (columnIndex) { - case NAME: - if (state.isStuttering()) - { - return "<Stuttering>"; - } else if (state.isBackToState()) - { - return "<Back to state " + state.getStateNumber() + ">"; - } - return state.getLabel(); - case VALUE: - if (state instanceof ActionClickListener.LoaderTLCState) { - return ""; - } else { - return "State (num = " + state.getStateNumber() + ")"; - } - // state.toString(); - default: - break; - } - } else if (element instanceof TLCVariable) - { - TLCVariable var = (TLCVariable) element; - switch (columnIndex) { - case NAME: - if (var.isTraceExplorerVar()) - { - return var.getSingleLineName(); - } else - { - return var.getName(); - } - case VALUE: - return var.getValue().toSimpleString(); - // Changed from toString by LL on 30 Aug 2009 - default: - break; - } - } else if (element instanceof TLCSetVariableValue || element instanceof TLCSequenceVariableValue - || element instanceof TLCSimpleVariableValue) - { - - TLCVariableValue varValue = (TLCVariableValue) element; - switch (columnIndex) { - case VALUE: - return varValue.toString(); - case NAME: - return ""; // added by LL on 5 Nov 2009 - default: - break; - } - } else if (element instanceof TLCNamedVariableValue) - { - TLCNamedVariableValue namedValue = (TLCNamedVariableValue) element; - switch (columnIndex) { - case NAME: - return namedValue.getName(); - case VALUE: - return ((TLCVariableValue) namedValue.getValue()).toSimpleString(); - // Changed from toString by LL on 30 Aug 2009 - default: - break; - } - } else if (element instanceof TLCFcnElementVariableValue) - { - TLCFcnElementVariableValue fcnElementValue = (TLCFcnElementVariableValue) element; - switch (columnIndex) { - case NAME: - return fcnElementValue.getFrom().toSimpleString(); - // Changed from toString by LL on 30 Aug 2009 - case VALUE: - return ((TLCVariableValue) fcnElementValue.getValue()).toSimpleString(); - // Changed from toString by LL on 30 Aug 2009 - default: - break; - } - } else if (element instanceof TLCRecordVariableValue) - { - TLCRecordVariableValue recordValue = (TLCRecordVariableValue) element; - switch (columnIndex) { - case NAME: - return ""; - case VALUE: - return recordValue.toSimpleString(); - default: - break; - } - } else if (element instanceof TLCFunctionVariableValue) - { - TLCFunctionVariableValue fcnValue = (TLCFunctionVariableValue) element; - switch (columnIndex) { - case NAME: - return ""; - case VALUE: - return fcnValue.toSimpleString(); - default: - break; - } - } - - return null; - } - - private static final Map<String, Color> location2color = new ConcurrentHashMap<String, Color>(); - //TODO Convert to Toolbox preference once this features proves useful. - private static final boolean coloring = Boolean.getBoolean(TLCErrorView.class.getName() + ".coloring"); - - /** - * The following method sets the background color of a row or column of - * the table. It highlights the entire row for an added or deleted item. - * For a changed value, only the value is highlighted. - */ - private Color getBackground(Object element, int column) { - if (element instanceof TLCVariable) { - final TLCVariable var = (TLCVariable) element; - if (var.isChanged() && column == VALUE) { - return TLCUIActivator.getDefault().getChangedColor(); - } - } else if (element instanceof TLCVariableValue) { - final TLCVariableValue value = (TLCVariableValue) element; - if (value.isChanged()) { - if (column == VALUE) { - return TLCUIActivator.getDefault().getChangedColor(); - } - } else if (value.isAdded()) { - // Added takes precedence over deleted. E.g. a value can be - // added to a set in this state and be removed in the next - // state. - return TLCUIActivator.getDefault().getAddedColor(); - } else if (value.isDeleted()) { - return TLCUIActivator.getDefault().getDeletedColor(); - } - } else if (coloring && element instanceof TLCState) { - // Assign a color to each location to make actions in the error - // viewer more easily distinguishable. - final TLCState state = (TLCState) element; - Location moduleLocation = state.getModuleLocation(); - if (moduleLocation == null) { - return null; - } - Color c = location2color.get(moduleLocation.toString()); - if (c == null) { - int color = SWT.COLOR_WHITE + (2 * location2color.size()); - c = TLCUIActivator.getColor(color); - location2color.put(state.getModuleLocation().toString(), c); - } - return c; - } - return null; - } - - private Color getForeground(Object element, int i) - { - return null; - } - - private Font getFont(Object element, int columnIndex) - { - if (element instanceof TLCVariable) - { - TLCVariable variable = (TLCVariable) element; - if (variable.isTraceExplorerVar()) - { - return JFaceResources.getFontRegistry().getBold(""); - } - } else if (element instanceof ActionClickListener.LoaderTLCState) { - return JFaceResources.getFontRegistry().getBold(""); - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose() - */ - public void dispose() - { - /* - * Remove images - */ - stateImage.dispose(); - varImage.dispose(); - recordImage.dispose(); - setImage.dispose(); - loadMoreImage.dispose(); - super.dispose(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IToolTipProvider#getToolTipText(java.lang.Object) - */ - public String getToolTipText(Object element) { - if (element instanceof LoaderTLCState) { - return "Double-click to load more states.\nIf the number of states is large, this might take a few seconds."; - } - return "Click on a row to see in viewer below, double-click to go to corresponding action in spec."; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell) - */ - public void update(ViewerCell cell) { - // labels - cell.setText(getColumnText(cell.getElement(), cell.getColumnIndex())); - - // images - cell.setImage(getColumnImage(cell.getElement(), cell.getColumnIndex())); - - // font - cell.setFont(getFont(cell.getElement(), cell.getColumnIndex())); - - // colors - cell.setForeground(getForeground(cell.getElement(), cell.getColumnIndex())); - cell.setBackground(getBackground(cell.getElement(), cell.getColumnIndex())); - } - } - + } + } + + /** + * Label provider for the tree table. Modified on 30 Aug 2009 by LL to + * implement ITableColorProvider instead of IColorProvider. This allows + * coloring of individual columns, not just of entire rows. + */ + static class StateLabelProvider extends CellLabelProvider + { + public static final int NAME = 0; + public static final int VALUE = 1; + + public static final int[] COLUMN_WIDTH = { 200, 200 }; + public static final String[] COLUMN_TEXTS = { "Name", "Value" }; + + private final Image stateImage; + private final Image varImage; + private final Image recordImage; + private final Image setImage; + private final Image loadMoreImage; + + public StateLabelProvider() + { + stateImage = TLCUIActivator.getImageDescriptor("/icons/full/default_co.gif").createImage(); + varImage = TLCUIActivator.getImageDescriptor("/icons/full/private_co.gif").createImage(); + recordImage = TLCUIActivator.getImageDescriptor("/icons/full/brkpi_obj.gif").createImage(); + // setImage = TLCUIActivator.getImageDescriptor("/icons/full/over_co.gif").createImage(); + setImage = TLCUIActivator.getImageDescriptor("/icons/full/compare_method.gif").createImage(); + loadMoreImage = TLCUIActivator.getImageDescriptor("/icons/full/add.gif").createImage(); // other candidate is newstream_wiz.gif, nav_go.gif, debugt_obj.gif + } + + private Image getColumnImage(Object element, int columnIndex) + { + if (columnIndex == NAME) + { + if (element instanceof LoaderTLCState) { + return loadMoreImage; + } + if (element instanceof TLCState) + { + return stateImage; + } else if (element instanceof TLCVariable) + { + return varImage; + } else if (element instanceof TLCNamedVariableValue) + { + return recordImage; + } else if (element instanceof TLCFcnElementVariableValue) + { + return recordImage; + } + return setImage; // other things appear in unordered collections + } + return null; + } + + private String getColumnText(Object element, int columnIndex) + { + if (element instanceof TLCState) + { + TLCState state = (TLCState) element; + + switch (columnIndex) { + case NAME: + if (state.isStuttering()) + { + return "<Stuttering>"; + } else if (state.isBackToState()) + { + return "<Back to state " + state.getStateNumber() + ">"; + } + return state.getLabel(); + case VALUE: + if (state instanceof RecordToSourceCoupler.LoaderTLCState) { + return ""; + } else { + return "State (num = " + state.getStateNumber() + ")"; + } + // state.toString(); + default: + break; + } + } else if (element instanceof TLCVariable) + { + TLCVariable var = (TLCVariable) element; + switch (columnIndex) { + case NAME: + if (var.isTraceExplorerVar()) + { + return var.getSingleLineName(); + } else + { + return var.getName(); + } + case VALUE: + return var.getValue().toSimpleString(); + // Changed from toString by LL on 30 Aug 2009 + default: + break; + } + } else if (element instanceof TLCSetVariableValue || element instanceof TLCSequenceVariableValue + || element instanceof TLCSimpleVariableValue) + { + + TLCVariableValue varValue = (TLCVariableValue) element; + switch (columnIndex) { + case VALUE: + return varValue.toString(); + case NAME: + return ""; // added by LL on 5 Nov 2009 + default: + break; + } + } else if (element instanceof TLCNamedVariableValue) + { + TLCNamedVariableValue namedValue = (TLCNamedVariableValue) element; + switch (columnIndex) { + case NAME: + return namedValue.getName(); + case VALUE: + return ((TLCVariableValue) namedValue.getValue()).toSimpleString(); + // Changed from toString by LL on 30 Aug 2009 + default: + break; + } + } else if (element instanceof TLCFcnElementVariableValue) + { + TLCFcnElementVariableValue fcnElementValue = (TLCFcnElementVariableValue) element; + switch (columnIndex) { + case NAME: + return fcnElementValue.getFrom().toSimpleString(); + // Changed from toString by LL on 30 Aug 2009 + case VALUE: + return ((TLCVariableValue) fcnElementValue.getValue()).toSimpleString(); + // Changed from toString by LL on 30 Aug 2009 + default: + break; + } + } else if (element instanceof TLCRecordVariableValue) + { + TLCRecordVariableValue recordValue = (TLCRecordVariableValue) element; + switch (columnIndex) { + case NAME: + return ""; + case VALUE: + return recordValue.toSimpleString(); + default: + break; + } + } else if (element instanceof TLCFunctionVariableValue) + { + TLCFunctionVariableValue fcnValue = (TLCFunctionVariableValue) element; + switch (columnIndex) { + case NAME: + return ""; + case VALUE: + return fcnValue.toSimpleString(); + default: + break; + } + } + + return null; + } + + private static final Map<String, Color> LOCATION_COLOR_MAP = new ConcurrentHashMap<String, Color>(); + //TODO Convert to Toolbox preference once this features proves useful. + private static final boolean COLORING_SYSTEM_PROPERTY = Boolean + .getBoolean(TLCErrorView.class.getName() + ".coloring"); + + /** + * The following method sets the background color of a row or column of + * the table. It highlights the entire row for an added or deleted item. + * For a changed value, only the value is highlighted. + */ + private Color getBackground(Object element, int column) { + if (element instanceof TLCVariable) { + final TLCVariable var = (TLCVariable) element; + if (var.isChanged() && column == VALUE) { + return TLCUIActivator.getDefault().getChangedColor(); + } + } else if (element instanceof TLCVariableValue) { + final TLCVariableValue value = (TLCVariableValue) element; + if (value.isChanged()) { + if (column == VALUE) { + return TLCUIActivator.getDefault().getChangedColor(); + } + } else if (value.isAdded()) { + // Added takes precedence over deleted. E.g. a value can be + // added to a set in this state and be removed in the next + // state. + return TLCUIActivator.getDefault().getAddedColor(); + } else if (value.isDeleted()) { + return TLCUIActivator.getDefault().getDeletedColor(); + } + } else if (COLORING_SYSTEM_PROPERTY && element instanceof TLCState) { + // Assign a color to each location to make actions in the error + // viewer more easily distinguishable. + final TLCState state = (TLCState) element; + Location moduleLocation = state.getModuleLocation(); + if (moduleLocation == null) { + return null; + } + Color c = LOCATION_COLOR_MAP.get(moduleLocation.toString()); + if (c == null) { + int color = SWT.COLOR_WHITE + (2 * LOCATION_COLOR_MAP.size()); + c = TLCUIActivator.getColor(color); + LOCATION_COLOR_MAP.put(state.getModuleLocation().toString(), c); + } + return c; + } + return null; + } + + private Color getForeground(Object element, int i) + { + return null; + } + + private Font getFont(Object element, int columnIndex) { + boolean returnBoldVersion = false; + + if (element instanceof TLCVariable) { + if (((TLCVariable) element).isTraceExplorerVar()) { + returnBoldVersion = true; + } + } else if (element instanceof RecordToSourceCoupler.LoaderTLCState) { + returnBoldVersion = true; + } + + final FontRegistry fr = JFaceResources.getFontRegistry(); + return returnBoldVersion ? fr.getBold(JFACE_ERROR_TRACE_ID) : fr.get(JFACE_ERROR_TRACE_ID); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose() + */ + public void dispose() + { + /* + * Remove images + */ + stateImage.dispose(); + varImage.dispose(); + recordImage.dispose(); + setImage.dispose(); + loadMoreImage.dispose(); + super.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IToolTipProvider#getToolTipText(java.lang.Object) + */ + public String getToolTipText(Object element) { + if (element instanceof LoaderTLCState) { + return "Double-click to load more states.\nIf the number of states is large, this might take a few seconds."; + } + return DEFAULT_TOOL_TIP; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell) + */ + public void update(ViewerCell cell) { + // labels + cell.setText(getColumnText(cell.getElement(), cell.getColumnIndex())); + + // images + cell.setImage(getColumnImage(cell.getElement(), cell.getColumnIndex())); + + // font + cell.setFont(getFont(cell.getElement(), cell.getColumnIndex())); + + // colors + cell.setForeground(getForeground(cell.getElement(), cell.getColumnIndex())); + cell.setBackground(getBackground(cell.getElement(), cell.getColumnIndex())); + } + } + public TLCError getTrace() { - if (variableViewer == null) - { - return null; - } + if (variableViewer == null) + { + return null; + } return (TLCError) variableViewer.getInput(); - } - - public Model getModel() { - return model; - } - - private class HelpAction extends Action - { - public HelpAction() - { - super("Help", JFaceResources.getImageRegistry().getDescriptor(Dialog.DLG_IMG_HELP)); - this.setDescription("Opens help"); - this.setToolTipText("Opens help for the TLC Error View."); - } - - public void run() - { - UIHelper.showDynamicHelp(); - } - } - - /** - * Sets the input of the trace viewer to states - * and sets the value viewer to "Select line in Error Trace to show its value here." - * if the list of states is not empty. - * - * @param states - */ + } + + public Model getModel() { + return model; + } + + private class HelpAction extends Action + { + public HelpAction() + { + super("Help", JFaceResources.getImageRegistry().getDescriptor(Dialog.DLG_IMG_HELP)); + this.setDescription("Opens help"); + this.setToolTipText("Opens help for the TLC Error View."); + } + + public void run() + { + UIHelper.showDynamicHelp(); + } + } + + /** + * Sets the input of the trace viewer to states + * and sets the value viewer to "Select line in Error Trace to show its value here." + * if the list of states is not empty. + * + * @param states + */ void setTraceInput(TLCError error) - { - // If itemCount is large (>10.000 items), the underlying OS window - // toolkit can be slow. As a possible fix, look into - // http://www.eclipse.org/nattable/. For background, read - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=129457#c27 - error.restrictTraceTo(numberOfStatesToShow); - variableViewer.getTree().setItemCount(error.getTraceSize() + (error.isTraceRestricted() ? 1 : 0)); - variableViewer.setInput(error); - // If the number of states in the trace is sufficiently small, eagerly - // expand all root level items (which translates to the states - // variables). This causes the TreeViewer to correctly determine the - // vertical scroll bar's height. For larger number of states, we accept - // an incorrect scroll bar height in return for lazy and thus much - // faster item handling. I pulled the limit out of thin air, but - // tested it on three modern (2015) laptops with Win/Mac/Linux. - // - // There seems to be an implementation inside the Eclipse SDK that - // correctly handles the expanded state of a virtual tree: - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=201135 - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=266189 - final int level = 1; - if (error.getTraceSize(level) < 1000) { - variableViewer.expandToLevel(level + 1); // viewer counts root node. + { + // If itemCount is large (>10.000 items), the underlying OS window + // toolkit can be slow. As a possible fix, look into + // http://www.eclipse.org/nattable/. For background, read + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=129457#c27 + error.restrictTraceTo(numberOfStatesToShow); + variableViewer.getTree().setItemCount(error.getTraceSize() + (error.isTraceRestricted() ? 1 : 0)); + variableViewer.setInput(error); + // If the number of states in the trace is sufficiently small, eagerly + // expand all root level items (which translates to the states + // variables). This causes the TreeViewer to correctly determine the + // vertical scroll bar's height. For larger number of states, we accept + // an incorrect scroll bar height in return for lazy and thus much + // faster item handling. I pulled the limit out of thin air, but + // tested it on three modern (2015) laptops with Win/Mac/Linux. + // + // There seems to be an implementation inside the Eclipse SDK that + // correctly handles the expanded state of a virtual tree: + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=201135 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=266189 + final int level = 1; + if (error.getTraceSize(level) < 1000) { + variableViewer.expandToLevel(level + 1); // viewer counts root node. } if (!error.isTraceEmpty()) - { - valueViewer.setDocument(NO_VALUE_DOCUMENT()); - } else - { - valueViewer.setDocument(EMPTY_DOCUMENT()); - } - } - - public void setOriginalTraceShown(boolean b) { - this.model.setOriginalTraceShown(b); - } - - TreeViewer getViewer() { - return variableViewer; - } -} + { + valueViewer.setDocument(NO_VALUE_DOCUMENT()); + } else + { + valueViewer.setDocument(EMPTY_DOCUMENT()); + } + } + + public void setOriginalTraceShown(boolean b) { + this.model.setOriginalTraceShown(b); + } + + TreeViewer getViewer() { + return variableViewer; + } + + + private class SyncStackTraversal extends Action { + SyncStackTraversal() { + super("Sync traversing of the stack trace by arrow keys to the editor.", AS_CHECK_BOX); + + final ImageDescriptor id = PlatformUI.getWorkbench().getSharedImages() + .getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED); + setImageDescriptor(id); + + final boolean enabled = Activator.getDefault().getDialogSettings().getBoolean(SYNCED_TRAVERSAL_KEY); + setChecked(enabled); + + run(); + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + final int value = isChecked() + ? (RecordToSourceCoupler.OBSERVE_ARROW_KEY | RecordToSourceCoupler.OBSERVE_SINGLE_CLICK) + : RecordToSourceCoupler.OBSERVE_DEFAULT; + + stackTraceActionListener.setNonDefaultObservables(value); + } + } + + + private static abstract class ShiftClickAction extends Action implements Listener { + private boolean holdDown = false; + + public ShiftClickAction(final String text, final ImageDescriptor imageDescriptor) { + super(text, imageDescriptor); + } + + @Override + public void runWithEvent(Event event) { + runWithKey(holdDown); + } + + abstract void runWithKey(boolean shiftPressed); + + @Override + public void handleEvent(Event event) { + if (event.keyCode == SWT.SHIFT) { + if (event.stateMask == SWT.SHIFT) { + holdDown = false; + } else if (event.stateMask == SWT.NONE){ + holdDown = true; + } + } + } + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java index 82adf0df88537ce7bd77e826bc4f0a314174835a..bd4844678c8cc21ae978ad282a5f9dc3962979e1 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java @@ -16,7 +16,6 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; import org.lamport.tla.toolbox.tool.tlc.model.Assignment; import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; @@ -105,7 +104,15 @@ public class AssignmentWizardPage extends WizardPage GridData gd; final Assignment assignment = getAssignment(); - paramComposite = new LabeledListComposite(container, assignment.getLocalLabel(), assignment.getParams()); + String localLabel = assignment.getLocalLabel(); + + // display source name and originally defined in module + OpDefNode node = ModelHelper.getOpDefNode(assignment.getLabel()); + if (node != null && node.getSource() != node) { + localLabel += " [" + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]"; + } + + paramComposite = new LabeledListComposite(container, localLabel, assignment.getParams()); gd = new GridData(SWT.LEFT, SWT.TOP, false, true); paramComposite.setLayoutData(gd); @@ -133,18 +140,6 @@ public class AssignmentWizardPage extends WizardPage gd.minimumHeight = 100; styledText.setLayoutData(gd); - // display source name and originally defined in module - OpDefNode node = ModelHelper.getOpDefNode(assignment.getLabel()); - if (node != null && node.getSource() != node) - { - GridData labelGridData = new GridData(); - labelGridData.horizontalSpan = 2; - Label moduleNameLabel = new Label(container, SWT.NONE); - moduleNameLabel.setText("From module " - + node.getSource().getOriginallyDefinedInModuleNode().getName().toString()); - moduleNameLabel.setLayoutData(labelGridData); - } - // constant, no parameters if (!paramComposite.hasParameters()) { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java index 83224827adc9e0adffb88867e22567115ad7f3b3..6b22a6cb50e86d57ca22e9da40b86efcb254f466 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java @@ -8,7 +8,6 @@ import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; /** * A wizard for entering formulas * @author Simon Zambrovski - * @version $Id$ */ public class FormulaWizard extends Wizard { @@ -18,9 +17,14 @@ public class FormulaWizard extends Wizard * */ public FormulaWizard(String action, String description) + { + this(action, description, null, null); + } + + public FormulaWizard(String action, String description, String extendedDescription, String helpId) { super(); - page = new FormulaWizardPage(action, description); + page = new FormulaWizardPage(action, description, extendedDescription, helpId); } /* diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizardPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizardPage.java index 4aba05c08e278a1f02fe7998cdff2f03898406ee..57b58f04fb6678e32c7b31c801b7f79bb8571f48 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizardPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizardPage.java @@ -1,32 +1,50 @@ package org.lamport.tla.toolbox.tool.tlc.ui.wizard; import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner; +import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner; +import org.lamport.tla.toolbox.editor.basic.TLASourceViewerConfiguration; import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper; +import org.lamport.tla.toolbox.util.UIHelper; /** * A page with a simple field for formula editing * @author Simon Zambrovski - * @version $Id$ */ public class FormulaWizardPage extends WizardPage { private SourceViewer sourceViewer; private Document document; + private final String extendedDescription; + private final String helpId; public FormulaWizardPage(String action, String description) + { + this(action, description, null, null); + } + + public FormulaWizardPage(String action, String description, String extendedDescription, String helpId) { super("FormulaWizardPage"); setTitle(action); setDescription(description); + this.extendedDescription = extendedDescription; + this.helpId = helpId; } /* (non-Javadoc) @@ -34,11 +52,39 @@ public class FormulaWizardPage extends WizardPage */ public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NULL); GridLayout layout = new GridLayout(1, false); container.setLayout(layout); + + if (helpId != null) { + UIHelper.setHelp(container, helpId); + } + + sourceViewer = FormHelper.createSourceViewer(container, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, + new TLASourceViewerConfiguration()); + sourceViewer.getTextWidget().addKeyListener(new KeyListener() { + @Override + public void keyPressed(KeyEvent e) { + if (isUndoKeyPress(e)) { + sourceViewer.doOperation(ITextOperationTarget.UNDO); + } else if (isRedoKeyPress(e)) { + sourceViewer.doOperation(ITextOperationTarget.REDO); + } + } + + private boolean isRedoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'y') || (e.keyCode == 'Y')); + } + + private boolean isUndoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'z') || (e.keyCode =='Z')); + } - sourceViewer = FormHelper.createSourceViewer(container, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + @Override + public void keyReleased(KeyEvent e) { + } + }); // SWT.FILL causes the text field to expand and contract // with changes in size of the dialog window. @@ -60,11 +106,28 @@ public class FormulaWizardPage extends WizardPage control.setEditable(true); control.setLayoutData(gd); + + if (this.document == null) { this.document = new Document(); } + final IDocumentPartitioner partitioner = new TLAFastPartitioner( + TLAEditorActivator.getDefault().getTLAPartitionScanner(), TLAPartitionScanner.TLA_PARTITION_TYPES); + document.setDocumentPartitioner(TLAPartitionScanner.TLA_PARTITIONING, partitioner); + partitioner.connect(document); sourceViewer.setDocument(this.getDocument()); + + + // Add extended description below source viewer if given. + if (extendedDescription != null) { + final Label extendedLbl = new Label(container, SWT.WRAP); + extendedLbl.setText(extendedDescription); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 400; // same width as source viewer + extendedLbl.setLayoutData(gd); + } + setControl(container); } diff --git a/org.lamport.tla.toolbox.tool.tlc/.classpath b/org.lamport.tla.toolbox.tool.tlc/.classpath index 098194ca4b7d8f45177f94e735506ae3a26b5c94..eca7bdba8f03f22510b7980a94dbfe10c16c0901 100644 --- a/org.lamport.tla.toolbox.tool.tlc/.classpath +++ b/org.lamport.tla.toolbox.tool.tlc/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> diff --git a/org.lamport.tla.toolbox.tool.tlc/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.tool.tlc/.settings/org.eclipse.jdt.core.prefs index f42de363afaae68bbd968318f1d331877f5514fc..0c68a61dca867ceb49e79d2402935261ec3e3809 100644 --- a/org.lamport.tla.toolbox.tool.tlc/.settings/org.eclipse.jdt.core.prefs +++ b/org.lamport.tla.toolbox.tool.tlc/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF index 0340f59fc66badf0b5ef43fac6bd685e264bac25..c267356c51e34edeecaa3013c27fb03c6de511b0 100644 --- a/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF @@ -26,3 +26,4 @@ Export-Package: org.lamport.tla.toolbox.tool.tlc, org.lamport.tla.toolbox.tool.tlc.traceexplorer, org.lamport.tla.toolbox.tool.tlc.util Import-Package: org.eclipse.ui.part +Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/LongFormDialog.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/LongFormDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..26c67346aeaf8354055e247eca96b8dd80578423 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/LongFormDialog.java @@ -0,0 +1,85 @@ +package org.lamport.tla.toolbox.tool.tlc; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.lamport.tla.toolbox.util.UIHelper; + +/** + * This class really belongs in the <code>...tlc.ui</code> project, except that + * this project has no cited dependency on that project and i'm hesitent to + * introduce new dependencies. + * + * @author loki der quaeler + */ +public class LongFormDialog extends Dialog { + private final String m_title; + private final String m_message; + + public LongFormDialog(final String title, final String message) { + super(UIHelper.getShellProvider()); + + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); + + m_title = title; + m_message = message; + } + + @Override + protected Control createDialogArea(final Composite parent) { + final Composite container = (Composite)super.createDialogArea(parent); + container.setLayout(new GridLayout(2, false)); + + final Display d = container.getDisplay(); + // There is no cross platform clear way to get decoration fonts; get the "system" font and fudge. + final Font f = d.getSystemFont(); + final GC gc = new GC(container.getShell()); + gc.setFont(f); + final Point roughTitleSize = gc.textExtent(m_title); + gc.dispose(); + + final Label errorIcon = new Label(container, SWT.NONE); + errorIcon.setImage(d.getSystemImage(SWT.ICON_ERROR)); + GridData gd = new GridData(); + gd.verticalAlignment = SWT.TOP; + errorIcon.setLayoutData(gd); + + final Text text = new Text(container, (SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY)); + gd = new GridData(); + gd.heightHint = 180; + gd.minimumWidth = Math.max(300, (int)((double)roughTitleSize.x * 1.2)); + gd.horizontalAlignment = SWT.FILL; + gd.verticalAlignment = SWT.FILL; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + text.setLayoutData(gd); + text.setText(m_message); + + container.pack(); + + return container; + } + + // Overridden so that we create only an "Ok" button as there is no state to cancel out of. + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + + @Override + protected void configureShell(final Shell newShell) { + super.configureShell(newShell); + newShell.setText(m_title); + } +} diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/TLCSpecLifeCycleParticipant.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/TLCSpecLifeCycleParticipant.java index 26635ecfdcf6dcdb17250c0077923867bd94d1e4..51cf1d66412af10eb5c9c58865a014522359ed5b 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/TLCSpecLifeCycleParticipant.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/TLCSpecLifeCycleParticipant.java @@ -1,7 +1,6 @@ package org.lamport.tla.toolbox.tool.tlc; import org.eclipse.core.runtime.jobs.Job; -import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.SpecEvent; import org.lamport.tla.toolbox.tool.SpecLifecycleParticipant; import org.lamport.tla.toolbox.tool.SpecRenameEvent; diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java index c57c0d90767e871e9f9568d7cf430c38326354bb..f2c113ddb92935e07e3fc2f6edc5ec1d5152be8b 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java @@ -12,4 +12,6 @@ public interface ITLCJobStatus extends IStatus { InputStream getOutput(); void killTLC(); + + boolean isReconnect(); } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCInternalJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCInternalJob.java deleted file mode 100644 index 8d2fe2e31cb2893b49b8daab36f156246d1e3e6f..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCInternalJob.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.lamport.tla.toolbox.tool.tlc.job; - - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.debug.core.ILaunch; -import org.lamport.tla.toolbox.tool.tlc.TLCActivator; -import org.lamport.tla.toolbox.tool.tlc.model.Model; -import org.lamport.tla.toolbox.tool.tlc.output.IProcessOutputSink; -import org.lamport.tla.toolbox.tool.tlc.output.internal.BroadcastStreamListener; -import org.lamport.tla.toolbox.util.RCPNameToFileIStream; -import org.lamport.tla.toolbox.util.ResourceHelper; - -import tlc2.TLC; -import util.ToolIO; - -/** - * Runs TLC as internal process - * @author Simon Zambrovski - * @version $Id$ - * @deprecated - */ -public class TLCInternalJob extends TLCJob -{ - private TLCThread tlcThread; - private BroadcastStreamListener outputListener; - private int reported; - - /** - * @param name - */ - public TLCInternalJob(String specName, String modelName, ILaunch launch) - { - super(specName, modelName, launch); - - // initialize the progress reporting variable - reported = 0; - - final Model model = launch.getLaunchConfiguration().getAdapter(Model.class); - outputListener = new BroadcastStreamListener(model, IProcessOutputSink.TYPE_OUT); - } - - protected IStatus run(IProgressMonitor monitor) - { - - monitor.beginTask("TLC run for " + rootModule.getName(), IProgressMonitor.UNKNOWN); - - monitor.subTask("Preparing the tool environment"); - // setup tool io - // Reset the tool output messages. - ToolIO.reset(); - ToolIO.setMode(ToolIO.TOOL); - ToolIO.setUserDir(ResourceHelper.getParentDirName(rootModule)); - monitor.worked(STEP); - - - monitor.subTask("Initilizing TLC"); - // create a TLC instance - TLC tlc = new TLC(); - - // setup name resolver - tlc.setResolver(new RCPNameToFileIStream(null)); - - // setup SpecObj from parser - // SpecObj specObj = ToolboxHandle.getSpecObj(); - // tlc.setSpecObject(specObj); - - // handle parameters - String[] params; - try - { - params = constructProgramArguments(); - } catch (CoreException e) - { - return new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Error reading model parameters", e); - } - - boolean status = tlc.handleParameters(params); - - // report errors in parameters - if (!status) - { - return new Status(Status.ERROR, TLCActivator.PLUGIN_ID, "Error processing arguments"); - } - monitor.worked(STEP); - - - // create thread for TLC running - tlcThread = new TLCThread(tlc); - - monitor.subTask("Starting TLC processing"); - - // Start the TLC thread - tlcThread.start(); - monitor.worked(STEP); - - monitor.subTask("Runing TLC"); - while (this.checkAndSleep()) - { - // report the messages created since last reporting - reportProgress(); - - // check the cancellation status - if (monitor.isCanceled()) - { - // cancel the TLC - tlc.setCanceledFlag(true); - - // report the messages created since last reporting - reportProgress(); - - // inform about completion - outputListener.streamClosed(); - - // abnormal termination - return Status.CANCEL_STATUS; - } - } - monitor.worked(STEP); - - // handle finish - doFinish(); - - // report progress - reportProgress(); - - // inform about completion - outputListener.streamClosed(); - - // successful termination - return Status.OK_STATUS; - } - - // decrement the number and sleep - protected boolean checkCondition() - { - // return true if the TLC is still calculating - return (tlcThread.isRunning()); - } - - /** - * Report progress to the fake listener - */ - protected void reportProgress() - { - // report progress - String[] messages = ToolIO.getAllMessages(); - for (; reported < messages.length; reported++) - { - outputListener.streamAppended(messages[reported], null); - } - } - - /** - * Thread to run TLC in - */ - class TLCThread extends Thread - { - private boolean isRunning = false; - private final TLC tlc; - - public TLCThread(TLC tlc) - { - this.tlc = tlc; - } - - public void run() - { - synchronized (this) - { - isRunning = true; - } - // start TLC - this.tlc.process(); - - synchronized (this) - { - isRunning = false; - } - } - - /** - * - * @return - */ - public synchronized boolean isRunning() - { - return isRunning; - } - } - -} diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java index 5507b1a9be244065dc81ab9e607676f03d0de000..7e7cc9da00eb2b49f748ef0c7fd40c54af933939 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java @@ -3,6 +3,7 @@ package org.lamport.tla.toolbox.tool.tlc.job; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Random; import java.util.Vector; import org.eclipse.core.resources.IFile; @@ -30,6 +31,7 @@ import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.ToolboxJob; import tlc2.TLCGlobals; +import tlc2.util.FP64; /** * Abstract TLC job @@ -49,13 +51,6 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC */ private static final int COVERAGE_INTERVAL = 3; - /* - * Number of minutes between checkpoints. It was changed from 20 or 30 to 3, - * apparently by Simon Z. Changed to 15 by LL for 10 Apr 2012 release - * - */ - private static final int CHECKPOINT_INTERVAL = 15 ; - protected long timeout = 1000L; protected IFile rootModule; protected IFile cfgFile; @@ -126,9 +121,9 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC } // adjust checkpointing - if (checkPoint()) { + if (!checkPoint()) { arguments.add("-checkpoint"); - arguments.add(String.valueOf(CHECKPOINT_INTERVAL)); + arguments.add(String.valueOf(0)); } final boolean hasSpec = hasSpec(config); @@ -190,8 +185,7 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC } // Defer liveness checking - final boolean deferLiveness = launch.getLaunchConfiguration().getAttribute(LAUNCH_DEFER_LIVENESS, false); - if (deferLiveness) { + if (deferLiveness()) { arguments.add("-lncheck"); arguments.add("final"); } @@ -204,9 +198,15 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC } // fp seed offset (decrease by one to map from [1, 64] interval to [0, 63] array address - final int fpSeedOffset = launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); - arguments.add("-fp"); - arguments.add(String.valueOf(fpSeedOffset - 1)); + if (launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX_RANDOM, LAUNCH_FP_INDEX_RANDOM_DEFAULT)) { + final int fpIndex = new Random().nextInt(FP64.Polys.length); + arguments.add("-fp"); + arguments.add(String.valueOf(fpIndex)); + } else { + final int fpSeedOffset = launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); + arguments.add("-fp"); + arguments.add(String.valueOf(fpSeedOffset)); + } // add maxSetSize argument if not equal to the default // code added by LL on 9 Mar 2012 @@ -232,7 +232,7 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC // Should not add a coverage option only if TLC is being run // without a spec. This change added 10 Sep 2009 by LL & DR - if (config.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT) != MODEL_BEHAVIOR_TYPE_NO_SPEC) + if (collectCoverage()) { // coverage 0.1 hour arguments.add("-coverage"); @@ -267,8 +267,23 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC return (String[]) arguments.toArray(new String[arguments.size()]); } + // Allow subclasses to veto command line parameters if needed. + + protected boolean deferLiveness() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(LAUNCH_DEFER_LIVENESS, false); + } + protected boolean collectCoverage() throws CoreException { + final ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration(); + if (launchConfiguration.getAttribute(LAUNCH_COVERAGE, LAUNCH_COVERAGE_DEFAULT) != Model.Coverage.OFF.ordinal()) { + return launchConfiguration.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, + MODEL_BEHAVIOR_TYPE_DEFAULT) != MODEL_BEHAVIOR_TYPE_NO_SPEC; + } else { + return false; + } + } + protected boolean recover() throws CoreException { return launch.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.LAUNCH_RECOVER, IModelConfigurationDefaults.LAUNCH_RECOVER_DEFAULT); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java index 7874d120cde4610fbb8a8b15d40863026d13141c..a8f678d99fc80d37c4f7b9f8d10b78a852050e93 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java @@ -2,14 +2,13 @@ package org.lamport.tla.toolbox.tool.tlc.job; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; @@ -30,6 +29,7 @@ import org.lamport.tla.toolbox.tool.tlc.output.internal.BroadcastStreamListener; import org.lamport.tla.toolbox.util.ResourceHelper; import tlc2.TLC; +import tlc2.output.EC; import tlc2.tool.fp.FPSetFactory; import tlc2.tool.fp.NoopFPSet; import tlc2.tool.fp.OffHeapDiskFPSet; @@ -87,31 +87,42 @@ public class TLCProcessJob extends TLCJob // Add 3rd party libraries to classpath. Star acts as wildcard // picking up all .jar files (added by MAK on 07/31/2012) final String libClasspath = runtimeClasspath + File.separator + "lib" + File.separator + "*"; + final String libMailClasspath = runtimeClasspath + File.separator + "lib" + File.separator + "javax.mail" + + File.separator + "*"; // classpath during toolbox development within Eclipse (will simply not // exist in packaged toolbox) final String devClasspath = runtimeClasspath + File.separator + "class"; - String[] classPath = new String[] { runtimeClasspath, libClasspath, devClasspath }; + + // Add TLA+ library path entries to the class path in case any one of them + // includes module overwrites. It is the last element on the classpath. + final Spec spec = Activator.getSpecManager().getSpecByName(specName); + final String libraryPathClassPath = spec.getTLALibraryPathAsClassPath(); + + final String[] classPath = new String[] { runtimeClasspath, libClasspath, libMailClasspath, devClasspath, libraryPathClassPath }; // arguments String[] arguments = constructProgramArguments(); - // log output - TLCActivator - .logInfo("TLC ARGUMENTS: " + Arrays.toString(arguments)); - final List<String> vmArgs = new ArrayList<String>(); // get max heap size as fraction from model editor - final double maxHeapSize = launch.getLaunchConfiguration().getAttribute(LAUNCH_MAX_HEAP_SIZE, HEAP_SIZE_DEFAULT) / 100d; + int maxHeapSize = launch.getLaunchConfiguration().getAttribute(LAUNCH_MAX_HEAP_SIZE, HEAP_SIZE_DEFAULT); + if (maxHeapSize < 1 || maxHeapSize > 99) { + TLCActivator.logInfo(String.format( + "Defaulting fraction of physical memory to %s because %s is out of range (0,100). Value can be adjusted on the model editor's \"Advanced TLC option\" tab.", + HEAP_SIZE_DEFAULT, maxHeapSize)); + // Dealing with a legacy model (absolute memory values) or somehow bogus input. + maxHeapSize = HEAP_SIZE_DEFAULT; + } final TLCRuntime instance = TLCRuntime.getInstance(); - long absolutePhysicalSystemMemory = instance.getAbsolutePhysicalSystemMemory(maxHeapSize); + long absolutePhysicalSystemMemory = instance.getAbsolutePhysicalSystemMemory(maxHeapSize / 100d); // Get class name of the user selected FPSet. If it is unset, try and load the // OffHeapDiskFPSet (which might not be supported). In unsupported, revert to // TLC's default set. // If the user happened to select OffHeapDiskFPSet, the -XX:MaxDirectMemorySize // is set by getVMArguments. - String clazz = launch.getLaunchConfiguration().getAttribute(LAUNCH_FPSET_IMPL, (String) null); + String clazz = getOptimalFPsetImpl(); if (!hasSpec(launch.getLaunchConfiguration())) { // If a spec has no behaviors, TLC won't need a fingerprint set. Thus, use the // NoopFPSet whose initialization cost is next to nothing. Real fpsets on the @@ -143,6 +154,9 @@ public class TLCProcessJob extends TLCJob vmArgs.add("-D" + FPSetFactory.IMPL_PROPERTY + "=" + clazz); } + // specify Java8+ acceptable GC + vmArgs.add("-XX:+UseParallelGC"); + // add remaining VM args vmArgs.addAll(getAdditionalVMArgs()); @@ -154,10 +168,8 @@ public class TLCProcessJob extends TLCJob tlcConfig.setVMArguments((String[]) vmArgs.toArray(new String[vmArgs.size()])); tlcConfig.setWorkingDirectory(ResourceHelper.getParentDirName(rootModule)); // Following added for testing by LL on 6 Jul 2012 - TLCActivator.logInfo("JAVA VM ARGUMENTS: " + Arrays.toString(tlcConfig.getVMArguments())); final IVMInstall vmInstall = getVMInstall(); - TLCActivator.logInfo("Nested JVM used for model checker is: " - + vmInstall.getInstallLocation()); + final IVMRunner runner = vmInstall.getVMRunner(ILaunchManager.RUN_MODE); @@ -170,11 +182,18 @@ public class TLCProcessJob extends TLCJob try { // step 3 - runner.run(tlcConfig, launch, new SubProgressMonitor(monitor, STEP)); + runner.run(tlcConfig, launch, new NullProgressMonitor()); tlcStartTime = System.currentTimeMillis(); } catch (CoreException e) { - return new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Error launching TLC modle checker", e); + // Include command-line for users to figure out what failed. + return new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, + String.format("Error launching TLC with command-line (CWD: %s): %s%sbin%sjava -cp %s %s %s %s", + tlcConfig.getWorkingDirectory(), vmInstall.getInstallLocation(), File.separator, + File.separator, String.join(File.pathSeparator, tlcConfig.getClassPath()), + String.join(" ", tlcConfig.getVMArguments()), + String.join(" ", tlcConfig.getClassToLaunch()), String.join(" ", arguments)), + e); } // find the running process @@ -187,6 +206,14 @@ public class TLCProcessJob extends TLCJob // process found if (this.process != null) { + // Log command-line that can (almost) copied&pasted verbatim to a shell to + // run TLC directly. + // (Working directory needed because TLC does not find MC.tla even if -metadir + // is set). + final String cmd = this.process.getAttribute(IProcess.ATTR_CMDLINE); + final String cwd = this.process.getAttribute(DebugPlugin.ATTR_WORKING_DIRECTORY); + TLCActivator.logInfo(String.format("TLC COMMAND-LINE (CWD: %s): %s", cwd, cmd)); + // step 5 monitor.worked(STEP); monitor.subTask("Model checking..."); @@ -313,22 +340,15 @@ public class TLCProcessJob extends TLCJob } } + protected String getOptimalFPsetImpl() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(LAUNCH_FPSET_IMPL, (String) null); + } + /** * @return A list of additional vm arguments */ protected List<String> getAdditionalVMArgs() throws CoreException { final List<String> result = new ArrayList<String>(0); - - /* - * Allow access to the java.activation module on Java9 - * https://bugs.eclipse.org/493761 - * http://download.java.net/java/jdk9/docs/api/java.activation-summary.html - * - * This is needed by MailSender.java. - */ - result.add("--add-modules=java.activation"); - // Have < Java9 ignore --add-modules=java.activation flag - result.add("-XX:+IgnoreUnrecognizedVMOptions"); // Library Path final Spec spec = Activator.getSpecManager().getSpecByName(specName); @@ -424,6 +444,10 @@ public class TLCProcessJob extends TLCJob shouldNotHappen.printStackTrace(); } } - return -1; + return 255; } + + public boolean hasCrashed() { + return EC.ExitStatus.exitStatusToCrash(getExitValue()); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java index 928034425dde06d258d2613b4298fe90abd64e43..a9d4e0fe560628d3e05779952d421cddfff6b784 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java @@ -1,8 +1,14 @@ package org.lamport.tla.toolbox.tool.tlc.job; +import java.util.List; + import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunch; import org.eclipse.swt.widgets.Display; +import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter; + +import tlc2.tool.fp.FPSetFactory; +import tlc2.tool.impl.SpecProcessor; /** * Extends {@link TLCProcessJob}. @@ -57,6 +63,17 @@ public class TraceExplorerJob extends TLCProcessJob return false; } + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob#getAdditionalVMArgs() + */ + @Override + protected List<String> getAdditionalVMArgs() throws CoreException { + final List<String> additionalVMArgs = super.getAdditionalVMArgs(); + additionalVMArgs.add( + String.format("-D%s=%s", SpecProcessor.LAZY_CONSTANT_OPERATORS, TraceExpressionModelWriter.POSITION)); + return additionalVMArgs; + } + /* (non-Javadoc) * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#isDepthFirst() */ @@ -107,4 +124,35 @@ public class TraceExplorerJob extends TLCProcessJob // exploration. A trace is just a txt file with a sequence of states. return false; } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#collectCoverage() + */ + @Override + protected boolean collectCoverage() throws CoreException { + // No need for coverage statistics when running error trace exploration. + return false; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#deferLiveness() + */ + @Override + protected boolean deferLiveness() throws CoreException { + // As a performance improvement, always defer liveness until the end of model + // checking in trace exploration. + return true; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob#getOptimalFPsetImpl() + */ + @Override + protected String getOptimalFPsetImpl() throws CoreException { + // A trace is a single behavior of usually about a dozen states and sometimes a + // few thousand. This range is easily handled by the default FPSet + // implementation which is faster to initialize compared to the optimized + // OffHeapDiskFPSet. This should make the trace explorer a lot snappier. + return FPSetFactory.getImplementationDefault(); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationConstants.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationConstants.java index f5bb35f8bb2b1aaa11df346376ad1f023ffc4543..098f4bbf018f9308f941212b04aa54c0bf15b64d 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationConstants.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationConstants.java @@ -21,6 +21,10 @@ public interface IConfigurationConstants * Name of the configuration (foo_mc_{i}) */ public static final String MODEL_NAME = "configurationName"; + /** + * Which profile to use for TLC configuration + */ + public static final String TLC_RESOURCES_PROFILE = "tlcResourcesProfile"; /** * Number of workers to use during TLC launch */ @@ -89,6 +93,10 @@ public interface IConfigurationConstants * the fp seed index "-fp" */ public static final String LAUNCH_FP_INDEX = "fpIndex"; + /** + * Choose FP index randomly + */ + public static final String LAUNCH_FP_INDEX_RANDOM = "fpIndexRandom"; /** * Defers verification of liveness properties upon the final stage of model @@ -99,6 +107,10 @@ public interface IConfigurationConstants * Visualize state graph after model checking with GraphViz. */ public static final String LAUNCH_VISUALIZE_STATEGRAPH = "visualizeStateGraph"; + /** + * Collect coverage statistics + */ + public static final String LAUNCH_COVERAGE = "collectCoverage"; /** * Run from the checkpoint */ diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationDefaults.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationDefaults.java index 2b1697fcb8a5aa45758d6b02ea840f4422e3ea3c..ed0d470495a7f44842fb64caae61a2069590867e 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationDefaults.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IConfigurationDefaults.java @@ -17,6 +17,8 @@ public interface IConfigurationDefaults * Default number of workers. Was set by Simon to be is 2. * Modified by LL on 11 October 2009 to be half the number of available processors. * Fixed by LL on 20 Oct 2009 to equal 1, not 0, if there is only 1 available processor. + * + * 20190302 - this will be deprecated in the future once TLCConsumptionProfile is fully adopted. */ public static final int LAUNCH_NUMBER_OF_WORKERS_DEFAULT = (Runtime.getRuntime().availableProcessors() > 1) ? (Runtime .getRuntime().availableProcessors() / 2) @@ -24,8 +26,12 @@ public interface IConfigurationDefaults /** * Run in distributed mode? + * + * We need two, because in some places we especially want to specify "do not launch remote workers" and will be + * shafted should some future developer change the default value. */ - public static final String LAUNCH_DISTRIBUTED_DEFAULT = "off"; + public static final String LAUNCH_DISTRIBUTED_NO = "off"; + public static final String LAUNCH_DISTRIBUTED_DEFAULT = LAUNCH_DISTRIBUTED_NO; /** * Launch distributed version of TLC and send result to this address @@ -93,6 +99,10 @@ public interface IConfigurationDefaults * Default fp seed is 1 meaning the first elem in the list */ public static final int LAUNCH_FP_INDEX_DEFAULT = 1; + /** + * Default fp seed is 1 meaning the first elem in the list + */ + public static final boolean LAUNCH_FP_INDEX_RANDOM_DEFAULT = true; /** * Default fp seed is 1 meaning the first elem in the list */ @@ -102,7 +112,11 @@ public interface IConfigurationDefaults */ public static final boolean LAUNCH_VISUALIZE_STATEGRAPH_DEFAULT = false; /** - * Do not recover from checkpoints by defualt + * Do not recover from checkpoints by default */ public static final boolean LAUNCH_RECOVER_DEFAULT = false; + /** + * Collect coverage and cost statistics by default + */ + public static final int LAUNCH_COVERAGE_DEFAULT = 1; } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java index 56d2e303be8eef74a998e539e71ac75decc5ad25..5e39863dd558beaa6848624f49052f044d94f660 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java @@ -2,7 +2,6 @@ package org.lamport.tla.toolbox.tool.tlc.launch; /** * @author Simon Zambrovski - * @version $Id$ */ public interface IModelConfigurationConstants extends IConfigurationConstants { @@ -105,4 +104,16 @@ public interface IModelConfigurationConstants extends IConfigurationConstants */ public static final String TRACE_EXPLORE_EXPRESSIONS = "traceExploreExpressions"; + /** + * a bitwise OR'd value representing which of the closeable tabs should be open on a model editor opening + */ + public static final String EDITOR_OPEN_TABS = "modelEditorOpenTabs"; + + /** + * values to use with the {@link #EDITOR_OPEN_TABS} attribute + */ + public static final int EDITOR_OPEN_TAB_NONE = 0; + public static final int EDITOR_OPEN_TAB_ADVANCED_MODEL = 1 << 1; + public static final int EDITOR_OPEN_TAB_ADVANCED_TLC = 1 << 2; + } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java index 8165a2afa9449550053844608faa7c26ce286084..7db19e7d1f9c177db6f47057f59d6f6d51f0b24a 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java @@ -8,10 +8,14 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.Random; import java.util.Vector; +import java.util.stream.Collectors; import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.resources.IFile; @@ -58,8 +62,10 @@ import org.lamport.tla.toolbox.tool.tlc.job.ITLCJobStatus; import org.lamport.tla.toolbox.tool.tlc.job.TLCJobFactory; import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; import org.lamport.tla.toolbox.tool.tlc.model.Assignment; +import org.lamport.tla.toolbox.tool.tlc.model.Formula; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; +import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; import org.lamport.tla.toolbox.tool.tlc.output.IProcessOutputSink; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; @@ -73,6 +79,8 @@ import org.osgi.framework.ServiceReference; import tla2sany.semantic.ModuleNode; import tla2sany.semantic.OpDeclNode; import tlc2.TLCGlobals; +import tlc2.util.FP64; +import util.ExecutionStatisticsCollector; /** * Represents a launch delegate for TLC<br> @@ -212,8 +220,6 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen IFile cfgFile = project.getFile(targetFolderPath.append(ModelHelper.FILE_CFG)); IFile outFile = project.getFile(targetFolderPath.append(ModelHelper.FILE_OUT)); - TLCActivator.logDebug("Writing files to: " + targetFolderPath.toOSString()); - final IFile[] files = new IFile[] { tlaFile, cfgFile, outFile }; if (modelFolder.exists()) @@ -452,16 +458,31 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen case MODEL_BEHAVIOR_TYPE_SPEC_CLOSED: // the specification name-formula pair - writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, - ModelWriter.SPEC_SCHEME, config), "SPECIFICATION", MODEL_BEHAVIOR_CLOSED_SPECIFICATION); + final String spec = config.getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, EMPTY_STRING); + if (model.getSpec().declares(spec) && !isExpression(spec)) { + writer.addFormulaList(spec, "SPECIFICATION", MODEL_BEHAVIOR_CLOSED_SPECIFICATION); + } else { + writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, + ModelWriter.SPEC_SCHEME, config), "SPECIFICATION", MODEL_BEHAVIOR_CLOSED_SPECIFICATION); + } break; case MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT: - - // the init and next formulas - writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, - ModelWriter.INIT_SCHEME, config), "INIT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT); - writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, - ModelWriter.NEXT_SCHEME, config), "NEXT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT); + // the init and next formulas + final String init = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, EMPTY_STRING); + if (model.getSpec().declares(init) && !isExpression(init)) { + writer.addFormulaList(init, "INIT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT); + } else { + writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, + ModelWriter.INIT_SCHEME, config), "INIT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT); + } + + final String next = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, EMPTY_STRING); + if (model.getSpec().declares(next) && !isExpression(next)) { + writer.addFormulaList(next, "NEXT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT); + } else { + writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, + ModelWriter.NEXT_SCHEME, config), "NEXT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT); + } break; } @@ -472,15 +493,16 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen // do not write invariants and properties if there is no behavior spec if (hasSpec) { - // invariants - writer.addFormulaList(ModelWriter.createFormulaListContent(config.getAttribute( - MODEL_CORRECTNESS_INVARIANTS, new Vector<String>()), ModelWriter.INVARIANT_SCHEME), "INVARIANT", - MODEL_CORRECTNESS_INVARIANTS); - - // properties - writer.addFormulaList(ModelWriter.createFormulaListContent(config.getAttribute( - MODEL_CORRECTNESS_PROPERTIES, new Vector<String>()), ModelWriter.PROP_SCHEME), "PROPERTY", - MODEL_CORRECTNESS_PROPERTIES); + // invariants (separate those declared in the spec from those declared in the model). + final List<String> invariants = config.getAttribute(MODEL_CORRECTNESS_INVARIANTS, new Vector<String>()); + writer.addFormulaList( + createProperties(writer, model.getSpec(), invariants, ModelWriter.INVARIANT_SCHEME), + "INVARIANT", MODEL_CORRECTNESS_INVARIANTS); + + // properties + final List<String> properties = config.getAttribute(MODEL_CORRECTNESS_PROPERTIES, new Vector<String>()); + writer.addFormulaList(createProperties(writer, model.getSpec(), properties, ModelWriter.PROP_SCHEME), + "PROPERTY", MODEL_CORRECTNESS_PROPERTIES); } monitor.worked(STEP); @@ -501,6 +523,46 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen // we don't want to rebuild the workspace return false; } + + private static boolean isExpression(final String formula) { + // TLC's config file only accepts identifiers but no expressions + // (tlc2.tool.ModelConfig.parse()). TLAplusParserTokenManager unfortunately does + // not parse tokens such as "C!Spec" into an identifier. Subsequently this leads + // to an invalid config. Thus, treat a formula with a bang as an expressions. If + // tla+.jj ever gets changed to handle instantiated operators, this + // workaround/hack can be removed. + return formula.contains("!"); + } + + private static List<String[]> createProperties(final ModelWriter writer, final TLCSpec spec, final List<String> properties, + final String scheme) { + + // Convert list of strings such as {"1Inv", "0x \in Nat"} into a subset of + // checked formulas (prefixed with 1). + final List<Formula> checkedFormula = ModelHelper.deserializeFormulaList(properties); + + // Create the input for the model writer out of all formula... + final List<String[]> createFormulaListContent = ModelWriter.createFormulaListContentFormula(checkedFormula, + scheme); + + // Collect those formula that are declared in the spec, not the MC.tla file. + final List<Formula> declaredFormula = checkedFormula.stream().filter(f -> spec.declares(f.getFormula()) && !isExpression(f.getFormula())) + .collect(Collectors.toList()); + + // Override each declared formula with its original declaration. This will cause + // ModelWriter.addFormulaList to omit it from the MC.tla file and only add it to MC.cfg. + declaredFormula.forEach(f -> createFormulaListContent.set(checkedFormula.indexOf(f), + new String[] { f.getFormula(), EMPTY_STRING, String.valueOf(checkedFormula.indexOf(f)) })); + + // createFormulaListContent has to be in the same order as checkedFormula. + // Otherwise, TLCModelLaunchDataProvider.createError(TLCRegion, + // String) would fail to match the violated invariant to the one stored in the + // model. This results in the Toolbox reporting the wrong invariant. As a second + // safeguard ModelWriter.createFormulaListContentFormula adds the formula's index + // to the String[] which - if present - is eventually used as the formula's index + // by ModelWriter.addFormulaList. + return createFormulaListContent; + } // Copy userModule overrides (see tlc2.tool.Spec.processSpec(SpecObj)) if // any. An override is an Java implementation of a user defined module. By @@ -557,8 +619,26 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen TLCActivator.logDebug("Errors in model file found " + rootModule.getLocation()); } - FileEditorInput fileEditorInput = new FileEditorInput((IFile) rootModule); + final Map<TLAMarkerInformationHolder, Hashtable<String, Object>> props = sany2ToolboxErrors(monitor, rootModule, + detectedErrors); + props.values().forEach(marker -> model.setMarker(marker, Model.TLC_MODEL_ERROR_MARKER_SANY)); + + if (MODE_GENERATE.equals(mode)) + { + // generation is done + // nothing to do more + return false; + } else + { + return status; + } + } + + protected Map<TLAMarkerInformationHolder, Hashtable<String, Object>> sany2ToolboxErrors(final IProgressMonitor monitor, final IFile rootModule, + final Vector<TLAMarkerInformationHolder> detectedErrors) throws CoreException { + FileEditorInput fileEditorInput = new FileEditorInput(rootModule); FileDocumentProvider fileDocumentProvider = new FileDocumentProvider(); + final Map<TLAMarkerInformationHolder, Hashtable<String, Object>> result = new HashMap<>(); try { @@ -585,13 +665,8 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen // find the error cause and install the error marker on the corresponding // field - Hashtable<String, Object> props = ModelHelper.createMarkerDescription(document, searchAdapter, - message, severity, coordinates); - if (props != null) - { - model.setMarker(props, Model.TLC_MODEL_ERROR_MARKER_SANY); - } - + result.put(markerHolder, ModelHelper.createMarkerDescription(rootModule, document, searchAdapter, + message, severity, coordinates)); } else { // see getLaunch(...) above @@ -628,18 +703,8 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen fileDocumentProvider.disconnect(fileEditorInput); monitor.done(); } - - if (MODE_GENERATE.equals(mode)) - { - // generation is done - // nothing to do more - return false; - } else - { - TLCActivator.logDebug("Final check for the " + mode + " mode. The result of the check is " + status); - return status; - } - } + return result; + } /** * 5. method called on launch @@ -734,14 +799,27 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen } props.put(TLCJobFactory.MAIL_ADDRESS, config.getAttribute( LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, "tlc@localhost")); + + final ExecutionStatisticsCollector udc = new ExecutionStatisticsCollector(); + if (udc.isEnabled()) { + props.put(ExecutionStatisticsCollector.PROP, udc.getIdentifier()); + } // The parameters below are the only one currently useful with CloudDistributedTLC final StringBuffer tlcParams = new StringBuffer(); - // fp seed offset (decrease by one to map from [1, 64] interval to [0, 63] array address - final int fpSeedOffset = launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); - tlcParams.append("-fp "); - tlcParams.append(String.valueOf(fpSeedOffset - 1)); + // fp seed offset (decrease by one to map from [1, 64] interval to [0, 63] array address) + if (launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX_RANDOM, LAUNCH_FP_INDEX_RANDOM_DEFAULT)) { + final int fpIndex = new Random().nextInt(FP64.Polys.length); + tlcParams.append("-fp"); + tlcParams.append(" "); + tlcParams.append(String.valueOf(fpIndex)); + } else { + final int fpSeedOffset = launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX, LAUNCH_FP_INDEX_DEFAULT); + tlcParams.append("-fp"); + tlcParams.append(" "); + tlcParams.append(String.valueOf(fpSeedOffset)); + } tlcParams.append(" "); // add maxSetSize argument if not equal to the default @@ -886,6 +964,13 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen final String message = status.getMessage(); if (status instanceof ITLCJobStatus) { final ITLCJobStatus result = (ITLCJobStatus) status; + + if (result.isReconnect()) { + // Do not open modal dialog if this is just a reconnect. In other words, no + // dialog if user is running cloud TLC repeatedly. + return; + } + final URL url = result.getURL(); Display.getDefault().asyncExec(new Runnable() { public void run() { @@ -976,7 +1061,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen Assert.isNotNull(event.getResult()); TLCProcessJob tlcJob = (TLCProcessJob) event.getJob(); - if (!Status.CANCEL_STATUS.equals(event.getJob().getResult()) && tlcJob.getExitValue() > 0) { + if (!Status.CANCEL_STATUS.equals(event.getJob().getResult()) && tlcJob.hasCrashed()) { // if TLC crashed with exit value > 0 and the user did *not* // click cancel, mark the job as crashed. model.setStale(); @@ -1126,7 +1211,6 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen break; } } - TLCActivator.logDebug("Job '" + jobName + "' terminated with status: { " + status + " }"); } }; diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java index bd64336d1d33575a656c34a8d4a29d0290c39408..be9717994ce3094c0ea75ebec2877d0665618537 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java @@ -28,10 +28,12 @@ package org.lamport.tla.toolbox.tool.tlc.launch; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; @@ -53,6 +55,7 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.lamport.tla.toolbox.spec.parser.ParseResult; import org.lamport.tla.toolbox.tool.IParseResult; import org.lamport.tla.toolbox.tool.ToolboxHandle; +import org.lamport.tla.toolbox.tool.tlc.LongFormDialog; import org.lamport.tla.toolbox.tool.tlc.TLCActivator; import org.lamport.tla.toolbox.tool.tlc.job.TLCJob; import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; @@ -417,6 +420,8 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename())); writeModelInfo(config, writer); + + writer.addTraceFunction(trace); /* * The following writes variable declarations and identifier definitions @@ -483,24 +488,30 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa /*********************************************************************************** * Check for parsing errors first. * ***********************************************************************************/ - if (parseResult.getDetectedErrors().size() > 0) + final Vector<TLAMarkerInformationHolder> detectedErrors = parseResult.getDetectedErrors(); + if (detectedErrors.size() > 0) { + final Map<TLAMarkerInformationHolder, Hashtable<String, Object>> props = sany2ToolboxErrors(monitor, rootModule, detectedErrors); + /* * This displays the parse errors to the user in an error * dialog. It attempts to replace messages containing references * to locations to module TE with the string from that location. */ final StringBuffer errorMessage = new StringBuffer(); - Iterator<TLAMarkerInformationHolder> it = parseResult.getDetectedErrors().iterator(); - while (it.hasNext()) - { - TLAMarkerInformationHolder errorInfo = it.next(); - errorMessage.append(errorInfo.getMessage() + "\n"); + for (final TLAMarkerInformationHolder errorInfo : parseResult.getDetectedErrors()) { + if (props.containsKey(errorInfo)) { + errorMessage.append(props.get(errorInfo).get(IMarker.MESSAGE)); + } else { + errorMessage.append(errorInfo.getMessage() + "\n"); + } } UIHelper.runUIAsync(new Runnable() { public void run() { - MessageDialog.openError(UIHelper.getShellProvider().getShell(), - "Parsing error when running trace explorer", errorMessage.toString()); + final LongFormDialog dialog = new LongFormDialog("Parsing error when running trace explorer", + errorMessage.toString()); + + dialog.open(); } }); return false; @@ -616,6 +627,8 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa // write constants, model values, new definitions, definition overrides writeModelInfo(configuration, writer); + + writer.addTraceFunction(trace); // variables declarations for trace explorer expressions writer.addVariablesAndDefinitions(traceExpressionData, TRACE_EXPLORE_EXPRESSIONS, false); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java index 67b27de16660a02122f6a0f434ab2beba35b65e6..8fb02ecb2a841f86d280e0655ee3dcc4897a071b 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java @@ -1,5 +1,8 @@ package org.lamport.tla.toolbox.tool.tlc.model; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Representation of a formula. * @author Simon Zambrovski @@ -40,4 +43,29 @@ public class Formula this.formula = formula; } + // MAK 03/2019: This methods below appear redundant to the Assignment subclass + // but I don't have time to look into it. + + public boolean isNamed() { + return !getLeftHandSide().equals(getFormula()); + } + + // DOTALL to match beyond line endings. + private static final Pattern pattern = Pattern.compile("^\\s*(\\w+)\\s*==(.*)$", Pattern.DOTALL); + + public String getLeftHandSide() { + final Matcher matcher = pattern.matcher(this.formula); + if (matcher.find()) { + return matcher.group(1).trim(); + } + return getFormula(); + } + + public String getRightHandSide() { + final Matcher matcher = pattern.matcher(this.formula); + if (matcher.find()) { + return matcher.group(2).trim(); + } + return getFormula(); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java index b90c75a3f47b33c3acfddadec964fca7f9fc6fa9..53b9447d5637f023e6979da8fedab3cee2347a9e 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java @@ -34,6 +34,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -48,6 +49,7 @@ import org.apache.commons.io.filefilter.NotFileFilter; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceRuleFactory; import org.eclipse.core.resources.IWorkspace; @@ -63,9 +65,11 @@ import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jface.text.BadLocationException; @@ -77,7 +81,10 @@ import org.eclipse.ui.part.FileEditorInput; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.TLCActivator; +import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationDefaults; import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate; import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent; import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent.State; import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState; @@ -128,12 +135,16 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } /** - * @param fullQualifiedModelName The full-qualified (includes the Spec name and separator too) name of the Model. + * @param modelName The full-qualified (includes the Spec name and separator too) name of the Model. * @return A Model, iff a Model by the given name exists and <code>null</code> otherwise. */ public static Model getByName(final String modelName) { return TLCModelFactory.getByName(modelName); } + + public static String fullyQualifiedNameFromSpecNameAndModelName(final String specName, final String modelName) { + return specName + SPEC_MODEL_DELIM + modelName; + } /** * A {@link StateChangeListener} is notified when the running state of the model @@ -248,18 +259,57 @@ public class Model implements IModelConfigurationConstants, IAdaptable { return this.spec; } - public Model copy(String newModelName) { - newModelName = sanitizeName(newModelName); + public Model copy(final String newModelName) { + final String sanitizedNewName = sanitizeName(newModelName); try { - final ILaunchConfigurationWorkingCopy copy = this.launchConfig - .copy(getSpec().getName() + SPEC_MODEL_DELIM + newModelName); - copy.setAttribute(ModelHelper.MODEL_NAME, newModelName); + final String fullyQualified = fullyQualifiedNameFromSpecNameAndModelName(spec.getName(), sanitizedNewName); + final ILaunchConfigurationWorkingCopy copy = this.launchConfig.copy(fullyQualified); + copy.setAttribute(IConfigurationConstants.SPEC_NAME, spec.getName()); + copy.setAttribute(IConfigurationConstants.MODEL_NAME, sanitizedNewName); return copy.doSave().getAdapter(Model.class); } catch (CoreException e) { TLCActivator.logError("Error cloning model.", e); return null; } } + + public Model copyIntoForeignSpec(final Spec foreignSpec, final String newModelName) { + final IProject foreignProject = foreignSpec.getProject(); + final ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager(); + final ILaunchConfigurationType launchConfigurationType + = launchManager.getLaunchConfigurationType(TLCModelLaunchDelegate.LAUNCH_CONFIGURATION_TYPE); + final String sanitizedNewName = sanitizeName(newModelName); + final String wholeName = fullyQualifiedNameFromSpecNameAndModelName(foreignSpec.getName(), sanitizedNewName); + + try { + final ILaunchConfigurationWorkingCopy copy = launchConfigurationType.newInstance(foreignProject, wholeName); + copyAttributesFromForeignModelToWorkingCopy(this, copy); + copy.setAttribute(IConfigurationConstants.SPEC_NAME, foreignSpec.getName()); + copy.setAttribute(IConfigurationConstants.MODEL_NAME, sanitizedNewName); + return copy.doSave().getAdapter(Model.class); + } catch (CoreException e) { + TLCActivator.logError("Error cloning foreign model.", e); + return null; + } + } + + // There is actually a method ILaunchConfigurationWorkingCopy.copyAttributes however the launch configuration + // need be a prototype; so we do this by hand. + private void copyAttributesFromForeignModelToWorkingCopy(final Model foreignModel, + final ILaunchConfigurationWorkingCopy copy) throws CoreException { + final ILaunchConfiguration foreignILC = foreignModel.getLaunchConfiguration(); + final Map<String, Object> workingCopyAttributes = copy.getAttributes(); + final Map<String, Object> foreignAttributes = foreignILC.getAttributes(); + + for (final Map.Entry<String, Object> me : foreignAttributes.entrySet()) { + copy.setAttribute(me.getKey(), me.getValue()); + workingCopyAttributes.remove(me.getKey()); + } + + for (final String key : workingCopyAttributes.keySet()) { + copy.removeAttribute(key); + } + } public void rename(String newModelName, IProgressMonitor monitor) throws CoreException { final Collection<Model> snapshots = getSnapshots(); @@ -299,8 +349,8 @@ public class Model implements IModelConfigurationConstants, IAdaptable { private void renameLaunch(final Spec newSpec, String newModelName) { try { // create the model with the new name - final ILaunchConfigurationWorkingCopy copy = this.launchConfig - .copy(newSpec.getName() + SPEC_MODEL_DELIM + newModelName); + final String fullyQualifiedName = fullyQualifiedNameFromSpecNameAndModelName(newSpec.getName(), newModelName); + final ILaunchConfigurationWorkingCopy copy = this.launchConfig.copy(fullyQualifiedName); copy.setAttribute(SPEC_NAME, newSpec.getName()); copy.setAttribute(ModelHelper.MODEL_NAME, newModelName); copy.setContainer(newSpec.getProject()); @@ -422,7 +472,16 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } public boolean isSnapshot() { - return getName().matches(".*" + SNAPSHOT_REGEXP); + final String name = getName(); + if (name == null) { + // When deleting a set of model and snapshots from the spec explorer, the spec + // explorer internally might access one of the already deleted models. A deleted + // model however has no name (name is null) causing a NullPointerException here. + // For the sake of simplicity, we define a model without a name to not be a + // snapshot. + return false; + } + return name.matches(".*" + SNAPSHOT_REGEXP); } public boolean hasSnapshots() { @@ -754,11 +813,34 @@ public class Model implements IModelConfigurationConstants, IAdaptable { return (IFolder) getSpec().getProject().findMember(getName()); } + public List<IFile> getSavedTLAFiles() { + try { + final List<IFile> res = new ArrayList<>(); + final IFolder targetDirectory = getTargetDirectory(); + if (targetDirectory == null) { + // Model has not been run yet. + return res; + } + final List<IResource> asList = Arrays.asList(targetDirectory.members()); + for (final IResource iResource : asList) { + if (iResource instanceof IFile) { + final IFile f = (IFile) iResource; + if (f.exists() && "tla".equalsIgnoreCase(f.getFileExtension())) { + res.add(f); + } + } + } + return res; + } catch (CoreException e) { + return new ArrayList<>(); + } + } + /** - * Retrieves the TLA file that is being model checked on the model run + * Retrieves the TLA file that is being model checked on the model run. This is + * the MC.tla file. * - * @param config - * configuration representing the model + * @param config configuration representing the model * @return a file handle or <code>null</code> */ public IFile getTLAFile() { @@ -1036,12 +1118,23 @@ public class Model implements IModelConfigurationConstants, IAdaptable { return new Vector<SimpleTLCState>(); } - /* (non-Javadoc) - * @see java.lang.Object#toString() + /** + * This currently invokes {@link #getFullyQualifiedName()} + * + * {@inheritDoc} */ public String toString() { - // The model's full-qualified name - return getSpec().getName() + SPEC_MODEL_DELIM + getName(); + return getFullyQualifiedName(); + } + + /** + * It's more sensible to have this explicitly named method, than rely on having the arcane knowledge that + * <code>toString()</code> returns this value. + * + * @return the fully qualified name of the model, which includes the spec name. + */ + public String getFullyQualifiedName() { + return fullyQualifiedNameFromSpecNameAndModelName(getSpec().getName(), getName()); } public List<String> getTraceExplorerExpressions() { @@ -1054,6 +1147,22 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } } + public List<Formula> getTraceExplorerExpressionsAsFormula() { + final List<String> traceExplorerExpressions = getTraceExplorerExpressions(); + return ModelHelper.deserializeFormulaList(traceExplorerExpressions); + } + + public Map<String, Formula> getNamedTraceExplorerExpressionsAsFormula() { + final List<Formula> traceExplorerExpressionsAsFormula = getTraceExplorerExpressionsAsFormula(); + final Map<String, Formula> result = new HashMap<>(); + for (Formula formula : traceExplorerExpressionsAsFormula) { + if (formula.isNamed()) { + result.put(formula.getLeftHandSide(), formula); + } + } + return result; + } + public void setTraceExplorerExpression(List<String> serializedInput) { // TODO Why is this written into a working copy? => One can only write // into a working copy, which is synced on save. Thus, make sure never @@ -1064,6 +1173,23 @@ public class Model implements IModelConfigurationConstants, IAdaptable { TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen); } } + + public void setOpenTabsValue(final int value) { + try { + getWorkingCopy().setAttribute(IModelConfigurationConstants.EDITOR_OPEN_TABS, value); + } catch (CoreException shouldNotHappen) { + TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen); + } + } + + public int getOpenTabsValue() { + try { + return getWorkingCopy().getAttribute(IModelConfigurationConstants.EDITOR_OPEN_TABS, + IModelConfigurationConstants.EDITOR_OPEN_TAB_NONE); + } catch (CoreException shouldNotHappen) { + return -1; + } + } public IFile getFile() { return getLaunchConfiguration().getFile(); @@ -1093,7 +1219,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable { TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen); } } - TLCActivator.logDebug("Trying to save a clean Model."); +// TLCActivator.logDebug("Trying to save a clean Model."); // Fluent return this; @@ -1119,6 +1245,10 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } } + public boolean hasAttribute(final String key) throws CoreException { + return this.launchConfig.hasAttribute(key); + } + public int getAttribute(String key, int defaultValue) throws CoreException { // TODO Replace this generic lookup method with real getters for the // various keys. E.g. see getEvalExpression/unsavedSetEvalExpression @@ -1183,6 +1313,42 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } } + // TLC's coverage implementation (see tlc2.tool.coverage.CostModelCreator) only + // supports two modes: Off and On. However, we consider On too much information + // for novice users who are (likely) only interested in identifying spec errors + // that leave a subset of actions permanently disabled. The Toolbox therefore + // adds a third mode "Action" which filters TLC's output for All. This obviously + // means that the overhead of collecting coverage in Action and On mode is + // identical. This shouldn't matter however as novice users don't create large + // specs anyway and the Toolbox warns users when a large spec has been + // configured with coverage. + // (see org.lamport.tla.toolbox.tool.tlc.output.data.CoverageUINotification) + // Alternatively, tlc2.tool.coverage.ActionWrapper.report() could be changed to + // omit the report of its children (line 126) to effectively create the Action + // mode at the TLC layer. I decided against it though, because I didn't want to + // extend the -coverage TLC parameter. + public enum Coverage { + OFF, ACTION, ON; + } + + public Coverage setCoverage(final Coverage c) { + setAttribute(LAUNCH_COVERAGE, c.ordinal()); + return c; + } + + public Coverage getCoverage() { + try { + final int ordinal = getAttribute(LAUNCH_COVERAGE, IConfigurationDefaults.LAUNCH_COVERAGE_DEFAULT); + return Coverage.values()[ordinal]; + } catch (DebugException legacyException) { + // Occurs for old models where the type wasn't int but bool. + } catch (CoreException shouldNotHappen) { + // We log the exceptions on setAttribute but expose exceptions with getAttribute %-) + TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen); + } + return Coverage.ACTION; + } + /* IAdaptable */ public <T> T getAdapter(Class<T> adapter) { diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java index eacbe82bd1f7c91e4071815ba4273029c2194ea3..db9283d25dac23ae7c5502edb3002d3066a8fcdc 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java @@ -25,6 +25,7 @@ ******************************************************************************/ package org.lamport.tla.toolbox.tool.tlc.model; +import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Vector; @@ -131,7 +132,7 @@ public class ModelWriter */ public void addPrimer(String moduleFilename, String extendedModuleName) { - tlaBuffer.append(ResourceHelper.getExtendingModuleContent(moduleFilename, extendedModuleName)); + tlaBuffer.append(ResourceHelper.getExtendingModuleContent(moduleFilename, new String[] {extendedModuleName, "TLC"})); } /** @@ -464,9 +465,14 @@ public class ModelWriter } } } - + public void addFormulaList(String element, String keyword, String attributeName) { + final List<String[]> elements = new ArrayList<>(1); + elements.add(new String[] {element, EMPTY_STRING}); + addFormulaList(elements, keyword, attributeName); + } + /** - * Puts (String[])element[0] to CFG file and element[1] to TLA_MC file + * Puts (String[])element[0] to CFG file and element[1] to TLA_MC file, if element[2] present, uses it as index. * * @param elements a list of String[] elements * @param keyword the keyword to be used in the CFG file @@ -485,12 +491,12 @@ public class ModelWriter { String[] element = elements.get(i); cfgBuffer.append(element[0]).append(CR); - // when a definition in the root module is overriden as a model value + // when a definition in the root module is overridden as a model value // there is nothing to add to the MC.tla file so, we do not do the following if (!element[1].equals(EMPTY_STRING)) { tlaBuffer.append(COMMENT).append(keyword + " definition ").append(ATTRIBUTE).append(attributeName) - .append(INDEX).append(i).append(CR); + .append(INDEX).append(element.length > 2 ? element[2] : i).append(CR); tlaBuffer.append(element[1]).append(CR).append(SEP).append(CR); } } @@ -560,7 +566,12 @@ public class ModelWriter public static List<String[]> createFormulaListContent(List<String> serializedFormulaList, String labelingScheme) { List<Formula> formulaList = ModelHelper.deserializeFormulaList(serializedFormulaList); - return (createListContent(formulaList, labelingScheme)); + return createFormulaListContentFormula(formulaList, labelingScheme); + } + + public static List<String[]> createFormulaListContentFormula(List<Formula> serializedFormulaList, String labelingScheme) + { + return createListContent(serializedFormulaList, labelingScheme); } /** @@ -719,7 +730,7 @@ public class ModelWriter // formulas // to .cfg : <id> // to _MC.tla : <id> == <expression> - content = new String[] { label, label + DEFINES_CR + formulaList.get(i).getFormula() }; + content = new String[] { label, label + DEFINES_CR + formulaList.get(i).getFormula(), String.valueOf(i) }; resultContent.add(content); } return resultContent; diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCModelFactory.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCModelFactory.java index c572c2f0b1ebba3b1cd3271f736228efbbd7e2f6..d877b865357dc84347e45ebcf4ec2ba058bc8616 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCModelFactory.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCModelFactory.java @@ -110,7 +110,7 @@ public class TLCModelFactory implements IAdapterFactory, ILaunchConfigurationLis */ public static Model getByName(final String fullQualifiedModelName) { Assert.isNotNull(fullQualifiedModelName); - Assert.isLegal(!fullQualifiedModelName.contains(Model.SPEC_MODEL_DELIM), "Not a full-qualified model name."); + Assert.isLegal(fullQualifiedModelName.contains(Model.SPEC_MODEL_DELIM), "Not a full-qualified model name."); final ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager(); final ILaunchConfigurationType launchConfigurationType = launchManager @@ -142,7 +142,6 @@ public class TLCModelFactory implements IAdapterFactory, ILaunchConfigurationLis try { final ILaunchConfiguration[] launchConfigurations = launchManager.getLaunchConfigurations(launchConfigurationType); for (int i = 0; i < launchConfigurations.length; i++) { - // Can do equals here because of full qualified name. final ILaunchConfiguration launchConfiguration = launchConfigurations[i]; if (aFile.equals(launchConfiguration.getFile())) { return launchConfiguration.getAdapter(Model.class); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java index ba16e0f9a60651daefdf591cf73d183cdd9c46c0..c31dfd75bfc97370a7f930e869d2772fbd615e95 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java @@ -40,6 +40,8 @@ import org.eclipse.debug.core.ILaunchManager; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate; +import tla2sany.modanalyzer.SpecObj; + /** * {@link TLCSpec} is the glue between {@link Spec} and {@link Model}. Why do we * need glue? The Toolbox is written in a modular style. Thus, it is @@ -54,13 +56,25 @@ import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate; */ public class TLCSpec extends Spec { + private final Spec spec; + /** * Only supposed to be called by {@link TLCSpecFactory} */ TLCSpec(Spec spec) { super(spec.getProject()); + this.spec = spec; + } + + @Override + public SpecObj getRootModule() { + return this.spec.getRootModule(); } + public Spec toSpec() { + return this.spec; + } + /** * @return All {@link Model}s associated with the given {@link Spec} excluding * snapshots of models. diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java index c1db2a1af2d9a651aa9f7da9ab35c5f15235dc37..2b8a78055c2930f8f19427f7aff4a80456f03709 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java @@ -33,9 +33,13 @@ import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState; import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCVariable; +import org.lamport.tla.toolbox.util.ResourceHelper; public class TraceExpressionModelWriter extends ModelWriter { + public static final String POSITION = "_TEPosition"; + public static final String TRACE = "_TETrace"; + /** * This only changes the tla file. This method generates and adds a variable declaration * for each expression in the list. It also creates an identifier for each @@ -70,12 +74,20 @@ public class TraceExpressionModelWriter extends ModelWriter { int position = 0; while (it.hasNext()) { - String expression = it.next().getFormula(); + final Formula formula = it.next(); + final String expression = formula.getFormula(); if (expression != null && expression.length() > 0) { - expressionData[position] = new TraceExpressionInformationHolder(expression, - getValidIdentifier(TRACE_EXPR_DEF_SCHEME), getValidIdentifier(TRACE_EXPR_VAR_SCHEME)); + final String identifier = getValidIdentifier(TRACE_EXPR_DEF_SCHEME); + if (formula.isNamed()) { + final String varname = formula.getLeftHandSide(); + String rightHandSide = formula.getRightHandSide(); + expressionData[position] = new TraceExpressionInformationHolder(rightHandSide, identifier, varname); + } else { + final String varname = getValidIdentifier(TRACE_EXPR_VAR_SCHEME); + expressionData[position] = new TraceExpressionInformationHolder(expression, identifier, varname); + } } position++; @@ -85,6 +97,61 @@ public class TraceExpressionModelWriter extends ModelWriter { return expressionData; } + + public void addPrimer(final String moduleFilename, final String extendedModuleName) { + // A TE spec has to extend Integers because of the _TEPosition operator. + tlaBuffer.append(ResourceHelper.getExtendingModuleContent(moduleFilename, + new String[] { extendedModuleName, "TLC", "Integers" })); + } + + public void addTraceFunction(final List<SimpleTLCState> input) { + // Filter stuttering or back2state instances from trace. + final List<SimpleTLCState> trace = input.stream() + .filter(state -> !state.isBackToState() && !state.isStuttering()) + .collect(java.util.stream.Collectors.toList()); + + if (trace.isEmpty()) { + return; + } + + final StringBuffer traceFunctionDef = new StringBuffer(); +// traceFunctionDef.append("---- MODULE __TEInner ----"); +// traceFunctionDef.append(CR).append(CR); + + // Trace + traceFunctionDef.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE) + .append("_TETrace").append(CR); + traceFunctionDef.append("_TETrace").append(DEFINES_CR); + traceFunctionDef.append(BEGIN_TUPLE).append(CR); + for (int j = 0; j < trace.size(); j++) { + final SimpleTLCState state = trace.get(j); + + traceFunctionDef.append(L_PAREN).append(state.asFunction()).append(R_PAREN); + + if (j < trace.size() - 1) { + traceFunctionDef.append(COMMA).append(CR); + } + } + traceFunctionDef.append(CR).append(END_TUPLE); + traceFunctionDef.append(CR); + traceFunctionDef.append(SEP).append(CR).append(CR); + + // Position + traceFunctionDef.append(COMMENT).append("TRACE EXPLORER Position identifier definition ").append(ATTRIBUTE) + .append(POSITION).append(CR); + traceFunctionDef.append(POSITION).append(DEFINES_CR); + traceFunctionDef.append( + String.format("IF TLCGet(\"level\") >= %s THEN %s ELSE TLCGet(\"level\") + 1", trace.size(), trace.size())); + traceFunctionDef.append(CR); + traceFunctionDef.append(SEP).append(CR).append(CR); +// +// // INSTANCE +// traceFunctionDef.append("====").append(CR); +// traceFunctionDef.append("LOCAL TE == INSTANCE __TEInner").append(CR).append(CR); + + // append the expression definitions + tlaBuffer.append(traceFunctionDef.toString()); + } /** * This only changes the tla file. This method adds a variable declaration @@ -138,7 +205,7 @@ public class TraceExpressionModelWriter extends ModelWriter { // expression // ---- definitions.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE).append( - attributeName).append(CR); + attributeName).append(INDEX).append(i).append(CR); definitions.append(expressionInfo.getIdentifier()).append(DEFINES_CR).append( expressionInfo.getExpression()).append(CR); definitions.append(SEP).append(CR).append(CR); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java index 2c77b45b1935a5f680c0644b21a26c0251478b0f..3b0ec75c18e62838baca31f65a1536058d0925cc 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java @@ -146,4 +146,21 @@ public class SimpleTLCState return (SimpleTLCVariable[]) vars.toArray(new SimpleTLCVariable[vars.size()]); } + public String asFunction() { + final StringBuffer buf = new StringBuffer(); + buf.append("["); + for (int i = 0; i < vars.length; i++) { + final SimpleTLCVariable var = vars[i]; + + buf.append(var.getVarName()); + buf.append(" |-> "); + buf.append(var.getValueAsString()); + + if (i < vars.length - 1) { + buf.append(org.lamport.tla.toolbox.tool.tlc.model.ModelWriter.COMMA); + } + } + buf.append("]"); + return buf.toString(); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java index fd07160c3f2f96e57fadfb08040cae60a213fca0..2af617ae063a3db4bbab2cd3da81cac0d930864a 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java @@ -108,14 +108,16 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur */ private static final String PARAM_DELIMITER = ":"; + public static final String FILE_TLA_EXTENSION = ".tla"; + public static final String MC_MODEL_NAME = "MC"; - public static final String FILE_TLA = MC_MODEL_NAME + ".tla"; + public static final String FILE_TLA = MC_MODEL_NAME + FILE_TLA_EXTENSION; public static final String FILE_CFG = MC_MODEL_NAME + ".cfg"; public static final String FILE_OUT = MC_MODEL_NAME + ".out"; // trace explorer file names public static final String TE_MODEL_NAME = "TE"; - public static final String TE_FILE_TLA = TE_MODEL_NAME + ".tla"; + public static final String TE_FILE_TLA = TE_MODEL_NAME + FILE_TLA_EXTENSION; public static final String TE_FILE_CFG = TE_MODEL_NAME + ".cfg"; public static final String TE_FILE_OUT = TE_MODEL_NAME + ".out"; // the file to which TLC's output is written so @@ -535,6 +537,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur /** * Using the supplied findReplaceAdapter finds the name of the attribute * (saved in the comment, previous to the region in which the error has been detected) + * @param rootModule * * @param document the document of the file containing the generated model .tla file * @param searchAdapter the search adapter on the document @@ -554,8 +557,8 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur * </ul> * @throws CoreException if something goes wrong */ - public static Hashtable<String, Object> createMarkerDescription(IDocument document, - FindReplaceDocumentAdapter searchAdapter, String message, int severity, int[] coordinates) + public static Hashtable<String, Object> createMarkerDescription(final IFile rootModule, final IDocument document, + final FindReplaceDocumentAdapter searchAdapter, String message, final int severity, final int[] coordinates) throws CoreException { String attributeName; @@ -564,23 +567,23 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur try { // find the line in the document - IRegion lineRegion = document.getLineInformation(coordinates[0] - 1); + final IRegion lineRegion = document.getLineInformation(coordinates[0] - 1); if (lineRegion != null) { - int errorLineOffset = lineRegion.getOffset(); + final int errorLineOffset = lineRegion.getOffset(); // find the previous comment - IRegion commentRegion = searchAdapter.find(errorLineOffset, ModelWriter.COMMENT, false, false, false, + final IRegion commentRegion = searchAdapter.find(errorLineOffset, ModelWriter.COMMENT, false, false, false, false); // find the next separator - IRegion separatorRegion = searchAdapter.find(errorLineOffset, ModelWriter.SEP, true, false, false, + final IRegion separatorRegion = searchAdapter.find(errorLineOffset, ModelWriter.SEP, true, false, false, false); if (separatorRegion != null && commentRegion != null) { // find the first attribute inside of the // comment - IRegion attributeRegion = searchAdapter.find(commentRegion.getOffset(), ModelWriter.ATTRIBUTE + final IRegion attributeRegion = searchAdapter.find(commentRegion.getOffset(), ModelWriter.ATTRIBUTE + "[a-z]*[A-Z]*", true, false, false, true); if (attributeRegion != null) { @@ -590,18 +593,18 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur .substring(ModelWriter.ATTRIBUTE.length()); // find the index - IRegion indexRegion = searchAdapter.find(attributeRegion.getOffset() + final IRegion indexRegion = searchAdapter.find(attributeRegion.getOffset() + attributeRegion.getLength(), ModelWriter.INDEX + "[0-9]+", true, false, false, true); if (indexRegion != null && indexRegion.getOffset() < separatorRegion.getOffset()) { // index value found - String indexString = document.get(indexRegion.getOffset(), indexRegion.getLength()); + final String indexString = document.get(indexRegion.getOffset(), indexRegion.getLength()); if (indexString != null && indexString.length() > 1) { try { attributeIndex = Integer.parseInt(indexString.substring(1)); - } catch (NumberFormatException e) + } catch (final NumberFormatException e) { throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Error during detection of the error position in MC.tla." @@ -616,7 +619,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur // the first character of the next line // after the comment - IRegion firstBlockLine = document.getLineInformation(document.getLineOfOffset(commentRegion + final IRegion firstBlockLine = document.getLineInformation(document.getLineOfOffset(commentRegion .getOffset()) + 1); int beginBlockOffset = firstBlockLine.getOffset(); // get the user input @@ -651,7 +654,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur { // equals to the begin line // mark the actual error region - int length = coordinates[3] - coordinates[1]; + final int length = coordinates[3] - coordinates[1]; errorRegion = new Region(errorLineOffset + coordinates[1] - beginBlockOffset, (length == 0) ? 1 : length); @@ -664,7 +667,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur // iterate over all full lines for (int l = coordinates[0] + 1; l < coordinates[2]; l++) { - IRegion line = document.getLineInformation(l - 1); + final IRegion line = document.getLineInformation(l - 1); summedLength = summedLength + line.getLength(); } // the part of the last line to the @@ -699,7 +702,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur "Error during detection of the error position in MC.tla." + "Could not data on specified location. " + message)); } - } catch (BadLocationException e) + } catch (final BadLocationException e) { throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Error during detection of the error position in MC.tla." + "Accessing MC.tla file failed. " @@ -708,7 +711,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur // If the message refers to module MC, this should be replaced with // the location in the model. - message = getMessageWithoutMC(message, attributeName, attributeIndex); + message = getMessageWithoutFile(rootModule, message, attributeName, attributeIndex); // create the return object Hashtable<String, Object> props = new Hashtable<String, Object>(); @@ -725,9 +728,9 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur /** * This method takes an error message generated by SANY for the - * MC.tla file and attempts to remove the mention of the MC file and insert + * MC.tla or TE.tla file and attempts to remove the mention of the MC or TE file and insert * the name of the model attribute and location within that attribute - * where the parse error occured. + * where the parse error occurred. * * For example, the location in the message returned by SANY that says * "at line 25, column 2 in module MC" will be replaced with something @@ -735,27 +738,29 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur * * It is definitely possible that the set of expressions searched for by this method * is not exhaustive, so some messages will remain the same even if they mention the - * MC file. + * MC or TE file. + * @param rootModule * - * @param message the SANY error message for the MC file - * @param attributeName the name of the model attribute where the error occured + * @param message the SANY error message for the MC or TE file + * @param attributeName the name of the model attribute where the error occurred * @param attributeIndex the 0-based index of the error within the model attribute. * For example, if the second definition override caused an error, the attributeIndex * should be 1. It can be -1 if no index is found, in which case no information about * the location within the model attribute will be included in the message. * @return the message without MC location information and with model location information */ - private static String getMessageWithoutMC(String message, String attributeName, int attributeIndex) + private static String getMessageWithoutFile(IFile rootModule, String message, String attributeName, int attributeIndex) { - if (message.indexOf("in module MC") != -1 || message.indexOf("of module MC") != -1) + String module = rootModule.getName().replace(".tla", ""); + if (message.indexOf("in module " + module) != -1 || message.indexOf("of module " + module) != -1) { // first possible expression - String[] splitMessage = message.split("at line [0-9]{1,}, column [0-9]{1,} in module MC", 2); + String[] splitMessage = message.split("at line [0-9]{1,}, column [0-9]{1,} in module " + module, 2); if (splitMessage.length != 2) { // split around other possibility splitMessage = message.split( - "line [0-9]{1,}, col [0-9]{1,} to line [0-9]{1,}, col [0-9]{1,} of module MC", 2); + "line [0-9]{1,}, col [0-9]{1,} to line [0-9]{1,}, col [0-9]{1,} of module " + module, 2); } if (splitMessage.length == 2) { @@ -826,6 +831,8 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur } else if (attributeName.equals(Model.MODEL_EXPRESSION_EVAL)) { return "Expression"; + } else if (attributeName.equals(TRACE_EXPLORE_EXPRESSIONS)) { + return "Error-Trace Exploration expression"; } return attributeName; } @@ -888,18 +895,23 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur */ if (specObj != null) { - OpDefNode[] opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs(); - for (int j = 0; j < opDefNodes.length; j++) - { - if (opDefNodes[j].getName().toString().equals(name)) - { - return opDefNodes[j]; - } - } + return getOpDefNode(specObj, name); } return null; } + public static OpDefNode getOpDefNode(SpecObj specObj, String name) { + OpDefNode[] opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs(); + for (int j = 0; j < opDefNodes.length; j++) + { + if (opDefNodes[j].getName().toString().equals(name)) + { + return opDefNodes[j]; + } + } + return null; + } + /** * Checks, whether a model attribute is a list * @param attributeName name of the attribute, see {@link IModelConfigurationConstants} diff --git a/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF index 1c3577f614d1afac577e708888e00f03a93aab42..d3f1e7b8c095781b60bfa08813c471f131652b08 100644 --- a/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF @@ -21,3 +21,4 @@ Eclipse-SupplementBundle: org.lamport.tla.toolbox* Export-Package: org.lamport.tla.toolbox.test, org.lamport.tla.toolbox.test.threading, org.lamport.tla.toolbox.ui.wizard +Automatic-Module-Name: org.lamport.tla.toolbox.uitest diff --git a/org.lamport.tla.toolbox.uitest/pom.xml b/org.lamport.tla.toolbox.uitest/pom.xml index a5ec737119fef4609bf45b21f67211b15f912368..25c497c169d12e5babcef72c333e041578b82d0f 100644 --- a/org.lamport.tla.toolbox.uitest/pom.xml +++ b/org.lamport.tla.toolbox.uitest/pom.xml @@ -12,18 +12,13 @@ <groupId>tlatoolbox</groupId> <artifactId>org.lamport.tla.toolbox.uitest</artifactId> <version>1.0.0-SNAPSHOT</version> - <packaging>eclipse-test-plugin</packaging> + <packaging>eclipse-plugin</packaging> <properties> <!-- Do not include test project in Sonar reporting. --> <sonar.skip>true</sonar.skip> </properties> <dependencies> - <dependency> - <groupId>org.aspectj</groupId> - <artifactId>aspectjrt</artifactId> - <version>1.9.1</version> - </dependency> <!-- Down below we manually install the standalone feature. Maven/Tycho isn't smart enough to figure this out by itself. Thus, we have to tell Tycho explicitly. --> @@ -39,7 +34,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.3</version> <executions> <execution> <goals> @@ -63,83 +58,6 @@ </excludeResources> </configuration> </plugin> - - <!-- Compile aspects --> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>aspectj-maven-plugin</artifactId> - <version>1.11</version> - <configuration> - <ajdtBuildDefFile>build.ajproperties</ajdtBuildDefFile> - </configuration> - <executions> - <execution> - <goals> - <goal>compile</goal> - </goals> - </execution> - </executions> - </plugin> - - <!-- Run JUnit tests --> - <plugin> - <groupId>org.eclipse.tycho</groupId> - <artifactId>tycho-surefire-plugin</artifactId> - <version>${tycho-version}</version> - - <configuration> - <showEclipseLog>true</showEclipseLog> - <useUIHarness>true</useUIHarness> - <useUIThread>${tycho.test.vm.useUiThread}</useUIThread> - <argLine>${tycho.test.vm.argline} ${tycho.testArgLine}</argLine> - <!-- use our product and application to launch the tests --> - <product>org.lamport.tla.toolbox.product.standalone.product</product> - <application>org.lamport.tla.toolbox.application</application> - - <systemProperties combine.children="append"> - <!-- References used by tests to access spec files --> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA>${project.build.directory}/../org.lamport.tla.toolbox.test/farsite/DistributedSystemModule.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA> - <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB>${project.build.directory}/../org.lamport.tla.toolbox.uitest/DieHard/DieHard.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB> - </systemProperties> - - <dependencies> - <!-- help system needs javax.servlet --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>javax.servlet</artifactId> - <version>2.5.0</version> - </dependency> - <!-- explicit dependency is only needed because SWTbot brings its own - hamcrest bundle which conflicts with the one from junit in the eclipse platform --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.hamcrest</artifactId> - <version>0.0.0</version> - </dependency> - <!-- explicit dependency is needed because product/app is provided - by this bundle --> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.lamport.tla.toolbox.product.standalone</artifactId> - <version>0.0.0</version> - </dependency> - <dependency> - <type>p2-installable-unit</type> - <artifactId>org.eclipse.equinox.event</artifactId> - <version>0.0.0</version> - </dependency> - </dependencies> - <bundleStartLevel> - <bundle> - <id>org.eclipse.equinox.event</id> - <level>4</level> - <autoStart>true</autoStart> - </bundle> - </bundleStartLevel> - - </configuration> - </plugin> - </plugins> </build> </project> diff --git a/org.lamport.tla.toolbox/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox/META-INF/MANIFEST.MF index 604b0d9588d70bd37653c41645f5c575d0b9d48c..743f3879dca9e692c7d9db5c12f2100f8e19a556 100644 --- a/org.lamport.tla.toolbox/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox/META-INF/MANIFEST.MF @@ -77,4 +77,5 @@ Import-Package: org.eclipse.e4.core.contexts, org.eclipse.e4.ui.workbench.lifecycle, org.eclipse.e4.ui.workbench.modeling, org.osgi.service.event;version="1.3.0" +Automatic-Module-Name: org.lamport.tla.toolbox diff --git a/org.lamport.tla.toolbox/helpContexts.xml b/org.lamport.tla.toolbox/helpContexts.xml index 92f1b81f5c3af4a791743d83aa64a8d5c3384156..fe4cf9b106214ad9a23d32f168c9936f24c63e1e 100644 --- a/org.lamport.tla.toolbox/helpContexts.xml +++ b/org.lamport.tla.toolbox/helpContexts.xml @@ -40,12 +40,20 @@ <description> This dialog lets you provide a new definition of the chosen operator that TLC will use instead of the actual definition. </description> - <topic label="Definition Override" href="../org.lamport.tla.toolbox.doc/html/model/advanced-page.html#override" /> + <topic label="Definition Override" href="../org.lamport.tla.toolbox.doc/html/model/spec-options-page.html#override" /> </context> <context id="GettingStarted" title="Getting Started"> <description>Click "Getting Started" below</description> <topic href="../org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html" label="Getting Started"/> </context> + <context id="ErrorTraceExplorerExpression" title="Error-Trace Explorer Expressions"> + <description>A named expression is syntactically equivalent to a zero-arity operator such that "id == expr" where "id" is an identifier not declared or defined elsewhere. Subsequent named expressions may refer to named expressions stated above. In other words, named expressions are composable. + +The _TEPosition operator is defined for each state to be equivalent to the value shown as "State (num = N)" in the Error-Trace where N is in Nat. + +_TETrace is defined to be the sequence of states such that _TETrace[_TEPosition] is equivalent to the state at position _TEPosition.</description> + <topic href="../org.lamport.tla.toolbox.doc/html/model/results-page.html" label="Model Checking Results Page"/> + </context> </contexts> diff --git a/org.lamport.tla.toolbox/plugin.xml b/org.lamport.tla.toolbox/plugin.xml index bb4747949db5de90d3543b80c276b8509978baed..a27a9698a4c96fc8182075fdcbf7e58b1ac76a96 100644 --- a/org.lamport.tla.toolbox/plugin.xml +++ b/org.lamport.tla.toolbox/plugin.xml @@ -795,7 +795,7 @@ <menuContribution locationURI="popup:toolbox.explorer.popup?after=group.properties"> <command - commandId="org.eclipse.ui.file.properties" + commandId="toolbox.command.spec.props" id="toolbox.popupmenu.props" label="Properties" mnemonic="I" @@ -985,30 +985,10 @@ </handler> <handler class="org.lamport.tla.toolbox.ui.handler.PropertiesHandler" - commandId="toolbox.command.spec.props"> - <activeWhen> - <with - variable="selection"> - <iterate - operator="or"> - <instanceof - value="org.lamport.tla.toolbox.spec.Spec"> - </instanceof> - </iterate> - </with> - </activeWhen> - <enabledWhen> - <with - variable="selection"> - <iterate - operator="or"> - <instanceof - value="org.lamport.tla.toolbox.spec.Spec"> - </instanceof> - </iterate> - </with> - </enabledWhen> - </handler> + commandId="toolbox.command.spec.props" /> + <handler + class="org.lamport.tla.toolbox.ui.handler.DeleteModuleHandler" + commandId="org.eclipse.ui.edit.delete" /> <handler class="org.lamport.tla.toolbox.ui.handler.ForgetSpecHandler" commandId="org.lamport.tla.toolbox.forget"> @@ -1371,8 +1351,14 @@ id="org.lamport.tla.tooblox.rss.feed" name="TLA+ News" uri="https://groups.google.com/forum/feed/tlaplus-announce/msgs/rss_v2_0.xml" - pollingInterval="60"> + pollingInterval="1440"> </feed> + <feed + id="org.lamport.tla.tooblox.discussion.feed" + name="TLA+ User Discussions" + uri="https://groups.google.com/forum/feed/tlaplus/msgs/rss_v2_0.xml" + pollingInterval="1440"> + </feed> </extension> <!-- --> diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Spec.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Spec.java index 0461895e93e72b66e8de8d9deec4fb70213ac3d6..d406b0d4c9fdf68c411ab6c0ce186487de2b6993 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Spec.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Spec.java @@ -1,10 +1,12 @@ package org.lamport.tla.toolbox.spec; import java.io.File; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,8 +25,9 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.text.ITextSelection; +import org.eclipse.ui.texteditor.ITextEditor; import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.spec.parser.IParseConstants; import org.lamport.tla.toolbox.tool.SpecLifecycleParticipant; @@ -35,7 +38,10 @@ import org.lamport.tla.toolbox.util.pref.PreferenceStoreHelper; import pcal.TLAtoPCalMapping; import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.Context; +import tla2sany.semantic.ExternalModuleTable; import util.SimpleFilenameToStream; +import util.UniqueString; /** * Represents a specification handle in the toolbox @@ -69,13 +75,11 @@ public class Spec implements IAdaptable { private final Map<String, TLAtoPCalMapping> spec2mappings = new HashMap<String, TLAtoPCalMapping>(); /** - * The following fields are used for remembering the jumping-off point for a + * The following stack is used for remembering the jumping-off point for a * Goto Declaration or ShowDefinitions command, so we can return to it with - * a Return from Goto Declaration command. They should probably be changed - * to arrays so we can call return from a Sequence of such commands. + * a Return from Goto Declaration command. */ - private String openDeclModuleName; - private ITextSelection openDeclSelection; + private final Deque<Pair> openDecls = new ArrayDeque<>(); /** * The following fields are used to remember the result of a Show Uses @@ -382,33 +386,31 @@ public class Spec implements IAdaptable { } /** - * @param openDeclModuleName - * the openDeclModuleName to set + * @param editor + * the ITextEditor whose current ITextSelection to remember. */ - public void setOpenDeclModuleName(String openDeclModuleName) { - this.openDeclModuleName = openDeclModuleName; - } + public void setOpenDeclModuleName(ITextEditor editor) { + this.setOpenDeclModuleName(editor, (ITextSelection) editor.getSelectionProvider().getSelection()); + } - /** - * @return the openDeclModuleName - */ - public String getOpenDeclModuleName() { - return openDeclModuleName; + public void setOpenDeclModuleName(ITextEditor editor, ITextSelection selection) { + this.openDecls.push(new Pair(editor, selection)); } - - /** - * @param openDeclSelection - * the openDeclSelection to set + + /** + * @return the openDeclModuleName */ - public void setOpenDeclSelection(ITextSelection openDeclSelection) { - this.openDeclSelection = openDeclSelection; + public Pair getOpenDeclModuleName() { + return this.openDecls.poll(); } - - /** - * @return the openDeclSelection - */ - public ITextSelection getOpenDeclSelection() { - return openDeclSelection; + + public static class Pair { + public final ITextEditor editor; + public final ITextSelection selection; + public Pair(ITextEditor editor, ITextSelection selection) { + this.editor = editor; + this.selection = selection; + } } /** @@ -502,6 +504,31 @@ public class Spec implements IAdaptable { return ""; } } + + public String getTLALibraryPathAsClassPath() { + final String[] tlaLibraryPath = getTLALibraryPath(); + + if (tlaLibraryPath.length > 0) { + final StringBuffer buf = new StringBuffer(tlaLibraryPath.length * 2); + + for (final String location : tlaLibraryPath) { + if (new File(location).isDirectory()) { + // For directories include everything. + buf.append(location + File.separator + "*") ; + } else { + buf.append(location); + } + buf.append(File.pathSeparator); + } + + final String vmArg = buf.toString(); + + // remove dangling pathSeparator + return vmArg.substring(0, vmArg.length() - 1); + } else { + return ""; + } + } private final Lock lock = new ReentrantLock(true); @@ -585,8 +612,7 @@ public class Spec implements IAdaptable { // nested. if (!mapping.equals(oldMapping)) { // Use a submonitor to show progress as well as failure - final SubProgressMonitor subProgressMonitor = new SubProgressMonitor( - monitor, 1); + final SubMonitor subProgressMonitor = SubMonitor.convert(monitor, 1); subProgressMonitor .setTaskName("Writing TLA+ to PCal mapping for " + filename); @@ -627,6 +653,16 @@ public class Spec implements IAdaptable { return Activator.getSpecManager().getSpecLoaded() == this; } + public Module getModule(final String moduleName) { + final List<Module> modules = getModules(); + for (Module module : modules) { + if (moduleName.equals(module.getModuleName())) { + return module; + } + } + return null; + } + public List<Module> getModules() { final List<Module> modules = new ArrayList<Module>(); final IResource[] moduleResources = getModuleResources(); @@ -641,4 +677,30 @@ public class Spec implements IAdaptable { } return modules; } + + public boolean declares(final String str) { + return declares(UniqueString.uniqueStringOf(str)); + } + + public boolean declares(final UniqueString us) { + if (getRootModule() != null) { + final ExternalModuleTable externalModuleTable = getRootModule().getExternalModuleTable(); + final Context context = externalModuleTable.getContextForRootModule(); + if (context != null) { + return context.occurSymbol(us); + } + } + return false; + } + + /** + * Transitively deletes the given marker type on all modules (including the root + * module) of the spec. + */ + public void deleteMarker(final String markerType) throws CoreException { + getRootFile().deleteMarkers(markerType, true, IResource.DEPTH_INFINITE); + for (IResource r : getModuleResources()) { + r.deleteMarkers(markerType, true, IResource.DEPTH_INFINITE); + } + } } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/ParserHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/ParserHelper.java index cdcf52ab21865556f2b32aa35dcdfdc0c3c44263..94c66e77150f3017f77019d9ca175290b288c42d 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/ParserHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/ParserHelper.java @@ -8,9 +8,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.spec.parser.ModuleParserLauncher; -import org.lamport.tla.toolbox.spec.parser.ParseResult; import org.lamport.tla.toolbox.spec.parser.SpecificationParserLauncher; -import org.lamport.tla.toolbox.util.AdapterFactory; /** * Encapsulates parser launching methods @@ -35,13 +33,11 @@ public class ParserHelper { return; } - Activator.getDefault().logDebug("Module build invoked on " + resource.getProjectRelativePath().toString() + " ..."); IWorkspaceRunnable run = new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { - ParseResult result = moduleParser.parseModule(resource, monitor); - Activator.getDefault().logDebug("Resulting status is: " + AdapterFactory.getStatusAsString(result.getStatus())); + moduleParser.parseModule(resource, monitor); } }; try @@ -51,7 +47,6 @@ public class ParserHelper { Activator.getDefault().logError("Error parsing a module", e); } - Activator.getDefault().logDebug("... build invocation finished."); } /** @@ -69,14 +64,8 @@ public class ParserHelper public void run(IProgressMonitor monitor) throws CoreException { - Activator.getDefault().logDebug("Spec build invoked on " + spec.getName() + " ..."); - // markers already removed in the parseSpecification launcher.parseSpecification(spec, monitor); - - Activator.getDefault().logDebug("Resulting status is: " - + AdapterFactory.getStatusAsString(spec) - + "\n... build invocation finished."); } }; try diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ParseResultBroadcaster.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ParseResultBroadcaster.java index 1586b860ae8bbcac2fb7c57cdc52cb0c800a64a5..433fcd7f8c8fbc62e5c81e3d9ed76926c56f681b 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ParseResultBroadcaster.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ParseResultBroadcaster.java @@ -2,9 +2,9 @@ package org.lamport.tla.toolbox.spec.parser; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; @@ -44,7 +44,7 @@ public class ParseResultBroadcaster { private static ParseResultBroadcaster instance; - private List<IParseResultListener> listeners; + private final List<IParseResultListener> listeners; /** * Map from {@link IPath} to the most recent * {@link ParseResult} containing that module that @@ -59,7 +59,7 @@ public class ParseResultBroadcaster */ private ParseResultBroadcaster() { - listeners = new LinkedList<IParseResultListener>(); + listeners = new CopyOnWriteArrayList<IParseResultListener>(); parseResults = new HashMap<IPath, ParseResult>(); Activator.getSpecManager().addSpecLifecycleParticipant(new SpecLifecycleParticipant() { /* (non-Javadoc) @@ -151,8 +151,6 @@ public class ParseResultBroadcaster if (!listeners.contains(parseResultListener)) { listeners.add(parseResultListener); - Activator.getDefault().logDebug("Added a parse result listener." - + "There are now " + listeners.size() + " listeners."); } } @@ -164,12 +162,7 @@ public class ParseResultBroadcaster */ public void removeParseResultListener(IParseResultListener parseResultListener) { - boolean removed = listeners.remove(parseResultListener); - if (removed) - { - Activator.getDefault().logDebug("Removed a parse result listener." - + "There are now " + listeners.size() + " listeners."); - } + listeners.remove(parseResultListener); } /** diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/SizeControlContribution.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/SizeControlContribution.java index 877e97f72af2e9aa5d7d3a8c0b4834b7607bb2eb..c1db6960f66cbe33f280a9d6a17b20204698b64f 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/SizeControlContribution.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/SizeControlContribution.java @@ -22,8 +22,8 @@ import org.eclipse.ui.menus.WorkbenchWindowControlContribution; import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.ToolboxDirectoryVisitor; import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.tool.SpecEvent; -import org.lamport.tla.toolbox.tool.SpecLifecycleParticipant; +import org.lamport.tla.toolbox.tool.SpecEvent; +import org.lamport.tla.toolbox.tool.SpecLifecycleParticipant; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.ToolboxJob; diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..423ce053cf82575f7d83f59b80a12efabbf6d0ba --- /dev/null +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java @@ -0,0 +1,115 @@ +package org.lamport.tla.toolbox.ui.handler; + +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.lamport.tla.toolbox.Activator; +import org.lamport.tla.toolbox.spec.Module; +import org.lamport.tla.toolbox.spec.Spec; +import org.lamport.tla.toolbox.spec.manager.WorkspaceSpecManager; +import org.lamport.tla.toolbox.util.ToolboxJob; + +/** + * If a module is selected and it is not the main module of the specification, facilitate its deletion. + */ +public class DeleteModuleHandler extends AbstractHandler { + private boolean m_enabled = false; + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(final Object evaluationContext) { + final Module m = getModuleFromContext((IEvaluationContext)evaluationContext); + + if (m != null) { + final WorkspaceSpecManager specManager = Activator.getSpecManager(); + final Spec loadedSpec = specManager.getSpecLoaded(); + final String specName = loadedSpec.getName(); + final String moduleName = m.getModuleName(); + + m_enabled = !specName.equals(moduleName); + + return; + } + + m_enabled = false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEnabled() { + return m_enabled; + } + + /** + * {@inheritDoc} + */ + public Object execute(ExecutionEvent event) throws ExecutionException { + final Module m = getModuleFromContext((IEvaluationContext)event.getApplicationContext()); + final Job j = new ToolboxJob("Removing module...") { + protected IStatus run(final IProgressMonitor monitor) { + try { + m.getResource().delete(IResource.NEVER_DELETE_PROJECT_CONTENT, monitor); + return Status.OK_STATUS; + } catch (Exception e) { + return Status.CANCEL_STATUS; + } + } + }; + final IWorkbenchWindow iww = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + final IWorkbenchPage page = iww.getActivePage(); + final IEditorReference[] refs = page.getEditorReferences(); + final String tabName = m.getModuleName() + ".tla"; + boolean removeModule = true; + for (final IEditorReference ier : refs) { + if (tabName.equals(ier.getName())) { + final IEditorPart editor = ier.getEditor(false); + + if (editor != null) { + // If dirty and they cancel the closing, this will return false + removeModule = page.closeEditor(editor, true); + } + } + } + + if (removeModule) { + j.schedule(); + } + + return null; + } + + private Module getModuleFromContext(final IEvaluationContext context) { + final Object defaultVariable = context.getDefaultVariable(); + + if (defaultVariable instanceof List) { + final List<?> list = (List<?>)defaultVariable; + + if (list.size() == 1) { + final Object o = list.get(0); + + if (o instanceof Module) { + return (Module)o; + } + } + } + + return null; + } +} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PropertiesHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PropertiesHandler.java index db27a0e46a7b55b32919c67f610266723de13ce3..4649c68e58eda314975dd669557aa919c3b4845d 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PropertiesHandler.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PropertiesHandler.java @@ -1,39 +1,66 @@ package org.lamport.tla.toolbox.ui.handler; +import java.util.List; + import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.commands.IHandler; +import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.jface.action.IAction; import org.eclipse.ui.dialogs.PropertyDialogAction; import org.lamport.tla.toolbox.Activator; +import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.util.UIHelper; /** - * Opens the properties dialog, the underlying object is fetched by the passed ISelectionProvider - * Currently it only returns selected Specs - * - * + * Opens the properties dialog; the underlying object is fetched by the passed + * ISelectionProvider. It only returns selected Specs. + * * @author Simon Zambrovski - * @version $Id$ - * @deprecated is not used any more; we're using the default handler. */ -public class PropertiesHandler extends AbstractHandler implements IHandler -{ - - /* (non-Javadoc) - * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) +public class PropertiesHandler extends AbstractHandler { + private boolean m_enabled = false; + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(final Object evaluationContext) { + final IEvaluationContext context = (IEvaluationContext)evaluationContext; + final Object defaultVariable = context.getDefaultVariable(); + Spec spec = null; + + if (defaultVariable instanceof List) { + final List<?> list = (List<?>)defaultVariable; + + if (list.size() == 1) { + final Object o = list.get(0); + + if (o instanceof Spec) { + spec = (Spec)o; + } + } + } + + m_enabled = (spec != null); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEnabled() { + return m_enabled; + } + + /** + * {@inheritDoc} */ - public Object execute(ExecutionEvent event) throws ExecutionException - { + public Object execute(ExecutionEvent event) throws ExecutionException { + final IAction action = new PropertyDialogAction(UIHelper.getShellProvider(), Activator.getSpecManager()); - - // FIXME Fix the selection of specs only - IAction action = new PropertyDialogAction(UIHelper.getShellProvider(), Activator.getSpecManager()); - // IAction action = new PropertyDialogAction(UIHelper.getShellProvider(), HandlerUtil.getActivePart(event)); - action.run(); - - return null; - } + action.run(); + return null; + } } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java index 3d2580cc3953731cdf7f6be0909ed16e63ff5aa3..4dd84014dedda4a1c4e707a1973680465233a4b6 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java @@ -29,6 +29,9 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I public static final String EDITOR_RIGHT_MARGIN = "editorRightMargin"; public static final int EDITOR_RIGHT_MARGIN_DEFAULT = 77; + public static final String EDITOR_ADD_MODIFICATION_HISTORY = "editorAddModificationHistory"; + public static final boolean EDITOR_ADD_MODIFICATION_HISTORY_DEFAULT = true; + public static final String CLEAR_DECLARATION_USE_MARKERS_ON_PARSE = "removeDeclarationUseMarkersOnParse"; public static final boolean CLEAR_DECLARATION_USE_MARKERS_ON_PARSE_DEFAULT = true; @@ -101,6 +104,9 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I addField(new BooleanFieldEditor(CLEAR_DECLARATION_USE_MARKERS_ON_PARSE, "&Clear declaration use markers when parsing", getFieldEditorParent())); + addField(new BooleanFieldEditor(EDITOR_ADD_MODIFICATION_HISTORY, + "&Add a modification history comment to new specs", getFieldEditorParent())); + // Preferences for renumbering. Added 25 July 2013 by LL Label lbl = new Label(getFieldEditorParent(), SWT.NONE); GridData gd = new GridData(); diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/LibraryPathComposite.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/LibraryPathComposite.java index 17c711e5d1997698518e8fc9e3ed4f7aad5d966e..c0b3463592f2de79a0edf9f48e4a746af3e6aa39 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/LibraryPathComposite.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/LibraryPathComposite.java @@ -45,6 +45,7 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.PlatformUI; import org.lamport.tla.toolbox.Activator; @@ -177,6 +178,18 @@ public class LibraryPathComposite { } }); + + button = SWTFactory.createPushButton(bcomp, + "Add Archive &File...", null); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String loc = getZipArchiveFile(null); + if (loc != null) { + addLocation(loc); + } + } + }); + final Button editbutton = SWTFactory.createPushButton(bcomp, "&Edit Location...", null); editbutton.setEnabled(false); @@ -382,7 +395,24 @@ public class LibraryPathComposite { if (prevLocation != null) { dialog.setFilterPath(prevLocation); } - return dialog.open() + File.separator; + final String open = dialog.open(); + if (open != null) { + return open + File.separator; + } + return null; + } + + String getZipArchiveFile(String prevLocation) { + final FileDialog dialog = new FileDialog(this.preferencePage.getShell()); + dialog.setFilterExtensions(new String[] {"*.jar", "*.zip"}); + if (prevLocation != null) { + dialog.setFilterPath(prevLocation); + } + final String open = dialog.open(); + if (open != null) { + return open; + } + return null; } /** @@ -413,6 +443,8 @@ public class LibraryPathComposite { String newloc = null; if (file.isDirectory()) { newloc = getDirectory(location); + } else { + newloc = getZipArchiveFile(location); } if (newloc != null) { fLocationList.remove(location); diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/view/ProblemView.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/view/ProblemView.java index 034642a8c2aae4aaa9cb2c5bdc067e0619992219..ce4103be53600bfe78bb65485f91a0869391796d 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/view/ProblemView.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/view/ProblemView.java @@ -83,7 +83,7 @@ public class ProblemView extends ViewPart // goto marker on click public void handleEvent(Event event) { - TLAMarkerHelper.gotoMarker(problem, ((event.stateMask & SWT.CTRL) != 0)); + TLAMarkerHelper.gotoMarker(problem, ((event.stateMask & SWT.MOD1) != 0)); } }; diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizard.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizard.java index f1901cab411eca874863a558ee950480c50b2d92..db0fdfa5180d234052745de4add56eb274f1c3f8 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizard.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizard.java @@ -22,6 +22,10 @@ public class NewSpecWizard extends Wizard implements INewWizard private boolean importExisting; private final String absolutePath; + public NewSpecWizard() { + this(""); + } + public NewSpecWizard(String absolutePath) { this.absolutePath = absolutePath; } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java index beb3e2c18426998c3f07d1726591ca3f088da236..857fb1bb5f9cccaf8f24ed7ccc2902ec73716112 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java @@ -2,9 +2,11 @@ package org.lamport.tla.toolbox.ui.wizard; import java.io.File; import java.io.IOException; +import java.util.UUID; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.DialogPage; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; @@ -24,6 +26,7 @@ import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.UIHelper; +import org.lamport.tla.toolbox.util.ZipUtil; /** * A wizard page input of the specification name and the location of the root file @@ -40,7 +43,7 @@ public class NewSpecWizardPage extends WizardPage private boolean specNameDirty = false; private boolean fileTextDirty = false; - public static final String[] ACCEPTED_EXTENSIONS = { "*.tla", "*.*" }; + public static final String[] ACCEPTED_EXTENSIONS = { "*.tla", "*.zip", "*.*" }; /** * Holds the path to the most recently browsed @@ -206,7 +209,7 @@ public class NewSpecWizardPage extends WizardPage openFileDialog.setFilterPath(rootPath); openFileDialog.setFilterExtensions(ACCEPTED_EXTENSIONS); - openFileDialog.setFilterNames(new String[]{"TLA+ files", "All files"}); + openFileDialog.setFilterNames(new String[]{"TLA+ files", "Zip Archive", "All files"}); String selected = openFileDialog.open(); if (selected != null) { @@ -235,10 +238,38 @@ public class NewSpecWizardPage extends WizardPage { reportError("Root file name should be provided"); return; + } else if (rootfilePath.contains("${rnd.tmp.dir}")) { + // For UI testing only. + String tmpdir = System.getProperty("java.io.tmpdir"); + if (Platform.getOS().equals(Platform.OS_MACOSX)) { + // On macOS java.io.tmpdir is a symlink to /private/... The Toolbox does not + // accept Symlinks because it fails to handle them correctly. + tmpdir = File.separator + "private" + tmpdir; + } + final String rndTmpDir = tmpdir + File.separator + UUID.randomUUID().toString(); + System.setProperty("tla.rcptt.spec.dir", rndTmpDir); + this.fileText.setText(rootfilePath.replace("${rnd.tmp.dir}", rndTmpDir)); + return; } else if (new File(rootfilePath).isDirectory()) { reportError("Root file should be a TLA file and not a directory"); return; + } else if (ZipUtil.isArchive(rootfilePath)) { + try { + // Expect the root module's name to be aligned with the archive's name (except for file extension). + final File zip = new File(rootfilePath); + + //TODO If the zip is large, this will block the main/UI thread. + final File destDir = ZipUtil.unzip(zip, new File(zip.getAbsolutePath().replaceFirst(".zip$", "")), true); + + // recursively trigger dialogChanged with now extracted spec. + this.fileText.setText( + destDir.getAbsolutePath() + File.separator + zip.getName().replaceFirst(".zip$", ".tla")); + return; + } catch (IOException e) { + reportError(String.format("Failed to unzip zip archive %s with error %s", rootfilePath, + e.getMessage())); + } } else if (!rootfilePath.endsWith(".tla")) { reportError("Root file name should have a file-system path and extension .tla"); diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java index 701383fc2a39e0f1643c33eedc95ead261180ca6..84e0bf004efcea24d6760b05b17933a3fe9e38a1 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java @@ -2,7 +2,6 @@ package org.lamport.tla.toolbox.util; import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; import java.net.URL; import org.eclipse.core.runtime.FileLocator; diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java index 6a242977610e1e083706b2c97cf46c6e3aab4c3c..f850ac0e823b3be525981c254f5dbb32d4924674 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java @@ -3,7 +3,6 @@ package org.lamport.tla.toolbox.util; /** * Constnats for help system * @author Simon Zambrovski - * @version $Id$ */ public interface IHelpConstants { @@ -22,9 +21,13 @@ public interface IHelpConstants public static final String MAIN_MODEL_PAGE = "mainModelPage"; public static final String ADVANCED_MODEL_PAGE = "advancedModelPage"; + public static final String ADVANCED_TLC_OPTIONS_PAGE = "advancedTLCOptionsPage"; public static final String RESULT_MODEL_PAGE = "resultModelPage"; + public static final String EVALUATE_CON_EX_PAGE = "evaluateConstantExpressionPage"; public static final String TLC_ERROR_VIEW = "TLCErrorView"; + public static final String TLC_ERROR_VIEW_EXPRESSION = "ErrorTraceExplorerExpression"; + /** * Menu new spec */ diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java index 301ccf20d72fb612438102470a63ecb1b1f5a2fd..c7b70b736966ebde245055f60ddf12f4d424ac09 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java @@ -3,6 +3,11 @@ package org.lamport.tla.toolbox.util; import java.io.File; import java.io.IOException; import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Enumeration; import java.util.Vector; @@ -135,18 +140,42 @@ public class RCPNameToFileIStream implements FilenameToStream sourceFile = new File(ToolIO.getUserDir(), name); } else { - sourceFile = new File(prefix + name); + if(FilenameToStream.isArchive(prefix)) { + sourceFile = getFromArchive(prefix, name); + if(sourceFile != null) { + return sourceFile; + } + } else { + sourceFile = new File(prefix + name); + } + } + if (sourceFile != null && sourceFile.exists()) { + break; + } + if (idx >= libraryPathEntries.size()) { + break; } - if (sourceFile.exists()) - break; - if (idx >= libraryPathEntries.size()) - break; prefix = (String) libraryPathEntries.elementAt(idx++); } return sourceFile; } + + // Extract the archive to a temporary directory from where the Toolbox will read + // the resource. The problem is, that the Toolbox and TLC work with File instead + // of InputStream which is why we can't extract to memory only. + private File getFromArchive(String prefix, String name) { + final File outputFile = new File(TMPDIR + File.separator + name); + outputFile.deleteOnExit(); // Written to TMPDIR which is likely deleted regularly anyway. + try (FileSystem fileSystem = FileSystems.newFileSystem(new File(prefix).toPath(), null)) { + Path fileToExtract = fileSystem.getPath(name); + Files.copy(fileToExtract, outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + return outputFile; + } catch (IOException e) { + return null; + } + } /** * Returns true iff moduleName is the name of a standard module. diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java index 21c3b34904b978d2241f0221da6dc016d7d2c8ca..a68ebb90f2586450f0f822aef944df4bb94437d1 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java @@ -39,7 +39,7 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.MultiRule; import org.eclipse.jface.dialogs.MessageDialog; @@ -98,13 +98,10 @@ import util.FilenameToStream; import util.UniqueString; /** - * A toolbox with resource related methods + * A utility class with resource related methods * @author Simon Zambrovski - * @version $Id$ */ -public class ResourceHelper -{ - +public class ResourceHelper { /** * Filename suffix for {@link TLAtoPCalMapping} files */ @@ -436,7 +433,7 @@ public class ResourceHelper String name = members[i].getName(); IPath newLocation = newLocationParent.append(name); - members[i].delete(true, new SubProgressMonitor(monitor, 1)); + members[i].delete(true, SubMonitor.convert(monitor).split(1)); if (newLocation.toFile().exists()) { getLinkedFile(project, ResourceHelper.PARENT_ONE_PROJECT_LOC + name, true); @@ -628,6 +625,9 @@ public class ResourceHelper { return null; } + if (resource.getLocation() == null) { + return null; + } return getModuleName(resource.getLocation().toOSString()); } @@ -732,11 +732,15 @@ public class ResourceHelper public static StringBuffer getModuleClosingTag() { StringBuffer buffer = new StringBuffer(); - buffer.append( - StringHelper.copyString("=", Activator.getDefault().getPreferenceStore().getInt( - EditorPreferencePage.EDITOR_RIGHT_MARGIN))).append("\n"+modificationHistory).append( - StringHelper.newline).append("\\* Created ").append(new Date()).append(" by ").append( - System.getProperty("user.name")).append(StringHelper.newline); + IPreferenceStore preferencesStore = Activator.getDefault().getPreferenceStore(); + int rightMarginWidth = preferencesStore.getInt(EditorPreferencePage.EDITOR_RIGHT_MARGIN); + buffer.append(StringHelper.copyString("=", rightMarginWidth)).append(StringHelper.newline); + + if (preferencesStore.getBoolean(EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY)) { + buffer.append(modificationHistory).append(StringHelper.newline) + .append("\\* Created ").append(new Date()).append(" by ") + .append(System.getProperty("user.name")).append(StringHelper.newline); + } return buffer; } @@ -757,11 +761,13 @@ public class ResourceHelper * @param moduleFileName, name of the file * @return the stream with content */ - public static StringBuffer getExtendingModuleContent(String moduleFilename, String extendedModuleName) + public static StringBuffer getExtendingModuleContent(String moduleFilename, String... extendedModuleName) { - StringBuffer buffer = new StringBuffer(); - buffer.append("---- MODULE ").append(ResourceHelper.getModuleNameChecked(moduleFilename, false)).append( - " ----\n").append("EXTENDS ").append(extendedModuleName).append(", TLC").append("\n\n"); + final StringBuffer buffer = new StringBuffer(); + buffer.append("---- MODULE ").append(ResourceHelper.getModuleNameChecked(moduleFilename, false)) + .append(" ----\n").append("EXTENDS "); + buffer.append(String.join(", ", extendedModuleName)); + buffer.append("\n\n"); return buffer; } @@ -2312,8 +2318,10 @@ public class ResourceHelper public static boolean isValidLibraryLocation(final String location) { if (location != null && location.length() > 0) { IPath path = new Path(location); - File directory = path.toFile(); - return directory.exists() && directory.isDirectory(); + File directoryOrArchive = path.toFile(); + // Not checking file extension here bc UI dialog only accepts .jar and .zip + // anyway. + return directoryOrArchive.exists(); } return false; } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/TLAMarkerHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/TLAMarkerHelper.java index ff0f524fe0e7193a3a3a517dc168d20f8faefb58..553e15863ce6ef694b4e1cc6222968aa8cdf1621 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/TLAMarkerHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/TLAMarkerHelper.java @@ -24,7 +24,6 @@ import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.ui.handler.OpenSpecHandler; import pcal.TLAtoPCalMapping; - import tla2sany.st.Location; /** diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java index 404063756b9a353ac2306e2e55785625e1d5a266..b0066f5fc5e422164726e3ceb7ada4b1a6bb63ea 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java @@ -1,10 +1,12 @@ package org.lamport.tla.toolbox.util; +import java.awt.Frame; import java.io.File; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.ExecutionException; @@ -22,8 +24,10 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.MUIElement; @@ -44,10 +48,15 @@ import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.SWT; +import org.eclipse.swt.awt.SWT_AWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.DPIUtil; +import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; @@ -70,6 +79,7 @@ import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.editors.text.FileDocumentProvider; +import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.part.FileEditorInput; @@ -96,11 +106,12 @@ import tla2sany.st.Location; /** * A Helper for handling the RCP Objects like windows, editors and views - * - * @version $Id$ - * @author zambrovski */ +@SuppressWarnings("restriction") // DPIUtil is restricted - another heckuva job by the SWT folks public class UIHelper { + private static final boolean PLATFORM_IS_LINUX = Platform.getOS().equals(Platform.OS_LINUX); + private static final AtomicBoolean SCALE_DETERMINATION_ATTEMPTED = new AtomicBoolean(false); + private static double DISPLAY_SCALE = 1.0; /** * Closes all windows with a perspective @@ -839,6 +850,8 @@ public class UIHelper { return (Control) control; } else if (control instanceof Spinner) { return (Control) control; + } else if (control instanceof Combo) { + return (Control) control; } else if (control instanceof Control) { // why not return the control when object is instanceof control? return null; @@ -868,7 +881,7 @@ public class UIHelper { * @see UIHelper#jumpToLocation(Location, boolean) */ public static void jumpToLocation(final Location location) { - jumpToLocation(location, false); + jumpToLocation(location, false, null); } /** @@ -876,8 +889,11 @@ public class UIHelper { * editor on the module if an editor is not already open on it. * * @param location + * @param jumpToPCal + * @param workbenchPart if non-null, this part will be given focus on the workbench after selecting the document + * location. */ - public static void jumpToLocation(Location location, final boolean jumpToPCal) { + public static void jumpToLocation(Location location, final boolean jumpToPCal, final IWorkbenchPart workbenchPart) { if (location != null) { // the source of a location is the module name IResource moduleResource = ResourceHelper.getResourceByModuleName(location.source()); @@ -984,7 +1000,7 @@ public class UIHelper { } } } - + if (textEditor != null) { // the text editor may not be active, so set // it active @@ -1011,6 +1027,14 @@ public class UIHelper { * is not necessary in this context. */ fileDocumentProvider.disconnect(fileEditorInput); + + if (workbenchPart != null) { + final IWorkbenchPage activePage = getActivePage(); + + if (activePage != null) { + activePage.activate(workbenchPart); + } + } } } } @@ -1139,41 +1163,45 @@ public class UIHelper { (IFile) moduleResource)); if (editor != null) { - ITextEditor textEditor; - /* - * Try to get the text editor that contains the module. The - * module may be open in a multipage editor. - */ - if (editor instanceof ITextEditor) { - textEditor = (ITextEditor) editor; - } else { - textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); - } + jumpToSelection(editor, its); + } + } + } - if (editor instanceof MultiPageEditorPart) { - /* - * In this case, get all editors that are part of the - * multipage editor. Iterate through until a text editor is - * found. - */ - IEditorPart[] editors = ((MultiPageEditorPart) editor).findEditors(editor.getEditorInput()); - for (int i = 0; i < editors.length; i++) { - if (editors[i] instanceof ITextEditor) { - textEditor = (ITextEditor) editors[i]; - } - } - } + public static void jumpToSelection(IEditorPart editor, ITextSelection its) { + ITextEditor textEditor; + /* + * Try to get the text editor that contains the module. The + * module may be open in a multipage editor. + */ + if (editor instanceof ITextEditor) { + textEditor = (ITextEditor) editor; + } else { + textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); + } - if (textEditor != null) { - // the text editor may not be active, so set it active - if (editor instanceof MultiPageEditorPart) { - ((MultiPageEditorPart) editor).setActiveEditor(textEditor); - } - // getActivePage().activate(textEditor); - textEditor.selectAndReveal(its.getOffset(), its.getLength()); + if (editor instanceof MultiPageEditorPart) { + /* + * In this case, get all editors that are part of the + * multipage editor. Iterate through until a text editor is + * found. + */ + IEditorPart[] editors = ((MultiPageEditorPart) editor).findEditors(editor.getEditorInput()); + for (int i = 0; i < editors.length; i++) { + if (editors[i] instanceof ITextEditor) { + textEditor = (ITextEditor) editors[i]; } } } + + if (textEditor != null) { + // the text editor may not be active, so set it active + if (editor instanceof MultiPageEditorPart) { + ((MultiPageEditorPart) editor).setActiveEditor(textEditor); + } + // getActivePage().activate(textEditor); + textEditor.selectAndReveal(its.getOffset(), its.getLength()); + } } /** @@ -1363,4 +1391,104 @@ public class UIHelper { } return false; } + + /** + * This appropriately scales the non-zero spatial values contained in the + * <code>TableWrapData</code> instance to observe display scaling. + * + * @param tableWrapData the <code>TableWrapData</code> which should be altered + */ + public static void appropriatelyScaleTableWrapData(final TableWrapData tableWrapData) { + // Windows and Mac appear to do the correct thing + if (Platform.getOS().equals(Platform.OS_LINUX)) { + final double scale = getDisplayScaleFactor(); + + tableWrapData.indent = (int)((double)tableWrapData.indent * scale); + + if (tableWrapData.maxWidth != SWT.DEFAULT) { + tableWrapData.maxWidth = (int)((double)tableWrapData.maxWidth * scale); + } + if (tableWrapData.maxHeight != SWT.DEFAULT) { + tableWrapData.maxHeight = (int)((double)tableWrapData.maxHeight * scale); + } + if (tableWrapData.heightHint != SWT.DEFAULT) { + tableWrapData.heightHint = (int)((double)tableWrapData.heightHint * scale); + } + } + } + + /** + * This appropriately scales the non-zero spatial values contained in the + * <code>GridData</code> instance to observe display scaling. + * + * @param gridData the <code>GridData</code> which should be altered + */ + public static void appropriatelyScaleGridData(final GridData gridData) { + // Windows and Mac appear to do the correct thing. + if (Platform.getOS().equals(Platform.OS_LINUX)) { + final double scale = getDisplayScaleFactor(); + + gridData.horizontalIndent = (int)((double)gridData.horizontalIndent * scale); + gridData.verticalIndent = (int)((double)gridData.verticalIndent * scale); + + if (gridData.widthHint != SWT.DEFAULT) { + gridData.widthHint = (int)((double)gridData.widthHint * scale); + } + if (gridData.heightHint != SWT.DEFAULT) { + gridData.heightHint = (int)((double)gridData.heightHint * scale); + } + gridData.minimumWidth = (int)((double)gridData.minimumWidth * scale); + gridData.minimumHeight = (int)((double)gridData.minimumHeight * scale); + } + } + + /** + * "HiDPI" on Linux (Ubu 18.04 GNOME) is a total hot mess. With the Tweaks font scaling set to 1.7, we see: + * gsettings com.ubuntu.user-interface.desktop text-scaling-factor 1.0 + * gsettings org.gnome.desktop.interface text-scaling-factor 1.7 + * DPIUtil.getDeviceZoom() == 100 + * Toolkit's DPI == 95 + * SWT Display's DPI == 96 + * GraphicsConfiguration's default AffineTransform's scale == 2.0 + * + * I'm not thrilled with relying on executing an external process to invoke gsettings and process that response. + * + * @return the scaling factor of the screen on which the app is running (<b>OR, NOTE</b> on the screen which the + * Eclipse which launched the app is sitting, if launched from Eclipse.) + */ + public static double getDisplayScaleFactor() { + if (!SCALE_DETERMINATION_ATTEMPTED.getAndSet(true)) { + if (PLATFORM_IS_LINUX) { + Shell s = null; + Composite c = null; + + try { + final Display d = PlatformUI.getWorkbench().getDisplay(); + + s = new Shell(d); + c = new Composite(s, SWT.EMBEDDED); + + final Frame f = SWT_AWT.new_Frame(c); + DISPLAY_SCALE = f.getGraphicsConfiguration().getDefaultTransform().getScaleX(); + } catch (Exception e) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + "Exception fetching Linux display scale.", e)); + + DISPLAY_SCALE = 1.0; + } finally { + if (c != null) { + c.dispose(); + } + + if (s != null) { + s.dispose(); + } + } + } else { + DISPLAY_SCALE = (double)DPIUtil.getDeviceZoom() / 100.0; + } + } + + return DISPLAY_SCALE; + } } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java index 8f8b34c4ec862a2fefe67daa2a3a346cb7f73db3..ea053313732d5553ddf5fb3f17fc08f172110bc1 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java @@ -35,13 +35,10 @@ import org.eclipse.core.runtime.IExecutableExtensionFactory; import org.eclipse.core.runtime.Status; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.ui.PlatformUI; import org.lamport.tla.toolbox.Activator; -import org.eclipse.e4.core.contexts.ContextInjectionFactory; -import org.eclipse.e4.core.contexts.IEclipseContext; -import org.eclipse.e4.core.di.annotations.Execute; -@SuppressWarnings("unused") public class E4HandlerWrapper implements IExecutableExtensionFactory, IExecutableExtension { private String clazz; diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java index 5016d3153614818b854d1949c4b4884912b48d27..d42d21aebe2f25459d8305283a1617a2afb63760 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java @@ -39,6 +39,9 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer store.setDefault(EditorPreferencePage.CLEAR_DECLARATION_USE_MARKERS_ON_PARSE, EditorPreferencePage.CLEAR_DECLARATION_USE_MARKERS_ON_PARSE_DEFAULT); + + store.setDefault(EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY, + EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY_DEFAULT); /* * Set default for Renumber Proof command option. diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java index 9acd6de61f22a788b112a1c335ac3cbc4a31ca47..5dff2ddb4d231e6e636ad08821c6f30f05f85a8e 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java @@ -63,10 +63,7 @@ public class PreferenceStoreHelper rootFileName = ResourceHelper.PARENT_ONE_PROJECT_LOC + path.lastSegment(); convertAbsoluteToRelative(projectPrefs, rootFileName); } - final IFile linkedFile = ResourceHelper.getLinkedFile(project, rootFileName); - Activator.getDefault().logDebug( - "footFileName = " + (linkedFile != null ? linkedFile.getLocation().toOSString() : null)); - return linkedFile; + return ResourceHelper.getLinkedFile(project, rootFileName); } } else { Activator.getDefault().logInfo("projectPrefs is null"); diff --git a/org.lamport.tlatools.api/META-INF/MANIFEST.MF b/org.lamport.tlatools.api/META-INF/MANIFEST.MF index d665f360357bedb03ae0f113c8bf6b395543ab23..ab8c722c258b394c38ab4b352b6b2927a2e08495 100644 --- a/org.lamport.tlatools.api/META-INF/MANIFEST.MF +++ b/org.lamport.tlatools.api/META-INF/MANIFEST.MF @@ -7,3 +7,4 @@ Import-Package: org.osgi.framework;version="1.3.0" Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: tlc2 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe +Automatic-Module-Name: org.lamport.tlatools.api diff --git a/org.lamport.tlatools.consumer.distributed/.project b/org.lamport.tlatools.consumer.distributed/.project index d16107ff3902c9b6f529aa8c6e107f74397e8575..e8723b50caa37027c5278705ba50d5867f603d2d 100644 --- a/org.lamport.tlatools.consumer.distributed/.project +++ b/org.lamport.tlatools.consumer.distributed/.project @@ -34,6 +34,5 @@ <natures> <nature>org.eclipse.pde.PluginNature</nature> <nature>org.eclipse.jdt.core.javanature</nature> - <nature>org.eclipse.recommenders.rcp.analysis.RecommendersNature</nature> </natures> </projectDescription> diff --git a/org.lamport.tlatools.consumer.distributed/META-INF/MANIFEST.MF b/org.lamport.tlatools.consumer.distributed/META-INF/MANIFEST.MF index 45d29c9ca2a1c3600cef4d53c4f9e1228b34a7c6..95b023a2658840f1558b2393d44cf97b1dea5c20 100644 --- a/org.lamport.tlatools.consumer.distributed/META-INF/MANIFEST.MF +++ b/org.lamport.tlatools.consumer.distributed/META-INF/MANIFEST.MF @@ -9,3 +9,5 @@ Service-Component: OSGi-INF/workerConsumer.xml, OSGi-INF/fpsetConsumer.xml Import-Package: org.osgi.framework;version="1.6.0", org.osgi.service.packageadmin +Automatic-Module-Name: org.lamport.tlatools.consumer.distributed +Bundle-ActivationPolicy: lazy diff --git a/org.lamport.tlatools.impl.distributed/META-INF/MANIFEST.MF b/org.lamport.tlatools.impl.distributed/META-INF/MANIFEST.MF index 49231a8548f389503da4497f6a233cda0124942e..449567b4609d03a4651cbe4d594ac9aed9f0bd9b 100644 --- a/org.lamport.tlatools.impl.distributed/META-INF/MANIFEST.MF +++ b/org.lamport.tlatools.impl.distributed/META-INF/MANIFEST.MF @@ -11,3 +11,4 @@ Service-Component: OSGI-INF/worker.xml, OSGI-INF/fpset.xml Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe Import-Package: org.osgi.framework;version="1.5.0" +Automatic-Module-Name: org.lamport.tlatools.impl.distributed diff --git a/pom.xml b/pom.xml index 0a64a5ac510af2d6670f23a3023f2d47f3975bad..b80cee85fb7025aaf11d94e86ecf209ef10dd892 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ <module>org.lamport.tlatools.consumer.distributed</module> <!-- bundles --> + <module>org.lamport.tla.toolbox.rss</module> <module>org.lamport.tla.toolbox</module> <module>org.lamport.tla.toolbox.jclouds</module> <module>org.lamport.tla.toolbox.jnlp</module> @@ -76,6 +77,8 @@ <!-- product related --> <module>org.lamport.tla.toolbox.product.product</module> + <!-- Finally run UI tests on fully built product (AUT) --> + <module>org.lamport.tla.toolbox.product.uitest</module> </modules> <!-- tycho requires maven >= 3.0 --> @@ -88,7 +91,8 @@ <!-- http://maven.apache.org/general.html#encoding-warning --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <tycho-version>1.1.0</tycho-version> + <!-- https://wiki.eclipse.org/Tycho/Release_Notes/1.4 --> + <tycho-version>1.4.0</tycho-version> <!-- no default here --> <tycho.test.vm.argline>-Xmx500m -Xdebug -Xrunjdwp:transport=dt_socket,address=1044,server=y,suspend=n</tycho.test.vm.argline> @@ -115,10 +119,44 @@ <!-- Report into the tlaplus organization at SonarQube. --> <!-- Organizations support reporting different branches. --> <sonar.organization>tlaplus</sonar.organization> + + <!-- Align toolbox.version with the version in + org.lamport.tla.toolbox.product.product.product + product.version. --> + <toolbox.version>1.6.0</toolbox.version> + + <!-- This is used in org.lamport.tla.toolbox.product.uitest but + has been placed at the top level should it need be referenced + in other POMs. This property is only referenced during the AUT + unpacking if it is occurring on mac - the AUT unpacks out of + the ZIP ok on Linux and Windows--> + <jdk-bundle-plugin-version>11.0.3.1</jdk-bundle-plugin-version> </properties> <build> <plugins> + <!-- Fail the build early and with a clear error message if the Java 11 + dependency isn't satisfied. https://github.com/tlaplus/tlaplus/issues/278 --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <version>3.0.0-M2</version> + <executions> + <execution> + <id>enforce-java</id> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <rules> + <requireJavaVersion> + <version>11</version> + </requireJavaVersion> + </rules> + </configuration> + </execution> + </executions> + </plugin> <!-- enable tycho build extension --> <plugin> <groupId>org.eclipse.tycho</groupId> @@ -230,12 +268,12 @@ </target> <!-- Need to specify mininum Java version. This defines what - java.* packages are available during dependency resolution. The default - is Java 1.4 which e.g. does not come with "java.security.sasl", a + java.* packages are available during dependency resolution. + Java 1.4, e.g. does not come with "java.security.sasl", a package that is indirectly referenced by the toolbox (indirectly via org.apache.mina.core). see http://dev.eclipse.org/mhonarc/lists/cbi-dev/msg00166.html --> - <executionEnvironment>JavaSE-1.8</executionEnvironment> + <executionEnvironment>JavaSE-11</executionEnvironment> <!-- configure the p2 target environments for multi-platform build --> <environments> diff --git a/tlatools/.classpath b/tlatools/.classpath index 973889d035931e7371769667c608904a77b482d9..4f732359a13d10f057d453de21402b3568383dde 100644 --- a/tlatools/.classpath +++ b/tlatools/.classpath @@ -1,6 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="module" value="true"/> + </attributes> + <accessrules> + <accessrule kind="accessible" pattern="jdk/internal/**"/> + </accessrules> + </classpathentry> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry excluding="tlc2/tool/WorkerMonitorAspect.aj|tlc2/tool/distributed/TLCServerMonitorAspect.aj|tlc2/tool/distributed/RMIMethodMonitorAspect.aj|tlc2/tool/distributed/RMIMethodMonitorAspect.aj|tlc2/tool/distributed/TLCServerMonitorAspect.aj" kind="src" path="src-aj"/> @@ -9,8 +16,14 @@ <classpathentry kind="src" path="test-concurrent"/> <classpathentry kind="src" path="test-verify"/> <classpathentry kind="src" path="test-benchmark"/> - <classpathentry kind="lib" path="lib/javax.mail.jar"/> + <classpathentry kind="lib" path="lib/javax.mail/mailapi-1.6.3.jar"/> <classpathentry kind="lib" path="lib/jpf.jar"/> <classpathentry kind="lib" path="lib/jmh/jmh-core-1.21.jar"/> + <classpathentry kind="lib" path="lib/jmh/commons-math3-3.2.jar"/> + <classpathentry kind="src" path=".apt_generated"> + <attributes> + <attribute name="optional" value="true"/> + </attributes> + </classpathentry> <classpathentry kind="output" path="class"/> </classpath> diff --git a/tlatools/.factorypath b/tlatools/.factorypath new file mode 100644 index 0000000000000000000000000000000000000000..82707435cb204e21ae2b472b2d0493bf1c86acd4 --- /dev/null +++ b/tlatools/.factorypath @@ -0,0 +1,4 @@ +<factorypath> + <factorypathentry kind="WKSPJAR" id="/tlatools/lib/jmh/jmh-core-1.21.jar" enabled="true" runInBatchMode="false"/> + <factorypathentry kind="WKSPJAR" id="/tlatools/lib/jmh/jmh-generator-annprocess-1.21.jar" enabled="true" runInBatchMode="false"/> +</factorypath> diff --git a/tlatools/.settings/org.eclipse.jdt.apt.core.prefs b/tlatools/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..fa6bcfb3fdb3a5ff5ccf658c79e656a02d8dbf61 --- /dev/null +++ b/tlatools/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=true +org.eclipse.jdt.apt.genSrcDir=.apt_generated +org.eclipse.jdt.apt.genTestSrcDir=.apt_generated_tests +org.eclipse.jdt.apt.reconcileEnabled=true diff --git a/tlatools/.settings/org.eclipse.jdt.core.prefs b/tlatools/.settings/org.eclipse.jdt.core.prefs index deac336a07ad19e9db9791516f09fedd665afdd9..eca77e2d236b4ea62572ace58ec574b5687412c2 100644 --- a/tlatools/.settings/org.eclipse.jdt.core.prefs +++ b/tlatools/.settings/org.eclipse.jdt.core.prefs @@ -6,6 +6,7 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota 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 @@ -96,4 +97,6 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=enabled +org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/tlatools/META-INF/MANIFEST.MF b/tlatools/META-INF/MANIFEST.MF index 8b455ca1cf02ceee0239f9f4f0193cf02d6e2779..dca81d29abbdfbbb2b9df9550fbb274473074dcd 100644 --- a/tlatools/META-INF/MANIFEST.MF +++ b/tlatools/META-INF/MANIFEST.MF @@ -21,12 +21,14 @@ Export-Package: pcal, tlc2.output, tlc2.pprint, tlc2.tool, + tlc2.tool.coverage, tlc2.tool.distributed, tlc2.tool.distributed.fp, tlc2.tool.distributed.management, tlc2.tool.distributed.selector, tlc2.tool.fp, tlc2.tool.fp.management, + tlc2.tool.impl, tlc2.tool.liveness, tlc2.tool.management, tlc2.tool.other, @@ -40,6 +42,6 @@ Eclipse-BundleShape: dir Require-Bundle: org.aspectj.runtime;bundle-version="1.6.0";resolution:=optional;x-installation:=greedy, org.junit;bundle-version="4.12.0";resolution:=optional;x-installation:=greedy, javax.mail;bundle-version="1.4.0";resolution:=optional, - javax.activation;bundle-version="1.1.0";resolution:=optional, org.easymock;bundle-version="2.4.0";resolution:=optional Bundle-ClassPath: . +Automatic-Module-Name: org.lamport.tlatools diff --git a/tlatools/build.properties b/tlatools/build.properties index ce318758b302beeea273f6a96e2008eee549884a..b96419813482e94c4ff0d8e530b7887a0c52db61 100644 --- a/tlatools/build.properties +++ b/tlatools/build.properties @@ -1,11 +1,8 @@ source.. = src/,\ - src-aj/,\ - test/,\ - test-concurrent/,\ - test-long/ + src-aj/ bin.includes = META-INF/,\ . -output.. = bin/ -jre.compilation.profile = J2SE-1.5 -javacSource = 1.5 -javacTarget = 1.5 +output.. = class/ +jre.compilation.profile = JavaSE-1.8 +javacSource = 1.8 +javacTarget = 1.8 diff --git a/tlatools/customBuild.xml b/tlatools/customBuild.xml index 7ec621c557a24b76bac98d6cf520f6dd3c3cb017..4234ab78838b63aac8f5d87f597f250cb5a441d2 100644 --- a/tlatools/customBuild.xml +++ b/tlatools/customBuild.xml @@ -24,7 +24,7 @@ <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"> <classpath> - <pathelement location="lib/aspectjtools-1.8.5.jar" /> + <pathelement location="lib/aspectjtools-1.9.2.jar" /> </classpath> </taskdef> @@ -48,11 +48,11 @@ </target> <target name="info" description="Prints information" depends="git-revision"> - <echo message="ANT_HOME : ${env.ANT_HOME}" /> - <echo message="Ant Version : ${ant.version}" /> - <echo message="Java Version : ${ant.java.version}" /> + <echo message="ANT_HOME : ${env.ANT_HOME}" /> + <echo message="Ant Version : ${ant.version}" /> + <echo message="Java Version : ${ant.java.version}" /> <echo message="Skipping Tests : ${test.skip}" /> - <echo message="With AspectJ: ${withaj}" /> + <echo message="With AspectJ : ${withaj}" /> <echo message="Git BuildNumber: ${git.branch}_${git.tag}_${git.shortRevision}" /> </target> @@ -65,6 +65,17 @@ <antcall target="dist" inheritall="true" inheritrefs="true" /> <antcall target="test-dist" inheritall="true" inheritrefs="true" /> </target> + + <!-- Similar to default except it skips test and only runs test-dist. This is called from pom.xml --> + <target name="default-maven" depends="info" description="Default"> + <antcall target="compile" inheritall="true" inheritrefs="true" /> + <antcall target="compile-aj" inheritall="true" inheritrefs="true" /> + <antcall target="compile-test" inheritall="true" inheritrefs="true" /> + <!-- <antcall target="test" inheritall="true" inheritrefs="true" /> --> + <antcall target="git-revision" inheritall="true" inheritrefs="true" /> + <antcall target="dist" inheritall="true" inheritrefs="true" /> + <antcall target="test-dist" inheritall="true" inheritrefs="true" /> + </target> <target name="default-release" depends="info" description="Produces a release"> <antcall target="compile" inheritall="true" inheritrefs="true" /> @@ -102,7 +113,10 @@ </delete> <!-- Delete leftovers from previous junit invocation --> <delete includeemptydirs="true" failonerror="false"> - <fileset dir="states/" includes="*/**" /> + <!-- Delete ALL states folders in the tlatools/ directory --> + <!-- A stale states/ folder in src/model/ once caused the --> + <!-- Maven build to fail with an OOM in the pack200 task. --> + <fileset dir="${basedir}" includes="**/states/**" /> </delete> </target> @@ -122,7 +136,7 @@ <!-- compilerarg value="-Xlint:deprecation"/--> <classpath refid="project.classpath" /> <classpath> - <pathelement location="lib/javax.mail.jar" /> + <pathelement location="lib/javax.mail/mailapi-1.6.3.jar" /> </classpath> </javac> @@ -133,6 +147,10 @@ <exclude name="**/*.java" /> <exclude name="**/*.~*" /> <exclude name="**/*##*" /> + <exclude name="**/*.09-09-07" /> + <exclude name="**/*.09-07-02" /> + <exclude name="**/*.11-02-10" /> + <exclude name="**/*.jpg" /> </fileset> </copy> </target> @@ -147,11 +165,15 @@ ==================================================================== </echo> <!-- compile aspectj related class files --> - <iajc destdir="${class.dir}" sourceRoots="${src-aj.dir}" debug="true" source="1.8" target="1.8"> + <iajc destdir="${class.dir}" debug="true" verbose="true" source="1.8" target="1.8"> + <sourceroots> + <!-- Here we implicitly decide to use AspectJ Load-Time weaving by excludign ${src.dir} as a pathelement. Adding ${src.dir} results in aspects being woven at compile-time as part of the ant build. --> + <pathelement location="${src-aj.dir}"/> + </sourceroots> <classpath refid="project.classpath" /> <classpath> - <pathelement location="lib/aspectjrt-1.8.5.jar" /> - <pathelement location="lib/aspectjtools-1.8.5.jar" /> + <pathelement location="lib/aspectjrt-1.9.2.jar" /> + <pathelement location="lib/aspectjtools-1.9.2.jar" /> <pathelement path="${class.dir}" /> </classpath> </iajc> @@ -168,8 +190,8 @@ <!-- These files are requried for load time weaving and during runtime --> <copy todir="${class.dir}/lib"> <fileset dir="lib/"> - <include name="aspectjrt-1.8.5.jar" /> - <include name="aspectjweaver-1.8.5.jar" /> + <include name="aspectjrt-1.9.2.jar" /> + <include name="aspectjweaver-1.9.2.jar" /> </fileset> </copy> </target> @@ -181,22 +203,64 @@ <!-- of TLC to a given email address. --> <!-- The javax.mail dependency as well as javax.activation is also depended upon --> <!-- by the tla2tools OSGi bundle and is expected to be the same version. --> - <unzip src="lib/javax.mail.jar" dest="${class.dir}"/> + <unzip src="lib/javax.mail/mailapi-1.6.3.jar" dest="${class.dir}"> + <patternset> + <include name="**/*.class"/> + <include name="META-INF/LICENSE.txt"/> + <include name="META-INF/mailcap"/> + <include name="META-INF/javamail.charset.map"/> + <exclude name="javax/mail/search/**"/> + </patternset> + </unzip> + <unzip src="lib/javax.mail/smtp-1.6.3.jar" dest="${class.dir}"> + <patternset> + <include name="**/*.class"/> + </patternset> + </unzip> + <unzip src="lib/javax.mail/javax.activation_1.1.0.v201211130549.jar" dest="${class.dir}"> + <patternset> + <include name="**/*.class"/> + <exclude name="org/**"/> + </patternset> + </unzip> + <touch file="${class.dir}/META-INF/javamail.default.address.map"/> <!-- Extract javax.mail to maven classes folder. This script is triggered by --> <!-- maven. However, maven compiles the code again to target/classes from --> <!-- where it creates the plugin --> - <unzip src="lib/javax.mail.jar" dest="target/classes"/> + <unzip src="lib/javax.mail/mailapi-1.6.3.jar" dest="target/classes"> + <patternset> + <include name="**/*.class"/> + <include name="META-INF/LICENSE.txt"/> + <include name="META-INF/mailcap"/> + <include name="META-INF/javamail.charset.map"/> + <exclude name="javax/mail/search/**"/> + </patternset> + </unzip> + <unzip src="lib/javax.mail/smtp-1.6.3.jar" dest="target/classes"> + <patternset> + <include name="**/*.class"/> + </patternset> + </unzip> + <unzip src="lib/javax.mail/javax.activation_1.1.0.v201211130549.jar" dest="target/classes"> + <patternset> + <include name="**/*.class"/> + <exclude name="org/**"/> + </patternset> + </unzip> + <touch file="target/classes/META-INF/javamail.default.address.map"/> - <!-- TODO: add javax.activation to lib/ and extract it here too. Otherwise we have a --> - <!-- runtime dependency on Java 6. --> <!-- create a JAR file for the users --> <mkdir dir="${dist.dir}" /> <jar destfile="${dist.file}" level="9"> <fileset dir="${class.dir}" includes="**/*" excludes=" **/*.jpg, + README.txt, + heapstats.jfc, + jpf.properties, tlc2/tool/fp/*.tla, + tlc2/value/*.tla, pcal/*.tla, META-INF/maven/, src/tla2sany/parser/ParseException.09-09-07, @@ -210,6 +274,7 @@ src/tla2sany/parser/TLAplusParserTokenManager.11-02-10, src/tla2sany/parser/Token.09-09-07, src/tla2sany/parser/TokenMgrError.09-09-07"/> + <fileset dir="${doc.dir}" includes="License.txt"/> <manifest> <attribute name="Built-By" value="${user.name}" /> <attribute name="Build-Tag" value="${env.BUILD_TAG}" /> @@ -217,6 +282,9 @@ <attribute name="Implementation-Title" value="TLA+ Tools" /> <attribute name="Implementation-Version" value="${version} ${TODAY}" /> <attribute name="Implementation-Vendor" value="Microsoft Corp." /> + <!-- The jar files contains many main classes (SANY, TEX, pcal, ...) --> + <!-- but lets consider TLC the one users primarily use. --> + <attribute name="Main-class" value="tlc2.TLC" /> <!-- Git revision --> <attribute name="X-Git-Branch" value="${git.branch}" /> <attribute name="X-Git-Tag" value="${git.tag}" /> @@ -264,15 +332,128 @@ <target name="test" unless="test.skip"> <!-- run junit tests --> <mkdir dir="${test.reports}" /> - <jacoco:coverage destfile="target/code-coverage.exec"> - <junit printsummary="yes" haltonfailure="${test.halt}" haltonerror="${test.halt}" forkmode="perTest" fork="yes"> + <!-- forkmode used to be "perBatch" on Java 1.8 using the util.IsolatedTestCaseRunner. + This concept broken with Java11 for unknown reasons which is why forkmode has been + changed to perTest to run each test in a separate VM. This is slower compared to + running all tests in a single VM. --> + <junit printsummary="yes" haltonfailure="${test.halt}" showoutput="no" haltonerror="${test.halt}" forkmode="perTest" fork="yes"> + <!-- enable all assertions --> + <jvmarg value="-ea"/> + <jvmarg value="-XX:MaxDirectMemorySize=512k"/> + <jvmarg value="-XX:+UseParallelGC"/> + <!-- Uncomment to open a debug port in each forked VM to remote attach your Eclipse at port 1044. + <jvmarg value="-Xdebug" /> + <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044" /> + --> + <classpath refid="project.classpath" /> + <classpath> + <pathelement location="lib/junit-4.12.jar" /> + <pathelement location="lib/hamcrest-core-1.3.jar" /> + <pathelement location="lib/cglib-nodep-3.1.jar" /> + <pathelement location="lib/objenesis-2.1.jar" /> + <pathelement location="lib/easymock-3.3.1.jar" /> + <pathelement location="lib/javax.mail/mailapi-1.6.3.jar" /> + <pathelement location="test-model/UserModuleOverrideFromJar.jar" /> + <pathelement path="${class.dir}" /> + <pathelement path="${test.class.dir}" /> + </classpath> + <formatter type="xml" /> + + <!-- Pass the base path of the tlatools project to unit tests in case they need it to locate TLA+ specs or configs --> + <sysproperty key="basedir" value="${basedir}/"/> + <sysproperty key="tlc2.tool.fp.FPSet.impl" value="tlc2.tool.fp.OffHeapDiskFPSet"/> + <sysproperty key="util.FileUtil.milliseconds" value="true"/> + <sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/> + <!-- The tests below can be tricked into running in a single VM by fiddling with the classloader + to reload and thus initialize all classes for each tests. --> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="**/*Test*.java" /> + + <!-- Produce bogus crash with Quarantine runner. --> + <exclude name="tlc2/tool/distributed/TLCSetTest.java" /> + <exclude name="tlc2/tool/distributed/DistributedDoInitFunctorEvalExceptionTest.java" /> + <!-- Just fail because of Quarantine runner. --> + <exclude name="tlc2/TLCTest.java"/> + <exclude name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/> + <exclude name="tlc2/tool/UserModuleOverrideTest.java" /> + <exclude name="tlc2/tool/UserModuleOverrideFromJarTest.java" /> + + <exclude name="**/PCalTest.java" /> + <exclude name="**/CommonTestCase.java" /> + <exclude name="**/ModelCheckerTestCase.java" /> + <exclude name="**/PCalModelCheckerTestCase.java" /> + <exclude name="**/SuiteTestCase.java" /> + <exclude name="**/SuiteETestCase.java" /> + <exclude name="**/DistributedTLCTestCase.java" /> + <exclude name="**/TLCServerTestCase.java" /> + <exclude name="**/SuccessfulSimulationTestCase.java" /> + <exclude name="**/AbstractExampleTestCase.java" /> + <exclude name="**/AbstractCoverageTest.java" /> + <exclude name="**/InitEvalOrderTest.java" /> + <exclude name="**/TestMPRecorder.java" /> + <exclude name="**/TestPrintStream.java" /> + <exclude name="**/BidirectionalTransitions1BTest.java" /> + <exclude name="**/BidirectionalTransitions2CTest.java" /> + <exclude name="**/Abstract*Test.java" /> + <exclude name="**/TestDriver.java" /> + <exclude name="**/TestDriver2.java" /> + <exclude name="**/AllTests.java" /> + <exclude name="util/IsolatedTestCaseRunner.java"/> + <!-- Known test failures --> + <exclude name="**/pcal/StackTestTest.java" /> + <exclude name="**/pcal/TestPCandStackTest.java" /> + <!-- These take too long --> + <exclude name="**/MacroQuicksortTest.java" /> + <exclude name="**/MacroRealQuicksortTest.java" /> + <exclude name="**/PcalPaxosTest.java" /> + <exclude name="**/DetlefsTest.java" /> + <exclude name="**/StarkMutexTest.java" /> + <exclude name="**/SimpleMultiProcTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/UserModuleOverrideFromJarTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/UserModuleOverrideTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/distributed/TLCSetTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/distributed/DistributedDoInitFunctorEvalExceptionTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/TLCTest.java"/> + <include name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/> + </fileset> + </batchtest> + </junit> + + <!-- remove copied class.dir --> + <delete dir="${ws.class.dir}" deleteonexit="true"/> + </target> + + <!-- Executes accompining unit tests on jar file --> + <target name="test-dist" unless="test.skip"> + <!-- run junit tests on tlatools.jar --> + <mkdir dir="${test.reports}/onJar" /> + <jacoco:coverage destfile="target/code-coverage.exec" includes="pcal.*:tla2sany.*:tla2tex.*:tlc2.*:util.*:org.lamport.*" excludes="com.sun.*:javax.*:**/Tests.*:**/*Test*"> + <junit printsummary="yes" haltonfailure="${test.halt}" haltonerror="${test.halt}" forkmode="perTest" fork="yes"> <!-- enable all assertions --> <jvmarg value="-ea"/> <jvmarg value="-XX:MaxDirectMemorySize=512k"/> - <!-- Uncomment to open a debug port in each forked VM to remote attach your Eclipse at port 1044. - <jvmarg value="-Xdebug" /> - <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044" /> - --> + <jvmarg value="-XX:+UseParallelGC"/> <classpath refid="project.classpath" /> <classpath> <pathelement location="lib/junit-4.12.jar" /> @@ -280,20 +461,30 @@ <pathelement location="lib/cglib-nodep-3.1.jar" /> <pathelement location="lib/objenesis-2.1.jar" /> <pathelement location="lib/easymock-3.3.1.jar" /> - <pathelement location="lib/javax.mail.jar" /> - <pathelement path="${class.dir}" /> + <pathelement location="${dist.file}" /> <pathelement path="${test.class.dir}" /> + <pathelement location="test-model/UserModuleOverrideFromJar.jar" /> </classpath> + <formatter type="xml" /> - - <!-- Pass the base path of the tlatools project to unit tests in case they need it to locate TLA+ specs or configs --> <sysproperty key="basedir" value="${basedir}/"/> - <sysproperty key="tlc2.tool.fp.FPSet.impl" value="tlc2.tool.fp.OffHeapDiskFPSet"/> <sysproperty key="util.FileUtil.milliseconds" value="true"/> - <sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/> - <batchtest fork="yes" todir="${test.reports}"> + <sysproperty key="tlc2.tool.fp.FPSet.impl" value="tlc2.tool.fp.OffHeapDiskFPSet"/> + <sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/> + + <batchtest fork="yes" todir="${test.reports}/onJar"> <fileset dir="${test.dir}"> - <include name="**/*Test*.java" /> + <include name="**/*Test*.java" /> + + <!-- Produce bogus crash with Quarantine runner. --> + <exclude name="tlc2/tool/distributed/TLCSetTest.java" /> + <exclude name="tlc2/tool/distributed/DistributedDoInitFunctorEvalExceptionTest.java" /> + <!-- Just fail because of Quarantine runner. --> + <exclude name="tlc2/TLCTest.java"/> + <exclude name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/> + <exclude name="tlc2/tool/UserModuleOverrideTest.java" /> + <exclude name="tlc2/tool/UserModuleOverrideFromJarTest.java" /> + <exclude name="**/PCalTest.java" /> <exclude name="**/CommonTestCase.java" /> <exclude name="**/ModelCheckerTestCase.java" /> @@ -303,13 +494,18 @@ <exclude name="**/DistributedTLCTestCase.java" /> <exclude name="**/TLCServerTestCase.java" /> <exclude name="**/SuccessfulSimulationTestCase.java" /> - <exclude name="**/AbstractExampleTestCase.java" /> + <exclude name="**/AbstractExampleTestCase.java" /> + <exclude name="**/AbstractCoverageTest.java" /> + <exclude name="**/InitEvalOrderTest.java" /> + <exclude name="**/BidirectionalTransitions1BTest.java" /> + <exclude name="**/BidirectionalTransitions2CTest.java" /> <exclude name="**/TestMPRecorder.java" /> <exclude name="**/TestPrintStream.java" /> <exclude name="**/Abstract*Test.java" /> <exclude name="**/TestDriver.java" /> <exclude name="**/TestDriver2.java" /> <exclude name="**/AllTests.java" /> + <exclude name="util/IsolatedTestCaseRunner.java"/> <!-- Known test failures --> <exclude name="**/pcal/StackTestTest.java" /> <exclude name="**/pcal/TestPCandStackTest.java" /> @@ -322,6 +518,32 @@ <exclude name="**/SimpleMultiProcTest.java" /> </fileset> </batchtest> + <batchtest fork="yes" todir="${test.reports}"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/UserModuleOverrideFromJarTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}/onJar"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/UserModuleOverrideTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}/onJar"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/distributed/TLCSetTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}/onJar"> + <fileset dir="${test.dir}"> + <include name="tlc2/tool/distributed/DistributedDoInitFunctorEvalExceptionTest.java" /> + </fileset> + </batchtest> + <batchtest fork="yes" todir="${test.reports}/onJar"> + <fileset dir="${test.dir}"> + <include name="tlc2/TLCTest.java"/> + <include name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/> + </fileset> + </batchtest> </junit> </jacoco:coverage> @@ -329,65 +551,6 @@ <delete dir="${ws.class.dir}" deleteonexit="true"/> </target> - <!-- Executes accompining unit tests on jar file --> - <target name="test-dist" unless="test.skip"> - <!-- run junit tests on tlatools.jar --> - <mkdir dir="${test.reports}/onJar" /> - <junit printsummary="yes" haltonfailure="${test.halt}" haltonerror="${test.halt}" forkmode="perTest" fork="yes"> - <!-- enable all assertions --> - <jvmarg value="-ea"/> - <classpath refid="project.classpath" /> - <classpath> - <pathelement location="lib/junit-4.12.jar" /> - <pathelement location="lib/hamcrest-core-1.3.jar" /> - <pathelement location="lib/cglib-nodep-3.1.jar" /> - <pathelement location="lib/objenesis-2.1.jar" /> - <pathelement location="lib/easymock-3.3.1.jar" /> - <pathelement location="${dist.file}" /> - <pathelement path="${test.class.dir}" /> - </classpath> - - <formatter type="xml" /> - <sysproperty key="basedir" value="${basedir}/"/> - <sysproperty key="util.FileUtil.milliseconds" value="true"/> - - <batchtest fork="yes" todir="${test.reports}/onJar"> - <fileset dir="${test.dir}"> - <include name="**/*Test*.java" /> - <exclude name="**/PCalTest.java" /> - <exclude name="**/CommonTestCase.java" /> - <exclude name="**/ModelCheckerTestCase.java" /> - <exclude name="**/PCalModelCheckerTestCase.java" /> - <exclude name="**/SuiteTestCase.java" /> - <exclude name="**/SuiteETestCase.java" /> - <exclude name="**/DistributedTLCTestCase.java" /> - <exclude name="**/TLCServerTestCase.java" /> - <exclude name="**/SuccessfulSimulationTestCase.java" /> - <exclude name="**/AbstractExampleTestCase.java" /> - <exclude name="**/TestMPRecorder.java" /> - <exclude name="**/TestPrintStream.java" /> - <exclude name="**/Abstract*Test.java" /> - <exclude name="**/TestDriver.java" /> - <exclude name="**/TestDriver2.java" /> - <exclude name="**/AllTests.java" /> - <!-- Known test failures --> - <exclude name="**/pcal/StackTestTest.java" /> - <exclude name="**/pcal/TestPCandStackTest.java" /> - <!-- These take too long --> - <exclude name="**/MacroQuicksortTest.java" /> - <exclude name="**/MacroRealQuicksortTest.java" /> - <exclude name="**/PcalPaxosTest.java" /> - <exclude name="**/DetlefsTest.java" /> - <exclude name="**/StarkMutexTest.java" /> - <exclude name="**/SimpleMultiProcTest.java" /> - </fileset> - </batchtest> - </junit> - - <!-- remove copied class.dir --> - <delete dir="${ws.class.dir}" deleteonexit="true"/> - </target> - <!-- Executes accompining long-running unit tests on jar file --> <target name="test-dist-long" unless="test.skip"> <!-- compile unit tests --> @@ -412,7 +575,7 @@ <junit printsummary="yes" haltonfailure="no" haltonerror="no" maxmemory="4096m" forkmode="perTest" fork="yes"> <!-- enable all assertions --> <jvmarg value="-ea"/> - <jvmarg value="-javaagent:lib/aspectjweaver-1.8.5.jar" /> + <jvmarg value="-javaagent:lib/aspectjweaver-1.9.2.jar" /> <sysproperty key="org.aspectj.weaver.showWeaveInfo" value="false"/> <sysproperty key="aj.weaving.verbose" value="false"/> <classpath refid="project.classpath" /> @@ -493,6 +656,7 @@ <classpath refid="project.classpath" /> <classpath> <pathelement path="${class.dir}" /> + <pathelement path="${test.class.dir}" /> <pathelement location="lib/jmh/jmh-core-1.21.jar" /> <pathelement location="lib/jmh/jmh-generator-annprocess-1.21.jar" /> </classpath> diff --git a/tlatools/doc/environment.txt b/tlatools/doc/environment.txt index c486f4f5075548a5599e2e0c9964183b362b3d6e..8dcd3e63f73bebbd632cc60b75e86a32c3975e62 100644 --- a/tlatools/doc/environment.txt +++ b/tlatools/doc/environment.txt @@ -1,6 +1,13 @@ Introduction =============================================================================== - This document describes the environment setup for development of TLA+ Tools. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +THIS DOCUMENT IS OBSOLETE - DO NOT USE AS CONSULTATION. +=============================================================================== +This document describes the environment setup for development of TLA+ Tools. It consists of the following sections: - Used versions - Environment setup diff --git a/tlatools/jfr/README.md b/tlatools/jfr/README.md index 9a594fa7efcd77b20147c75f42538fa56864d981..c1789a8627567d245ea3c9aea9654cacaa482633 100644 --- a/tlatools/jfr/README.md +++ b/tlatools/jfr/README.md @@ -2,8 +2,7 @@ This folder contains all libraries and config files to profile TLC with Java Fli A default JFR is created with: --XX:+UnlockCommercialFeatures --XX:+FlightRecorder +-XX:StartFlightRecording=settings=default -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,dumponexit=true,dumponexitpath=dump.jfr,maxage=1h,settings=${project_loc:tlatools}/jfr/tlc.jfc To additionally record JMX data in the flight recording, add: diff --git a/tlatools/lib/aspectjrt-1.8.5.jar b/tlatools/lib/aspectjrt-1.8.5.jar deleted file mode 100644 index b8241c820410996cc4a13dc942c27c6b0d9d6050..0000000000000000000000000000000000000000 Binary files a/tlatools/lib/aspectjrt-1.8.5.jar and /dev/null differ diff --git a/tlatools/lib/aspectjrt-1.9.2.jar b/tlatools/lib/aspectjrt-1.9.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..6b5c2032e2c75ebdefc0969d65bbc69db8ca9cb3 Binary files /dev/null and b/tlatools/lib/aspectjrt-1.9.2.jar differ diff --git a/tlatools/lib/aspectjtools-1.8.5.jar b/tlatools/lib/aspectjtools-1.9.2.jar similarity index 53% rename from tlatools/lib/aspectjtools-1.8.5.jar rename to tlatools/lib/aspectjtools-1.9.2.jar index 31f045d54150a074202fafac517f9be9243d0519..660ad6eaac8ae9c75d93e1af50eaed4213447f2f 100644 Binary files a/tlatools/lib/aspectjtools-1.8.5.jar and b/tlatools/lib/aspectjtools-1.9.2.jar differ diff --git a/tlatools/lib/aspectjweaver-1.8.5.jar b/tlatools/lib/aspectjweaver-1.8.5.jar deleted file mode 100644 index 952a8e4c7cae616b1d20da5dde99a820911df527..0000000000000000000000000000000000000000 Binary files a/tlatools/lib/aspectjweaver-1.8.5.jar and /dev/null differ diff --git a/tlatools/lib/aspectjweaver-1.9.2.jar b/tlatools/lib/aspectjweaver-1.9.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..ea0d8df17889cee1f9c465fd7e6918ce2baa00c7 Binary files /dev/null and b/tlatools/lib/aspectjweaver-1.9.2.jar differ diff --git a/tlatools/lib/jacocoant.jar b/tlatools/lib/jacocoant.jar index e6c0d786172a99832381bc1e876ec0b0cc4e5d8b..09ac4a806f595e54eeb4623d20e134ebf2706b89 100644 Binary files a/tlatools/lib/jacocoant.jar and b/tlatools/lib/jacocoant.jar differ diff --git a/tlatools/lib/javax.mail.jar b/tlatools/lib/javax.mail.jar deleted file mode 100644 index dd06a6a0965a3439620391bcf4b166316e903e88..0000000000000000000000000000000000000000 Binary files a/tlatools/lib/javax.mail.jar and /dev/null differ diff --git a/tlatools/lib/javax.mail/javax.activation_1.1.0.v201211130549.jar b/tlatools/lib/javax.mail/javax.activation_1.1.0.v201211130549.jar new file mode 100644 index 0000000000000000000000000000000000000000..fb4f69d92fa98abeff31c378428cbc2984be89e7 Binary files /dev/null and b/tlatools/lib/javax.mail/javax.activation_1.1.0.v201211130549.jar differ diff --git a/tlatools/lib/javax.mail/mailapi-1.6.3.jar b/tlatools/lib/javax.mail/mailapi-1.6.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..dec5ed8ffa782974f85c3ed791e258faa3452aea Binary files /dev/null and b/tlatools/lib/javax.mail/mailapi-1.6.3.jar differ diff --git a/tlatools/lib/javax.mail/smtp-1.6.3.jar b/tlatools/lib/javax.mail/smtp-1.6.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..ea4dafb079d35a02eae8baf976ea79413bc43be7 Binary files /dev/null and b/tlatools/lib/javax.mail/smtp-1.6.3.jar differ diff --git a/tlatools/lib/jpf/jgraphx.jar b/tlatools/lib/jpf/jgraphx.jar new file mode 100644 index 0000000000000000000000000000000000000000..cd3f469fd1b63142eccf308ece42ae3dcd3a08c3 Binary files /dev/null and b/tlatools/lib/jpf/jgraphx.jar differ diff --git a/tlatools/lib/jpf/jpf-shell.jar b/tlatools/lib/jpf/jpf-shell.jar new file mode 100644 index 0000000000000000000000000000000000000000..5da542e93f1b135d74e19b1cf53683da3dccf106 Binary files /dev/null and b/tlatools/lib/jpf/jpf-shell.jar differ diff --git a/tlatools/lib/jpf/jpf-visual.jar b/tlatools/lib/jpf/jpf-visual.jar new file mode 100644 index 0000000000000000000000000000000000000000..2fa0b7fcb560be4936b9129a15279837a9501a60 Binary files /dev/null and b/tlatools/lib/jpf/jpf-visual.jar differ diff --git a/tlatools/pom.xml b/tlatools/pom.xml index 867aa9fcac6e8591ca34c7d2712bb94ad1a5e16a..2c306879d369b4f6d461a4483750a2c87024aa26 100644 --- a/tlatools/pom.xml +++ b/tlatools/pom.xml @@ -20,7 +20,7 @@ <!-- which gets invoked from maven. Unfortunately, it means that the tasks which are executed --> <!-- by ant are not visible to maven. In this case it results in sonar not finding necessary --> <!-- data to include coverage information. The properties below make sure that sonar finds the data. --> - <sonar.sources>src,src-gen,src-aj</sonar.sources> + <sonar.sources>src,src-aj</sonar.sources> <sonar.tests>test,test-verify,test-long,test-concurrent</sonar.tests> <sonar.java.binaries>class</sonar.java.binaries> @@ -33,9 +33,6 @@ <sonar.surefire.reportsPath>target/surefire-reports</sonar.surefire.reportsPath> <sonar.junit.reportsPath>target/surefire-reports</sonar.junit.reportsPath> <sonar.jacoco.reportPaths>target/code-coverage.exec</sonar.jacoco.reportPaths> - - <!-- I have no idea why those two are special and have to be excluded. --> - <sonar.exclusions>src-gen/tla2sany/parser/TLAplusParser.java,src/tlc2/value/FcnParams.java</sonar.exclusions> </properties> @@ -80,8 +77,30 @@ <property name="maven.test.skip" value="${maven.test.skip}"/> <property name="maven.test.halt" value="${maven.test.halt}"/> <ant antfile="customBuild.xml" inheritRefs="true"> - <target name="default" /> - <target name="dist-mixed-zip" /> + <target name="default-maven" /> + </ant> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + <!-- Run customBuild.xml's clean target --> + <execution> + <id>clean</id> + <phase>clean</phase> + <configuration> + <tasks> + + <taskdef name="junit" + classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask" + classpathref="maven.test.classpath" /> + + <property name="build.compiler" value="extJavac"/> + <property name="maven.test.skip" value="${maven.test.skip}"/> + <property name="maven.test.halt" value="${maven.test.halt}"/> + <ant antfile="customBuild.xml" inheritRefs="true"> + <target name="clean" /> </ant> </tasks> </configuration> @@ -108,9 +127,10 @@ <!-- Compile aspects --> <plugin> - <groupId>org.codehaus.mojo</groupId> + <!-- https://github.com/nickwongdev/aspectj-maven-plugin --> + <groupId>com.nickwongdev</groupId> <artifactId>aspectj-maven-plugin</artifactId> - <version>1.11</version> + <version>1.12.1</version> <configuration> <ajdtBuildDefFile>build.ajproperties</ajdtBuildDefFile> </configuration> @@ -119,6 +139,11 @@ <goals> <goal>compile</goal> </goals> + <configuration> + <complianceLevel>1.8</complianceLevel> + <source>1.8</source> + <target>1.8</target> + </configuration> </execution> </executions> </plugin> diff --git a/tlatools/project.properties b/tlatools/project.properties index b98226fd30c7696b0ab55dfc66744510f9069373..170b370d0f59900dbfb579a684b26451d5db4556 100644 --- a/tlatools/project.properties +++ b/tlatools/project.properties @@ -12,8 +12,6 @@ dist.file =${dist.dir}/tla2tools.jar dist-mixed.file =${dist.dir}/tla.zip dist-mixed.file.jar =${dist.dir}/tla2tools-mixed.jar -srcgen.dir =src-gen - test.reports =target/surefire-reports/ examples.dir =../examples diff --git a/tlatools/src-aj/META-INF/aop-ajc.xml b/tlatools/src-aj/META-INF/aop-ajc.xml index c425d69c2e85a51b25349b374bea97f310a8b088..71712cc740e474162e42029adff926e78fb8f5c1 100644 --- a/tlatools/src-aj/META-INF/aop-ajc.xml +++ b/tlatools/src-aj/META-INF/aop-ajc.xml @@ -5,6 +5,18 @@ <aspect name="tlc2.tool.WorkerMonitorAspect"/> <aspect name="tlc2.tool.distributed.RMIMethodMonitorAspect"/> <aspect name="tlc2.tool.distributed.TLCServerMonitorAspect"/> + <!-- + <aspect name="tlc2.tool.CostModelAspect"/> + --> </aspects> - + + <!-- + Dump load-time weaving classes to disk. + https://www.eclipse.org/aspectj/doc/released/pdguide/ltwdump.html#ltwdump-examples + --> + <weaver options="-verbose -debug"> + <!-- dump before and after they are woven. --> + <dump within="tlc2..*" beforeandafter="true"/> + <include within="tlc2..*"/> + </weaver> </aspectj> diff --git a/tlatools/src-aj/META-INF/aop.xml b/tlatools/src-aj/META-INF/aop.xml index c425d69c2e85a51b25349b374bea97f310a8b088..102e0e21286937a8ac5e7838e17aa15eb1b6a47d 100644 --- a/tlatools/src-aj/META-INF/aop.xml +++ b/tlatools/src-aj/META-INF/aop.xml @@ -5,6 +5,18 @@ <aspect name="tlc2.tool.WorkerMonitorAspect"/> <aspect name="tlc2.tool.distributed.RMIMethodMonitorAspect"/> <aspect name="tlc2.tool.distributed.TLCServerMonitorAspect"/> + <!-- + <aspect name="tlc2.tool.CostModelAspect"/> + --> </aspects> + <!-- + Dump load-time weaving classes to disk. + https://www.eclipse.org/aspectj/doc/released/pdguide/ltwdump.html#ltwdump-examples + --> + <weaver options="-verbose -debug"> + <!-- dump before and after they are woven. --> + <dump within="tlc2..*" beforeandafter="true"/> + <include within="tlc2..*"/> + </weaver> </aspectj> diff --git a/tlatools/src-aj/tlc2/tool/CostModelAspect.aj b/tlatools/src-aj/tlc2/tool/CostModelAspect.aj new file mode 100644 index 0000000000000000000000000000000000000000..a050d7549097664583a61ae31ca309e6ded2a7e3 --- /dev/null +++ b/tlatools/src-aj/tlc2/tool/CostModelAspect.aj @@ -0,0 +1,244 @@ +///******************************************************************************* +// * Copyright (c) 2018 Microsoft Research. All rights reserved. +// * +// * The MIT License (MIT) +// * +// * 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. +// * +// * Contributors: +// * Markus Alexander Kuppe - initial API and implementation +// ******************************************************************************/ +//package tlc2.tool; +// +//import tlc2.tool.Action; +//import tlc2.tool.ActionItemList; +//import tlc2.tool.IStateFunctor; +//import tlc2.tool.StateVec; +//import tlc2.tool.TLCState; +//import tlc2.tool.coverage.CostModel; +//import tlc2.util.Context; +//import tlc2.TLCGlobals; +//import tla2sany.semantic.OpApplNode; +//import tla2sany.semantic.SemanticNode; +// +//public final aspect CostModelAspect { +// +// // -------------------------------- // +// +///* +// private final void getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states, CostModel cm) { +// */ +// +// final pointcut getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states, CostModel cm): +// execution(private void tlc2.tool.Tool.getInitStates(ActionItemList, TLCState, IStateFunctor, CostModel)) +// && args(acts, ps, states, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()) ; +// +// void around(ActionItemList acts, TLCState ps, IStateFunctor states, CostModel cm): (getInitStates(acts, ps, states, cm)) { +// if (acts.isEmpty() || ps.allAssigned()) { +// cm.incInvocations(); +// cm.getRoot().incInvocations(); +// } +// proceed(acts, ps, states, cm); +// } +// +// // -------------------------------- // +// +///* +// public StateVec getNextStates(Action action, TLCState state) { +// action.cm.incInvocations(nss.size()); +// } +//*/ +// +// final pointcut getNextStatesAction(Action action, TLCState state): +// execution(public tlc2.tool.StateVec tlc2.tool.Tool.getNextStates(Action, TLCState)) +// && args(action, state) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// //TODO Rewrite to after returning? +// StateVec around(final Action action, final TLCState state): (getNextStatesAction(action, state)) { +// final StateVec nss = (StateVec) proceed(action, state); +// action.cm.incInvocations(nss.size()); +// +// return nss; +// } +// +// // -------------------------------- // +// +///* +// private final TLCState getNextStates(ActionItemList acts, final TLCState s0, final TLCState s1, final StateVec nss, CostModel cm) { +// final TLCState copy = getNextStates0(acts, s0, s1, nss, cm); +// if (copy != s1) { +// cm.incInvocations(); +// } +// return copy; +// } +//*/ +// +// final pointcut getNextStates(ActionItemList acts, TLCState s0, TLCState s1, StateVec nss, CostModel cm): +// execution(private tlc2.tool.TLCState tlc2.tool.Tool.getNextStates(ActionItemList, TLCState, TLCState, StateVec, CostModel)) +// && args(acts, s0, s1, nss, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// TLCState around(ActionItemList acts, TLCState s0, TLCState s1, StateVec nss, CostModel cm): (getNextStates(acts, s0, s1, nss, cm)) { +// final TLCState copy = (TLCState) proceed(acts, s0, s1, nss, cm); +// if (copy != s1) { +// cm.incInvocations(); +// } +// return copy; +// } +// +// // -------------------------------- // +// +///* +// private final Value setSource(final SemanticNode expr, final Value value, CostModel cm) { +// value.setCostModel(cm.get(expr)); +//*/ +// +// final pointcut setSource(SemanticNode expr, final Value value, CostModel cm): +// execution(private tlc2.value.Value tlc2.tool.Tool.setSource(SemanticNode, Value, CostModel)) +// && args(expr, value, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// Value around(SemanticNode expr, final Value value, CostModel cm): (setSource(expr, value, cm)) { +// value.setCostModel(cm.get(expr)); +// return proceed(expr, value, cm); +// } +// +// // -------------------------------- // +// +///* +// private final Value evalAppl(final OpApplNode expr, Context c, TLCState s0, TLCState s1, final int control, CostModel cm) { +// cm = cm.get(expr); +// cm.incInvocations(); +//*/ +// +// final pointcut evalsAppl(OpApplNode expr, Context c, TLCState s0, TLCState s1, int control, CostModel cm): +// execution(private tlc2.value.Value tlc2.tool.Tool.evalAppl(tla2sany.semantic.OpApplNode, Context, TLCState, TLCState, int, CostModel)) +// && args(expr, c, s0, s1, control, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// Value around(OpApplNode expr, Context c, TLCState s0, TLCState s1, int control, CostModel cm): (evalsAppl(expr, c, s0, s1, control, cm)) { +// return proceed(expr, c, s0, s1, control, cm.get(expr).incInvocations()); +// } +// +// // -------------------------------- // +// +///* +// +// private final TLCState getNextStates(SemanticNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, CostModel cm) { +// cm = cm.get(pred); +// +// private final TLCState processUnchanged(SemanticNode expr, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, CostModel cm) { +// cm = cm.get(expr); +//*/ +// +// final pointcut evals6(SemanticNode expr, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, +// CostModel cm): +// (execution(private tlc2.tool.TLCState tlc2.tool.Tool.getNextStates(SemanticNode, ActionItemList, Context, TLCState, TLCState, StateVec, CostModel)) || +// execution(private tlc2.tool.TLCState tlc2.tool.Tool.processUnchanged(SemanticNode, ActionItemList, Context, TLCState, TLCState, StateVec, CostModel))) +// && args(expr, acts, c, s0, s1, nss, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// TLCState around(SemanticNode expr, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, CostModel cm): (evals6(expr, acts, c, s0, s1, nss, cm)) { +// return proceed(expr, acts, c, s0, s1, nss, cm.get(expr)); +// } +// +// // -------------------------------- // +// +///* +// private final void getInitStatesAppl(OpApplNode init, ActionItemList acts, Context c, TLCState ps, IStateFunctor states, CostModel cm) { +// cm = cm.get(init); +//*/ +// +// final pointcut getInitStatesAppl(OpApplNode expr, ActionItemList acts, Context c, TLCState ps, IStateFunctor states, CostModel cm): +// execution(private void tlc2.tool.Tool.getInitStatesAppl(OpApplNode, ActionItemList, Context, TLCState, IStateFunctor, CostModel)) +// && args(expr, acts, c, ps, states, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// void around(OpApplNode expr, ActionItemList acts, Context c, TLCState ps, IStateFunctor states, CostModel cm): (getInitStatesAppl(expr, acts, c, ps, states, cm)) { +// proceed(expr, acts, c, ps, states, cm.get(expr)); +// } +// +// // -------------------------------- // +// +///* +// private final TLCState enabledAppl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm) { +// cm = cm.get(pred); +//*/ +// +// final pointcut enableAppl(OpApplNode expr, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm): +// execution(private tlc2.tool.TLCState tlc2.tool.Tool.enabledAppl(OpApplNode, ActionItemList, Context, TLCState, TLCState, CostModel)) +// && args(expr, acts, c, s0, s1, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// TLCState around(OpApplNode expr, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm): (enableAppl(expr, acts, c, s0, s1, cm)) { +// return proceed(expr, acts, c, s0, s1, cm.get(expr)); +// } +// +// // -------------------------------- // +// +///* +// public final Value eval(SemanticNode expr, Context c, TLCState s0, TLCState s1, final int control, CostModel cm) { +// cm = cm.get(expr) +//*/ +// +// final pointcut eval(SemanticNode expr, Context c, TLCState s0, TLCState s1, int control, CostModel cm): +// execution(public tlc2.value.Value tlc2.tool.Tool.eval(SemanticNode, Context, TLCState, TLCState, int, CostModel)) +// && args(expr, c, s0, s1, control, cm) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// Value around(SemanticNode expr, Context c, TLCState s0, TLCState s1, int control, CostModel cm): (eval(expr, c, s0, s1, control, cm)) { +// return proceed(expr, c, s0, s1, control, cm.get(expr)); +// } +// +// // ---------------- Pass on CostModel instances from existing Value to newly instantiated ones. ---------------- // +// +// final pointcut newValueCtor() : call(tlc2.value.Value+.new(..)) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// after() returning(final Value newValue) : newValueCtor() { +// if (thisJoinPoint.getThis() instanceof Value) { +// // Get CostModel instance from existing Value and attach to new one. +// final Value existingValue = (Value) thisJoinPoint.getThis(); +// newValue.setCostModel(existingValue.getCostModel()); +// } +// } +// +// // ---------------- (Finally) count invocations to ValueEnumerator#elements to measure costs. ---------------- // +// +// final pointcut elementsExec(Enumerable en): +// execution(public tlc2.value.ValueEnumeration tlc2.value.Enumerable+.elements(..)) +// && target(en) && !within(CostModelAspect) && if(TLCGlobals.isCoverageEnabled()); +// +// ValueEnumeration around(Enumerable en): (elementsExec(en)) { +// return new WrappingValueEnumeration(((Enumerable) en).getCostModel(), (ValueEnumeration) proceed(en)); +// } +// +// private static class WrappingValueEnumeration implements ValueEnumeration { +// +// private final CostModel cm; +// private final ValueEnumeration ve; +// +// public WrappingValueEnumeration(CostModel costModel, ValueEnumeration ve) { +// this.cm = costModel.incInvocations(1); +// this.ve = ve; +// } +// +// @Override +// public void reset() { +// ve.reset(); +// } +// +// @Override +// public Value nextElement() { +// cm.incSecondary(); +// return ve.nextElement(); +// } +// } +//} diff --git a/tlatools/src-gen/ParseException.java b/tlatools/src-gen/ParseException.java deleted file mode 100644 index 0e7cb108aa68dd60cb2ceb49b4a8b6108327a7ab..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/ParseException.java +++ /dev/null @@ -1,192 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -package tla2sany.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: <result of getMessage> - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - StringBuffer expected = new StringBuffer(); - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" "); - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} diff --git a/tlatools/src-gen/SimpleCharStream.java b/tlatools/src-gen/SimpleCharStream.java deleted file mode 100644 index c2dc2c544e95069ecdb665120b7aee98f732c2f4..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/SimpleCharStream.java +++ /dev/null @@ -1,439 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ -package tla2sany.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} diff --git a/tlatools/src-gen/TLAplusParser.java b/tlatools/src-gen/TLAplusParser.java deleted file mode 100644 index 4e42677bfab62ea0ff886456b5a284fe8882e4a1..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/TLAplusParser.java +++ /dev/null @@ -1,12012 +0,0 @@ -/* Generated By:55&JavaCC: Do not edit this line. TLAplusParser.java */ -package tla2sany.parser; - -import tla2sany.st.ParseTree; -import tla2sany.st.TreeNode; - -import tla2sany.utilities.Vector; -import tla2sany.utilities.Stack; -import tla2sany.utilities.Assert; -import util.UniqueString; -import util.ToolIO; - -public class TLAplusParser implements tla2sany.st.SyntaxTreeConstants, ParseTree, TLAplusParserConstants { - - public String[] dependencies() { - /*********************************************************************** - * This method is used in modanalyzer/{SyntaxTreePrinter,ParserUnit}. * - ***********************************************************************/ - String[]deps = new String[ dependencyList.size() ]; - for (int lvi =0; lvi < deps.length; lvi++) - deps[lvi] = ((UniqueString)dependencyList.elementAt(lvi)).toString(); - return deps; - } - public TreeNode rootNode() { return ParseTree; } - public String moduleName() { return mn.toString(); } -// public tla2sany.st.ParseErrors getErrors() { return PErrors; } Unused, apparently -// The front end can simply read the public PErrors. - - public SyntaxTreeNode ParseTree; - /*********************************************************************** - * The root node. * - ***********************************************************************/ - - public Vector dependencyList = new Vector( 20 ); - - private UniqueString mn = null; - /********************************************************************** - * The module name. * - **********************************************************************/ - - private boolean numberFlag = false; - private boolean decimalFlag = false; - - private Operator FcnOp = Operators.getOperator( UniqueString.uniqueStringOf("[" )); - private SyntaxTreeNode FairnessHook; - - private UniqueString At = UniqueString.uniqueStringOf("@"); - - ParseErrors PErrors = new ParseErrors(); - - private tla2sany.parser.OperatorStack OperatorStack = new tla2sany.parser.OperatorStack( PErrors ); - - private BracketStack BStack; - /*********************************************************************** - * This is a stack of the kinds and offsets of the tokens that start a * - * bulleted list within which the parser is currently grabbing tokens. * - ***********************************************************************/ - - public boolean parse() { - /*********************************************************************** - * This is a wrapper for actual parsing procedure CompilationUnit(). * - * If an exception occurs, or if an error was pushed onto PErrors, * - * then an error message is printed and it returns false. Otherwise, * - * it returns true. Note that if we want to be able to parse an * - * expression, we need to implement a similar wrapper for * - * Expression(). * - ***********************************************************************/ - - /*********************************************************************** - * The following code sets BStack to a new BracketStack object and * - * initializes its classes field as described in BracketStack.java. * - ***********************************************************************/ - BStack = new BracketStack(); - BStack.newClass(); -// BStack.registerInCurrentClass( BAND ); - BStack.registerInCurrentClass( AND ); - BStack.newClass(); -// BStack.registerInCurrentClass( BOR ); - BStack.registerInCurrentClass( OR ); - BStack.newClass(); - BStack.registerInCurrentClass( PROOF ); - BStack.newClass(); - BStack.registerInCurrentClass( LBR ); - BStack.newClass(); - BStack.registerInCurrentClass( ASSUME ); - - try { ParseTree = CompilationUnit(); } - catch( ParseException e ) { - PErrors.push( new ParseError( msgStackToString(e) ) ); } - catch( TokenMgrError tme ) { - // lexical error. - String msg = tme.getMessage(); - int bl = jj_input_stream.getBeginLine() + 1; - int el = jj_input_stream.getEndLine() + 1; - // lexical error. - if ( (msg.indexOf("EOF") != -1) && (bl != el) ) { - PErrors.push(new ParseError( - "Lexical {error: EOF reached, " + - "possibly open comment starting around line " + - (bl-1) )) ; - } else PErrors.push( new ParseError( msg )) ; -// PErrors.push( new ParseError( tme.getMessage() )) ; - } /*** end catch(TokenMgrError) ****/ - if ( PErrors.empty() ) Assert.assertion( heirsIndex == 0 ); - /********************************************************************* - * This is a sanity check. The assertion should never be false. * - *********************************************************************/ - else { - /********************************************************************* - * An error has been pushed onto PErrors. It might have been done * - * when an exception was caught, or by detecting an error during the * - * parsing without throwing an exception. This happens in * - * ExceptComponent() if it finds "!.@", and in FairnessExpr(). * - *********************************************************************/ - tla2sany.st.ParseError list[] = PErrors.errors(); - for (int i = 0; i < list.length; i++ ) { - ToolIO.out.println( list[i].reportedError() ); -// ToolIO.out.println( "+ " + list[i].defaultError() ); - } - } -// ParseTree.setNumberFlags( numberFlag, decimalFlag ); - return PErrors.empty(); - } - -/* - this is required to store temporarily information required by - the semantic lookahead, as it doesn't have access to the variables - of the production -*/ - private SyntaxTreeNode local; - - void registerTN( SyntaxTreeNode some) { local = some ; } - - boolean testTN() { - /*********************************************************************** - * THIS METHOD IS APPARENTLY NOT USED. * - ***********************************************************************/ - return local.isKind(N_IdPrefix) - && BStack.aboveReference( local.first().first().location[0] ) ; - } - - private SyntaxTreeNode anchor = null; - /*********************************************************************** - * This is set to a non-null value only in Expression(). If a * - * ClosedExpressionOrOp node is found when parsing an expression, * - * anchor is set to that node. It is set to null in the following * - * places: * - * * - * - When beginning to parse a Substitution() * - * * - * - When OpSuite() or Substitution() finds that anchor equals an * - * Op Symbol, as described below. * - * * - * The Substitution() and OpSuite() procedures look for an * - * Expression or Op Symbol by calling Expression() and, if that throws * - * an exception, catching the expression and checking if anchor is the * - * desired Op Symbol. * - ***********************************************************************/ - -// Lookahead mechanisms for definitions - /************************************************************************* - * The following code is lifted directly from the getToken method * - * created by JavaCC in the file TLAplusParser.java. * - * * - * J-Ch doesn't remember why he defined this method instead of just * - * using the GetToken method. He thinks that it was to make sure * - * it would always return a token rather than null. * - *************************************************************************/ - final private Token getNextPreviewToken(Token t) { - if (t.next == null) t.next = token_source.getNextToken(); - /******************************************************************** - * token_source is declared in configuration/Configuration.java to * - * be a ConfigurationTokenManager. * - ********************************************************************/ - return t.next; - } - -// borrowed from code generated by JavaCC. - final private Token initPreviewToken() { - return lookingAhead ? jj_scanpos : token; - /********************************************************************* - * `lookingAhead', `token', and `jj_scanpos' are declared in * - * TLAplusParser (created by javacc from this file). The javacc * - * documentation says that token is the value returned by * - * getToken(0). God only knows what lookingAhead and jj_scanpos * - * are. * - *********************************************************************/ - } - - private final void belchDEF() { - /*********************************************************************** - * The purpose of this method seems to be to introduce a dummy * - * <DEFBREAK> token into the token stream, which is used in parsing * - * the OperatorOrFunctionDefinition non-terminal. * - ***********************************************************************/ - Token previousT = initPreviewToken(); - Token currentT = getNextPreviewToken( previousT ); - previousT.next = null; // <-- to break recursion - Token nextT = getNextPreviewToken( currentT ); - currentT.next = previousT; - while ( nextT.kind != EOF - && nextT.kind != THEOREM -// && nextT.kind != ASSUME - /**************************************************************** - * This test for ASSUME removed on 26 June 2007. * - * It made belchDEF get hung up on nested ASSUME/PROVEs. * - * However, this permitted extra DEFBREAK tokens to be inserted. * - * Those extra tokens were eliminated by the change on the same * - * date described below. * - ****************************************************************/ - && nextT.kind != ASSUMPTION - && nextT.kind != END_MODULE) { - /********************************************************************* - * As long as we have not yet reached the end of the stream or a * - * THEOREM, ASSUME, or END_MODULE token, move forward through the * - * token stream looking for a "==" token. Maintain a chain of the * - * tokens passed over, with t.next equal to the previous token, and * - * t.next = null for the first token. * - * * - * At this point, the last three tokens obtained are previoustT, * - * currentT, and nextT, where currentT.next = previousT and * - * nextT.next points to the first unexamined token. * - *********************************************************************/ - if ( currentT.kind == DEF ) { - /******************************************************************* - * currentT is a "==" token. * - *******************************************************************/ - Token t = previousT; - if ( t.kind == RBR || t.kind == RSB ) { - /***************************************************************** - * t = previousT is a ")" or "]" token. * - *****************************************************************/ - // the following code assumes that parentheses are evenly balanced. - // something could be added to reinforce the test. - // they do not have to be on the same line either, btw. - int depth = 1; - while (t.next != null) { - t = t.next; - if ( (t.kind == LBR || t.kind == LSB) && depth == 1 ) break; - if ( (t.kind == LBR || t.kind == LSB) && depth > 1 ) depth--; - if ( (t.kind == RBR || t.kind == RSB) ) depth++; - } - if (t.next == null ) break; - else if (t.next.kind == IDENTIFIER) - t = t.next; - // we are positioned at first symbol before "[" or "(" : must be an identifier - } else - /***************************************************************** - * t = previousT is not a ")" or "]" token. * - *****************************************************************/ - if ( t.kind == IDENTIFIER ) { - /************************************************************** - * t is an IDENTIFIER token. * - * * - * If t.next [the previous token in the input stream] is a * - * non-prefix operator and is not preceded in the stream by * - * "<-" [so it belongs to a preceding substitution], then set * - * t to t.next if it is a prefix operator and to t.next.next * - * if it is an infix operator. * - * * - * Note: If belchDef is called with the input stream at * - * something like "++ a ==", then evaluating t.next.next * - * dereferences null. This should happen only if the user * - * has left off the first parameter of the definitiion and * - * the resulting exception seems to be caught, but it * - * produces a misleading error message. This type of rare * - * error is hardly worth worrying about, but it would be easy * - * enough to add a test and might be worth doing if it's easy * - * to produce the right error message. * - **************************************************************/ - Token identifier = t; - if ( isOp( t.next ) && ! isPostfixOp( t.next ) ) { - t = t.next; - if ( t.next.kind == SUBSTITUTE ) - t = identifier; // skip back - else if ( isInfixOp( t ) ) t = t.next; - // else assume prefix - } - } else { - /************************************************************** - * t is not an IDENTIFIER token. * - * * - * If it is an operator token, set t to t.next. (It will be * - * a postfix operator unless the user made an error.) * - **************************************************************/ - if ( isOp(t) ) { // assume postfix op, the parser will catch the error - t = t.next; - } - } - /******************************************************************* - * Insert a DEFBREAK token into the input stream right before * - * token t, and exit the while loop. * - * * - * Changed by LL on 26 June 2007 so it doesn't add the DEFBREAK * - * token if there's already one there. (This could happen because * - * of the change to pass over ASSUMEs described above.) * - *******************************************************************/ - if ( (t.next == null) - || (t.next.kind != DEFBREAK)) { - Token i = new Token(); - i.kind = DEFBREAK; - i.image = "Beginning of definition"; - i.beginLine = t.beginLine; - i.beginColumn = t.beginColumn; - i.endLine = t.endLine; - i.endColumn = t.endColumn; - i.next = t.next; - t.next = i; - } ; - break; /* EXIT while */ - } else { - /******************************************************************* - * currentT is not a "==" token. * - *******************************************************************/ - previousT = currentT; - currentT = nextT; - nextT = getNextPreviewToken( currentT ); - currentT.next = previousT; - } - } /* END while */ - // reverse pointers. - /*********************************************************************** - * Go back through the examined tokens, making t.next point to the * - * next one for each token t. * - ***********************************************************************/ - while (previousT != null ) { - currentT.next = nextT; - nextT = currentT; - currentT = previousT; - previousT = currentT.next; - } - // relink firstT - currentT.next = nextT; - } - -// - void skipOver( int l ) { - while ( true ) { - Token t = getToken(1); - int k = t.kind; - if ( (k == EOF) || (t.beginColumn < l ) ) return; - t = getNextToken(); - } - } - -/*************************************************************************** -* Note: the non-terminal ClosedStart was commented out, apparently to be * -* replaced by this boolean-valued method. * -***************************************************************************/ -boolean -ClosedStart( Token t ) { - return t.kind == IDENTIFIER - || (t.kind >= op_57 && t.kind <= op_119) - /**************************************************************** - * These are all prefix, infix, and postfix operators. * - ****************************************************************/ - || t.kind == NUMBER_LITERAL - || t.kind == LBR - || t.kind == LSB - || t.kind == LAB - || t.kind == LBC - || t.kind == LWB - || t.kind == STRING_LITERAL - || t.kind == WF - || t.kind == SF; -} - -boolean -isOp( Token t ) { - return t.kind >= op_57 && t.kind <= op_119; -} - -boolean isInfixOp( Token t ) { - return t.kind >= op_1 && t.kind <= op_119; -} - -boolean isPostfixOp( Token t ) { - return t.kind >= op_57 && t.kind <= op_70; -} - -boolean isPrefixOp( Token t ) { - return t.kind >= op_26 && t.kind <= op_116; -} - -// global variable follows !!! Make sure it is set everywhere as required -Operator lastOp; - /************************************************************************* - * This seems to equal the last Prefix, Infix, PostFix, or NonExpPrefix * - * op that was parsed. * - *************************************************************************/ - - boolean isGenOp(SyntaxTreeNode tn) { /* has to be of the form prefix, opsym */ - int kind = tn.getKind(); - if ( kind == N_GenPrefixOp - || kind == N_GenNonExpPrefixOp - || kind == N_GenInfixOp - || kind == N_GenPostfixOp - || kind == N_FcnAppl ) - return true; - else - return false; - } - -// boolean IsNotExpression () { -// /*********************************************************************** -// * This method is called only in NumberedAssumeProve. * -// ***********************************************************************/ -// Token t = initPreviewToken(); -// t = getNextPreviewToken(t); -// /********************************************************************* -// * Previous statement added on 1 Mar 2007 by J-Ch and LL to fix bug. * -// *********************************************************************/ -// int k = t.kind; -// if ( k == US || k == LOCAL || k == VARIABLE || k == PARAMETER || k == INSTANCE || k == CONSTANT || k == STATE || k == ACTION || k == TEMPORAL ) return true; -// else { -// t = getNextPreviewToken(t); k = t.kind; -// if ( k == US || k == DEF || k == LSB ) -// return true; -// else if (k == LBR) { -// int depth = 1; -// Token nt = getNextPreviewToken(t); -// while (true) { -// t = nt; nt = getNextPreviewToken(t); k = t.kind; -// if ( k == RBR ) { -// if ( depth == 1 ) -// if ( nt.kind == DEF ) return true; -// else return false; -// else -// depth--; -// } else -// if ( k == LBR ) { depth++; -// } else -// if ( k == EOF ) return false; -// } -// } -// } -// return false; -// } -// - boolean isFieldNameToken( Token t ) { - /*********************************************************************** - * Modified by LL on 10 Oct 2007 because of new keywords added and * - * obsolete ones removed. * - ***********************************************************************/ - if ( (t.kind >= ACTION && t.kind <= EXCEPT) - ||(t.kind == EXTENDS) - ||(t.kind >= IF && t.kind <= SF) - ||(t.kind == STATE) - ||(t.kind >= THEN && t.kind <= WITH) - ||(t.kind == US) - ||(t.kind >= op_112 && t.kind <= op_116) - ) - return true; - else - return false; - } - - boolean isLabel(SyntaxTreeNode node) { - /*********************************************************************** - * Checks that node is a label, meaning that it is either an * - * identifier token or else an OpApplication node each of whose * - * arguments is an OpArgs node whose child is a GeneralId node with an * - * empty IdPrefix. * - ***********************************************************************/ - if (node == null) {return false;} ; - if (node.isKind(N_GeneralId)) { - return (node.heirs()[0].heirs().length == 0) ; - } ; - if (! node.isKind(N_OpApplication)) {return false;} ; - SyntaxTreeNode opArgs = (SyntaxTreeNode) node.heirs()[1] ; -if (opArgs.kind != N_OpArgs) { ToolIO.out.println("Bug: not N_OpArgs node"); }; - /******************************************************************* - * Sanity check--can be removed after debugging. * - *******************************************************************/ - for (int i = 1; i < opArgs.heirs().length; i = i+2) { - /********************************************************************* - * THe OpArg node for Op(arg_1, ... , arg_N) has the 2N+1 heirs * - * * - * "(" arg_1 "," ... "," arg_N ")" * - *********************************************************************/ - SyntaxTreeNode genId = (SyntaxTreeNode) opArgs.heirs()[i] ; - if (genId.kind != N_GeneralId) {return false;} ; - if (genId.heirs()[0].heirs().length != 0){return false;} - } // for - return true; - } - - boolean labelDoesNotChangeParse(SyntaxTreeNode labeledExpr, - Operator labelOp) { - /*********************************************************************** - * Checks if preceding the expression labeledExpr with a label has not * - * changed the parsing of the enclosing expression. It has changed * - * the parsing iff * - * /\ labeledExpr is an infix or postfix expression with operator * - * labelOp * - * /\ the top of OperatorStack is an infix or prefix operator stackOp * - * /\ it is not the case that stackOp \prec labelOp. * - ***********************************************************************/ - if ( ! ( labeledExpr.isKind(N_InfixExpr) - || labeledExpr.isKind(N_PostfixExpr) ) ) {return true;} ; - - OSelement topNode = OperatorStack.topOfStack(); - if (topNode == null) {return true;} ; - Operator stackOp = topNode.getOperator() ; - return (stackOp == null) || Operator.prec(stackOp, labelOp) ; - } - - void checkIndentation(SyntaxTreeNode nd, SyntaxTreeNode junct) - throws ParseException { - /*********************************************************************** - * Goes through the descendants of node nd, stopping at an N_DisjList * - * or N_ConjList node. For each node it finds, if checks whether it * - * is properly indented with respect to the current N_DisjItem or * - * N_ConjItem junct. If not, it reports an error by throwing an * - * exception. * - ***********************************************************************/ - TreeNode[] children = nd.heirs() ; - for (int i = 0; i < children.length; i++) { - SyntaxTreeNode child = (SyntaxTreeNode) children[i] ; - if (! ( child.isKind(N_ConjList) - || child.isKind(N_DisjList))) { - if (!BStack.aboveReference(child.location[1])) { - throw new ParseException( - "Item at " + child.getLocation().toString() + - " is not properly indented inside conjunction or " + - " disjunction list item at " + junct.getLocation().toString()) ; - } ; - checkIndentation(child, junct) ; - } ; - } ; - } - -// predicate used in lookahead to discriminate between the Case Separator and -// the box operator. Returns true if it is most likely not the separator. -// This is a weak mechanism. - boolean boxDisc() { - Token t = getToken(1); - if ( t.kind == CASESEP ) - return OperatorStack.preInEmptyTop(); - else - return true; - } - - boolean caseSep() { - Token t = getToken(1); - return ( t.kind == CASESEP ); - } - - boolean matchFcnConst () { - /*********************************************************************** - * Seems to return true iff the next current token sequence begins * - * with "<< ... >> \in" or "Identifier [, Identifier] \in". It is * - * used after a "{" to see if this is a subset expression such as "{x * - * \in S : exp}" and after a "[" to see if it is a function expression * - * such as "[x \in S |-> exp]". This leads to the bug that it starts * - * incorrectly interpreting the expressions "{x \in S}" and * - * "{<<1, 2>> \in {}}" as a subset expression and reports an error. * - ***********************************************************************/ - Token t = initPreviewToken(); - t = getNextPreviewToken( t ); - if (t.kind == LAB) { - int count = 1; - while (count != 0 ) { - t = getNextPreviewToken( t ); - if (t.kind == LAB) count++; - if (t.kind == RAB) count--; - if (t.kind == EOF) return false; - } - t = getNextPreviewToken( t ); - return (t.kind == IN ); - } else - if (t.kind == IDENTIFIER) { - t = getNextPreviewToken( t ); - while ( t.kind == COMMA ) { - t = getNextPreviewToken( t ); - if (t.kind != IDENTIFIER) return false; - t = getNextPreviewToken( t ); - } - return (t.kind == IN ); - } else - return false; - } - -// int numberFromStep( String step ) { -// int top = step.indexOf('>'); -// return Integer.parseInt( step.substring( 1, top ) ); -// } -// - Object msgStack[] = new Object[ 512 ]; - int msgStackMaxSize = 512; - int msgStackCurrentSize = 0; - - private final void pushMsg( String s, Token t ) { - if ( msgStackCurrentSize == msgStackMaxSize) { - Object neo[] = new Object[ 2 * msgStackMaxSize ]; - System.arraycopy(msgStack, 0, neo, 0, msgStackMaxSize); - msgStack = neo; - msgStackMaxSize *= 2; - } - msgStack [ msgStackCurrentSize ] = s; - msgStack [ msgStackCurrentSize+1 ] = t; - msgStackCurrentSize +=2; - } - - private final void popMsg() { - msgStackCurrentSize -=2; - } - - private String expecting = "nothing"; - /*********************************************************************** - * It appears that the value of expecting is what is printed out in * - * error messages as what the parser was expecting when it encountered * - * an error. * - ***********************************************************************/ - - private final String msgStackToString(ParseException e) { - StringBuffer msg; - String name = " *unknown* (error occurred before module header)"; - if (mn != null) name = mn.toString(); - - msg = new StringBuffer("***Parse Error***\n"); - if ( expecting != emptyString ) { - msg.append("Was expecting \""); - msg.append( expecting ); - msg.append("\"\n"); - } - - msg.append(e.getShortMessage()); -// msg.append(" while parsing "); -// msg.append(name); -// -// msg.append(".\nResidual stack trace follows:\n"); - - msg.append("\n\nResidual stack trace follows:\n"); - int last = msgStackCurrentSize - 10; - if (last < 0 ) last = 0; - for ( int lvi = msgStackCurrentSize; lvi > last; lvi -=2 ) { - msg.append( (String) msgStack[lvi -2 ] ); - msg.append(" starting at line "); - Token t = (Token) msgStack[lvi - 1 ]; - msg.append( t.beginLine ); - msg.append(", column "); - msg.append( t.beginColumn ); - msg.append(".\n"); - } - return msg.toString(); - } - -// - - /************************************************************************* - * heirsTable is an array of physical length heirsSize that implements a * - * dynamic array of length heirsIndex, where heirsIndex <= heirsSize. * - * Elements are added to heirsTable by the addHeir method, which * - * increments heirsSize if needed. Elements are removed from the array * - * by the getLastHeirs() and popHeir() methods. * - * * - * It appears that the heirsTable is used as a stack of sequences of * - * syntax tree nodes, each being the sequence of heirs (children) of a * - * node that is currently being parsed. The top of the stack is the * - * sequence at the end of the heirsTable array. Each sequence is begun * - * by a null entry. The bpa() method is called when about to push such * - * a sequence onto the stack; it adds the null element that marks the * - * beginning of the sequence. Similarly, the epa() method is called * - * after popping a sequence off the top of the stack; it removes the * - * null element. * - *************************************************************************/ - private SyntaxTreeNode heirsTable[] = new SyntaxTreeNode[ 512 ]; - private int heirsSize = 512; - private int heirsIndex = 0; - - private final void addHeir( SyntaxTreeNode sn ) { - /*********************************************************************** - * Appends the syntax tree sn to the end of the dynamic array * - * implemented by heirsTable. * - ***********************************************************************/ - if ( heirsIndex == heirsSize ) { - SyntaxTreeNode nh[] = new SyntaxTreeNode[ heirsSize + 512 ]; - System.arraycopy( heirsTable, 0, nh, 0, heirsSize ); - heirsSize += 512; - heirsTable = nh; - } - heirsTable[ heirsIndex ] = sn; heirsIndex++; - } - - private final SyntaxTreeNode[] getLastHeirs() { - /*********************************************************************** - * This method will throw an array-out-of-bounds exception if called * - * when heirsIndex = 0 (so the dynamic array implemented by heirsTable * - * is empty) or if that dynamic array contains no null entry. * - * * - * If the last element of the dynamic heirsTable array is null, then * - * it returns null. Otherwise, it returns an array equal to the * - * sequence of non-null elements at the end of the dynamic heirsTable * - * array and removes them from that array. * - ***********************************************************************/ - int lvi = heirsIndex - 1; - while (heirsTable[ lvi ] != null ) lvi--; - /*********************************************************************** - * Assert: /\ lvi < heirsIndex * - * /\ heirsTable[lvi] = null * - * /\ \A i \in lvi+1 .. heirsIndex-1 : heirsTable[i] # null * - ***********************************************************************/ - int as = heirsIndex - lvi - 1; - if (as == 0) - return null; - else { - SyntaxTreeNode ts[] = new SyntaxTreeNode[ as ]; - System.arraycopy( heirsTable, lvi + 1, ts, 0, as); - heirsIndex = lvi + 1; - /********************************************************************* - * Assert /\ as > 0 * - * /\ \A i \in 0..as-1 : ts[i] = heirsTable[lvi + i + 1] * - * /\ heirsIndex = lvi + 1 * - *********************************************************************/ - return ts; - } - } - - private final boolean popHeir() { - /************************************************************************ - * Throws an array-out-of-bounds exception if heirsIndex = 0 (meaning * - * that the dynamic array implemented by heirsTable is empty). * - * * - * It removes the last element from the heirsTable array and returns * - * true iff the new last element is null. * - ************************************************************************/ - return heirsTable[ --heirsIndex ] == null; - } - - private String emptyString = ""; - - private final void bpa( String s) { // Beginning of Production Actions - addHeir( null ); -if (System.getProperty("TLA-StackTrace", "off").equals("on")) ToolIO.out.println("Beginning " + s); - pushMsg( s, getToken(1) ); - expecting = emptyString; - } - - private final void epa() { - popMsg(); -if (System.getProperty("TLA-StackTrace", "off").equals("on")) ToolIO.out.println("Ending " + msgStack [ msgStackCurrentSize ]); - Assert.assertion( popHeir() ); - expecting = emptyString; - } -// - - Stack internals = new Stack(); - - private final void addDependency( UniqueString s ) { - int lvi = internals.search( s ); - if ( lvi < 0 ) - dependencyList.addElement( s ); - } - - private final UniqueString reduceString( String s ) { - int l = s.length(); - StringBuffer copy = new StringBuffer( l ); - int i = 0; - int j = 0; - while ( i!= l ) { - if (s.charAt(i) == '\\' ) { - i++; char c = s.charAt(i); - if (c == '\\') copy.append( '\\'); - else if (c == 'n') copy.append( '\n'); - else if (c == 'r') copy.append( '\r'); - else if (c == 'f') copy.append( '\f'); - else if (c == 't') copy.append( '\t'); - else if (c == '"') copy.append( '"'); - } else - copy.append( s.charAt(i)); - i++; j++; - } - copy.setLength(j); - return UniqueString.uniqueStringOf(copy.toString()); - } - -/*************************************************************************** -* Fields and methods for parsing proofs. * -***************************************************************************/ -private int proofDepth = -1 ; - /************************************************************************* - * The nesting level of the proof we're currently processing, counting * - * from 0 a la Java. * - *************************************************************************/ - -private final int MaxProofDepth = 100 ; -private int[] proofLevelStack = new int[MaxProofDepth] ; - /************************************************************************* - * The level number of a proof with steps numbered <n>x is n. The value * - * of proofLevelStack[proofDepth] is the level number of the current * - * proof. If we have started processing a proof haven't yet determined * - * its level, then proofLevelStack[proofDepth] equals -1. * - *************************************************************************/ - -private int levelOfProofStepLexeme(Token tok){ - /************************************************************************* - * The level of a ProofStepLexeme or ProofStepDotLexeme. It returns -1 * - * for "*" and -2 for "*". * - *************************************************************************/ - String im = tok.image ; - if (im.substring(1,2).equals("*")) {return -1;} ; - if (im.substring(1,2).equals("+")) {return -2;} ; - return new Integer(im.substring(1, im.indexOf('>'))).intValue() ; - /*********************************************************************** - * The ".intValue()" added by SZ because Java 1.4 doesn't support * - * auto-boxing. * - ***********************************************************************/ - } - -/*************************************************************************** -* The following method returns the canonical form of the step number * -* contained in token t. This means that a "+" or "*" is replaced by the * -* appropriate level number, and leading zeros are removed from a regular * -* level number. * -***************************************************************************/ -private UniqueString correctedStepNum(Token t) { - String str = t.image ; - if ( str.substring(1,2).equals("*") - || str.substring(1,2).equals("+") ) { - int level = getProofLevel() ; - if ((level < 0) && (proofDepth > 0)) { - /********************************************************************* - * We've started a proof without yet determining the level number. * - * Since this method is being called when encountering a step number * - * token, this means we've encountered a step number inside a BY. So * - * the actual level number to use here is the "previous" level * - * number. * - *********************************************************************/ - level = proofLevelStack[proofDepth-1] ; - } - str = "<" + level + str.substring(2) ; - } - else {str = "<" + levelOfProofStepLexeme(t) + str.substring(str.indexOf('>')); - } ; - return UniqueString.uniqueStringOf(str) ; - } ; - -private void pushProofLevel() throws ParseException { - /************************************************************************* - * Called to begin the processing of a new proof level. It increments * - * proofDepth and sets the proofLevelStack entry to -1. * - *************************************************************************/ - proofDepth++ ; - if (proofDepth >= MaxProofDepth) { - throw new ParseException("Proofs nested more than " + - MaxProofDepth + "deep.") ; - } ; - proofLevelStack[proofDepth] = -1 ; - } - -private void popProofLevel() throws ParseException { - if (proofDepth < 0) { - throw new ParseException("Parser bug: an extra QED step found." ) ; - } ; - proofDepth-- ; - } - -private void setProofLevel(int val) throws ParseException { - if (proofDepth < 0) { - throw new ParseException("Parser bug: proof step found outside proof." ) ; - } ; - proofLevelStack[proofDepth] = val; - } - -private int getProofLevel() { - if (proofDepth < 0) { return proofDepth; } ; - return proofLevelStack[proofDepth]; } - -private boolean beginsProof(Token tok) { - /************************************************************************* - * True iff the token tok begins a new proof--that is, iff it is either * - * "BY", "PROOF", a step number that has a higher level than the current * - * level, begins "<+>", or begins "<*>" and we are not inside a proof. * - *************************************************************************/ - String im = tok.image ; - if (im.length() < 2) {return false;} - /*********************************************************************** - * This can happen if the user makes a weird error. * - ***********************************************************************/ - if (im.substring(1,2).equals("*")) {return (proofDepth < 0);} ; - - if (im.substring(1,2).equals("+")) {return true ;} ; - switch (tok.kind) { - case ProofStepLexeme : - case BareLevelLexeme : - case UnnumberedStepLexeme : - case ProofStepDotLexeme : - if (proofDepth < 0) {return true ;} ; - int tokLevel = levelOfProofStepLexeme(tok) ; - return (proofLevelStack[proofDepth] >= 0) - && (tokLevel > proofLevelStack[proofDepth]) ; - case BY : - case PROOF : - case OBVIOUS : - case OMITTED : - return true ; - }; // switch - return false ; - } - -private boolean correctLevel(Token tok) { - /************************************************************************* - * True iff tok is a correct proof step token for the current level of * - * proof, where precedeByPROOF is true iff the proof is preceded by a * - * "PROOF" token (needed in case this is the first step of the proof). * - * If this is the first step being processed for current proof, then it * - * sets the current proof level. * - *************************************************************************/ - int tokLevel = levelOfProofStepLexeme(tok) ; - - /************************************************************************* - * Set lastDepth to the level of the containing proof, or -1 if this is * - * the top-level proof. * - *************************************************************************/ - int lastLevel = -1 ; - if (proofDepth > 0) {lastLevel = proofLevelStack[proofDepth-1] ;} - switch (tokLevel) { - case -1 : - /********************************************************************* - * tok is <*>... This is always legal because it can begin a proof * - * iff it was preceded by a "PROOF". * - *********************************************************************/ - if (proofLevelStack[proofDepth] < 0) { - proofLevelStack[proofDepth] = lastLevel + 1 ; - } ; - return true ; - - case -2 : - /********************************************************************* - * tok is <+>... This is legal iff it begins a proof. * - *********************************************************************/ - if (proofLevelStack[proofDepth] < 0) { - proofLevelStack[proofDepth] = lastLevel + 1 ; - return true ; - } - else return false ; - - default : - if (proofLevelStack[proofDepth] < 0) { - proofLevelStack[proofDepth] = tokLevel; - return (tokLevel > lastLevel) ; - } - else return (proofLevelStack[proofDepth] == tokLevel) ; - } - } - -/* beginning of the grammar productions */ - final public Token PrefixOpToken() throws ParseException { - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_26: - t = jj_consume_token(op_26); - break; - case op_29: - t = jj_consume_token(op_29); - break; - case op_58: - t = jj_consume_token(op_58); - break; - case CASESEP: - t = jj_consume_token(CASESEP); - break; - case op_61: - t = jj_consume_token(op_61); - break; - case op_112: - t = jj_consume_token(op_112); - break; - case op_113: - t = jj_consume_token(op_113); - break; - case op_114: - t = jj_consume_token(op_114); - break; - case op_115: - t = jj_consume_token(op_115); - break; - case op_116: - t = jj_consume_token(op_116); - break; - default: - jj_la1[0] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t;} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* NEPrefixOpToken and PrefixOpToken differ because the first includes * -* "-." while the second contains does not. Neither includes "-". * -***************************************************************************/ - final public Token NEPrefixOpToken() throws ParseException { - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_26: - t = jj_consume_token(op_26); - break; - case op_29: - t = jj_consume_token(op_29); - break; - case op_58: - t = jj_consume_token(op_58); - break; - case CASESEP: - t = jj_consume_token(CASESEP); - break; - case op_61: - t = jj_consume_token(op_61); - break; - case op_76: - t = jj_consume_token(op_76); - break; - case op_112: - t = jj_consume_token(op_112); - break; - case op_113: - t = jj_consume_token(op_113); - break; - case op_114: - t = jj_consume_token(op_114); - break; - case op_115: - t = jj_consume_token(op_115); - break; - case op_116: - t = jj_consume_token(op_116); - break; - default: - jj_la1[1] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t;} - throw new Error("Missing return statement in function"); - } - - final public Token InfixOpToken() throws ParseException { - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_1: - t = jj_consume_token(op_1); - break; - case AND: - t = jj_consume_token(AND); - break; - case op_3: - t = jj_consume_token(op_3); - break; - case op_4: - t = jj_consume_token(op_4); - break; - case OR: - t = jj_consume_token(OR); - break; - case op_6: - t = jj_consume_token(op_6); - break; - case op_7: - t = jj_consume_token(op_7); - break; - case op_8: - t = jj_consume_token(op_8); - break; - case op_9: - t = jj_consume_token(op_9); - break; - case op_10: - t = jj_consume_token(op_10); - break; - case op_11: - t = jj_consume_token(op_11); - break; - case op_12: - t = jj_consume_token(op_12); - break; - case op_13: - t = jj_consume_token(op_13); - break; - case op_14: - t = jj_consume_token(op_14); - break; - case op_15: - t = jj_consume_token(op_15); - break; - case op_16: - t = jj_consume_token(op_16); - break; - case op_17: - t = jj_consume_token(op_17); - break; - case op_18: - t = jj_consume_token(op_18); - break; - case op_19: - t = jj_consume_token(op_19); - break; - case IN: - t = jj_consume_token(IN); - break; - case op_21: - t = jj_consume_token(op_21); - break; - case op_22: - t = jj_consume_token(op_22); - break; - case op_23: - t = jj_consume_token(op_23); - break; - case op_24: - t = jj_consume_token(op_24); - break; - case op_25: - t = jj_consume_token(op_25); - break; - case op_27: - t = jj_consume_token(op_27); - break; - case op_30: - t = jj_consume_token(op_30); - break; - case op_31: - t = jj_consume_token(op_31); - break; - case op_32: - t = jj_consume_token(op_32); - break; - case op_33: - t = jj_consume_token(op_33); - break; - case op_34: - t = jj_consume_token(op_34); - break; - case op_35: - t = jj_consume_token(op_35); - break; - case op_36: - t = jj_consume_token(op_36); - break; - case op_37: - t = jj_consume_token(op_37); - break; - case op_38: - t = jj_consume_token(op_38); - break; - case op_39: - t = jj_consume_token(op_39); - break; - case op_40: - t = jj_consume_token(op_40); - break; - case op_41: - t = jj_consume_token(op_41); - break; - case op_42: - t = jj_consume_token(op_42); - break; - case op_43: - t = jj_consume_token(op_43); - break; - case op_44: - t = jj_consume_token(op_44); - break; - case op_45: - t = jj_consume_token(op_45); - break; - case op_46: - t = jj_consume_token(op_46); - break; - case op_47: - t = jj_consume_token(op_47); - break; - case op_48: - t = jj_consume_token(op_48); - break; - case op_49: - t = jj_consume_token(op_49); - break; - case op_50: - t = jj_consume_token(op_50); - break; - case op_51: - t = jj_consume_token(op_51); - break; - case op_52: - t = jj_consume_token(op_52); - break; - case op_53: - t = jj_consume_token(op_53); - break; - case op_54: - t = jj_consume_token(op_54); - break; - case op_55: - t = jj_consume_token(op_55); - break; - case op_56: - t = jj_consume_token(op_56); - break; - case op_59: - t = jj_consume_token(op_59); - break; - case op_62: - t = jj_consume_token(op_62); - break; - case op_63: - t = jj_consume_token(op_63); - break; - case op_64: - t = jj_consume_token(op_64); - break; - case EQUALS: - t = jj_consume_token(EQUALS); - break; - case op_66: - t = jj_consume_token(op_66); - break; - case op_67: - t = jj_consume_token(op_67); - break; - case op_71: - t = jj_consume_token(op_71); - break; - case op_72: - t = jj_consume_token(op_72); - break; - case op_73: - t = jj_consume_token(op_73); - break; - case op_74: - t = jj_consume_token(op_74); - break; - case op_75: - t = jj_consume_token(op_75); - break; - case op_77: - t = jj_consume_token(op_77); - break; - case op_78: - t = jj_consume_token(op_78); - break; - case op_79: - t = jj_consume_token(op_79); - break; - case op_80: - t = jj_consume_token(op_80); - break; - case op_81: - t = jj_consume_token(op_81); - break; - case op_82: - t = jj_consume_token(op_82); - break; - case op_83: - t = jj_consume_token(op_83); - break; - case op_84: - t = jj_consume_token(op_84); - break; - case op_85: - t = jj_consume_token(op_85); - break; - case op_86: - t = jj_consume_token(op_86); - break; - case op_87: - t = jj_consume_token(op_87); - break; - case op_88: - t = jj_consume_token(op_88); - break; - case op_89: - t = jj_consume_token(op_89); - break; - case op_90: - t = jj_consume_token(op_90); - break; - case op_91: - t = jj_consume_token(op_91); - break; - case op_92: - t = jj_consume_token(op_92); - break; - case op_93: - t = jj_consume_token(op_93); - break; - case op_94: - t = jj_consume_token(op_94); - break; - case op_95: - t = jj_consume_token(op_95); - break; - case op_96: - t = jj_consume_token(op_96); - break; - case op_97: - t = jj_consume_token(op_97); - break; - case op_98: - t = jj_consume_token(op_98); - break; - case op_100: - t = jj_consume_token(op_100); - break; - case op_101: - t = jj_consume_token(op_101); - break; - case op_102: - t = jj_consume_token(op_102); - break; - case op_103: - t = jj_consume_token(op_103); - break; - case op_104: - t = jj_consume_token(op_104); - break; - case op_105: - t = jj_consume_token(op_105); - break; - case op_106: - t = jj_consume_token(op_106); - break; - case op_107: - t = jj_consume_token(op_107); - break; - case op_108: - t = jj_consume_token(op_108); - break; - case op_109: - t = jj_consume_token(op_109); - break; - case op_110: - t = jj_consume_token(op_110); - break; - case op_111: - t = jj_consume_token(op_111); - break; - case op_117: - t = jj_consume_token(op_117); - break; - case op_118: - t = jj_consume_token(op_118); - break; - case op_119: - t = jj_consume_token(op_119); - break; - default: - jj_la1[2] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t;} - throw new Error("Missing return statement in function"); - } - - final public Token PostfixOpToken() throws ParseException { -Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_57: - t = jj_consume_token(op_57); - break; - case op_68: - t = jj_consume_token(op_68); - break; - case op_69: - t = jj_consume_token(op_69); - break; - case op_70: - t = jj_consume_token(op_70); - break; - default: - jj_la1[3] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode CompilationUnit() throws ParseException { - SyntaxTreeNode tempASTN; - belchDEF(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case BEGIN_PRAGMA: - Prelude(); - break; - default: - jj_la1[4] = jj_gen; - ; - } - tempASTN = Module(); - token_source.SwitchTo(0); - {if (true) return tempASTN;} - throw new Error("Missing return statement in function"); - } - -/* SwitchTo is used to reset the state of the tokenizer */ - final public void Prelude() throws ParseException { - jj_consume_token(BEGIN_PRAGMA); - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NUMBER: - case IDENTIFIER: - ; - break; - default: - jj_la1[5] = jj_gen; - break label_1; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NUMBER: - jj_consume_token(NUMBER); - break; - case IDENTIFIER: - jj_consume_token(IDENTIFIER); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - - final public SyntaxTreeNode Module() throws ParseException { - Token t; - SyntaxTreeNode lSTN[] = new SyntaxTreeNode[ 4 ]; - bpa( "Module definition" ); - internals.push( null ); - Object pop = null; - expecting = "---- MODULE"; - lSTN[0] = BeginModule(); - expecting = "EXTENDS clause or module body"; - lSTN[1] = Extends(); - expecting = "Module body"; - lSTN[2] = Body(); - expecting = "==== or more Module body"; - lSTN[3] = EndModule(); - do { pop = internals.pop(); } while (pop != null ); - internals.push( lSTN[0].zero[1].image ); - epa(); {if (true) return new SyntaxTreeNode( mn, N_Module, lSTN );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode BeginModule() throws ParseException { - SyntaxTreeNode lSTN[] = new SyntaxTreeNode[3]; - Token t; - bpa( "Begin module" ); - expecting = "---- MODULE (beginning of module)"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case _BM0: - t = jj_consume_token(_BM0); - break; - case _BM1: - t = jj_consume_token(_BM1); - break; - case _BM2: - t = jj_consume_token(_BM2); - break; - default: - jj_la1[7] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - lSTN[0] = new SyntaxTreeNode(mn, t); - expecting = "Identifier"; - t = getToken(1); - if (isFieldNameToken( t )) t.kind = IDENTIFIER; - lSTN[1] = Identifier(); - if ( mn == null ) mn = lSTN[1].image; - expecting = "----"; - t = jj_consume_token(SEPARATOR); - lSTN[2] = new SyntaxTreeNode(mn, t ); - epa(); {if (true) return new SyntaxTreeNode( mn, N_BeginModule, lSTN );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode EndModule() throws ParseException { - SyntaxTreeNode lSTN[] = new SyntaxTreeNode[1]; - Token t; - t = jj_consume_token(END_MODULE); - lSTN[0] = new SyntaxTreeNode(mn, t); - {if (true) return new SyntaxTreeNode(mn, N_EndModule, lSTN );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Extends() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa( "Extends" ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EXTENDS: - t = jj_consume_token(EXTENDS); - addHeir( new SyntaxTreeNode(mn, t)); - expecting = "Identifier"; - t = getToken(1); - if (isFieldNameToken( t )) t.kind = IDENTIFIER; - tn = Identifier(); - addDependency( tn.image ); addHeir( tn ); - expecting = "comma or module body"; - label_2: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[8] = jj_gen; - break label_2; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "Identifier"; - t = getToken(1); - if (isFieldNameToken( t )) t.kind = IDENTIFIER; - tn = Identifier(); - addDependency( tn.image ); addHeir( tn ); - } - break; - default: - jj_la1[9] = jj_gen; - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_Extends, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Body() throws ParseException { - SyntaxTreeNode tn, sn[]; - Token t; - bpa("Module body"); - expecting = "LOCAL, INSTANCE, PROOF, ASSUMPTION, THEOREM, " + - "RECURSIVE, declaration, or definition"; - label_3: - while (true) { - if (jj_2_1(1)) { - ; - } else { - break label_3; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case SEPARATOR: - t = jj_consume_token(SEPARATOR); - tn = new SyntaxTreeNode(mn, t); - break; - case VARIABLE: - tn = VariableDeclaration(); - break; - case CONSTANT: - tn = ParamDeclaration(); - break; - default: - jj_la1[10] = jj_gen; - if (jj_2_2(2)) { - tn = OperatorOrFunctionDefinition(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case RECURSIVE: - tn = Recursive(); - break; - default: - jj_la1[11] = jj_gen; - if (jj_2_3(2)) { - tn = Instance(); - } else if (jj_2_4(2)) { - tn = Assumption(); - } else if (jj_2_5(2)) { - tn = Theorem(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case _BM1: - case _BM2: - case _BM0: - tn = Module(); - belchDEF(); - break; - default: - jj_la1[12] = jj_gen; - if ((getToken(1).kind == USE && getToken(2).kind != ONLY) - || (getToken(1).kind == HIDE)) { - tn = UseOrHideOrBy(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - } - } - } - addHeir(tn); - } - sn = getLastHeirs(); epa(); - {if (true) return new SyntaxTreeNode(mn, N_Body, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode VariableDeclaration() throws ParseException { - SyntaxTreeNode tn, sn[]; - Token t; - SyntaxTreeNode lSTN[] = new SyntaxTreeNode[1]; - bpa( "variable declaration" ); - t = jj_consume_token(VARIABLE); - lSTN[0] = new SyntaxTreeNode( mn, t); - expecting = "Identifier"; - tn = Identifier(); - addHeir( tn ); - expecting = "comma or module body"; - label_4: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[13] = jj_gen; - break label_4; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode( mn, t) ) ; - expecting = "Identifier"; - tn = Identifier(); - addHeir( tn ); - } - sn = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_VariableDeclaration, lSTN, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ParamDeclaration() throws ParseException { - SyntaxTreeNode tn, sn[]; - Token t; - bpa("Parameter declaration"); - expecting = "CONSTANT"; - tn = ParamSubDecl(); - addHeir(tn); - expecting = "Identifier, operator or _"; - tn = ConstantDeclarationItems(); - addHeir(tn); - expecting = ","; - label_5: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[14] = jj_gen; - break label_5; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ) ; - expecting = "Identifier, operator or _"; - tn = ConstantDeclarationItems(); - addHeir(tn); - } - sn = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_ParamDeclaration, sn );} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Used to allow "STATE FUNCTION", "TEMPORAL", etc. * -***************************************************************************/ - final public SyntaxTreeNode ParamSubDecl() throws ParseException { - SyntaxTreeNode tn, sn[]; - Token t, u; - bpa("Parameter declaration item"); - t = jj_consume_token(CONSTANT); - sn = new SyntaxTreeNode[1]; sn[0] = new SyntaxTreeNode(mn, t); - tn = new SyntaxTreeNode(mn, N_ConsDecl, sn ); - epa(); - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Recursive ::= <CONSTANT> ConstantDeclarationItems * -* ( <COMMA> ConstantDeclarationItems )* * -* * -* Produces an N_Recursive node. * -***************************************************************************/ - final public SyntaxTreeNode Recursive() throws ParseException { - SyntaxTreeNode tn, sn[]; - Token t; - bpa("Recursive"); - expecting = "RECURSIVE"; - t = jj_consume_token(RECURSIVE); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "Identifier, operator or _"; - tn = ConstantDeclarationItems(); - addHeir(tn); - expecting = ","; - label_6: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[15] = jj_gen; - break label_6; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ) ; - expecting = "Identifier, operator or _"; - tn = ConstantDeclarationItems(); - addHeir(tn); - expecting = "`,' or `)'"; - } - sn = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_Recursive, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ConstantDeclarationItems() throws ParseException { - SyntaxTreeNode tn, sn[]; - int kind; - Token t; - bpa( "Constant declaration items"); - expecting = "Identifier, _ or prefix op"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - addHeir( tn ); kind = N_IdentDecl; -expecting = "(, comma, or Module Body"; - if (jj_2_6(2)) { - /******************************************************************* - * The following comment apparently made sense at the time. I * - * wonder what it should have said. * - * * - * This lookahead was added by J-Ch & LL on 1 Mar 2007 to fix the * - * error when it tried to parse * - * * - * CONSTANT ASSUME A * - * (B+C) * - * PROVE ... * - *******************************************************************/ - t = jj_consume_token(LBR); - addHeir( new SyntaxTreeNode( mn, t) ) ; -expecting = "_"; - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode( mn, t) ) ; -expecting = "comma or )"; - label_7: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[16] = jj_gen; - break label_7; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode( mn, t) ) ; -expecting = "_"; - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode( mn, t) ) ; -expecting = "comma or )"; - } - t = jj_consume_token(RBR); - addHeir( new SyntaxTreeNode( mn, t) ) ; - } else { - ; - } - break; - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - // LOOKAHEAD( <OpSymbol>, { isPrefixDeclOp( getToken(1) ) } ) - tn = NonExpPrefixOp(); -expecting = "_"; - kind = N_PrefixDecl; addHeir( tn ); - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode( mn, t) ) ; - break; - case US: - t = jj_consume_token(US); -expecting = "prefix or postfix operator"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); -expecting = "_"; - kind = N_InfixDecl; - addHeir( new SyntaxTreeNode( mn, t) ); - addHeir(tn); - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode( mn, t) ) ; - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - kind = N_PostfixDecl; - addHeir( new SyntaxTreeNode( mn, t) ); - addHeir(tn); - break; - default: - jj_la1[17] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[18] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - sn = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode( mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* The following production OperatorOrFunctionDefinition() produces an * -* N_OperatorDefinition, N_FunctionDefinition, or N_ModuleDefinition * -* node. These nodes have syntax "[LOCAL] ...". The resulting node n * -* has n.zero equal to null if the "LOCAL" is missing and equal to an * -* array of length 1 containing the LOCAL token if it is present. The * -* rest of the children/heirs of the node are in the array n.one. * -***************************************************************************/ - final public SyntaxTreeNode OperatorOrFunctionDefinition() throws ParseException { - SyntaxTreeNode tn; - SyntaxTreeNode zn = null; - bpa("Definition"); - int kind = 0; - String n; - Token t; - expecting = "LOCAL, Identifier or Operator Symbol"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LOCAL: - t = jj_consume_token(LOCAL); - zn = new SyntaxTreeNode( mn, t); - break; - default: - jj_la1[19] = jj_gen; - ; - } - t = jj_consume_token(DEFBREAK); - expecting = "LOCAL, Identifier or Operator Symbol"; - if (jj_2_8(2147483647)) { - /* recognize function */ - tn = Identifier(); - addHeir( tn ); kind = N_FunctionDefinition; -expecting = "["; - t = jj_consume_token(LSB); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier"; - tn = QuantBound(); - addHeir( tn ); -expecting = "COMMA or ]"; - label_8: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[20] = jj_gen; - break label_8; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier"; - tn = QuantBound(); - addHeir( tn ); - } - t = jj_consume_token(RSB); -expecting = "=="; - addHeir( new SyntaxTreeNode(mn, t) ); - t = jj_consume_token(DEF); - belchDEF(); addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression"; - tn = Expression(); - addHeir( tn ); - } else if (jj_2_9(2147483647)) { - tn = PostfixLHS(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - belchDEF(); kind = N_OperatorDefinition; - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression"; - tn = Expression(); - addHeir( tn ); - } else if (jj_2_10(2147483647)) { - tn = InfixLHS(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - belchDEF(); kind = N_OperatorDefinition; - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression"; - tn = Expression(); - addHeir( tn ); - } else if (jj_2_11(2147483647)) { - /* recognize operator OR module instance */ - tn = IdentLHS(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - belchDEF(); addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression or Instance"; - if (jj_2_7(1)) { - tn = Expression(); - kind = N_OperatorDefinition; - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case INSTANCE: - tn = Instantiation(); - kind = N_ModuleDefinition; - break; - default: - jj_la1[21] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - addHeir( tn ); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = PrefixLHS(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - belchDEF(); - kind = N_OperatorDefinition; - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression"; - tn = Expression(); - addHeir( tn ); - break; - default: - jj_la1[22] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn,kind, zn, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IdentifierTuple() throws ParseException { - SyntaxTreeNode tn; - SyntaxTreeNode hn[]; - Token t; - bpa("Identifier tuple"); - t = jj_consume_token(LAB); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier or >>"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - addHeir( tn ); -expecting = "COMMA or >>"; - label_9: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[23] = jj_gen; - break label_9; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "COMMA or >>"; - tn = Identifier(); - addHeir( tn ); -expecting = "COMMA or >>"; - } - break; - default: - jj_la1[24] = jj_gen; - ; - } - t = jj_consume_token(RAB); - addHeir( new SyntaxTreeNode(mn, t) ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_IdentifierTuple, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IdentLHS() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Identifier LHS"); - tn = Identifier(); - addHeir( tn ); -expecting = "( or =="; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - t = jj_consume_token(LBR); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier Declaration, prefix op, _ or )"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = IdentDecl(); - break; - case US: - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = SomeFixDecl(); - break; - default: - jj_la1[25] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( tn ); -expecting = "COMMA or )"; - label_10: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[26] = jj_gen; - break label_10; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier Declaration, prefix op or _"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = IdentDecl(); - break; - case US: - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = SomeFixDecl(); - break; - default: - jj_la1[27] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( tn ); -expecting = "COMMA or )"; - } - t = jj_consume_token(RBR); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - default: - jj_la1[28] = jj_gen; - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_IdentLHS, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode PrefixLHS() throws ParseException { - SyntaxTreeNode sn[] = new SyntaxTreeNode[2]; - SyntaxTreeNode tn; - Token t; - bpa("Prefix LHS"); - t = NEPrefixOpToken(); - sn[0] = new SyntaxTreeNode(mn, t); -expecting = "Identifier"; - tn = Identifier(); - sn[1] = tn; - epa(); {if (true) return new SyntaxTreeNode( mn, N_PrefixLHS, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode InfixLHS() throws ParseException { - SyntaxTreeNode sn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode tn; - Token t; - bpa("Infix LHS"); - tn = Identifier(); - sn[0] = tn; - t = InfixOpToken(); - sn[1] = new SyntaxTreeNode(mn, t); - tn = Identifier(); - sn[2] = tn; - epa(); {if (true) return new SyntaxTreeNode( mn, N_InfixLHS, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode PostfixLHS() throws ParseException { - SyntaxTreeNode sn[] = new SyntaxTreeNode[2]; - SyntaxTreeNode tn; - Token t; - bpa("Postfix LHS"); - tn = Identifier(); - sn[0] = tn; - t = PostfixOpToken(); - sn[1] = new SyntaxTreeNode(mn, t); - epa(); {if (true) return new SyntaxTreeNode( mn, N_PostfixLHS, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IdentDecl() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Identifier Declation"); - tn = Identifier(); - addHeir( tn ); -expecting = "( or ..."; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - t = jj_consume_token(LBR); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "_"; - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "COMMA or )"; - label_11: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[29] = jj_gen; - break label_11; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "_"; - t = jj_consume_token(US); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "COMMA or )"; - } - t = jj_consume_token(RBR); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - default: - jj_la1[30] = jj_gen; - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_IdentDecl, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode SomeFixDecl() throws ParseException { - SyntaxTreeNode localASTN = null; - SyntaxTreeNode tn; - SyntaxTreeNode sn[] = null; - int kind; - Token t; - UniqueString n; - bpa("Op. Symbol Declaration"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - // LOOKAHEAD( <OpSymbol>, { isPrefixDeclOp( getToken(1) ) } ) - tn = NonExpPrefixOp(); - kind = N_PrefixDecl; n = lastOp.getIdentifier(); - sn = new SyntaxTreeNode[2]; sn[0] = tn; -expecting = "_"; - t = jj_consume_token(US); - sn[1] = new SyntaxTreeNode(mn, t); - break; - case US: - t = jj_consume_token(US); -expecting = "infix or postfix operator"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - kind = N_InfixDecl; n = lastOp.getIdentifier(); - sn = new SyntaxTreeNode[3]; sn[1] = tn; - sn[0] = new SyntaxTreeNode(mn, t); -expecting = "_"; - t = jj_consume_token(US); - sn[2] = new SyntaxTreeNode(mn, t); - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - kind = N_PostfixDecl; n = lastOp.getIdentifier(); - sn = new SyntaxTreeNode[2]; sn[1] = tn; - sn[0] = new SyntaxTreeNode(mn, t); - break; - default: - jj_la1[31] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[32] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - epa(); {if (true) return new SyntaxTreeNode(mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Instance() throws ParseException { - SyntaxTreeNode tn; - SyntaxTreeNode zn = null; - Token t; - bpa("Instance"); -expecting = "LOCAL or instance"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LOCAL: - t = jj_consume_token(LOCAL); - zn = new SyntaxTreeNode(mn, t); - break; - default: - jj_la1[33] = jj_gen; - ; - } - tn = Instantiation(); - addHeir( tn ); -expecting = "COMMA or Module Body"; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_Instance, zn, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Instantiation() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("NonLocalInstance"); - t = jj_consume_token(INSTANCE); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Module identifier"; - t = getToken(1); - if (isFieldNameToken( t )) t.kind = IDENTIFIER; - tn = Identifier(); - addDependency( tn.image ); addHeir( tn ); -expecting = "WITH or another definition."; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case WITH: - t = jj_consume_token(WITH); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = emptyString; - tn = Substitution(); - addHeir( tn ); -expecting = emptyString; - label_12: - while (true) { - if (jj_2_12(3)) { - ; - } else { - break label_12; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = emptyString; - tn = Substitution(); - addHeir( tn ); -expecting = emptyString; - } - break; - default: - jj_la1[34] = jj_gen; - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_NonLocalInstance, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Substitution() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode tn = null; - Token t; - anchor = null; - /*********************************************************************** - * See the comments for the declaration of anchor to see what this is * - * being used for. * - ***********************************************************************/ - String n; - bpa("Substitution"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - zn[0] = tn; - break; - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = NonExpPrefixOp(); - zn[0] = tn; - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - zn[0] = tn; - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - zn[0] = tn; - break; - default: - jj_la1[35] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - expecting = "<-"; - t = jj_consume_token(SUBSTITUTE); - n = tn.getImage(); - zn[1] = new SyntaxTreeNode(mn, t); -expecting = "Expression or Op. Symbol"; - tn = OpOrExpr(); - epa(); zn[2] = tn; {if (true) return new SyntaxTreeNode(mn, N_Substitution, zn );} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Substitution ::= * -* ( Identifier | NonExpPrefixOp | InfixOp | PostfixOp) * -* <SUBSTITUTE> ( <op_76> | Lambda | Expression ) * -* * -* Note: <op_76> is "-.", the prefix - operator. * -* <SUBSTITUTE> is "<-" * -* * -* Modified 27 March 2007 by LL to allow Lambda substitutions. * -***************************************************************************/ - final public SyntaxTreeNode OldSubstitution() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode tn = null; - Token t; - anchor = null; - /*********************************************************************** - * See the comments for the declaration of anchor to see what this is * - * being used for. * - ***********************************************************************/ - String n; - bpa("Substitution"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - zn[0] = tn; - break; - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = NonExpPrefixOp(); - zn[0] = tn; - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - zn[0] = tn; - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - zn[0] = tn; - break; - default: - jj_la1[36] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - expecting = "<-"; - t = jj_consume_token(SUBSTITUTE); - n = tn.getImage(); - zn[1] = new SyntaxTreeNode(mn, t); -expecting = "Expression or Op. Symbol"; - try { - if (jj_2_13(2147483647)) { - t = jj_consume_token(op_76); - SyntaxTreeNode zzn[] = new SyntaxTreeNode[2]; - zzn[0] = new SyntaxTreeNode( mn, N_IdPrefix, new SyntaxTreeNode[0] ); - zzn[1] = new SyntaxTreeNode( mn, N_NonExpPrefixOp, t ); - tn = new SyntaxTreeNode( mn, N_GenNonExpPrefixOp, zzn ); - } else if (jj_2_14(1)) { - tn = Expression(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAMBDA: - tn = Lambda(); - break; - default: - jj_la1[37] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } catch (ParseException e) { -// first things first - restore evaluation stack - if ( OperatorStack.isWellReduced() ) - OperatorStack.popStack(); - else - {if (true) throw e;} -// check the nature of the node returned. It can only be a GenOp. */ -// should be reviewed - N_GenNonExpPrefixOp may be unnecessary because -. has been checked. - if ( ( anchor != null ) - &&( anchor.isKind( N_GenPrefixOp ) || anchor.isKind( N_GenInfixOp ) || anchor.isKind( N_GenPostfixOp ) || anchor.isKind( N_GenNonExpPrefixOp ) ) ) { - tn = anchor; anchor = null; - } else - {if (true) throw e;} - } - epa(); zn[2] = tn; {if (true) return new SyntaxTreeNode(mn, N_Substitution, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode PrefixOp() throws ParseException { - Token t; - t = PrefixOpToken(); - lastOp = Operators.getOperator( UniqueString.uniqueStringOf(t.image) ); // YYY to revise - {if (true) return new SyntaxTreeNode(mn, N_PrefixOp, t) ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode NonExpPrefixOp() throws ParseException { - Token t; - t = NEPrefixOpToken(); - lastOp = Operators.getOperator( UniqueString.uniqueStringOf(t.image) ); // YYY to revise - {if (true) return new SyntaxTreeNode(mn, N_NonExpPrefixOp, t) ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode InfixOp() throws ParseException { - Token t; -bpa("Infix Op") ; - t = InfixOpToken(); - lastOp = Operators.getOperator( UniqueString.uniqueStringOf(t.image) ); // YYY to revise -epa(); - {if (true) return new SyntaxTreeNode( mn, N_InfixOp, t) ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode PostfixOp() throws ParseException { - Token t; - t = PostfixOpToken(); - lastOp = Operators.getOperator( UniqueString.uniqueStringOf(t.image) ); // YYY to revise - {if (true) return new SyntaxTreeNode(mn, N_PostfixOp, t) ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Identifier() throws ParseException { - Token t; - t = jj_consume_token(IDENTIFIER); - {if (true) return new SyntaxTreeNode(mn, t);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Assumption ::= ( <ASSUME> | <ASSUMPTION> ) * -* ( Identifier <DEF> )? Expression * -***************************************************************************/ - final public SyntaxTreeNode Assumption() throws ParseException { - SyntaxTreeNode tn; - SyntaxTreeNode zn = null; - Token t; - bpa("Assumption"); -// expecting = "LOCAL or ASSUM..."; -expecting = "ASSUM..."; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ASSUMPTION: - t = jj_consume_token(ASSUMPTION); - break; - case ASSUME: - t = jj_consume_token(ASSUME); - break; - default: - jj_la1[38] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( new SyntaxTreeNode(mn, t) ); - if (jj_2_15(2)) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DEFBREAK: - t = jj_consume_token(DEFBREAK); - break; - default: - jj_la1[39] = jj_gen; - ; - } - /* A DEFBREAK might get added here by belchDEF */ - tn = Identifier(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - // belchDEF(); extra belchDEF removed 15 Mar 2007 by LL because it caused - // an extra <DEFBREAK> to be inserted, producing an error. - addHeir( new SyntaxTreeNode(mn, t) ); - } else { - ; - } - belchDEF(); -expecting = "Expression"; - tn = Expression(); - addHeir(tn); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_Assumption, zn, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode AssumeProve() throws ParseException { - /************************************************************************* - * AssumeProve ::= (<IDENTIFIER> <COLONCOLON>)? * - * <ASSUME> (AssumeProve | NewDecl | Expression) * - * (<COMMA> (AssumeProve | NewDecl | Expression))+ * - * <PROVE> Expression * - * * - * For ASSUME A1, A2 PROVE B, it constructs an AssumeProve node tn with * - * tn.zero equal to the array containing the 6 elements * - * * - * "ASSUME" A1 "," A2 "PROVE" B * - * * - * If there is a label "foo::", it returns an N_Label node. * - * * - * Changed 18 May 2008 by LL to allow a label. * - *************************************************************************/ - SyntaxTreeNode tn; - Token t; - SyntaxTreeNode sn[] ; - bpa("Assume-Prove"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - /********************************************************************* - * The semantic analyzer expects the label name to be a GeneralId * - * node whose first child is an empty N_IdPrefix node and whose * - * second child is the label's Identifier node. * - *********************************************************************/ - addHeir(new SyntaxTreeNode( - mn, - N_GeneralId, - new SyntaxTreeNode[] { - new SyntaxTreeNode( - mn, - N_IdPrefix, - new SyntaxTreeNode[0]), - tn} - ) ) ; - t = jj_consume_token(COLONCOLON); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = AssumeProve(); - addHeir(tn); - sn = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode( mn, N_Label, sn);} - break; - default: - jj_la1[40] = jj_gen; - ; - } - t = jj_consume_token(ASSUME); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression, Declaration, or AssumeProve"; - if ((getToken(1).kind == ASSUME) - || ((getToken(2).kind == COLONCOLON) && - (getToken(3).kind == ASSUME) )) { - /***************************************************** - * Check for COLONCOLON added by LL 17 Feb 2009. * - *****************************************************/ - tn = AssumeProve(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ACTION: - case CONSTANT: - case NEW: - case STATE: - case TEMPORAL: - case VARIABLE: - tn = NewSymb(); - break; - default: - jj_la1[41] = jj_gen; - if (jj_2_16(1)) { - tn = Expression(); - - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - addHeir(tn); -expecting = "PROVE or `,'"; - label_13: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[42] = jj_gen; - break label_13; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression, Declaration, or AssumeProve"; - if ((getToken(1).kind == ASSUME) - || ((getToken(2).kind == COLONCOLON) && - (getToken(3).kind == ASSUME) )) { - /***************************************************** - * Check for COLONCOLON added by LL 17 Feb 2009. * - *****************************************************/ - tn = AssumeProve(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ACTION: - case CONSTANT: - case NEW: - case STATE: - case TEMPORAL: - case VARIABLE: - tn = NewSymb(); - break; - default: - jj_la1[43] = jj_gen; - if (jj_2_17(1)) { - tn = Expression(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - addHeir(tn); -expecting = "PROVE or `,'"; - } - t = jj_consume_token(PROVE); - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Expression"; - tn = Expression(); - addHeir( tn ); - sn = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_AssumeProve, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode NewSymb() throws ParseException { - /************************************************************************* - * NewSymb ::= (<NEW> | <CONSTANT> | <NEW> <CONSTANT>) * - * (Identifier <IN> Expression | IdentDecl | SomeFixDecl) * - * | [<NEW>] <VARIABLE> Identifier * - * | [<NEW>] (<STATE> | <ACTION> | <TEMPORAL>) * - * (IdentDecl | SomeFixDecl) * - *************************************************************************/ - SyntaxTreeNode tn ; - Token t ; - boolean hasArgs ; - /*********************************************************************** - * We want to allow "NEW Id \in S" but disallow "NEW Id(_) \in S". * - * For simplicity, the we do this by letting javacc accept either, but * - * set hasArgs to true in the latter case and report the error when we * - * detect the "\in". * - ***********************************************************************/ - bpa( "NEW symbol declaration"); - expecting = "NEW, CONSTANT, VARIABLE, STATE, ACTION, or TEMPORAL"; - if (jj_2_20(2)) { - if (jj_2_18(2)) { - t = jj_consume_token(NEW); - addHeir( new SyntaxTreeNode(mn, t) ); - t = jj_consume_token(CONSTANT); - addHeir( new SyntaxTreeNode(mn, t) ); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NEW: - t = jj_consume_token(NEW); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - case CONSTANT: - t = jj_consume_token(CONSTANT); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - default: - jj_la1[44] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - expecting = "Constant declaration"; - if (jj_2_19(2)) { - tn = IdentDecl(); - hasArgs = tn.heirs().length > 1; - addHeir (tn) ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IN: - t = jj_consume_token(IN); - if (hasArgs) { - {if (true) throw new ParseException( - "declared symbol with arguments before \\in at " - + tn.getLocation().toString());} - } ; - addHeir(new SyntaxTreeNode(mn, t) ); - expecting = "Expression"; - tn = Expression(); - addHeir (tn) ; - break; - default: - jj_la1[45] = jj_gen; - ; - } - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case US: - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = SomeFixDecl(); - addHeir (tn) ; - break; - default: - jj_la1[46] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } else if (jj_2_21(2)) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NEW: - t = jj_consume_token(NEW); - addHeir(new SyntaxTreeNode(mn, t) ); - break; - default: - jj_la1[47] = jj_gen; - ; - } - t = jj_consume_token(VARIABLE); - addHeir(new SyntaxTreeNode(mn, t) ); - expecting = "Identifier"; - tn = Identifier(); - /************************************************** - * The semantic processor expects an N_IdentDecl * - * node, and doesn't cope with a bare Identifier * - * node. * - **************************************************/ - SyntaxTreeNode[] sn = new SyntaxTreeNode[1] ; - sn[0] = tn ; - addHeir(new SyntaxTreeNode( mn, N_IdentDecl, sn)); - } else if (jj_2_22(2)) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NEW: - t = jj_consume_token(NEW); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[48] = jj_gen; - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case STATE: - t = jj_consume_token(STATE); - break; - case ACTION: - t = jj_consume_token(ACTION); - break; - case TEMPORAL: - t = jj_consume_token(TEMPORAL); - break; - default: - jj_la1[49] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( new SyntaxTreeNode(mn, t)); - expecting = "Declaration" ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = IdentDecl(); - addHeir(tn); - break; - case US: - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = SomeFixDecl(); - addHeir(tn); - break; - default: - jj_la1[50] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } else { - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_NewSymb, sn);} - throw new Error("Missing return statement in function"); - } - -// NumberedAssumeProve() commented out 5 Mar 2007 by LL -// number . sequence -// SyntaxTreeNode -// NumberedAssumeProve () : { -// SyntaxTreeNode tn; -// Token t; -// boolean b = false; -// bpa("Numbered Assume-Prove"); -// }{ -// [ LOOKAHEAD(2) -// t = <NUMBER_LITERAL> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "."; } -// t = <DOT> { -// BStack.newReference(t.endColumn, ASSUME); b = true; -// addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "Assume-Prove, Assume-Decl or expression"; } ] -// ( tn = AssumeProve() -// | LOOKAHEAD( { IsNotExpression() } ) tn = AssumeDecl() -// | tn = Expression() ) /* XXX parser confusion here !!! */ -// { if (b) BStack.popReference(); -// addHeir(tn); -// SyntaxTreeNode sn[] = getLastHeirs(); -// epa(); return new SyntaxTreeNode( mn, N_NumberedAssumeProve, sn); } -// } - -// AssumeDecl() commented out 27 March 2007; it seems to be left over -// from the old proof grammar. -// SyntaxTreeNode -// AssumeDecl () : { -// SyntaxTreeNode zn[] = null; -// SyntaxTreeNode tn; -// Token t; -// bpa("Assume Decl."); -// }{ -// ( tn = VariableDeclaration() { zn = new SyntaxTreeNode[1]; zn[0] = tn; } -// | ( tn = ParamDeclaration() { -// zn = new SyntaxTreeNode[2]; zn[0] = tn; -// expecting = "optional \\in or ..."; } -// zn[1] = MaybeBound() ) -// | LOOKAHEAD (2) tn = OperatorOrFunctionDefinition() { zn = new SyntaxTreeNode[1]; zn[0] = tn; } -// | tn = Instance() { zn = new SyntaxTreeNode[1]; zn[0] = tn; } ) -// { epa(); -// return new SyntaxTreeNode( mn, N_AssumeDecl, zn ); } -// } - final public SyntaxTreeNode MaybeBound() throws ParseException { - SyntaxTreeNode zn[] = null; - SyntaxTreeNode tn; - Token t; - bpa("Domain binding"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IN: - t = jj_consume_token(IN); - zn = new SyntaxTreeNode[2]; - zn[0] = new SyntaxTreeNode(mn, t); - zn[0].setKind(T_IN); -expecting = "Expression"; - zn[1] = Expression(); - break; - default: - jj_la1[51] = jj_gen; - ; - } - epa(); {if (true) return new SyntaxTreeNode( mn, N_MaybeBound, zn);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Theorem ::= ( <THEOREM> | <PROPOSITION> ) * -* ( Identifier <DEF> )? ( AssumeProve | Expression ) * -* * -* Produces a Theorem node tn with tn.zero containing 2 or 4 nodes, * -* depending on whether or not the "Identifier <DEF>" is present. * -***************************************************************************/ - final public SyntaxTreeNode Theorem() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Theorem"); -expecting= "THEOREM, PROPOSITION"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case THEOREM: - t = jj_consume_token(THEOREM); - break; - case PROPOSITION: - t = jj_consume_token(PROPOSITION); - break; - default: - jj_la1[52] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( new SyntaxTreeNode(mn, t) ); -expecting = "Identifier, Assume-Prove or Expression"; - if (jj_2_23(2)) { - tn = Identifier(); - addHeir( tn ); -expecting = "=="; - t = jj_consume_token(DEF); - // belchDEF(); extra belchDEF removed 15 Mar 2007 by LL because it caused - // an extra <DEFBREAK> to be inserted, producing an error. - addHeir( new SyntaxTreeNode(mn, t) ); - } else { - ; - } - belchDEF(); - if (jj_2_24(3)) { - if (getToken(1).kind == ASSUME) { - - } else { - jj_consume_token(-1); - throw new ParseException(); - } - tn = AssumeProve(); - } else if (jj_2_25(1)) { - tn = Expression(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - addHeir(tn); - if (beginsProof(getToken(1))) { - tn = Proof(); - addHeir(tn) ; - } else { - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_Theorem, sn);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* The Grammar of Proofs * -* XXXXXXX THIS IS OBSOLETE * -* Proof ::= InnerProof * -* // Proof checks that we're not inside a proof at the end. * -* * -* InnerProof ::= * -* TerminalProof * -* | (<PROOF>)? * -* ( Step )* // Terminated by lookahead for "QED" * -* QEDStep * -* * -* // Note: (InnerProof)? uses lookahead for beginsProof(...) * -* * -* TerminalProof ::= <BY> ... * -* | (<PROOF>)? OBVIOUS * -* QEDStep ::= (<ProofStepLexeme> | <ProofStepDotLexeme> )? * -* <QED> (InnerProof)? * -* * -* Step ::= N_DefStep * -* | N_UseOrHide * -* | N_NonLocalInstance * -* | N_NumerableStep * -* | N_QEDStep * -* * -* NumerableStep == ExprStep * -* | NumberedStep * -* | UnnumberedStep * -* * -* DefStep ::= (<DEFINE>)? OperatorOrFunctionDefinition * -* * -* NumberedStep ::= (<ProofStepLexeme> | <ProofStepDotLexeme> ) * -* UnnumberedStep * -* * -* ExprStep ::= ( <PROVE> * -* | <SUFFICES> * -* | (<ProofStepLexeme> | <ProofStepDotLexeme> ) * -* (<SUFFICES>)? * -* ) * -* Expression * -* * -* UnnumberedStep ::= * -* Have * -* | Take * -* | Witness * -* | ( Pick * -* | (<SUFFICES>)? (AssumeProve | <CASE> Expression) * -* ) * -* (InnerProof)? * -***************************************************************************/ - final public SyntaxTreeNode Proof() throws ParseException { -/*************************************************************************** -* Returns an N_Proof or N_TerminalProof node. The heirs of an N_Proof * -* node consist of an option PROOF token followed by a seequence of * -* N_ProofStep nodes. The heirs of an N_ProofStep node are a StartStep() * -* token, a statement body, and an optional proof. A statement body is * -* one of the following node kinds: * -* * -* Have no proof: * -* N_DefStep N_UseOrHide N_NonLocalInstance N_HaveStep, * -* N_TakeStep N_WitnessStep * -* * -* Have a proof * -* N_QEDStep N_PickStep N_CaseStep N_AssertStep * -***************************************************************************/ - SyntaxTreeNode tn; - Token t = null ; - Token t0 = null; - pushProofLevel() ; - bpa("Proof"); - if ((getToken(1).kind == BY) || (getToken(2).kind == BY)) { - tn = UseOrHideOrBy(); - } else if (jj_2_27(2)) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case PROOF: - t0 = jj_consume_token(PROOF); - break; - default: - jj_la1[53] = jj_gen; - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OBVIOUS: - t = jj_consume_token(OBVIOUS); - break; - case OMITTED: - t = jj_consume_token(OMITTED); - break; - default: - jj_la1[54] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode sn[] ; - if (t0 != null) { - sn = new SyntaxTreeNode[2]; - sn[0] = new SyntaxTreeNode(mn, t0); - sn[1] = new SyntaxTreeNode(mn, t); - } - else { - sn = new SyntaxTreeNode[1]; - sn[0] = new SyntaxTreeNode(mn, t); - }; - tn = new SyntaxTreeNode(mn, N_TerminalProof, sn ); - } else if (jj_2_28(1)) { - if (jj_2_26(2)) { - t = jj_consume_token(PROOF); - addHeir(new SyntaxTreeNode(mn, t)); - } else { - ; - } - label_14: - while (true) { - if (getToken(2).kind != QED) { - ; - } else { - break label_14; - } - tn = Step(); - addHeir(tn); - expecting = "a proof step"; - } - tn = QEDStep(); - addHeir(tn); - SyntaxTreeNode sn[] = getLastHeirs(); - tn = new SyntaxTreeNode(mn, N_Proof, sn ); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - epa(); - popProofLevel() ; - {if (true) return tn ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode UseOrHideOrBy() throws ParseException { -/*************************************************************************** -* Returns an N_TerminalProof (for a BY) or N_UseOrHide node. Having * -* one nonterminal that returns both is the only easy way I know to * -* avoid having to duplicate the code for handling BY and for handling * -* USE/HIDE. Lookahead should prevent it from being called to parse * -* the wrong kind of object. * -* * -* Note: This production accepts a By, USE, or HIDE with no items. This * -* should be reported by an error in the semantic analysis phase. * -***************************************************************************/ - SyntaxTreeNode tn; - Token t; - int kind = N_UseOrHide; - bpa("UseOrHideOrBy"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case BY: - case PROOF: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case PROOF: - t = jj_consume_token(PROOF); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[55] = jj_gen; - ; - } - t = jj_consume_token(BY); - kind = N_TerminalProof; - addHeir(new SyntaxTreeNode(mn, t)); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ONLY: - t = jj_consume_token(ONLY); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[56] = jj_gen; - ; - } - break; - case USE: - t = jj_consume_token(USE); - addHeir(new SyntaxTreeNode(mn, t)); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ONLY: - t = jj_consume_token(ONLY); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[57] = jj_gen; - ; - } - break; - case HIDE: - t = jj_consume_token(HIDE); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[58] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - expecting = "an expression, `MODULE' or `DEF'"; - if (jj_2_31(1)) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MODULE: - t = jj_consume_token(MODULE); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn); - break; - default: - jj_la1[59] = jj_gen; - if (jj_2_29(1)) { - tn = Expression(); - addHeir(tn); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - label_15: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[60] = jj_gen; - break label_15; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "MODULE or expression"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MODULE: - t = jj_consume_token(MODULE); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn); - break; - default: - jj_la1[61] = jj_gen; - if (jj_2_30(1)) { - tn = Expression(); - addHeir(tn); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - if (kind == N_TerminalProof) { expecting = "comma, DEF, or [.]"; } - else {expecting = "comma, DEF, or proof step";}; - } - } else { - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DF: - t = jj_consume_token(DF); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "MODULE or expression"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MODULE: - t = jj_consume_token(MODULE); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn); - break; - default: - jj_la1[62] = jj_gen; - if (jj_2_32(1)) { - tn = Expression(); - addHeir(tn); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - label_16: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[63] = jj_gen; - break label_16; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "MODULE or expression"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MODULE: - t = jj_consume_token(MODULE); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn); - break; - default: - jj_la1[64] = jj_gen; - if (jj_2_33(1)) { - tn = Expression(); - addHeir(tn); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - if (kind == N_TerminalProof) { expecting = "comma or [.]"; } - else {expecting = "comma or proof step" ; }; - } - break; - default: - jj_la1[65] = jj_gen; - ; - } - if (kind == N_TerminalProof) {expecting = "[.]";}; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, kind, sn );} - throw new Error("Missing return statement in function"); - } - - final public Token StepStartToken() throws ParseException { - Token t ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ProofStepLexeme: - t = jj_consume_token(ProofStepLexeme); - break; - case ProofImplicitStepLexeme: - t = jj_consume_token(ProofImplicitStepLexeme); - break; - case ProofStepDotLexeme: - t = jj_consume_token(ProofStepDotLexeme); - break; - case BareLevelLexeme: - t = jj_consume_token(BareLevelLexeme); - break; - case UnnumberedStepLexeme: - t = jj_consume_token(UnnumberedStepLexeme); - break; - default: - jj_la1[66] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return t ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode QEDStep() throws ParseException { -/*************************************************************************** -* Returns an N_ProofStep node whose body is an N_QEDStep node. * -***************************************************************************/ - Token t ; - SyntaxTreeNode tn; - SyntaxTreeNode[] sn; - int level = -1 ; - bpa("QED step") ; - expecting = "Step number" ; - t = StepStartToken(); - tn = new SyntaxTreeNode(mn, t) ; - if (!correctLevel(t)) { - {if (true) throw new ParseException(tn.getLocation().toString() + - ": QED step's number has bad level." );} - }; - if ( (t.kind == ProofImplicitStepLexeme) - || (t.kind == ProofStepLexeme) - || (t.kind == ProofStepDotLexeme)) { - tn.originalImage = tn.image ; - tn.image = correctedStepNum(t) ; -// ToolIO.out.println("correcting " + tn.originalImage) ; - } ; -// ToolIO.out.println("xyz: t.image = " + t.image + ", correctedImage = " -// + tn.image + ", t.kind = " + t.kind ) ; - - addHeir(tn) ; - expecting = "QED" ; - t = jj_consume_token(QED); - sn = new SyntaxTreeNode[1] ; - sn[0] = new SyntaxTreeNode(mn, t) ; - addHeir(new SyntaxTreeNode(mn, N_QEDStep, sn)); - if (beginsProof(getToken(1))) { - tn = Proof(); - addHeir(tn) ; - } else { - ; - } - sn = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_ProofStep, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Step() throws ParseException { -/*************************************************************************** -* Returns an N_ProofStep node with the following heirs: * -* * -* - A StepStart() token. * -* * -* - An N_DefStep (for an operator or function def or named * -* instantiation, N_UseOrHide, N_NonLocalInstance, N_HaveStep, * -* N_TakeStep, N_WitnessStep, N_PickStep, N_CaseStep, or * -* N_AssertStep node. (An N_AssertStep node has an optional * -* "SUFFICES" followed by an expression or N_AssumeProve node.) * -* * -* - An optional N_Proof or N_TerminalProof node. * -* * -* Note: The grammar accepts a USE or HIDE with no items. This should * -* be reported as an error in the semantic analysis phase. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - boolean mayHaveProof = false ; - bpa("Step") ; - expecting = "Step number" ; - t = StepStartToken(); - tn = new SyntaxTreeNode(mn, t); - if (!correctLevel(t)) { - {if (true) throw new ParseException(tn.getLocation().toString() + - ": step's number has bad level." );} - }; - if ( (t.kind == ProofImplicitStepLexeme) - || (t.kind == ProofStepLexeme) - || (t.kind == ProofStepDotLexeme)) { - tn.originalImage = tn.image ; - tn.image = correctedStepNum(t) ; - } ; -// ToolIO.out.println("xyz2: t.image = " + t.image + ", correctedImage = " -// + tn.image + ", t.kind = " + t.kind ) ; - addHeir(tn) ; - expecting = "proof step"; - if ((getToken(1).kind == USE) || (getToken(1).kind == HIDE)) { - tn = UseOrHideOrBy(); - addHeir(tn) ; - } else if (getToken(1).kind == INSTANCE) { - tn = Instantiation(); - addHeir(tn) ; - } else if ((getToken(1).kind == DEFBREAK) - || (getToken(1).kind == DEFINE)) { - tn = DefStep(); - addHeir(tn) ; - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case HAVE: - tn = HaveStep(); - addHeir(tn) ; - break; - case TAKE: - tn = TakeStep(); - addHeir(tn) ; - break; - case WITNESS: - tn = WitnessStep(); - addHeir(tn) ; - break; - case PICK: - tn = PickStep(); - addHeir(tn) ; mayHaveProof = true; - break; - case CASE: - tn = CaseStep(); - addHeir(tn) ; mayHaveProof = true; - break; - default: - jj_la1[67] = jj_gen; - if (jj_2_34(1)) { - tn = AssertStep(); - addHeir(tn) ; mayHaveProof = true; - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - if (beginsProof(getToken(1))) { - if (! mayHaveProof) { - {if (true) throw new ParseException(tn.getLocation().toString() + - ": proof of step that does not take a proof." );} - } ; - tn = Proof(); - addHeir(tn) ; - } else { - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_ProofStep, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode DefStep() throws ParseException { -/*************************************************************************** -* Returns an N_DefStep node whose heirs begin with an optional <DEFINE> * -* followed by a non-empty sequence of nodes returned by * -* OperatorOrFunctionDefinition(). * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("DefStep") ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DEFINE: - t = jj_consume_token(DEFINE); - addHeir(new SyntaxTreeNode(mn, t)); - break; - default: - jj_la1[68] = jj_gen; - ; - } - label_17: - while (true) { - tn = OperatorOrFunctionDefinition(); - addHeir(tn) ; - if (jj_2_35(2)) { - ; - } else { - break label_17; - } - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_DefStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode HaveStep() throws ParseException { -/*************************************************************************** -* Returns an N_HaveStep node whose heirs are a <HAVE> token and an * -* expression node. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("HaveStep") ; - t = jj_consume_token(HAVE); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "expression"; - tn = Expression(); - addHeir(tn) ; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_HaveStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode TakeStep() throws ParseException { -/*************************************************************************** -* Returns an N_TakeStep node whose first heir is a <TAKE> token and whose * -* remaining heirs are a sequence of QuantBound() nodes or a sequence of * -* identifiers. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("TakeStep") ; - t = jj_consume_token(TAKE); - addHeir(new SyntaxTreeNode(mn, t)) ; - expecting = "identifier"; - if (jj_2_36(2147483647)) { - tn = QuantBound(); - addHeir(tn) ; - expecting = "comma or step"; - label_18: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[69] = jj_gen; - break label_18; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier or tuple of identifiers"; - tn = QuantBound(); - addHeir(tn) ; - expecting = "comma or proof step"; - } - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn = Identifier(); - addHeir(tn) ; - expecting = "comma or proof step"; - label_19: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[70] = jj_gen; - break label_19; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn) ; - expecting = "comma or proof step"; - } - break; - default: - jj_la1[71] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_TakeStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode WitnessStep() throws ParseException { -/*************************************************************************** -* Returns an N_WitnessStep node whose heirs are a <WITNESS> token and a * -* sequence of expression nodes. It's up to later processing to decide if * -* those expressions have the form <<expr, ... , expr>> \in expr, * -* expr \in expr, or just expr. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("WitnessStep") ; - t = jj_consume_token(WITNESS); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "expression"; - tn = Expression(); - addHeir(tn) ; - label_20: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[72] = jj_gen; - break label_20; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "expression"; - tn = Expression(); - addHeir(tn) ; - expecting = "comma or colon"; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_WitnessStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode PickStep() throws ParseException { -/*************************************************************************** -* Returns an N_PickStep node whose heirs are a <PICK> token and an * -* expression node. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("PickStep") ; - t = jj_consume_token(PICK); - addHeir(new SyntaxTreeNode(mn, t)) ; - expecting = "identifier"; - if (jj_2_37(2147483647)) { - /* CommaList Identifier */ - tn = Identifier(); - addHeir(tn) ; - expecting = "comma, or colon"; - label_21: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[73] = jj_gen; - break label_21; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier"; - tn = Identifier(); - addHeir(tn) ; - expecting = "comma or colon"; - } - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAB: - case IDENTIFIER: - tn = QuantBound(); - addHeir(tn) ; - expecting = "comma or colon"; - label_22: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[74] = jj_gen; - break label_22; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "identifier or tuple of identifiers"; - tn = QuantBound(); - addHeir(tn) ; - expecting = "comma or colon"; - } - break; - default: - jj_la1[75] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - t = jj_consume_token(COLON); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "expression"; - tn = Expression(); - addHeir(tn) ; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_PickStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode CaseStep() throws ParseException { -/*************************************************************************** -* Returns an N_CaseStep node whose heirs are a <CASE> token and an * -* expression node. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("CaseStep") ; - t = jj_consume_token(CASE); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "expression"; - tn = Expression(); - addHeir(tn) ; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_CaseStep, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode AssertStep() throws ParseException { -/*************************************************************************** -* Returns an N_AssertStep node whose heirs are an optional <SUFFICES> * -* token and an expression or N_AssumeProve node. * -***************************************************************************/ - Token t = null; - SyntaxTreeNode tn = null; - bpa("AssertStep") ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case SUFFICES: - t = jj_consume_token(SUFFICES); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "expression or ASSUME/PROVE"; - break; - default: - jj_la1[76] = jj_gen; - ; - } - if (jj_2_38(1)) { - tn = Expression(); - } else if (getToken(1).kind == ASSUME) { - tn = AssumeProve(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - addHeir(tn) ; - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode(mn, N_AssertStep, sn );} - throw new Error("Missing return statement in function"); - } - -// SyntaxTreeNode -// NumerableStep() : { -// /*************************************************************************** -// * Returns an N_NumerableStep node, which has the syntax * -// * * -// * ( <ProofStep[Dot]Lexeme> (N_NonExprBody node) * -// * | N_NonExprBody node ) * -// * ( N_Proof node | N_TerminalProof node)? * -// ***************************************************************************/ -// Token t = null; -// SyntaxTreeNode tn = null; -// boolean mayHaveProof = true ; -// bpa("NumerableStep") ; -// }{( LOOKAHEAD(2) -// (t = <ProofStepLexeme> | t = <ProofStepDotLexeme>) -// { tn = new SyntaxTreeNode(mn, t) ; -// addHeir(tn); -// if ((proofDepth > 0) && (proofLevelStack[proofDepth-1] == -1)){ -// throw new ParseException(tn.getLocation() + -// ": numbered step inside unnumbered proof."); -// } ; -// if (!correctLevel(t)) { -// throw new ParseException(tn.getLocation() + -// ": step number has incorrect level."); -// } ; -// } -// ( (t = <CASE> {addHeir(new SyntaxTreeNode(mn, t)); })? // XXXX -// // ^^^^^^^^^^^ -// // javacc generates the following warning here: -// // Choice conflict in [...] construct at line 2700, column 8. -// // Expansion nested within construct and expansion following construct -// // have common prefixes, one of which is: "CASE" -// // Consider using a lookahead of 2 or more for nested expansion. -// // -// // This conflict is between "<1>2. CASE expr" and -// // "<1>2. CASE p -> ...". This is an inherent ambiguity that arises -// // from the use of "CASE" as a keyword here. Javacc resolves -// // conflicts by choosing the first successful match. Here, this -// // means that "<1>2. CASE p -> ..." is parsed as -// // -// // <ProofStepDotLexeme> <CASE> Expression() -// // -// // causing an error when it tries to parse "-> ..." as an expression. -// -// -// -// tn = Expression() {addHeir(tn); // XXXX -// mayHaveProof = true ;} // XXXX -// | // XXXX -// tn = NonExprBody() {addHeir(tn); -// mayHaveProof = nonExprBodyMayHaveProof;} -// ) // XXXX -// | t = <CASE> {addHeir(new SyntaxTreeNode(mn, t)); } // XXXX -// tn = Expression() {addHeir(tn); // XXXX -// mayHaveProof = nonExprBodyMayHaveProof;} // XXXX -// -// | tn = NonExprBody() -// { addHeir(tn); -// mayHaveProof = nonExprBodyMayHaveProof; -// if (getProofLevel() == -2) -// { setProofLevel(-1) ; -// } -// else { -// if (getProofLevel() != -1) { -// throw new ParseException(tn.getLocation() + -// ": Unnumbered step in numbered proof."); -// } -// } -// } -// ) -// ( LOOKAHEAD( {mayHaveProof && beginsProof(getToken(1))} ) -// tn = Proof() -// { addHeir(tn) ; } -// )? -// { SyntaxTreeNode sn[] = getLastHeirs(); -// epa(); -// return new SyntaxTreeNode(mn, N_NumerableStep, sn); -// } -// } - -// /*************************************************************************** -// * Hack: In addition to returning a node, NonExprBody() needs to return a * -// * boolean saying whether or not the statement it is returning can have a * -// * proof. It does this by setting the field nonExprBodyMayHaveProof. * -// ***************************************************************************/ -// SyntaxTreeNode -// NonExprBody() : { -// SyntaxTreeNode tn = null; -// Token t = null; -// nonExprBodyMayHaveProof = false ; -// bpa("NonExprBody") ; -// }{ ( LOOKAHEAD(2) -// (t = <SUFFICES> { addHeir(new SyntaxTreeNode(mn, t)); }) ? -// tn = AssumeProve() { addHeir(tn) ; -// nonExprBodyMayHaveProof = true;} -// | LOOKAHEAD(2) -// ( t = <PROVE> | t = <SUFFICES>) // | t = <PROOFCASE> -// { addHeir(new SyntaxTreeNode(mn, t)); -// expecting = "expression";} -// tn = Expression() { addHeir(tn) ; -// nonExprBodyMayHaveProof = true;} -// | t = <HAVE> { addHeir(new SyntaxTreeNode(mn, t)) ; -// expecting = "expression";} -// tn = Expression() { addHeir(tn) ; } -// | t = <TAKE> { addHeir(new SyntaxTreeNode(mn, t)) ; -// expecting = "identifier";} -// ( LOOKAHEAD ( <IDENTIFIER> (<COMMA> <IDENTIFIER>)* <IN> -// | <LAB>) -// tn = QuantBound() { addHeir(tn) ; -// expecting = "comma or step";} -// ( t = <COMMA> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "identifier or tuple of identifiers";} -// tn = QuantBound() { addHeir(tn) ; -// expecting = "comma or proof step";} -// )* -// | -// tn = Identifier() { addHeir(tn) ; -// expecting = "comma or proof step";} -// ( t = <COMMA> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "identifier";} -// tn = Identifier() { addHeir(tn) ; -// expecting = "comma or proof step";} -// )* -// ) -// -// | t = <WITNESS> { addHeir(new SyntaxTreeNode(mn, t)) ; -// expecting = "expression";} -// tn = Expression() { addHeir(tn) ; } -// /********************************************************************* -// * Note: The semantic phase must determine if this is expr \in expr, * -// * or <<expr, ... , expr>> \in expr, or just expr. * -// *********************************************************************/ -// ( t = <COMMA> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "expression";} -// tn = Expression() { addHeir(tn) ; -// expecting = "comma or colon";} -// )* -// -// | t = <PICK> { addHeir(new SyntaxTreeNode(mn, t)) ; -// expecting = "identifier";} -// ( LOOKAHEAD ( <IDENTIFIER> ( <COMMA> <IDENTIFIER> )* <COLON> ) -// /* CommaList Identifier */ -// tn = Identifier() { addHeir(tn) ; -// expecting = "comma, or colon";} -// ( t = <COMMA> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "identifier";} -// tn = Identifier() { addHeir(tn) ; -// expecting = "comma or colon";} -// )* -// | -// tn = QuantBound() { addHeir(tn) ; -// expecting = "comma or colon";} -// ( t = <COMMA> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "identifier or tuple of identifiers";} -// tn = QuantBound() { addHeir(tn) ; -// expecting = "comma or colon";} -// )* -// ) -// t = <COLON> { addHeir( new SyntaxTreeNode(mn, t) ); -// expecting = "expression";} -// tn = Expression() { addHeir(tn) ; } -// { nonExprBodyMayHaveProof = true;} -// ) -// { SyntaxTreeNode sn[] = getLastHeirs(); -// epa(); -// return new SyntaxTreeNode(mn, N_NonExprBody, sn); -// } -// } - - - -/*************************************************************************** -* The GeneralId() production is not used and can be deleted. The parser * -* uses Java code to construct N_GeneralId nodes inside Extension(), * -* NoOpExtension(), and BraceCases() * -***************************************************************************/ - final public SyntaxTreeNode GeneralId() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[2]; - Token t; - bpa("General ID"); - zn[0] = IdPrefix(); - zn[1] = Identifier(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_GeneralId, zn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IdPrefix() throws ParseException { - SyntaxTreeNode tn; - bpa("ID Prefix"); - label_23: - while (true) { - if (jj_2_39(2147483647)) { - ; - } else { - break label_23; - } - tn = IdPrefixElement(); - addHeir( tn ); - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_Proof, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IdPrefixElement() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("ID Prefix Element"); - tn = Identifier(); - addHeir( tn ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - tn = OpArgs(); - addHeir( tn ); - break; - default: - jj_la1[77] = jj_gen; - ; - } - t = jj_consume_token(BANG); - addHeir( new SyntaxTreeNode(mn, t) ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_IdPrefixElement, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ParenthesesExpression() throws ParseException { - SyntaxTreeNode tn; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - tn = ParenExpr(); - break; - case LBC: - tn = BraceCases(); - break; - case LSB: - tn = SBracketCases(); - break; - case LWB: - tn = SetExcept(); - break; - case LAB: - tn = TupleOrAction(); - break; - case SF: - case WF: - tn = FairnessExpr(); - break; - default: - jj_la1[78] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ClosedExpressionOrOp() throws ParseException { - SyntaxTreeNode tn; - Token t; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NUMBER_LITERAL: - case STRING_LITERAL: - case op_57: - case op_68: - case op_69: - case op_70: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - case IDENTIFIER: - tn = ElementaryExpression(); - break; - case SF: - case WF: - case LBR: - case LSB: - case LWB: - case LBC: - case LAB: - tn = ParenthesesExpression(); - break; - default: - jj_la1[79] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* The following does not seem to be used anywhere. * -***************************************************************************/ - final public SyntaxTreeNode ClosedExpressionOnly() throws ParseException { - SyntaxTreeNode tn; - tn = ClosedExpressionOrOp(); - if ( isGenOp( tn ) ) {if (true) throw new ParseException( "Encountered unexpected Operator" );} - else {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode OpenExpression() throws ParseException { - SyntaxTreeNode tn; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EXISTS: - case FORALL: - tn = SomeQuant(); - break; - case T_EXISTS: - case T_FORALL: - tn = SomeTQuant(); - break; - case IF: - tn = IfThenElse(); - break; - case CASE: - tn = Case(); - break; - case LET: - tn = LetIn(); - break; - case CHOOSE: - tn = UnboundOrBoundChoose(); - break; - default: - jj_la1[80] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - -/* - L.GeneralId, L.OpApplication, L.String, L.Number, L.GenOp... -*/ - final public SyntaxTreeNode ElementaryExpression() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Elementary expression"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_57: - case op_68: - case op_69: - case op_70: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - case IDENTIFIER: - tn = Extension(); - break; - case STRING_LITERAL: - tn = String(); - epa(); - break; - case NUMBER_LITERAL: - tn = Number(); - epa(); - break; - default: - jj_la1[81] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode String() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("String"); - t = jj_consume_token(STRING_LITERAL); - tn = new SyntaxTreeNode( mn, N_String, t); - tn.image = reduceString( tn.image.toString() ); - epa(); - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Number() throws ParseException { - SyntaxTreeNode tn, sn[] = null; - Token t1, t2; - int kind = N_Number; - t1 = jj_consume_token(NUMBER_LITERAL); - if (jj_2_40(2)) { - t2 = jj_consume_token(DOT); - kind = N_Real; - decimalFlag = true; - sn = new SyntaxTreeNode[3]; - sn[0] = new SyntaxTreeNode(mn, t1); - sn[1] = new SyntaxTreeNode(mn, t2); - t1 = jj_consume_token(NUMBER_LITERAL); - sn[2] = new SyntaxTreeNode(mn,t1); - } else { - ; - } - if (sn == null) { - numberFlag = true; - sn = new SyntaxTreeNode[1]; - sn[0] = new SyntaxTreeNode(mn, t1); - kind = N_Number; - } - {if (true) return new SyntaxTreeNode(mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Extension() throws ParseException { - SyntaxTreeNode last = null, tid, top = null; - Token t = null; - SyntaxTreeNode heirs[]; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - // LOOKAHEAD( { isPrefixOp( getToken(1) ) } ) - top = PrefixOp(); - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - heirs[1] = top; - last = new SyntaxTreeNode( mn, N_GenPrefixOp, heirs ); - epa(); - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - // LOOKAHEAD( { isInfixOp( getToken(1) ) } ) - top = InfixOp(); - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - heirs[1] = top; - last = new SyntaxTreeNode( mn, N_GenInfixOp, heirs ); - epa(); - break; - case op_57: - case op_68: - case op_69: - case op_70: - // LOOKAHEAD( { isPostfixOp( getToken(1) ) } ) - top = PostfixOp(); - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - heirs[1] = top; - last = new SyntaxTreeNode( mn, N_GenPostfixOp, heirs ); - epa(); - break; - case IDENTIFIER: - tid = Identifier(); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - top = OpArgs(); - break; - default: - jj_la1[82] = jj_gen; - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case BANG: - t = jj_consume_token(BANG); - if ( top == null ) { - heirs = new SyntaxTreeNode[2]; - heirs[1] = new SyntaxTreeNode( mn, t ); - } else { - heirs = new SyntaxTreeNode[3]; - heirs[1] = top; - heirs[2] = new SyntaxTreeNode(mn, t ); - } - heirs[0] = tid; - SyntaxTreeNode current = new SyntaxTreeNode( mn, N_IdPrefixElement, heirs ); - addHeir( current ); - last = Extension(); - break; - default: - jj_la1[83] = jj_gen; - ; - } - if ( last == null ) { - if ( top == null ) { - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - heirs[1] = tid; - last = new SyntaxTreeNode( mn, N_GeneralId, heirs ); - } else { -/* XXX Wrong. - addHeir( tid ); - tid = new SyntaxTreeNode( mn, N_GeneralId, getLastHeirs() ); -*/ - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - heirs[1] = tid; - tid = new SyntaxTreeNode( mn, N_GeneralId, heirs ); - - heirs = new SyntaxTreeNode[2]; - heirs[0] = tid; - heirs[1] = top; - last = new SyntaxTreeNode( mn, N_OpApplication, heirs ); - } - epa(); - } - break; - default: - jj_la1[84] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return last;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode OpArgs() throws ParseException { - // OpSuite contributes to Heir list. - SyntaxTreeNode tn; - Token t; - bpa("Optional Arguments"); - t = jj_consume_token(LBR); - addHeir( new SyntaxTreeNode(mn, t) ); - OpSuite(); - label_24: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[85] = jj_gen; - break label_24; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - OpSuite(); - } - t = jj_consume_token(RBR); - addHeir( new SyntaxTreeNode(mn, t) ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_OpArgs, sn);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* OpOrExpr ::= (NonExpPrefixOp | InfixOp | PostfixOp) * -* followed by * -* "," | ")" | <DEFBREAK> | "LOCAL" | "INSTANCE" | * -* "THEOREM" | "ASSUME" | "ASSUMPTION" | * -* "CONSTANT" | "VARIABLE" | "RECURSIVE" | * -* <END_MODULE> | <SEPARATOR> | <BEGIN_MODULE> * -* | Lambda * -* | Expression * -* * -* This production is called where either an operator or an expression is * -* expected--which is either as the argument of an operator or in a * -* substitution. For an expression or an operator argument that's a * -* LAMBDA expression, there's no problem. However, something like Foo!Bar * -* could be either an expression or an operator. In TLA+2, something like * -* Foo!+!Bar could only be an operator, while something like * -* Foo!+(a,b)!Bar could only be an expression. However, in order to * -* minimize the changes from the TLA+1 parser, we represent both Foo!+!Bar * -* and Foo!+(a,b)!Bar as a GeneralId node and leave it to the semantic * -* processing to sort things out. Thus, Foo!+(a,b)!Bar produces the * -* folowing tree of SyntaxTreeNode objects: * -* * -* N_GeneralId * -* _.N_IdPrefix * -* _._.N_IdPrefixElement * -* _._._.IDENTIFIER "Foo" * -* _._._.BANG "!" * -* _._.N_IdPrefixElement * -* _._._.N_InfixOp + * -* _._._.N_OpArgs * -* _._._._.LBR "(" * -* _._._._.whatever a produces * -* _._._._.COMMA "," * -* _._._._.whatever b produces * -* _._._._.RBR ")" * -* _._._.BANG "!" * -* _.IDENTIFIER "Bar" * -* * -* Something like Foo!+(a,b)!Bar(x) producs an N_OpApplication node * -* whose first child is the N_GeneralId node above and whose second * -* child is an N_OpArgs node. * -* * -* TLA+2 adds labels and structural operators like "<<" to this kind of * -* operator or expression. A label in such an expression looks just like * -* an ordinary identifier. A structural operator is represented by a * -* token with the new kind "N_StructOp". Such a node is created by * -* * -* new SynaxTreeNode(moduleName, N_StructOp, node) * -* * -* where node is created by either * -* * -* new SyntaxTreeNode(moduleName, tok) * -* * -* where tok is "<<", ">>", "@", or ":", or by * -* * -* new SynaxTreeNode(moduleName, N_Number, ...) * -* * -* for a <NUMBER_LITERAL> token. * -* * -* Let OpArgs = (arg_1, ... , arg_k). In general, there are three * -* interesting classes of expressions of the form e_1!e_2!...!e_n. * -* * -* Case 1: e_n = tok OpArgs, * -* where tok is an Identifier or an In/Pre/PostfixOp. * -* In this case an OpApplication node is produced with two children: * -* - An N_GeneralId node with children * -* - An N_IdPrefixNode with n-1 children consisting N_IdPRefixElement * -* nodes for e_1!, ... , e_n-1!. * -* - A node of kind IDENTIFIER, N_PrefixOp, etc. for tok * -* - An N_OpArgs nodes obtained from OpArgs * -* * -* Case 2: e_n = tok * -* where tok is an Identifier or an In/Pre/PostfixOp. * -* In this case, it produces just the N_GeneralId node of Case 1 * -* * -* Case 3: e_n = OpArgs * -* In this case, a GeneralId node is produced with two children: * -* - The N_IdPrefixNode node produced in cases 1 and 2 * -* - An N_OpArgs node for OpArgs. * -***************************************************************************/ - final public SyntaxTreeNode OpOrExpr() throws ParseException { - /************************************************************************* - * Used for parsing an operator argument or the right-hand side of a * - * substitution, which could be either an operator (like +) or an * - * expression (like a+b). * - *************************************************************************/ -SyntaxTreeNode tn; -int kind ; - if (jj_2_41(2) && (BStack.aboveReference( getToken(1).beginColumn))) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = NonExpPrefixOp(); - kind = N_GenNonExpPrefixOp; - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - kind = N_GenInfixOp; - if ( (tn.image == UniqueString.uniqueStringOf("\\X")) - || (tn.image == UniqueString.uniqueStringOf("\\times"))){ - {if (true) throw new ParseException( - tn.getLocation().toString() + - ": \\X may not be used as an infix operator.");} - }; - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - kind = N_GenPostfixOp; - break; - default: - jj_la1[86] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode heirs[] = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, ( SyntaxTreeNode []) null ); - heirs[1] = tn; - tn = new SyntaxTreeNode(mn, kind, heirs); - } else if (jj_2_42(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - /*********************************************************************** - * Need the BStack.aboveReference check to make sure that the LAMBDA * - * is properly indented with respect to any enclosing dis/conjunction * - * list. However, without the <LAMBDA>, the lookahead would succeed * - * and the next production would be executed even if it shouldn't * - * match. * - ***********************************************************************/ - tn = Lambda(); - } else if (jj_2_43(1)) { - tn = Expression(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - final public void OpSuite() throws ParseException { -SyntaxTreeNode tn; - tn = OpOrExpr(); - addHeir(tn); - } - - // OpSuite - - -// void /* nodes are linked internally here : no value returned */ -// oldOpSuite() : { -// SyntaxTreeNode tn = null; -// anchor = null; -// /*********************************************************************** -// * See the comments for the declaration of anchor to see what this is * -// * being used for. * -// ***********************************************************************/ -// Token t; -// } { -// ( /*********************************************************************** -// * This handles the operator argument "-." (token op_76) * -// ***********************************************************************/ -// // XXXXX -- this won't work with the new expression syntax. -// t = <op_76> { -// tn = new SyntaxTreeNode(mn, N_NonExpPrefixOp, t); -// SyntaxTreeNode heirs[] = new SyntaxTreeNode[2]; -// heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, ( SyntaxTreeNode []) null ); -// heirs[1] = tn; -// tn = new SyntaxTreeNode( mn, N_GenNonExpPrefixOp, heirs ); } -// | LOOKAHEAD( (<AND> | <OR>) (<COMMA>|<RBR>) ) -// tn = InfixOp() { -// heirs = new SyntaxTreeNode[2]; -// heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, (SyntaxTreeNode []) null ); -// heirs[1] = tn; -// tn = new SyntaxTreeNode( mn, N_GenInfixOp, heirs ); -// } -// | tn = Lambda() -// | try { -// tn = Expression() -// } catch ( ParseException e ) { -// // ToolIO.out.println("Caught exception (bis)"); -// // first things first - restore evaluation stack -// if ( OperatorStack.isWellReduced() ) -// OperatorStack.popStack(); -// else -// throw e; -// /* it wasn't an expression, what was it ? */ -// /* check the nature of the node returned. It can only be a prefixed op. */ -// if ( ( anchor != null ) -// &&( anchor.isKind( N_GenPrefixOp ) -// || anchor.isKind( N_GenInfixOp ) -// || anchor.isKind( N_GenPostfixOp ) ) ) {tn = anchor; anchor = null; -// } else { -// // ToolIO.out.println("anchor is " + anchor.toString()); -// throw e; -// } // end else -// } // end catch. -// ) -// /* it wasn't an expression, what was it ? L.GenNonExpPrefixOp | L.GenInfixOp | L.GenPostfixOp */ -// /* check the nature of the node returned . Below Expression, it has to be a prefixed op. */ -// { addHeir( tn ); } -// } - final public SyntaxTreeNode ParenExpr() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode tn; - Token t; - t = jj_consume_token(LBR); - zn[0] = new SyntaxTreeNode(mn, t); - zn[1] = Expression(); - t = jj_consume_token(RBR); - zn[2] = new SyntaxTreeNode(mn, t); - {if (true) return new SyntaxTreeNode(mn, N_ParenExpr, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode SomeQuant() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Quantified form"); - int kind; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EXISTS: - t = jj_consume_token(EXISTS); - break; - case FORALL: - t = jj_consume_token(FORALL); - break; - default: - jj_la1[87] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( new SyntaxTreeNode(mn, t)); - if (jj_2_44(2147483647)) { - tn = Identifier(); - kind = N_UnboundQuant; - addHeir( tn ); - label_25: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[88] = jj_gen; - break label_25; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Identifier(); - addHeir( tn ); - } - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAB: - case IDENTIFIER: - tn = QuantBound(); - kind = N_BoundQuant; - addHeir( tn ); - label_26: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[89] = jj_gen; - break label_26; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - } - break; - default: - jj_la1[90] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - t = jj_consume_token(COLON); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode SomeTQuant() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Bound Quantified Expression"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case T_EXISTS: - t = jj_consume_token(T_EXISTS); - break; - case T_FORALL: - t = jj_consume_token(T_FORALL); - break; - default: - jj_la1[91] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Identifier(); - addHeir( tn ); - label_27: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[92] = jj_gen; - break label_27; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Identifier(); - addHeir( tn ); - } - t = jj_consume_token(COLON); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_UnboundQuant, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode QuantBound() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Quant Bound"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAB: - tn = IdentifierTuple(); - addHeir( tn ); - break; - case IDENTIFIER: - tn = Identifier(); - addHeir( tn ); - label_28: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[93] = jj_gen; - break label_28; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Identifier(); - addHeir( tn ); - expecting = ", or \\in"; - } - break; - default: - jj_la1[94] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - t = jj_consume_token(IN); - tn = new SyntaxTreeNode(mn, t); - tn.setKind(T_IN); - addHeir(tn); - tn = Expression(); - addHeir( tn ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_QuantBound, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode BraceCases() throws ParseException { - int kind = N_SetEnumerate; // set by default. - SyntaxTreeNode tn, tn_0, tn_1, tn_2, htn = null; - Token t; - boolean te = false; - /*********************************************************************** - * The value of te is set in a couple of places, but it is never * - * read. J-Ch hopes it's obsolete. * - ***********************************************************************/ - bpa("Some { } form"); - t = jj_consume_token(LBC); - addHeir( new SyntaxTreeNode(mn, t) ); - if (jj_2_48(1)) { - if (matchFcnConst()) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAB: - tn = IdentifierTuple(); - break; - case IDENTIFIER: - tn = Identifier(); - break; - default: - jj_la1[95] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - tn_0 = tn; - expecting = "\\in"; - // At this stage, we need to break since it maybe a MaybeBound or - // a SubsetOf - // So we'll hold to the pieces in the meantime. - t = jj_consume_token(IN); - tn_1 = new SyntaxTreeNode(mn, t); - tn_1.setKind(T_IN); - /******************************************************************* - * Changed from tn.setKind(T_IN) by LL on 19 Mar 2007. * - * * - * Appears to fix bug that caused semantic error on something like * - * {<<m, n>> \in Nat \X Nat : m > 0}. * - *******************************************************************/ - -// addHeir(tn); - - tn_2 = Expression(); -// addHeir( tn ); -// need to create a node for a N_InfixExpr. Some reassembly required, but if course it may be for naught. -// This is in case it isn't a N_SubsetOf - expecting = "':', ',' or '}'"; - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode wn[]= new SyntaxTreeNode[2]; - wn[0] = new SyntaxTreeNode(mn, N_IdPrefix, new SyntaxTreeNode[0]); - wn[1] = tn_0; - zn[0] = new SyntaxTreeNode(mn, N_GeneralId, wn); - wn = new SyntaxTreeNode[2]; - wn[0] = new SyntaxTreeNode(mn, N_IdPrefix, new SyntaxTreeNode[0]); - wn[1] = tn_1; - zn[1] = new SyntaxTreeNode(mn, N_GenInfixOp, wn); - zn[2] = tn_2; - htn = new SyntaxTreeNode( mn, N_InfixExpr, zn); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - case COLON: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COLON: - t = jj_consume_token(COLON); - htn = null; // it was for naught, ignore it later. - addHeir(tn_0); // ID - addHeir(tn_1); // \\in - addHeir(tn_2); // expression - addHeir( new SyntaxTreeNode(mn, t) ); - kind = N_SubsetOf; - tn = Expression(); - addHeir( tn ); - break; - case COMMA: - label_29: - while (true) { - t = jj_consume_token(COMMA); - if (htn != null) { - addHeir( htn); htn = null; - } - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[96] = jj_gen; - break label_29; - } - } - break; - default: - jj_la1[97] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[98] = jj_gen; - ; - } - } else if (jj_2_45(2147483647)) { - tn = Expression(); - kind = N_SetEnumerate; - addHeir( tn ); - label_30: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[99] = jj_gen; - break label_30; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - } - } else if (jj_2_46(2147483647)) { - te = true; kind = N_SetOfAll; - tn = Expression(); - addHeir( tn ); - t = jj_consume_token(COLON); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - label_31: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[100] = jj_gen; - break label_31; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - } - } else if (jj_2_47(1)) { - tn = Expression(); - addHeir( tn ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - case COLON: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COLON: - t = jj_consume_token(COLON); - te = true; kind = N_SetOfAll; -// IF tn is infix expression, with operator IN, we have a pbm for throw new ParseException( "Form {a \in b : c \in d } is forbidden" ); - - /******************************************************************* - * The following code causes an incorrect error on the legal * - * expression {1 \in x : x \in T}. It seems to me that this * - * test should simply be eliminated. It seems to be based on the * - * mistaken belief that {x \in S : x \in T} is illegal, when it's * - * actually an expression of type N_SubsetOf. * - *******************************************************************/ - SyntaxTreeNode Hone[] = (SyntaxTreeNode[])tn.heirs(); - if (Hone.length>1) { // better make sure it's long enough. - Hone = (SyntaxTreeNode[])Hone[1].heirs(); // second heir of second heir - if ( tn.isKind( N_InfixExpr ) && Hone[1].getImage().equals("\\in") ) { - {if (true) throw new ParseException( "Form {a \\in b : c \\in d }, at line " + t.beginLine + ", is not allowed" );} - } - } - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - label_32: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[101] = jj_gen; - break label_32; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - } - break; - case COMMA: - label_33: - while (true) { - t = jj_consume_token(COMMA); - kind = N_SetEnumerate; - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[102] = jj_gen; - break label_33; - } - } - break; - default: - jj_la1[103] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - break; - default: - jj_la1[104] = jj_gen; - ; - } - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } else { - ; - } - t = jj_consume_token(RBC); - if (htn!=null) addHeir(htn); - addHeir( new SyntaxTreeNode(mn, t) ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode SBracketCases() throws ParseException { - SyntaxTreeNode tn; - Token t; - int kind = 0; - bpa("Some [] Form"); - t = jj_consume_token(LSB); - addHeir( new SyntaxTreeNode(mn, t) ); - if (matchFcnConst()) { - // FcnConst - because we use OpSymbol rather than IN, we need to use semantic detection. - tn = QuantBound(); - kind = N_FcnConst; - addHeir( tn ); - label_34: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[105] = jj_gen; - break label_34; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = QuantBound(); - addHeir( tn ); - } - t = jj_consume_token(MAPTO); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - } else if (jj_2_49(2147483647)) { - /* RcdConstructor */ - tn = FieldVal(); - kind = N_RcdConstructor; - addHeir( tn ); - label_35: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[106] = jj_gen; - break label_35; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = FieldVal(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - } else if ((getToken(2).kind == MAPTO) && isFieldNameToken( getToken(1))) { - getToken(1).kind = IDENTIFIER; - tn = FieldVal(); - kind = N_RcdConstructor; - addHeir( tn ); - label_36: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[107] = jj_gen; - break label_36; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = FieldVal(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - } else if (jj_2_50(2147483647)) { - /* SetOfRcds */ - tn = FieldSet(); - kind = N_SetOfRcds; - addHeir( tn ); - label_37: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[108] = jj_gen; - break label_37; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = FieldSet(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - } else if (jj_2_51(1)) { - tn = Expression(); - addHeir( tn ); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - case RSB: - label_38: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[109] = jj_gen; - break label_38; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - kind = N_FcnAppl; - lastOp = FcnOp; - break; - case ARROW: - t = jj_consume_token(ARROW); - // SetOfFcns - kind = N_SetOfFcns; - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - case EXCEPT: - t = jj_consume_token(EXCEPT); - // Except - kind = N_Except; - addHeir( new SyntaxTreeNode(mn, t) ); - tn = ExceptSpec(); - addHeir( tn ); - label_39: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[110] = jj_gen; - break label_39; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = ExceptSpec(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - case ARSB: - t = jj_consume_token(ARSB); - kind = N_ActionExpr; - addHeir( new SyntaxTreeNode(mn, t) ); - tn = ReducedExpression(); - addHeir( tn ); - break; - default: - jj_la1[111] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } else { - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode sn[] = getLastHeirs(); - Assert.assertion(kind !=0); - epa(); {if (true) return new SyntaxTreeNode(mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode FieldVal() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - Token t; - bpa("Field Value"); - zn[0] = Identifier(); - t = jj_consume_token(MAPTO); - zn[1] = new SyntaxTreeNode(mn, t); - zn[2] = Expression(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_FieldVal, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode FieldSet() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - SyntaxTreeNode tn; - Token t; - bpa("Field Set"); - zn[0] = Identifier(); - t = jj_consume_token(COLON); - zn[1] = new SyntaxTreeNode(mn, t); - zn[2] = Expression(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_FieldSet, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ExceptSpec() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Except Spec"); - t = jj_consume_token(BANG); - addHeir( new SyntaxTreeNode(mn, t) ); - label_40: - while (true) { - tn = ExceptComponent(); - addHeir( tn ); - expecting = "= or ,"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOT: - case LSB: - ; - break; - default: - jj_la1[112] = jj_gen; - break label_40; - } - } - t = jj_consume_token(EQUALS); - tn = new SyntaxTreeNode(mn, t); - tn.setKind(T_EQUAL); - addHeir(tn); - tn = Expression(); - addHeir( tn ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_ExceptSpec, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ExceptComponent() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Except Component"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOT: - t = jj_consume_token(DOT); - addHeir( new SyntaxTreeNode(mn, t) ); - /*********************************************************** - * Following added by LL on 10 Oct 2007 to make something * - * like "!.THEN" work right. * - ***********************************************************/ - Token next = getToken(1); - if (isFieldNameToken( next )) next.kind = IDENTIFIER; - tn = Identifier(); - if (tn.getUS().equals(At) ) { - PErrors.push( new ParseError("@ used in !.@") ); - } - addHeir( tn ); - break; - case LSB: - t = jj_consume_token(LSB); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - label_41: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[113] = jj_gen; - break label_41; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - } - t = jj_consume_token(RSB); - addHeir( new SyntaxTreeNode(mn, t) ); - break; - default: - jj_la1[114] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode sn[] = getLastHeirs(); epa(); - {if (true) return new SyntaxTreeNode( mn, N_ExceptComponent, sn );} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* The SetExcept non-terminal was eliminated from the grammar, but not * -* from the parser. * -***************************************************************************/ - final public SyntaxTreeNode SetExcept() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Set Except"); - t = jj_consume_token(LWB); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - t = jj_consume_token(EXCEPT); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = SExceptSpec(); - addHeir( tn ); - label_42: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[115] = jj_gen; - break label_42; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = SExceptSpec(); - addHeir( tn ); - } - t = jj_consume_token(RWB); - addHeir( new SyntaxTreeNode(mn, t) ); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_SetExcept, sn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode SExceptSpec() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[4]; - SyntaxTreeNode tn; - Token t; - bpa("Set Expect Spec"); - t = jj_consume_token(BANG); - zn[0] = new SyntaxTreeNode(mn, t); - zn[1] = ExceptComponent(); - expecting = "= or \\in"; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EQUALS: - t = jj_consume_token(EQUALS); - zn[2] = new SyntaxTreeNode(mn, t); zn[2].setKind( T_EQUAL ); - break; - case IN: - t = jj_consume_token(IN); - zn[2] = new SyntaxTreeNode(mn, t); zn[2].setKind( T_IN ); - break; - default: - jj_la1[116] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - zn[3] = Expression(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_SExceptSpec, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode TupleOrAction() throws ParseException { - int kind = 0; - SyntaxTreeNode tn; - Token t; - bpa("Some << -- >> or >>_ Form"); - t = jj_consume_token(LAB); - addHeir( new SyntaxTreeNode(mn, t) ); - if (jj_2_52(1)) { - tn = Expression(); - addHeir( tn ); - label_43: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[117] = jj_gen; - break label_43; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = Expression(); - addHeir( tn ); - } - } else { - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case RAB: - t = jj_consume_token(RAB); - kind = N_Tuple; addHeir( new SyntaxTreeNode(mn, t) ); - break; - case ARAB: - t = jj_consume_token(ARAB); - kind = N_ActionExpr; addHeir( new SyntaxTreeNode(mn, t) ); - tn = ReducedExpression(); - addHeir( tn ); - break; - default: - jj_la1[118] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, kind, sn );} - throw new Error("Missing return statement in function"); - } - -// new SyntaxTreeNode( N_IdPrefix ) ??? - final public SyntaxTreeNode NoOpExtension() throws ParseException { - SyntaxTreeNode tid, top, last; - last = null; top = null; - Token t = null; - tid = Identifier(); - if (jj_2_53(2)) { - top = OpArgs(); - } else { - ; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case BANG: - t = jj_consume_token(BANG); - SyntaxTreeNode heirs[]; - if ( top == null ) { - heirs = new SyntaxTreeNode[2]; - heirs[1] = new SyntaxTreeNode( mn, t ); - } else { - heirs = new SyntaxTreeNode[3]; - heirs[1] = top; - heirs[2] = new SyntaxTreeNode(mn, t ); - } - heirs[0] = tid; - SyntaxTreeNode current = new SyntaxTreeNode( mn, N_IdPrefixElement, heirs ); - addHeir( current ); - last = NoOpExtension(); - break; - default: - jj_la1[119] = jj_gen; - ; - } - if ( last == null ) { // means no bang, bottom of recursion - if ( top != null ) - FairnessHook = top; - else - FairnessHook = null; - SyntaxTreeNode zn[] = new SyntaxTreeNode[2]; - zn[0] = new SyntaxTreeNode( mn, N_IdPrefix, getLastHeirs() ); - zn[1] = tid; - last = new SyntaxTreeNode( mn, N_GeneralId, zn ); - } - {if (true) return last;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode ReducedExpression() throws ParseException { - /************************************************************************* - * This is an expression that can follow "[...]_" or "<<...>>_". * - *************************************************************************/ - SyntaxTreeNode expr; - bpa("restricted form of expression"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - expr = NoOpExtension(); - break; - case LBR: - expr = ParenExpr(); - break; - case LBC: - expr = BraceCases(); - break; - case LSB: - expr = SBracketCases(); - break; - case LWB: - expr = SetExcept(); - break; - case LAB: - expr = TupleOrAction(); - break; - default: - jj_la1[120] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - epa(); {if (true) return expr;} - throw new Error("Missing return statement in function"); - } - -// The following cases - for the first expression - must be recognized : -// "GeneralId", "OpApplication", "RecordComponent", "FcnAppl", "ParenExpr", "SetEnumerate", "SubsetOf", "SetOfAll", "FcnConst", "SetOfFcns", "RcdConstructor", "SetOfRcds", "Except", "Tuple", "ActionExpr" -// The cases break down in two categories: two set of () or a single one. -// in general, it's going to be some () [] or {} expression, or an Identifier foollowed by . () or []. -// Note that FcnAppl may be more intricate. - final public SyntaxTreeNode FairnessExpr() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[5]; - SyntaxTreeNode tn, expr; - Token t; - FairnessHook = null; - bpa("Fairness Expression"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case WF: - t = jj_consume_token(WF); - break; - case SF: - t = jj_consume_token(SF); - break; - default: - jj_la1[121] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - zn[0] = new SyntaxTreeNode(mn, t); - expr = ReducedExpression(); - if (jj_2_54(2)) { - t = jj_consume_token(LBR); -// ^^^ -// Warning 3 -- Eliminated by LOOKAHEAD - zn[1] = expr; expr = null; - zn[2] = new SyntaxTreeNode(mn, t); - zn[3] = Expression(); - t = jj_consume_token(RBR); - zn[4] = new SyntaxTreeNode(mn, t); - } else { - ; - } - epa(); - if ( expr != null ) { // no extra (), FairnessHook can't be null ** Add check. - if (FairnessHook == null) { - {if (true) throw new ParseException("Ill-structured fairness expression at line " + zn[0].location[0] + ", column " + zn[0].location[1]);} - } - - SyntaxTreeNode parameters[] = (SyntaxTreeNode[]) FairnessHook.heirs(); - if ( parameters != null && parameters.length == 3) { // was FairnessHook - zn[1] = expr; - zn[2] = parameters[0]; - zn[3] = parameters[1]; - zn[4] = parameters[2]; - } else { - PErrors.push( new ParseError("Error in fairness expression at " + zn[0].location[0] + ": " + zn[0].location[1] + "\n", "-- --") ); - {if (true) return expr;} - } -// left for level checking. -// if ( expr.isKind( N_ActionExpr ) ) { -// PErrors.push( new ParseError("Error in fairness expression at " + zn[0].location[0] + ": " + zn[0].location[1] + ": use of an action form\n", "-- --") ); -// return expr; -// } - } else { // reattach FairnessHook ! unless it is tuple -// "GeneralId", "RecordComponent", "FcnAppl", - if ( zn[1].isKind( N_GeneralId ) && FairnessHook != null ) { - SyntaxTreeNode ozn[] = new SyntaxTreeNode[2]; - ozn[0] = zn[1]; - ozn[1] = FairnessHook; - zn[1] = new SyntaxTreeNode( mn, N_OpApplication, ozn ); - } else if ( ! (zn[1].isKind( N_Tuple )|| zn[1].isKind( N_ParenExpr ) || zn[1].isKind( N_SetEnumerate )|| zn[1].isKind( N_SubsetOf )|| zn[1].isKind( N_SetOfAll )|| zn[1].isKind( N_SetOfFcns )|| zn[1].isKind( N_RcdConstructor )|| zn[1].isKind( N_SetOfRcds )|| zn[1].isKind( N_Except )|| zn[1].isKind( N_FcnConst )|| zn[1].isKind( N_ActionExpr )) ){ -// "ParenExpr", "SetEnumerate", "SubsetOf", "SetOfAll", "FcnConst", -// "SetOfFcns", "RcdConstructor", "SetOfRcds", "Except", -// "Tuple", "ActionExpr" - PErrors.push( new ParseError("Error in fairness expression at " + zn[0].location[0] + ": " + zn[0].location[1] + ": could not link arguments\n", "-- --") ); - {if (true) return zn[1];} - } - } - {if (true) return new SyntaxTreeNode( mn, N_FairnessExpr, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode IfThenElse() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[6]; - Token t; - bpa("IF THEN ELSE"); - t = jj_consume_token(IF); - zn[0] = new SyntaxTreeNode(mn, t); - zn[1] = Expression(); - t = jj_consume_token(THEN); - zn[2] = new SyntaxTreeNode(mn, t); - zn[3] = Expression(); - t = jj_consume_token(ELSE); - zn[4] = new SyntaxTreeNode(mn, t); - zn[5] = Expression(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_IfThenElse, zn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Case() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("CASE Expression"); - t = jj_consume_token(CASE); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = CaseArm(); - addHeir( tn ); - label_44: - while (true) { - if (caseSep() && (getToken(2).kind != OTHER)) { - ; - } else { - break label_44; - } - t = jj_consume_token(CASESEP); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = CaseArm(); - addHeir( tn ); - } - if (caseSep()) { - t = jj_consume_token(CASESEP); - addHeir( new SyntaxTreeNode(mn, t) ); - tn = OtherArm(); - addHeir( tn ); - } else { - ; - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_Case, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode CaseArm() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - Token t; - bpa("Case Arm"); - zn[0] = Expression(); - t = jj_consume_token(ARROW); - zn[1] = new SyntaxTreeNode(mn, t); - zn[2] = Expression(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_CaseArm, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode OtherArm() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[3]; - Token t; - bpa("Case Other Arm"); - t = jj_consume_token(OTHER); - zn[0] = new SyntaxTreeNode(mn, t); - t = jj_consume_token(ARROW); - zn[1] = new SyntaxTreeNode(mn, t); - zn[2] = Expression(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_OtherArm, zn );} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* LetIn ::= <LET> LetDefinitions() <LETIN> Expression() * -* * -* It produces a SyntaxTreeNode tn with the four heirs * -* "LET", LetDefinitions, "IN", Expression * -* in tn.zero. * -***************************************************************************/ - final public SyntaxTreeNode LetIn() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[4]; - SyntaxTreeNode tn; - Token t; - bpa("Case Other Arm"); - t = jj_consume_token(LET); - zn[0] = new SyntaxTreeNode(mn, t); - zn[1] = LetDefinitions(); - t = jj_consume_token(LETIN); - zn[2] = new SyntaxTreeNode(mn, t); - zn[3] = Expression(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_LetIn, zn );} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode LetDefinitions() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Let Definitions"); - label_45: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LOCAL: - case DEFBREAK: - tn = OperatorOrFunctionDefinition(); - addHeir( tn ); - break; - case RECURSIVE: - tn = Recursive(); - addHeir( tn ); - break; - default: - jj_la1[122] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LOCAL: - case RECURSIVE: - case DEFBREAK: - ; - break; - default: - jj_la1[123] = jj_gen; - break label_45; - } - } - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode(mn, N_LetDefinitions, sn);} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode Junctions() throws ParseException { - BStack.newReference(getToken(1).endColumn, getToken(1).kind); - /*********************************************************************** - * Pushes onto BStack an element of the appropriate kind with offest * - * equal to the column of the last character in the /\ or \/ token. * - ***********************************************************************/ - - bpa("AND-OR Junction"); - int kind; - if (jj_2_55(2147483647)) { - kind = N_DisjList; - DisjList(); - } else if (jj_2_56(2147483647)) { - kind = N_ConjList; - ConjList(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - BStack.popReference(); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, kind, sn);} - throw new Error("Missing return statement in function"); - } - - final public void DisjList() throws ParseException { - SyntaxTreeNode tn; - tn = JuncItem(N_DisjItem); - addHeir(tn); - label_46: - while (true) { - if (BStack.onReference( getToken(1).endColumn, getToken(1).kind )) { - ; - } else { - break label_46; - } - tn = JuncItem(N_DisjItem); - addHeir(tn); - } - } - - final public void ConjList() throws ParseException { - SyntaxTreeNode tn; - tn = JuncItem(N_ConjItem); - addHeir( tn ); - label_47: - while (true) { - if (BStack.onReference( getToken(1).endColumn, getToken(1).kind )) { - ; - } else { - break label_47; - } - tn = JuncItem(N_ConjItem); - addHeir( tn ); - } - } - - final public SyntaxTreeNode JuncItem(int itemKind) throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[2]; - SyntaxTreeNode tn; - Token t; - bpa("Junction Item"); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OR: - /* t = <BOR> | */ t = jj_consume_token(OR); - break; - case AND: - t = jj_consume_token(AND); - break; - default: - jj_la1[124] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - zn[0] = new SyntaxTreeNode(mn, t); - zn[1] = Expression(); - epa(); - /*********************************************************************** - * Check for indentation errors. * - ***********************************************************************/ - tn = new SyntaxTreeNode( mn, itemKind, zn ); - TreeNode[] children = tn.heirs() ; - for (int i = 1; i < children.length; i++) { - checkIndentation((SyntaxTreeNode) children[i], tn) ; - }; - {if (true) return tn ;} - throw new Error("Missing return statement in function"); - } - - final public SyntaxTreeNode UnboundOrBoundChoose() throws ParseException { - SyntaxTreeNode zn[] = new SyntaxTreeNode[5]; - SyntaxTreeNode tn; - Token t; - bpa("(Un)Bounded Choose"); - t = jj_consume_token(CHOOSE); - zn[0] = new SyntaxTreeNode(mn, t); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - zn[1] = Identifier(); - break; - case LAB: - zn[1] = IdentifierTuple(); - break; - default: - jj_la1[125] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - zn[2] = MaybeBound(); - t = jj_consume_token(COLON); - zn[3] = new SyntaxTreeNode(mn, t); - zn[4] = Expression(); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); {if (true) return new SyntaxTreeNode( mn, N_UnboundOrBoundChoose, zn);} - throw new Error("Missing return statement in function"); - } - -/*************************************************************************** -* Lambda expression added by LL on 27 March 2007 * -* * -* L.Lambda ::= * -* <LAMBDA> * -* (IdentDecl | SomeFixDecl) (<COMMA> (IdentDecl | SomeFixDecl))* * -* <COLON> Expression * -***************************************************************************/ - final public SyntaxTreeNode Lambda() throws ParseException { - SyntaxTreeNode tn; - Token t; - bpa("Lambda"); - t = jj_consume_token(LAMBDA); - addHeir(new SyntaxTreeNode(mn, t)); - expecting = "Identifier"; - tn = Identifier(); - addHeir( tn ); - expecting = "`,' or `:'"; - label_48: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[126] = jj_gen; - break label_48; - } - t = jj_consume_token(COMMA); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "Identifier"; - tn = Identifier(); - addHeir( tn ); - expecting = "`,' or `:'"; - } - t = jj_consume_token(COLON); - addHeir( new SyntaxTreeNode(mn, t) ); - expecting = "Expression"; - tn = Expression(); - addHeir(tn); - SyntaxTreeNode sn[] = getLastHeirs(); - epa(); - {if (true) return new SyntaxTreeNode( mn, N_Lambda, sn);} - throw new Error("Missing return statement in function"); - } - -// boxDisc (riminate) uses preInEmptyTop -// note that junction is processed separately. - final public SyntaxTreeNode Expression() throws ParseException { - SyntaxTreeNode tn, tn0, tn1, tn2; - int kind ; - Token t; - bpa("Expression"); - OperatorStack.newStack(); - label_49: - while (true) { - if (jj_2_57(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - ; - } else { - break label_49; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = PrefixOp(); - kind = N_GenPrefixOp; - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - kind = N_GenInfixOp; - break; - default: - jj_la1[127] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - SyntaxTreeNode[] heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, (SyntaxTreeNode []) null); - heirs[1] = tn ; - OperatorStack.pushOnStack(new SyntaxTreeNode(mn, kind, heirs), lastOp); - if (OperatorStack.size() != 1) {OperatorStack.reduceStack();} ; - /***************************************************************** - * This is probably a no-op since we can't reduce the stack at * - * this point. * - *****************************************************************/ - - } - if (jj_2_58(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = OpenExpression(); - OperatorStack.pushOnStack( tn, null ); - } else if (BStack.aboveReference( getToken(1).beginColumn)) { - ExtendableExpr(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - epa(); - tn = OperatorStack.finalReduce(); - if (tn==null) { - {if (true) throw new ParseException(" Couldn't reduce expression stack.");} - } ; - OperatorStack.popStack(); - {if (true) return tn ;} - throw new Error("Missing return statement in function"); - } - - // Expression - final public void ExtendableExpr() throws ParseException { - SyntaxTreeNode tn, tn0, tn1, tn2; - SyntaxTreeNode[] heirs; - int kind ; - Token t; - bpa("ExtendableExpr") ; - if (jj_2_59(2147483647) && (OperatorStack.preInEmptyTop() - // && BStack.aboveReference( getToken(1).beginColumn) - )) { - tn = Junctions(); - OperatorStack.pushOnStack( tn, null ); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case SF: - case WF: - case LBR: - case LSB: - case LWB: - case LBC: - case LAB: - /************************************************************************ - * ParenthesesExpression * - ************************************************************************/ - tn = ParenthesesExpression(); - OperatorStack.pushOnStack( tn, null ); - break; - default: - jj_la1[128] = jj_gen; - if (jj_2_60(1)) { - /************************************************************************ - * PrimitiveExpression * - ************************************************************************/ - tn = PrimitiveExp(); - OperatorStack.pushOnStack( tn, null ); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - label_50: - while (true) { - if (jj_2_61(1)) { - ; - } else { - break label_50; - } - if (jj_2_62(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = PostfixOp(); - heirs = new SyntaxTreeNode[2]; - heirs[0] = - new SyntaxTreeNode( mn, N_IdPrefix, (SyntaxTreeNode []) null); - heirs[1] = tn ; - OperatorStack.pushOnStack(new SyntaxTreeNode(mn, N_GenPostfixOp, heirs), - lastOp); - if (OperatorStack.size() != 1) {OperatorStack.reduceStack();} ; - } else if (jj_2_63(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - t = jj_consume_token(DOT); - Token next = getToken(1); - if (isFieldNameToken( next )) next.kind = IDENTIFIER; - if (BStack.aboveReference( getToken(1).beginColumn)) { - - } else { - jj_consume_token(-1); - throw new ParseException(); - } - tn = Identifier(); - OperatorStack.reduceRecord( new SyntaxTreeNode(mn, t) , tn ); - } else if (jj_2_64(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - expecting = "function argument"; - tn = SBracketCases(); - if ( isGenOp( tn ) ) { - /******************************************************************* - * In the normal case, tn will be an N_FcnAppl node and * - * isGenOp(tn) will be true. In an error case, isGenOp(tn) should * - * be false, and whatever is returned will presumably not be an * - * operator and pushing it on the stack will produce an error * - * because the stack will have two expressions with no intervening * - * infix operator. * - *******************************************************************/ - OperatorStack.pushOnStack( tn, lastOp ); - if (OperatorStack.size() != 1) {OperatorStack.reduceStack();} ; - } - else {OperatorStack.pushOnStack( tn, null );}; - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - if (jj_2_69(1)) { - if (jj_2_67(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = InfixOp(); - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, (SyntaxTreeNode []) null); - heirs[1] = tn ; - OperatorStack.pushOnStack(new SyntaxTreeNode(mn, N_GenInfixOp, heirs), - lastOp); - if (OperatorStack.size() != 1) {OperatorStack.reduceStack();} ; - label_51: - while (true) { - if (jj_2_65(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - ; - } else { - break label_51; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = PrefixOp(); - kind = N_GenPrefixOp; - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - kind = N_GenInfixOp; - break; - default: - jj_la1[129] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, (SyntaxTreeNode []) null); - heirs[1] = tn ; - OperatorStack.pushOnStack(new SyntaxTreeNode(mn, kind, heirs), lastOp); - if (OperatorStack.size() != 1) {OperatorStack.reduceStack();} ; - /***************************************************************** - * This is probably a no-op since we can't reduce the stack at * - * this point. * - *****************************************************************/ - - } - if (jj_2_66(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = OpenExpression(); - OperatorStack.pushOnStack( tn, null ); - } else if (BStack.aboveReference( getToken(1).beginColumn)) { - ExtendableExpr(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } else if (jj_2_68(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - t = jj_consume_token(COLONCOLON); - tn1 = new SyntaxTreeNode(mn, t) ; - tn0 = OperatorStack.topOfStack().getNode(); - if (! isLabel(tn0)) { - {if (true) throw new ParseException("`::' at " + tn1.getLocation().toString() - + " does not follow a label.") ;} - } ; - OperatorStack.popCurrentTop() ; - // t = <COLONCOLON> - tn2 = Expression(); - if (! labelDoesNotChangeParse(tn2, lastOp)) { - /***************************************************************** - * Note: if tn1 is a prefix, infix, or postfix expression, then * - * I believe (perhaps naively) that lastOp will be its operator. * - *****************************************************************/ - {if (true) throw new ParseException( - "Removing label at " + tn0.getLocation().toString() + - " would change expression parsing.") ;} - } ; - SyntaxTreeNode labelHeirs[] = {tn0, tn1, tn2} ; - tn = new SyntaxTreeNode(N_Label, labelHeirs) ; - OperatorStack.pushOnStack( tn, null ); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } else { - ; - } - epa() ; - } - - // ExtendableExpr - final public SyntaxTreeNode PrimitiveExp() throws ParseException { - SyntaxTreeNode tn, tn0, tn1, tn2; - SyntaxTreeNode tnOpArgs = null ; - SyntaxTreeNode tnBangs[] = null ; - SyntaxTreeNode[] heirs ; - Token t; - bpa("Primitive expression") ; - if (jj_2_72(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = String(); - } else if (jj_2_73(2147483647) && (BStack.aboveReference( getToken(1).beginColumn))) { - tn = Number(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_57: - case op_68: - case op_69: - case op_70: - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - case IDENTIFIER: - case ProofStepLexeme: - case ProofImplicitStepLexeme: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - tn0 = Identifier(); - break; - case ProofStepLexeme: - case ProofImplicitStepLexeme: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case ProofStepLexeme: - t = jj_consume_token(ProofStepLexeme); - break; - case ProofImplicitStepLexeme: - t = jj_consume_token(ProofImplicitStepLexeme); - break; - default: - jj_la1[130] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - tn0 = new SyntaxTreeNode(mn, t); - if ((getProofLevel() < 0) && (proofDepth <= 0)) { - {if (true) throw new - ParseException(tn0.getLocation().toString() + - ": Step number used outside proof.");} - } ; - if (t.image.substring(1,2).equals("+")) { - {if (true) throw new ParseException(tn0.getLocation().toString() + - ": <+> step number used in an expression.");} - } ; - if (t.kind == ProofImplicitStepLexeme) { - tn0.originalImage = tn0.image ; - tn0.image = correctedStepNum(t) ; - } ; - -// ToolIO.out.println("xyz-expr: t.image = " + t.image + -// ", correctedImage = " + tn0.image) ; - - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn0 = InfixOp(); - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn0 = PostfixOp(); - break; - default: - jj_la1[131] = jj_gen; - if (jj_2_70(2147483647)) { - tn0 = NonExpPrefixOp(); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - if (jj_2_71(2)) { - tnOpArgs = OpArgs(); - } else { - ; - } - label_52: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case BANG: - ; - break; - default: - jj_la1[132] = jj_gen; - break label_52; - } - tn1 = BangExt(); - addHeir(tn1) ; - } - tnBangs = getLastHeirs() ; - if (tnBangs == null) { - heirs = new SyntaxTreeNode[2]; - heirs[0] = new SyntaxTreeNode( mn, N_IdPrefix, - new SyntaxTreeNode[0]); - heirs[1] = tn0; - tn1 = new SyntaxTreeNode(mn, N_GeneralId, heirs) ; - if (tnOpArgs == null) {tn = tn1;} - else { heirs = new SyntaxTreeNode[2]; - heirs[0] = tn1 ; - heirs[1] = tnOpArgs ; - tn = new SyntaxTreeNode(mn, N_OpApplication, heirs) ; - } - } // if (tnBangs == null) - else { - /****************************************************************** - * There is a BangExt. The parse tree constructed so far needs * - * to be rearranged to be what is expected of the parser * - * (because the parser was designed for TLA+1). For example, if * - * we're parsing * - * * - * foo(1)!b!c(2,3), so far we have * - * tn0 = foo * - * tnOpArgs = OpArgs[1] * - * tnBangs = IdPrefixElement[! b] * - * IdPrefixElement[! c OpArgs[2, 3]] * - * * - * and we must turn that into * - * * - * OpAppl[ GeneralId[ IdPrefix[IdPrefixElement[foo OpArgs[1] !] * - * IdPrefixElement[b !]] * - * c] * - * OpArgs[2, 3]] * - * * - * Note that the result is an OpAppl node iff the last * - * IdPrefixElement contains an OpArg heir, otherwise it is a * - * GeneralId node. * - ******************************************************************/ - - /****************************************************************** - * We set heirs to the array of IdPrefixElement nodes that are * - * the heirs of the IdPrefix node that is the first heir of the * - * GeneralId node. * - ******************************************************************/ - heirs = new SyntaxTreeNode[tnBangs.length] ; - - /****************************************************************** - * Set eltHeirs to the heirs of heirs[0]. * - ******************************************************************/ - SyntaxTreeNode[] eltHeirs; - if (tnOpArgs == null) { - eltHeirs = new SyntaxTreeNode[2] ; - eltHeirs[0] = tn0 ; - eltHeirs[1] = (SyntaxTreeNode) tnBangs[0].heirs()[0] ; - } - else { - eltHeirs = new SyntaxTreeNode[3] ; - eltHeirs[0] = tn0 ; - eltHeirs[1] = tnOpArgs; - eltHeirs[2] = (SyntaxTreeNode) tnBangs[0].heirs()[0] ; - } ; - heirs[0] = - new SyntaxTreeNode(mn, N_IdPrefixElement, eltHeirs); - for (int i = 0; i < tnBangs.length - 1; i++) { - eltHeirs = - new SyntaxTreeNode[tnBangs[i].heirs().length] ; - for (int j = 0 ; j < eltHeirs.length-1; j++) { - eltHeirs[j] = (SyntaxTreeNode) tnBangs[i].heirs()[j+1]; - } ; - eltHeirs[eltHeirs.length-1] = (SyntaxTreeNode) - tnBangs[i+1].heirs()[0]; - heirs[i+1] = new SyntaxTreeNode(mn, N_IdPrefixElement, eltHeirs); - } // for - TreeNode[] lastBang = tnBangs[tnBangs.length-1].heirs() ; - SyntaxTreeNode[] genIdHeirs = new SyntaxTreeNode[2] ; - genIdHeirs[0] = new SyntaxTreeNode(mn, N_IdPrefix, heirs) ; - genIdHeirs[1] = (SyntaxTreeNode) lastBang[1]; - SyntaxTreeNode genId = - new SyntaxTreeNode(mn, N_GeneralId, genIdHeirs) ; - if (lastBang.length == 2) {tn = genId;} - else { heirs = new SyntaxTreeNode[2] ; - heirs[0] = genId ; - heirs[1] = (SyntaxTreeNode) lastBang[2] ; - tn = new SyntaxTreeNode(mn, N_OpApplication, heirs) ; - } // else - } // else - - break; - default: - jj_la1[133] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - epa() ; - {if (true) return tn;} - throw new Error("Missing return statement in function"); - } - - // PrimitiveExp - final public SyntaxTreeNode BangExt() throws ParseException { - /************************************************************************* - * Returns an N_IdPrefixElement node with 2 or 3 heirs consisting of: * - * - A "!" (<BANG>) token. * - * - An Identifier(), PrefixOp(), InfixOp(), or PostfixOp() node. * - * - An optional OpArgs() node. * - * Note that this is not the kind of N_IdPrefixElement that the parser * - * ultimately produces, which ends with a "!" rather than beginning with * - * one. * - *************************************************************************/ - SyntaxTreeNode tn ; - Token t; - bpa("Bang Extension") ; - t = jj_consume_token(BANG); - addHeir(new SyntaxTreeNode(mn, t)) ; - if (jj_2_76(1)) { - if (jj_2_74(2147483647) && (!getToken(1).image.equals("@"))) { - tn = Identifier(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case op_76: - case op_26: - case op_29: - case op_58: - case CASESEP: - case op_61: - case op_112: - case op_113: - case op_114: - case op_115: - case op_116: - tn = NonExpPrefixOp(); - break; - case op_1: - case AND: - case op_3: - case op_4: - case OR: - case op_6: - case op_7: - case op_8: - case op_9: - case op_10: - case op_11: - case op_12: - case op_13: - case op_14: - case op_15: - case op_16: - case op_17: - case op_18: - case op_19: - case IN: - case op_21: - case op_22: - case op_23: - case op_24: - case op_25: - case op_27: - case op_30: - case op_31: - case op_32: - case op_33: - case op_34: - case op_35: - case op_36: - case op_37: - case op_38: - case op_39: - case op_40: - case op_41: - case op_42: - case op_43: - case op_44: - case op_45: - case op_46: - case op_47: - case op_48: - case op_49: - case op_50: - case op_51: - case op_52: - case op_53: - case op_54: - case op_55: - case op_56: - case op_59: - case op_62: - case op_63: - case op_64: - case EQUALS: - case op_66: - case op_67: - case op_71: - case op_72: - case op_73: - case op_74: - case op_75: - case op_77: - case op_78: - case op_79: - case op_80: - case op_81: - case op_82: - case op_83: - case op_84: - case op_85: - case op_86: - case op_87: - case op_88: - case op_89: - case op_90: - case op_91: - case op_92: - case op_93: - case op_94: - case op_95: - case op_96: - case op_97: - case op_98: - case op_100: - case op_101: - case op_102: - case op_103: - case op_104: - case op_105: - case op_106: - case op_107: - case op_108: - case op_109: - case op_110: - case op_111: - case op_117: - case op_118: - case op_119: - tn = InfixOp(); - break; - case op_57: - case op_68: - case op_69: - case op_70: - tn = PostfixOp(); - break; - default: - jj_la1[134] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - addHeir(tn); - if (jj_2_75(2)) { - tn = OpArgs(); - addHeir(tn) ; - } else { - ; - } - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LBR: - tn = OpArgs(); - addHeir(tn) ; - break; - default: - jj_la1[135] = jj_gen; - if (jj_2_77(1)) { - tn = StructOp(); - addHeir(tn) ; - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - } - tn = new SyntaxTreeNode(mn, N_IdPrefixElement, getLastHeirs()); - epa(); - {if (true) return tn ;} - throw new Error("Missing return statement in function"); - } - - // BangExt - final public SyntaxTreeNode StructOp() throws ParseException { - SyntaxTreeNode tn = null ; - Token t = null; - bpa("StructOp"); - expecting = "`<<' , `>>' , `:' , `@' , or number" ; - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LAB: - t = jj_consume_token(LAB); - break; - case RAB: - t = jj_consume_token(RAB); - break; - case COLON: - t = jj_consume_token(COLON); - break; - case NUMBER_LITERAL: - tn = Number(); - break; - default: - jj_la1[136] = jj_gen; - if (getToken(1).image.equals("@")) { - t = jj_consume_token(IDENTIFIER); - } else { - jj_consume_token(-1); - throw new ParseException(); - } - } - epa() ; - if (tn == null){{if (true) return new SyntaxTreeNode(mn, N_StructOp, t) ;} } - else { if (tn.getKind() == N_Real) { - {if (true) throw new ParseException( - "Illegal structural term at " + - tn.getLocation().toString());} - }; - SyntaxTreeNode[] heirs = new SyntaxTreeNode[1] ; - heirs[0] = tn; - {if (true) return new SyntaxTreeNode(mn, N_StructOp, heirs) ;} } ; - throw new Error("Missing return statement in function"); - } - -// SyntaxTreeNode -// oldExpression() : { -// /************************************************************************* -// * The basic production is * -// * * -// * Expression ::= ( OpenExpression * -// * | (Junctions * -// * | ClosedExpressionOrOp * -// * | <DOT> Identifier * -// * | <COLONCOLON> Expression * -// * )+ * -// * ( OpenExpression )? * -// * ) * -// *************************************************************************/ -// SyntaxTreeNode tn, tn0, tn1, tn2; -// Token t; -// OperatorStack.newStack(); -// } { -// ( -// LOOKAHEAD(OpenStart(), {BStack.aboveReference( getToken(1).beginColumn) } ) -// tn = OpenExpression() { OperatorStack.pushOnStack( tn, null ); } -// | ( LOOKAHEAD( /* <BAND> | <BOR> | */ <AND> | <OR>, -// // ^^^ -// // Warning 4 -- Eliminated in SANY2 -// { OperatorStack.preInEmptyTop() && -// BStack.aboveReference( getToken(1).beginColumn) } ) -// tn = Junctions() { OperatorStack.pushOnStack( tn, null ); } -// | LOOKAHEAD( { ClosedStart(getToken(1)) -// && boxDisc() -// /*************************************************** -// * \equiv * -// * (token is "[]" => it's the temporal operator) * -// ***************************************************/ -// && BStack.aboveReference( -// getToken(1).beginColumn) }) -// tn = ClosedExpressionOrOp() { -// anchor = tn; // XXX is this correct ? Why had it disappered ? -// // This is the only place where anchor is set it seems. -// /***************************************************************** -// * If tn is an operator, push it on the stack and, if it's not * -// * the only thing on the stack, then reduce the stack. * -// * Otherwise, just push it on the stack. * -// *****************************************************************/ -// if ( isGenOp( tn ) ) { -// OperatorStack.pushOnStack( tn, lastOp ); -// if (OperatorStack.size() != 1) -// OperatorStack.reduceStack(); -// // else -// // ToolIO.out.println("size of 1"); -// } else OperatorStack.pushOnStack( tn, null ); -// } -// | -// t = <DOT> { -// Token next = getToken(1); -// if (isFieldNameToken( next )) next.kind = IDENTIFIER; -// } -// tn = Identifier() -// { OperatorStack.reduceRecord( new SyntaxTreeNode(mn, t) , tn ); } -// | -// t = <COLONCOLON> { -// tn1 = new SyntaxTreeNode(mn, t) ; -// tn0 = OperatorStack.topOfStack().getNode(); -// if (! isLabel(tn0)) { -// throw new ParseException("`::' at " + tn1.getLocation().toString() -// + " does not follow a label.") ; -// } ; -// OperatorStack.popCurrentTop() ; -// } // t = <COLONCOLON> -// tn2 = Expression() { -// // String str = "null" ; -// // if (lastOp != null) { str = lastOp.toString(); } ; -// // ToolIO.out.println("lastOp after parsing labeled expression is: " + str); -// if (! labelDoesNotChangeParse(tn2, lastOp)) { -// /***************************************************************** -// * Note: if tn1 is a prefix, infix, or postfix expression, then * -// * I believe (perhaps naively) that lastOp will be its operator. * -// *****************************************************************/ -// throw new ParseException( -// "Removing label at " + tn0.getLocation().toString() + -// " would change expression parsing.") ; -// } ; -// SyntaxTreeNode labelHeirs[] = {tn0, tn1, tn2} ; -// tn = new SyntaxTreeNode(N_Label, labelHeirs) ; -// OperatorStack.pushOnStack( tn, null ); -// } -// )+ -// [ LOOKAHEAD( OpenStart(), {BStack.aboveReference( getToken(1).beginColumn) } ) -// tn = OpenExpression() { OperatorStack.pushOnStack( tn, null ); } ] -// ) -// { tn = OperatorStack.finalReduce(); -// if (tn==null) throw new ParseException( " Couldn't reduce expression stack."); -// OperatorStack.popStack(); -// return tn; } -// } // Expression() - -/* Obsolete -void -ClosedStart() : { -}{ - <IDENTIFIER> | <STRING_LITERAL> | <NUMBER_LITERAL> | <LBR> | <LSB> | <LAB> | <LBC> | <LWB> | <OpSymbol> | <OR> | <AND> | <WF> | <SF> -} -*/ - final public void OpenStart() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case CASE: - jj_consume_token(CASE); - break; - case CHOOSE: - jj_consume_token(CHOOSE); - break; - case EXISTS: - jj_consume_token(EXISTS); - break; - case FORALL: - jj_consume_token(FORALL); - break; - case IF: - jj_consume_token(IF); - break; - case LET: - jj_consume_token(LET); - break; - case T_EXISTS: - jj_consume_token(T_EXISTS); - break; - case T_FORALL: - jj_consume_token(T_FORALL); - break; - default: - jj_la1[137] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - - final private boolean jj_2_1(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_1(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(0, xla); } - } - - final private boolean jj_2_2(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_2(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(1, xla); } - } - - final private boolean jj_2_3(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_3(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(2, xla); } - } - - final private boolean jj_2_4(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_4(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(3, xla); } - } - - final private boolean jj_2_5(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_5(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(4, xla); } - } - - final private boolean jj_2_6(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_6(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(5, xla); } - } - - final private boolean jj_2_7(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_7(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(6, xla); } - } - - final private boolean jj_2_8(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_8(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(7, xla); } - } - - final private boolean jj_2_9(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_9(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(8, xla); } - } - - final private boolean jj_2_10(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_10(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(9, xla); } - } - - final private boolean jj_2_11(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_11(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(10, xla); } - } - - final private boolean jj_2_12(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_12(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(11, xla); } - } - - final private boolean jj_2_13(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_13(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(12, xla); } - } - - final private boolean jj_2_14(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_14(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(13, xla); } - } - - final private boolean jj_2_15(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_15(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(14, xla); } - } - - final private boolean jj_2_16(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_16(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(15, xla); } - } - - final private boolean jj_2_17(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_17(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(16, xla); } - } - - final private boolean jj_2_18(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_18(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(17, xla); } - } - - final private boolean jj_2_19(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_19(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(18, xla); } - } - - final private boolean jj_2_20(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_20(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(19, xla); } - } - - final private boolean jj_2_21(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_21(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(20, xla); } - } - - final private boolean jj_2_22(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_22(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(21, xla); } - } - - final private boolean jj_2_23(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_23(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(22, xla); } - } - - final private boolean jj_2_24(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_24(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(23, xla); } - } - - final private boolean jj_2_25(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_25(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(24, xla); } - } - - final private boolean jj_2_26(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_26(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(25, xla); } - } - - final private boolean jj_2_27(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_27(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(26, xla); } - } - - final private boolean jj_2_28(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_28(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(27, xla); } - } - - final private boolean jj_2_29(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_29(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(28, xla); } - } - - final private boolean jj_2_30(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_30(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(29, xla); } - } - - final private boolean jj_2_31(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_31(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(30, xla); } - } - - final private boolean jj_2_32(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_32(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(31, xla); } - } - - final private boolean jj_2_33(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_33(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(32, xla); } - } - - final private boolean jj_2_34(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_34(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(33, xla); } - } - - final private boolean jj_2_35(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_35(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(34, xla); } - } - - final private boolean jj_2_36(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_36(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(35, xla); } - } - - final private boolean jj_2_37(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_37(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(36, xla); } - } - - final private boolean jj_2_38(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_38(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(37, xla); } - } - - final private boolean jj_2_39(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_39(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(38, xla); } - } - - final private boolean jj_2_40(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_40(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(39, xla); } - } - - final private boolean jj_2_41(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_41(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(40, xla); } - } - - final private boolean jj_2_42(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_42(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(41, xla); } - } - - final private boolean jj_2_43(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_43(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(42, xla); } - } - - final private boolean jj_2_44(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_44(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(43, xla); } - } - - final private boolean jj_2_45(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_45(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(44, xla); } - } - - final private boolean jj_2_46(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_46(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(45, xla); } - } - - final private boolean jj_2_47(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_47(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(46, xla); } - } - - final private boolean jj_2_48(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_48(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(47, xla); } - } - - final private boolean jj_2_49(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_49(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(48, xla); } - } - - final private boolean jj_2_50(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_50(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(49, xla); } - } - - final private boolean jj_2_51(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_51(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(50, xla); } - } - - final private boolean jj_2_52(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_52(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(51, xla); } - } - - final private boolean jj_2_53(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_53(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(52, xla); } - } - - final private boolean jj_2_54(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_54(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(53, xla); } - } - - final private boolean jj_2_55(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_55(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(54, xla); } - } - - final private boolean jj_2_56(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_56(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(55, xla); } - } - - final private boolean jj_2_57(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_57(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(56, xla); } - } - - final private boolean jj_2_58(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_58(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(57, xla); } - } - - final private boolean jj_2_59(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_59(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(58, xla); } - } - - final private boolean jj_2_60(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_60(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(59, xla); } - } - - final private boolean jj_2_61(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_61(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(60, xla); } - } - - final private boolean jj_2_62(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_62(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(61, xla); } - } - - final private boolean jj_2_63(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_63(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(62, xla); } - } - - final private boolean jj_2_64(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_64(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(63, xla); } - } - - final private boolean jj_2_65(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_65(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(64, xla); } - } - - final private boolean jj_2_66(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_66(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(65, xla); } - } - - final private boolean jj_2_67(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_67(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(66, xla); } - } - - final private boolean jj_2_68(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_68(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(67, xla); } - } - - final private boolean jj_2_69(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_69(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(68, xla); } - } - - final private boolean jj_2_70(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_70(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(69, xla); } - } - - final private boolean jj_2_71(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_71(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(70, xla); } - } - - final private boolean jj_2_72(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_72(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(71, xla); } - } - - final private boolean jj_2_73(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_73(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(72, xla); } - } - - final private boolean jj_2_74(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_74(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(73, xla); } - } - - final private boolean jj_2_75(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_75(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(74, xla); } - } - - final private boolean jj_2_76(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_76(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(75, xla); } - } - - final private boolean jj_2_77(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_77(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(76, xla); } - } - - final private boolean jj_3R_93() { - if (jj_3R_63()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_292()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3_15() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(93)) jj_scanpos = xsp; - if (jj_3R_67()) return true; - if (jj_scan_token(DEF)) return true; - return false; - } - - final private boolean jj_3R_312() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_61() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(39)) { - jj_scanpos = xsp; - if (jj_scan_token(38)) return true; - } - xsp = jj_scanpos; - if (jj_3_15()) jj_scanpos = xsp; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_304() { - Token xsp; - if (jj_3R_312()) return true; - while (true) { - xsp = jj_scanpos; - if (jj_3R_312()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3_68() { - if (jj_scan_token(COLONCOLON)) return true; - return false; - } - - final private boolean jj_3R_303() { - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_291() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_303()) { - jj_scanpos = xsp; - if (jj_3R_304()) return true; - } - return false; - } - - final private boolean jj_3R_84() { - if (jj_scan_token(COMMA)) return true; - if (jj_scan_token(IDENTIFIER)) return true; - return false; - } - - final private boolean jj_3_66() { - if (jj_3R_97()) return true; - return false; - } - - final private boolean jj_3R_67() { - if (jj_scan_token(IDENTIFIER)) return true; - return false; - } - - final private boolean jj_3R_106() { - if (jj_scan_token(COLONCOLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_148() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_261() { - if (jj_3R_169()) return true; - return false; - } - - final private boolean jj_3R_260() { - if (jj_3R_168()) return true; - return false; - } - - final private boolean jj_3_37() { - if (jj_scan_token(IDENTIFIER)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_84()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(COLON)) return true; - return false; - } - - final private boolean jj_3R_102() { - if (jj_3R_64()) return true; - return false; - } - - final private boolean jj_3R_103() { - if (jj_3R_150()) return true; - return false; - } - - final private boolean jj_3_65() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_103()) { - jj_scanpos = xsp; - if (jj_scan_token(192)) return true; - } - return false; - } - - final private boolean jj_3R_267() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_104() { - if (jj_3R_65()) return true; - return false; - } - - final private boolean jj_3R_266() { - if (jj_3R_182()) return true; - return false; - } - - final private boolean jj_3_67() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_259() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_266()) { - jj_scanpos = xsp; - if (jj_3R_267()) return true; - } - return false; - } - - final private boolean jj_3R_147() { - if (jj_3R_146()) return true; - return false; - } - - final private boolean jj_3R_155() { - if (jj_3R_145()) return true; - return false; - } - - final private boolean jj_3R_92() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_147()) { - jj_scanpos = xsp; - if (jj_3R_148()) return true; - } - if (jj_scan_token(IN)) return true; - if (jj_3R_63()) return true; - xsp = jj_scanpos; - if (jj_3R_291()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3_48() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = matchFcnConst(); - lookingAhead = false; - if (!jj_semLA || jj_3R_92()) { - jj_scanpos = xsp; - if (jj_3R_93()) { - jj_scanpos = xsp; - if (jj_3R_94()) { - jj_scanpos = xsp; - if (jj_3_47()) return true; - } - } - } - return false; - } - - final private boolean jj_3R_218() { - if (jj_scan_token(LBC)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_48()) jj_scanpos = xsp; - if (jj_scan_token(RBC)) return true; - return false; - } - - final private boolean jj_3R_105() { - if (jj_3R_104()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_259()) { jj_scanpos = xsp; break; } - } - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_260()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_261()) return true; - } - return false; - } - - final private boolean jj_3_69() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_105()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_106()) return true; - } - return false; - } - - final private boolean jj_3R_182() { - if (jj_3R_150()) return true; - return false; - } - - final private boolean jj_3R_65() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(127)) { - jj_scanpos = xsp; - if (jj_scan_token(128)) { - jj_scanpos = xsp; - if (jj_scan_token(129)) { - jj_scanpos = xsp; - if (jj_scan_token(130)) { - jj_scanpos = xsp; - if (jj_scan_token(131)) { - jj_scanpos = xsp; - if (jj_scan_token(132)) { - jj_scanpos = xsp; - if (jj_scan_token(133)) { - jj_scanpos = xsp; - if (jj_scan_token(134)) { - jj_scanpos = xsp; - if (jj_scan_token(135)) { - jj_scanpos = xsp; - if (jj_scan_token(136)) { - jj_scanpos = xsp; - if (jj_scan_token(137)) { - jj_scanpos = xsp; - if (jj_scan_token(138)) { - jj_scanpos = xsp; - if (jj_scan_token(139)) { - jj_scanpos = xsp; - if (jj_scan_token(140)) { - jj_scanpos = xsp; - if (jj_scan_token(141)) { - jj_scanpos = xsp; - if (jj_scan_token(142)) { - jj_scanpos = xsp; - if (jj_scan_token(143)) { - jj_scanpos = xsp; - if (jj_scan_token(144)) { - jj_scanpos = xsp; - if (jj_scan_token(145)) { - jj_scanpos = xsp; - if (jj_scan_token(146)) { - jj_scanpos = xsp; - if (jj_scan_token(147)) { - jj_scanpos = xsp; - if (jj_scan_token(148)) { - jj_scanpos = xsp; - if (jj_scan_token(149)) { - jj_scanpos = xsp; - if (jj_scan_token(150)) { - jj_scanpos = xsp; - if (jj_scan_token(151)) { - jj_scanpos = xsp; - if (jj_scan_token(152)) { - jj_scanpos = xsp; - if (jj_scan_token(153)) { - jj_scanpos = xsp; - if (jj_scan_token(154)) { - jj_scanpos = xsp; - if (jj_scan_token(155)) { - jj_scanpos = xsp; - if (jj_scan_token(156)) { - jj_scanpos = xsp; - if (jj_scan_token(157)) { - jj_scanpos = xsp; - if (jj_scan_token(158)) { - jj_scanpos = xsp; - if (jj_scan_token(159)) { - jj_scanpos = xsp; - if (jj_scan_token(160)) { - jj_scanpos = xsp; - if (jj_scan_token(161)) { - jj_scanpos = xsp; - if (jj_scan_token(162)) { - jj_scanpos = xsp; - if (jj_scan_token(163)) { - jj_scanpos = xsp; - if (jj_scan_token(164)) { - jj_scanpos = xsp; - if (jj_scan_token(165)) { - jj_scanpos = xsp; - if (jj_scan_token(166)) { - jj_scanpos = xsp; - if (jj_scan_token(167)) { - jj_scanpos = xsp; - if (jj_scan_token(168)) { - jj_scanpos = xsp; - if (jj_scan_token(169)) { - jj_scanpos = xsp; - if (jj_scan_token(170)) { - jj_scanpos = xsp; - if (jj_scan_token(171)) { - jj_scanpos = xsp; - if (jj_scan_token(172)) { - jj_scanpos = xsp; - if (jj_scan_token(173)) { - jj_scanpos = xsp; - if (jj_scan_token(174)) { - jj_scanpos = xsp; - if (jj_scan_token(175)) { - jj_scanpos = xsp; - if (jj_scan_token(176)) { - jj_scanpos = xsp; - if (jj_scan_token(177)) { - jj_scanpos = xsp; - if (jj_scan_token(178)) { - jj_scanpos = xsp; - if (jj_scan_token(179)) { - jj_scanpos = xsp; - if (jj_scan_token(180)) { - jj_scanpos = xsp; - if (jj_scan_token(181)) { - jj_scanpos = xsp; - if (jj_scan_token(182)) { - jj_scanpos = xsp; - if (jj_scan_token(183)) { - jj_scanpos = xsp; - if (jj_scan_token(184)) { - jj_scanpos = xsp; - if (jj_scan_token(185)) { - jj_scanpos = xsp; - if (jj_scan_token(186)) { - jj_scanpos = xsp; - if (jj_scan_token(187)) { - jj_scanpos = xsp; - if (jj_scan_token(188)) { - jj_scanpos = xsp; - if (jj_scan_token(189)) { - jj_scanpos = xsp; - if (jj_scan_token(190)) { - jj_scanpos = xsp; - if (jj_scan_token(191)) { - jj_scanpos = xsp; - if (jj_scan_token(192)) { - jj_scanpos = xsp; - if (jj_scan_token(193)) { - jj_scanpos = xsp; - if (jj_scan_token(194)) { - jj_scanpos = xsp; - if (jj_scan_token(195)) { - jj_scanpos = xsp; - if (jj_scan_token(196)) { - jj_scanpos = xsp; - if (jj_scan_token(197)) { - jj_scanpos = xsp; - if (jj_scan_token(198)) { - jj_scanpos = xsp; - if (jj_scan_token(199)) { - jj_scanpos = xsp; - if (jj_scan_token(200)) { - jj_scanpos = xsp; - if (jj_scan_token(201)) { - jj_scanpos = xsp; - if (jj_scan_token(202)) { - jj_scanpos = xsp; - if (jj_scan_token(203)) { - jj_scanpos = xsp; - if (jj_scan_token(204)) { - jj_scanpos = xsp; - if (jj_scan_token(205)) { - jj_scanpos = xsp; - if (jj_scan_token(206)) { - jj_scanpos = xsp; - if (jj_scan_token(207)) { - jj_scanpos = xsp; - if (jj_scan_token(208)) { - jj_scanpos = xsp; - if (jj_scan_token(209)) { - jj_scanpos = xsp; - if (jj_scan_token(210)) { - jj_scanpos = xsp; - if (jj_scan_token(211)) { - jj_scanpos = xsp; - if (jj_scan_token(212)) { - jj_scanpos = xsp; - if (jj_scan_token(213)) { - jj_scanpos = xsp; - if (jj_scan_token(214)) { - jj_scanpos = xsp; - if (jj_scan_token(215)) { - jj_scanpos = xsp; - if (jj_scan_token(216)) { - jj_scanpos = xsp; - if (jj_scan_token(217)) { - jj_scanpos = xsp; - if (jj_scan_token(218)) { - jj_scanpos = xsp; - if (jj_scan_token(219)) { - jj_scanpos = xsp; - if (jj_scan_token(220)) { - jj_scanpos = xsp; - if (jj_scan_token(221)) { - jj_scanpos = xsp; - if (jj_scan_token(222)) { - jj_scanpos = xsp; - if (jj_scan_token(223)) { - jj_scanpos = xsp; - if (jj_scan_token(224)) { - jj_scanpos = xsp; - if (jj_scan_token(225)) { - jj_scanpos = xsp; - if (jj_scan_token(226)) { - jj_scanpos = xsp; - if (jj_scan_token(227)) { - jj_scanpos = xsp; - if (jj_scan_token(228)) return true; - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3_64() { - if (jj_scan_token(LSB)) return true; - return false; - } - - final private boolean jj_3R_280() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3_13() { - if (jj_scan_token(op_76)) return true; - return false; - } - - final private boolean jj_3_63() { - if (jj_scan_token(DOT)) return true; - return false; - } - - final private boolean jj_3R_143() { - if (jj_scan_token(COMMA)) return true; - if (jj_scan_token(IDENTIFIER)) return true; - return false; - } - - final private boolean jj_3R_101() { - if (jj_3R_154()) return true; - return false; - } - - final private boolean jj_3R_145() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(117)) { - jj_scanpos = xsp; - if (jj_scan_token(118)) { - jj_scanpos = xsp; - if (jj_scan_token(119)) { - jj_scanpos = xsp; - if (jj_scan_token(120)) { - jj_scanpos = xsp; - if (jj_scan_token(121)) { - jj_scanpos = xsp; - if (jj_scan_token(116)) { - jj_scanpos = xsp; - if (jj_scan_token(122)) { - jj_scanpos = xsp; - if (jj_scan_token(123)) { - jj_scanpos = xsp; - if (jj_scan_token(124)) { - jj_scanpos = xsp; - if (jj_scan_token(125)) { - jj_scanpos = xsp; - if (jj_scan_token(126)) return true; - } - } - } - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3R_258() { - return false; - } - - final private boolean jj_3R_234() { - if (jj_3R_67()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_280()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3_14() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_233() { - if (jj_3R_146()) return true; - return false; - } - - final private boolean jj_3R_230() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_233()) { - jj_scanpos = xsp; - if (jj_3R_234()) return true; - } - if (jj_scan_token(IN)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_62() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_100() { - if (jj_scan_token(DOT)) return true; - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_258()) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_83() { - if (jj_scan_token(IDENTIFIER)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_143()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(IN)) return true; - return false; - } - - final private boolean jj_3_36() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_83()) { - jj_scanpos = xsp; - if (jj_scan_token(101)) return true; - } - return false; - } - - final private boolean jj_3R_99() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3_61() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_99()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_100()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_101()) return true; - } - } - return false; - } - - final private boolean jj_3R_254() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3_60() { - if (jj_3R_98()) return true; - return false; - } - - final private boolean jj_3R_150() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(117)) { - jj_scanpos = xsp; - if (jj_scan_token(118)) { - jj_scanpos = xsp; - if (jj_scan_token(119)) { - jj_scanpos = xsp; - if (jj_scan_token(120)) { - jj_scanpos = xsp; - if (jj_scan_token(121)) { - jj_scanpos = xsp; - if (jj_scan_token(122)) { - jj_scanpos = xsp; - if (jj_scan_token(123)) { - jj_scanpos = xsp; - if (jj_scan_token(124)) { - jj_scanpos = xsp; - if (jj_scan_token(125)) { - jj_scanpos = xsp; - if (jj_scan_token(126)) return true; - } - } - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3R_89() { - if (jj_scan_token(COMMA)) return true; - if (jj_scan_token(IDENTIFIER)) return true; - return false; - } - - final private boolean jj_3R_196() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(58)) { - jj_scanpos = xsp; - if (jj_scan_token(59)) return true; - } - if (jj_3R_67()) return true; - while (true) { - xsp = jj_scanpos; - if (jj_3R_254()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_190() { - if (jj_3R_202()) return true; - return false; - } - - final private boolean jj_3_59() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(128)) { - jj_scanpos = xsp; - if (jj_scan_token(131)) return true; - } - return false; - } - - final private boolean jj_3R_189() { - if (jj_3R_201()) return true; - return false; - } - - final private boolean jj_3R_263() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_230()) return true; - return false; - } - - final private boolean jj_3_44() { - if (jj_scan_token(IDENTIFIER)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_89()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(COLON)) return true; - return false; - } - - final private boolean jj_3R_169() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = OperatorStack.preInEmptyTop(); - lookingAhead = false; - if (!jj_semLA || jj_3R_189()) { - jj_scanpos = xsp; - if (jj_3R_190()) { - jj_scanpos = xsp; - if (jj_3_60()) return true; - } - } - while (true) { - xsp = jj_scanpos; - if (jj_3_61()) { jj_scanpos = xsp; break; } - } - xsp = jj_scanpos; - if (jj_3_69()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_262() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_224() { - if (jj_3R_230()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_263()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_223() { - if (jj_3R_67()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_262()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_195() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(45)) { - jj_scanpos = xsp; - if (jj_scan_token(47)) return true; - } - xsp = jj_scanpos; - if (jj_3R_223()) { - jj_scanpos = xsp; - if (jj_3R_224()) return true; - } - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_58() { - if (jj_3R_97()) return true; - return false; - } - - final private boolean jj_3R_132() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_131() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_130() { - if (jj_3R_155()) return true; - return false; - } - - final private boolean jj_3R_128() { - if (jj_3R_169()) return true; - return false; - } - - final private boolean jj_3_35() { - if (jj_3R_59()) return true; - return false; - } - - final private boolean jj_3R_127() { - if (jj_3R_168()) return true; - return false; - } - - final private boolean jj_3R_129() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_217() { - if (jj_scan_token(LBR)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3R_66() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_129()) { - jj_scanpos = xsp; - if (jj_3R_130()) { - jj_scanpos = xsp; - if (jj_3R_131()) { - jj_scanpos = xsp; - if (jj_3R_132()) return true; - } - } - } - if (jj_scan_token(SUBSTITUTE)) return true; - if (jj_3R_174()) return true; - return false; - } - - final private boolean jj_3R_96() { - if (jj_3R_150()) return true; - return false; - } - - final private boolean jj_3_57() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_96()) { - jj_scanpos = xsp; - if (jj_scan_token(192)) return true; - } - return false; - } - - final private boolean jj_3R_167() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_166() { - if (jj_3R_182()) return true; - return false; - } - - final private boolean jj_3R_126() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_166()) { - jj_scanpos = xsp; - if (jj_3R_167()) return true; - } - return false; - } - - final private boolean jj_3R_63() { - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_126()) { jj_scanpos = xsp; break; } - } - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_127()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_128()) return true; - } - return false; - } - - final private boolean jj_3_34() { - if (jj_3R_82()) return true; - return false; - } - - final private boolean jj_3_12() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_66()) return true; - return false; - } - - final private boolean jj_3R_318() { - if (jj_scan_token(WITH)) return true; - if (jj_3R_66()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3_12()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_229() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_206() { - if (jj_scan_token(LAMBDA)) return true; - if (jj_3R_67()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_229()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_125() { - if (jj_scan_token(INSTANCE)) return true; - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_318()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_88() { - if (jj_3R_64()) return true; - return false; - } - - final private boolean jj_3R_124() { - if (jj_scan_token(LOCAL)) return true; - return false; - } - - final private boolean jj_3R_60() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_124()) jj_scanpos = xsp; - if (jj_3R_125()) return true; - return false; - } - - final private boolean jj_3R_149() { - if (jj_3R_174()) return true; - return false; - } - - final private boolean jj_3R_228() { - if (jj_3R_146()) return true; - return false; - } - - final private boolean jj_3R_227() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_87() { - if (jj_3R_65()) return true; - return false; - } - - final private boolean jj_3R_324() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_200() { - if (jj_scan_token(CHOOSE)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_227()) { - jj_scanpos = xsp; - if (jj_3R_228()) return true; - } - if (jj_3R_257()) return true; - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_42() { - if (jj_scan_token(LAMBDA)) return true; - return false; - } - - final private boolean jj_3_43() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_323() { - if (jj_3R_104()) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_139() { - if (jj_3R_140()) return true; - return false; - } - - final private boolean jj_3R_194() { - if (jj_3R_206()) return true; - return false; - } - - final private boolean jj_3R_205() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_171() { - if (jj_scan_token(US)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_323()) { - jj_scanpos = xsp; - if (jj_3R_324()) return true; - } - return false; - } - - final private boolean jj_3R_170() { - if (jj_3R_155()) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_86() { - if (jj_3R_145()) return true; - return false; - } - - final private boolean jj_3_41() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_86()) { - jj_scanpos = xsp; - if (jj_3R_87()) { - jj_scanpos = xsp; - if (jj_3R_88()) return true; - } - } - xsp = jj_scanpos; - if (jj_scan_token(85)) { - jj_scanpos = xsp; - if (jj_scan_token(92)) { - jj_scanpos = xsp; - if (jj_scan_token(93)) { - jj_scanpos = xsp; - if (jj_scan_token(52)) { - jj_scanpos = xsp; - if (jj_scan_token(49)) { - jj_scanpos = xsp; - if (jj_scan_token(65)) { - jj_scanpos = xsp; - if (jj_scan_token(38)) { - jj_scanpos = xsp; - if (jj_scan_token(36)) { - jj_scanpos = xsp; - if (jj_scan_token(35)) { - jj_scanpos = xsp; - if (jj_scan_token(34)) { - jj_scanpos = xsp; - if (jj_scan_token(39)) { - jj_scanpos = xsp; - if (jj_scan_token(42)) { - jj_scanpos = xsp; - if (jj_scan_token(82)) { - jj_scanpos = xsp; - if (jj_scan_token(76)) return true; - } - } - } - } - } - } - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3R_204() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_134() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_170()) { - jj_scanpos = xsp; - if (jj_3R_171()) return true; - } - return false; - } - - final private boolean jj_3R_222() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(131)) { - jj_scanpos = xsp; - if (jj_scan_token(128)) return true; - } - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_203() { - if (jj_3R_155()) return true; - return false; - } - - final private boolean jj_3_56() { - if (jj_scan_token(AND)) return true; - return false; - } - - final private boolean jj_3R_193() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_203()) { - jj_scanpos = xsp; - if (jj_3R_204()) { - jj_scanpos = xsp; - if (jj_3R_205()) return true; - } - } - return false; - } - - final private boolean jj_3R_269() { - if (jj_3R_222()) return true; - return false; - } - - final private boolean jj_3_55() { - if (jj_scan_token(OR)) return true; - return false; - } - - final private boolean jj_3R_174() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_193()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_194()) { - jj_scanpos = xsp; - if (jj_3_43()) return true; - } - } - return false; - } - - final private boolean jj_3R_216() { - if (jj_3R_222()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_269()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_322() { - if (jj_scan_token(COMMA)) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_268() { - if (jj_3R_222()) return true; - return false; - } - - final private boolean jj_3R_133() { - if (jj_scan_token(LBR)) return true; - if (jj_scan_token(US)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_322()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3R_215() { - if (jj_3R_222()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_268()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_68() { - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_133()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_208() { - if (jj_3R_216()) return true; - return false; - } - - final private boolean jj_3R_207() { - if (jj_3R_215()) return true; - return false; - } - - final private boolean jj_3R_201() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_207()) { - jj_scanpos = xsp; - if (jj_3R_208()) return true; - } - return false; - } - - final private boolean jj_3R_162() { - if (jj_3R_67()) return true; - if (jj_3R_64()) return true; - return false; - } - - final private boolean jj_3R_80() { - if (jj_3R_140()) return true; - return false; - } - - final private boolean jj_3R_236() { - if (jj_3R_115()) return true; - return false; - } - - final private boolean jj_3R_163() { - if (jj_3R_67()) return true; - if (jj_3R_65()) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_235() { - if (jj_3R_59()) return true; - return false; - } - - final private boolean jj_3R_231() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_235()) { - jj_scanpos = xsp; - if (jj_3R_236()) return true; - } - return false; - } - - final private boolean jj_3R_321() { - if (jj_3R_134()) return true; - return false; - } - - final private boolean jj_3R_226() { - Token xsp; - if (jj_3R_231()) return true; - while (true) { - xsp = jj_scanpos; - if (jj_3R_231()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_316() { - if (jj_3R_134()) return true; - return false; - } - - final private boolean jj_3R_140() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(232)) { - jj_scanpos = xsp; - if (jj_scan_token(233)) { - jj_scanpos = xsp; - if (jj_scan_token(234)) { - jj_scanpos = xsp; - if (jj_scan_token(235)) { - jj_scanpos = xsp; - if (jj_scan_token(236)) return true; - } - } - } - } - return false; - } - - final private boolean jj_3R_165() { - if (jj_3R_145()) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_199() { - if (jj_scan_token(LET)) return true; - if (jj_3R_226()) return true; - if (jj_scan_token(LETIN)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_320() { - if (jj_3R_68()) return true; - return false; - } - - final private boolean jj_3_33() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_317() { - if (jj_scan_token(COMMA)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_320()) { - jj_scanpos = xsp; - if (jj_3R_321()) return true; - } - return false; - } - - final private boolean jj_3R_315() { - if (jj_3R_68()) return true; - return false; - } - - final private boolean jj_3R_309() { - if (jj_scan_token(LBR)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_315()) { - jj_scanpos = xsp; - if (jj_3R_316()) return true; - } - while (true) { - xsp = jj_scanpos; - if (jj_3R_317()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3_32() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_264() { - if (jj_scan_token(OTHER)) return true; - if (jj_scan_token(ARROW)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_164() { - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_309()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3_30() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_225() { - if (jj_3R_63()) return true; - if (jj_scan_token(ARROW)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_192() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3_29() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_81() { - if (jj_scan_token(MODULE)) return true; - return false; - } - - final private boolean jj_3R_191() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_149()) return true; - return false; - } - - final private boolean jj_3R_173() { - if (jj_3R_67()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_192()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3_31() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_81()) { - jj_scanpos = xsp; - if (jj_3_29()) return true; - } - return false; - } - - final private boolean jj_3R_146() { - if (jj_scan_token(LAB)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_173()) jj_scanpos = xsp; - if (jj_scan_token(RAB)) return true; - return false; - } - - final private boolean jj_3R_95() { - if (jj_scan_token(LBR)) return true; - if (jj_3R_149()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_191()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3R_161() { - if (jj_scan_token(HIDE)) return true; - return false; - } - - final private boolean jj_3R_256() { - if (jj_scan_token(CASESEP)) return true; - if (jj_3R_264()) return true; - return false; - } - - final private boolean jj_3R_255() { - if (jj_scan_token(CASESEP)) return true; - if (jj_3R_225()) return true; - return false; - } - - final private boolean jj_3R_160() { - if (jj_scan_token(USE)) return true; - return false; - } - - final private boolean jj_3R_181() { - if (jj_scan_token(PROOF)) return true; - return false; - } - - final private boolean jj_3R_198() { - if (jj_scan_token(CASE)) return true; - if (jj_3R_225()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_255()) { jj_scanpos = xsp; break; } - } - xsp = jj_scanpos; - if (jj_3R_256()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_159() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_181()) jj_scanpos = xsp; - if (jj_scan_token(BY)) return true; - return false; - } - - final private boolean jj_3R_117() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_159()) { - jj_scanpos = xsp; - if (jj_3R_160()) { - jj_scanpos = xsp; - if (jj_3R_161()) return true; - } - } - return false; - } - - final private boolean jj_3_11() { - if (jj_scan_token(IDENTIFIER)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(91)) { - jj_scanpos = xsp; - if (jj_scan_token(90)) return true; - } - return false; - } - - final private boolean jj_3R_299() { - if (jj_3R_125()) return true; - return false; - } - - final private boolean jj_3_7() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_123() { - if (jj_3R_165()) return true; - if (jj_scan_token(DEF)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_10() { - if (jj_scan_token(IDENTIFIER)) return true; - if (jj_3R_65()) return true; - return false; - } - - final private boolean jj_3R_197() { - if (jj_scan_token(IF)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(THEN)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(ELSE)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_122() { - if (jj_3R_164()) return true; - if (jj_scan_token(DEF)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_7()) { - jj_scanpos = xsp; - if (jj_3R_299()) return true; - } - return false; - } - - final private boolean jj_3_9() { - if (jj_scan_token(IDENTIFIER)) return true; - if (jj_3R_64()) return true; - return false; - } - - final private boolean jj_3R_121() { - if (jj_3R_163()) return true; - if (jj_scan_token(DEF)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_79() { - if (jj_3R_139()) return true; - return false; - } - - final private boolean jj_3R_120() { - if (jj_3R_162()) return true; - if (jj_scan_token(DEF)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_26() { - if (jj_scan_token(PROOF)) return true; - return false; - } - - final private boolean jj_3_28() { - Token xsp; - xsp = jj_scanpos; - if (jj_3_26()) jj_scanpos = xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_79()) { jj_scanpos = xsp; break; } - } - if (jj_3R_80()) return true; - return false; - } - - final private boolean jj_3R_298() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_230()) return true; - return false; - } - - final private boolean jj_3_8() { - if (jj_scan_token(IDENTIFIER)) return true; - if (jj_scan_token(LSB)) return true; - return false; - } - - final private boolean jj_3_27() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(73)) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_scan_token(69)) { - jj_scanpos = xsp; - if (jj_scan_token(70)) return true; - } - return false; - } - - final private boolean jj_3R_119() { - if (jj_3R_67()) return true; - if (jj_scan_token(LSB)) return true; - if (jj_3R_230()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_298()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - if (jj_scan_token(DEF)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_118() { - if (jj_scan_token(LOCAL)) return true; - return false; - } - - final private boolean jj_3R_59() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_118()) jj_scanpos = xsp; - if (jj_scan_token(DEFBREAK)) return true; - xsp = jj_scanpos; - if (jj_3R_119()) { - jj_scanpos = xsp; - if (jj_3R_120()) { - jj_scanpos = xsp; - if (jj_3R_121()) { - jj_scanpos = xsp; - if (jj_3R_122()) { - jj_scanpos = xsp; - if (jj_3R_123()) return true; - } - } - } - } - return false; - } - - final private boolean jj_3_54() { - if (jj_scan_token(LBR)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3R_221() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(83)) { - jj_scanpos = xsp; - if (jj_scan_token(57)) return true; - } - if (jj_3R_243()) return true; - xsp = jj_scanpos; - if (jj_3_54()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_311() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_97() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(40)) { - jj_scanpos = xsp; - if (jj_scan_token(41)) { - jj_scanpos = xsp; - if (jj_scan_token(45)) { - jj_scanpos = xsp; - if (jj_scan_token(47)) { - jj_scanpos = xsp; - if (jj_scan_token(48)) { - jj_scanpos = xsp; - if (jj_scan_token(50)) { - jj_scanpos = xsp; - if (jj_scan_token(58)) { - jj_scanpos = xsp; - if (jj_scan_token(59)) return true; - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3_40() { - if (jj_scan_token(DOT)) return true; - if (jj_scan_token(NUMBER_LITERAL)) return true; - return false; - } - - final private boolean jj_3R_310() { - if (jj_3R_104()) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_252() { - if (jj_3R_220()) return true; - return false; - } - - final private boolean jj_3R_251() { - if (jj_3R_219()) return true; - return false; - } - - final private boolean jj_3R_250() { - if (jj_3R_154()) return true; - return false; - } - - final private boolean jj_3R_185() { - if (jj_3R_197()) return true; - return false; - } - - final private boolean jj_3R_175() { - if (jj_scan_token(NUMBER_LITERAL)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_40()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_249() { - if (jj_3R_218()) return true; - return false; - } - - final private boolean jj_3R_248() { - if (jj_3R_217()) return true; - return false; - } - - final private boolean jj_3R_247() { - if (jj_3R_253()) return true; - return false; - } - - final private boolean jj_3R_302() { - if (jj_scan_token(US)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_310()) { - jj_scanpos = xsp; - if (jj_3R_311()) return true; - } - return false; - } - - final private boolean jj_3R_243() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_247()) { - jj_scanpos = xsp; - if (jj_3R_248()) { - jj_scanpos = xsp; - if (jj_3R_249()) { - jj_scanpos = xsp; - if (jj_3R_250()) { - jj_scanpos = xsp; - if (jj_3R_251()) { - jj_scanpos = xsp; - if (jj_3R_252()) return true; - } - } - } - } - } - return false; - } - - final private boolean jj_3R_301() { - if (jj_3R_155()) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_188() { - if (jj_3R_200()) return true; - return false; - } - - final private boolean jj_3R_319() { - if (jj_scan_token(COMMA)) return true; - if (jj_scan_token(US)) return true; - return false; - } - - final private boolean jj_3R_107() { - if (jj_scan_token(STRING_LITERAL)) return true; - return false; - } - - final private boolean jj_3R_184() { - if (jj_3R_196()) return true; - return false; - } - - final private boolean jj_3R_187() { - if (jj_3R_199()) return true; - return false; - } - - final private boolean jj_3R_214() { - if (jj_3R_221()) return true; - return false; - } - - final private boolean jj_3_6() { - if (jj_scan_token(LBR)) return true; - if (jj_scan_token(US)) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_319()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RBR)) return true; - return false; - } - - final private boolean jj_3R_211() { - if (jj_3R_154()) return true; - return false; - } - - final private boolean jj_3R_300() { - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_6()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_186() { - if (jj_3R_198()) return true; - return false; - } - - final private boolean jj_3R_308() { - if (jj_scan_token(BANG)) return true; - if (jj_3R_253()) return true; - return false; - } - - final private boolean jj_3R_183() { - if (jj_3R_195()) return true; - return false; - } - - final private boolean jj_3R_289() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_300()) { - jj_scanpos = xsp; - if (jj_3R_301()) { - jj_scanpos = xsp; - if (jj_3R_302()) return true; - } - } - return false; - } - - final private boolean jj_3R_168() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_183()) { - jj_scanpos = xsp; - if (jj_3R_184()) { - jj_scanpos = xsp; - if (jj_3R_185()) { - jj_scanpos = xsp; - if (jj_3R_186()) { - jj_scanpos = xsp; - if (jj_3R_187()) { - jj_scanpos = xsp; - if (jj_3R_188()) return true; - } - } - } - } - } - return false; - } - - final private boolean jj_3_53() { - if (jj_3R_95()) return true; - return false; - } - - final private boolean jj_3R_253() { - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_53()) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_3R_308()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_213() { - if (jj_3R_220()) return true; - return false; - } - - final private boolean jj_3_25() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_210() { - if (jj_3R_218()) return true; - return false; - } - - final private boolean jj_3R_290() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_289()) return true; - return false; - } - - final private boolean jj_3R_77() { - return false; - } - - final private boolean jj_3_24() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = getToken(1).kind == ASSUME; - lookingAhead = false; - if (!jj_semLA || jj_3R_77()) return true; - if (jj_3R_78()) return true; - return false; - } - - final private boolean jj_3R_115() { - if (jj_scan_token(RECURSIVE)) return true; - if (jj_3R_289()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_290()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_242() { - if (jj_scan_token(ARAB)) return true; - if (jj_3R_243()) return true; - return false; - } - - final private boolean jj_3R_241() { - if (jj_scan_token(RAB)) return true; - return false; - } - - final private boolean jj_3R_284() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_23() { - if (jj_3R_67()) return true; - if (jj_scan_token(DEF)) return true; - return false; - } - - final private boolean jj_3_52() { - if (jj_3R_63()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_284()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_62() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(65)) { - jj_scanpos = xsp; - if (jj_scan_token(56)) return true; - } - xsp = jj_scanpos; - if (jj_3_23()) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_3_24()) { - jj_scanpos = xsp; - if (jj_3_25()) return true; - } - return false; - } - - final private boolean jj_3R_220() { - if (jj_scan_token(LAB)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_52()) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_3R_241()) { - jj_scanpos = xsp; - if (jj_3R_242()) return true; - } - return false; - } - - final private boolean jj_3R_212() { - if (jj_3R_219()) return true; - return false; - } - - final private boolean jj_3R_209() { - if (jj_3R_217()) return true; - return false; - } - - final private boolean jj_3R_202() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_209()) { - jj_scanpos = xsp; - if (jj_3R_210()) { - jj_scanpos = xsp; - if (jj_3R_211()) { - jj_scanpos = xsp; - if (jj_3R_212()) { - jj_scanpos = xsp; - if (jj_3R_213()) { - jj_scanpos = xsp; - if (jj_3R_214()) return true; - } - } - } - } - } - return false; - } - - final private boolean jj_3R_157() { - if (jj_scan_token(CONSTANT)) return true; - return false; - } - - final private boolean jj_3R_283() { - if (jj_scan_token(IN)) return true; - return false; - } - - final private boolean jj_3R_156() { - if (jj_3R_175()) return true; - return false; - } - - final private boolean jj_3R_282() { - if (jj_scan_token(EQUALS)) return true; - return false; - } - - final private boolean jj_3R_144() { - if (jj_3R_95()) return true; - return false; - } - - final private boolean jj_3_39() { - if (jj_3R_85()) return true; - return false; - } - - final private boolean jj_3R_85() { - if (jj_3R_67()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_144()) jj_scanpos = xsp; - if (jj_scan_token(BANG)) return true; - return false; - } - - final private boolean jj_3R_270() { - if (jj_scan_token(BANG)) return true; - if (jj_3R_281()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_282()) { - jj_scanpos = xsp; - if (jj_3R_283()) return true; - } - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_265() { - if (jj_scan_token(IN)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_257() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_265()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_271() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_270()) return true; - return false; - } - - final private boolean jj_3R_114() { - if (jj_3R_157()) return true; - return false; - } - - final private boolean jj_3R_219() { - if (jj_scan_token(LWB)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(EXCEPT)) return true; - if (jj_3R_270()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_271()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RWB)) return true; - return false; - } - - final private boolean jj_3R_307() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_112() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(101)) { - jj_scanpos = xsp; - if (jj_scan_token(103)) { - jj_scanpos = xsp; - if (jj_scan_token(86)) { - jj_scanpos = xsp; - if (jj_3R_156()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = getToken(1).image.equals("@"); - lookingAhead = false; - if (!jj_semLA || jj_scan_token(229)) return true; - } - } - } - } - return false; - } - - final private boolean jj_3R_113() { - if (jj_scan_token(VARIABLE)) return true; - return false; - } - - final private boolean jj_3R_56() { - if (jj_3R_115()) return true; - return false; - } - - final private boolean jj_3R_296() { - if (jj_scan_token(LSB)) return true; - if (jj_3R_63()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_307()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3_77() { - if (jj_3R_112()) return true; - return false; - } - - final private boolean jj_3R_285() { - if (jj_3R_95()) return true; - return false; - } - - final private boolean jj_3R_58() { - if (jj_3R_117()) return true; - return false; - } - - final private boolean jj_3_75() { - if (jj_3R_95()) return true; - return false; - } - - final private boolean jj_3_74() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_57() { - if (jj_3R_116()) return true; - return false; - } - - final private boolean jj_3R_111() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3_5() { - if (jj_3R_62()) return true; - return false; - } - - final private boolean jj_3_4() { - if (jj_3R_61()) return true; - return false; - } - - final private boolean jj_3_3() { - if (jj_3R_60()) return true; - return false; - } - - final private boolean jj_3_2() { - if (jj_3R_59()) return true; - return false; - } - - final private boolean jj_3R_110() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_295() { - if (jj_scan_token(DOT)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_55() { - if (jj_3R_114()) return true; - return false; - } - - final private boolean jj_3R_109() { - if (jj_3R_155()) return true; - return false; - } - - final private boolean jj_3R_54() { - if (jj_3R_113()) return true; - return false; - } - - final private boolean jj_3R_281() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_295()) { - jj_scanpos = xsp; - if (jj_3R_296()) return true; - } - return false; - } - - final private boolean jj_3R_53() { - if (jj_scan_token(SEPARATOR)) return true; - return false; - } - - final private boolean jj_3R_108() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3_1() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_53()) { - jj_scanpos = xsp; - if (jj_3R_54()) { - jj_scanpos = xsp; - if (jj_3R_55()) { - jj_scanpos = xsp; - if (jj_3_2()) { - jj_scanpos = xsp; - if (jj_3R_56()) { - jj_scanpos = xsp; - if (jj_3_3()) { - jj_scanpos = xsp; - if (jj_3_4()) { - jj_scanpos = xsp; - if (jj_3_5()) { - jj_scanpos = xsp; - if (jj_3R_57()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = (getToken(1).kind == USE && getToken(2).kind != ONLY) - || (getToken(1).kind == HIDE); - lookingAhead = false; - if (!jj_semLA || jj_3R_58()) return true; - } - } - } - } - } - } - } - } - } - return false; - } - - final private boolean jj_3_76() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = !getToken(1).image.equals("@"); - lookingAhead = false; - if (!jj_semLA || jj_3R_108()) { - jj_scanpos = xsp; - if (jj_3R_109()) { - jj_scanpos = xsp; - if (jj_3R_110()) { - jj_scanpos = xsp; - if (jj_3R_111()) return true; - } - } - } - xsp = jj_scanpos; - if (jj_3_75()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_76() { - if (jj_3R_134()) return true; - return false; - } - - final private boolean jj_3R_244() { - if (jj_scan_token(BANG)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3_76()) { - jj_scanpos = xsp; - if (jj_3R_285()) { - jj_scanpos = xsp; - if (jj_3_77()) return true; - } - } - return false; - } - - final private boolean jj_3R_75() { - if (jj_3R_68()) return true; - return false; - } - - final private boolean jj_3R_74() { - if (jj_scan_token(NEW)) return true; - return false; - } - - final private boolean jj_3_22() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_74()) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_scan_token(77)) { - jj_scanpos = xsp; - if (jj_scan_token(37)) { - jj_scanpos = xsp; - if (jj_scan_token(78)) return true; - } - } - xsp = jj_scanpos; - if (jj_3R_75()) { - jj_scanpos = xsp; - if (jj_3R_76()) return true; - } - return false; - } - - final private boolean jj_3R_297() { - if (jj_3R_281()) return true; - return false; - } - - final private boolean jj_3R_287() { - if (jj_scan_token(BANG)) return true; - Token xsp; - if (jj_3R_297()) return true; - while (true) { - xsp = jj_scanpos; - if (jj_3R_297()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(EQUALS)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_73() { - if (jj_scan_token(NEW)) return true; - return false; - } - - final private boolean jj_3R_72() { - if (jj_3R_134()) return true; - return false; - } - - final private boolean jj_3_21() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_73()) jj_scanpos = xsp; - if (jj_scan_token(VARIABLE)) return true; - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_246() { - if (jj_3R_67()) return true; - if (jj_scan_token(COLON)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_69() { - if (jj_scan_token(IN)) return true; - return false; - } - - final private boolean jj_3_19() { - if (jj_3R_68()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_69()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_71() { - if (jj_scan_token(CONSTANT)) return true; - return false; - } - - final private boolean jj_3R_245() { - if (jj_3R_67()) return true; - if (jj_scan_token(MAPTO)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_70() { - if (jj_scan_token(NEW)) return true; - return false; - } - - final private boolean jj_3_18() { - if (jj_scan_token(NEW)) return true; - if (jj_scan_token(CONSTANT)) return true; - return false; - } - - final private boolean jj_3_20() { - Token xsp; - xsp = jj_scanpos; - if (jj_3_18()) { - jj_scanpos = xsp; - if (jj_3R_70()) { - jj_scanpos = xsp; - if (jj_3R_71()) return true; - } - } - xsp = jj_scanpos; - if (jj_3_19()) { - jj_scanpos = xsp; - if (jj_3R_72()) return true; - } - return false; - } - - final private boolean jj_3R_279() { - if (jj_scan_token(ARSB)) return true; - if (jj_3R_243()) return true; - return false; - } - - final private boolean jj_3R_172() { - Token xsp; - xsp = jj_scanpos; - if (jj_3_20()) { - jj_scanpos = xsp; - if (jj_3_21()) { - jj_scanpos = xsp; - if (jj_3_22()) return true; - } - } - return false; - } - - final private boolean jj_3R_288() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_287()) return true; - return false; - } - - final private boolean jj_3R_158() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(34)) { - jj_scanpos = xsp; - if (jj_scan_token(3)) { - jj_scanpos = xsp; - if (jj_scan_token(20)) return true; - } - } - return false; - } - - final private boolean jj_3R_278() { - if (jj_scan_token(EXCEPT)) return true; - if (jj_3R_287()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_288()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3R_277() { - if (jj_scan_token(ARROW)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3R_286() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3_50() { - if (jj_scan_token(IDENTIFIER)) return true; - if (jj_scan_token(COLON)) return true; - return false; - } - - final private boolean jj_3R_276() { - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_286()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3_51() { - if (jj_3R_63()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_276()) { - jj_scanpos = xsp; - if (jj_3R_277()) { - jj_scanpos = xsp; - if (jj_3R_278()) { - jj_scanpos = xsp; - if (jj_3R_279()) return true; - } - } - } - return false; - } - - final private boolean jj_3R_275() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_246()) return true; - return false; - } - - final private boolean jj_3R_116() { - if (jj_3R_158()) return true; - return false; - } - - final private boolean jj_3_17() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_240() { - if (jj_3R_246()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_275()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3R_274() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_245()) return true; - return false; - } - - final private boolean jj_3_49() { - if (jj_scan_token(IDENTIFIER)) return true; - if (jj_scan_token(MAPTO)) return true; - return false; - } - - final private boolean jj_3R_239() { - if (jj_3R_245()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_274()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3R_273() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_245()) return true; - return false; - } - - final private boolean jj_3R_138() { - if (jj_scan_token(COMMA)) return true; - return false; - } - - final private boolean jj_3_16() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_137() { - if (jj_3R_172()) return true; - return false; - } - - final private boolean jj_3R_238() { - if (jj_3R_245()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_273()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3R_272() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_230()) return true; - return false; - } - - final private boolean jj_3R_136() { - if (jj_3R_78()) return true; - return false; - } - - final private boolean jj_3R_237() { - if (jj_3R_230()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_272()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(MAPTO)) return true; - if (jj_3R_63()) return true; - if (jj_scan_token(RSB)) return true; - return false; - } - - final private boolean jj_3_70() { - if (jj_scan_token(op_76)) return true; - return false; - } - - final private boolean jj_3R_232() { - if (jj_3R_244()) return true; - return false; - } - - final private boolean jj_3R_154() { - if (jj_scan_token(LSB)) return true; - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = matchFcnConst(); - lookingAhead = false; - if (!jj_semLA || jj_3R_237()) { - jj_scanpos = xsp; - if (jj_3R_238()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = (getToken(2).kind == MAPTO) && isFieldNameToken( getToken(1)); - lookingAhead = false; - if (!jj_semLA || jj_3R_239()) { - jj_scanpos = xsp; - if (jj_3R_240()) { - jj_scanpos = xsp; - if (jj_3_51()) return true; - } - } - } - } - return false; - } - - final private boolean jj_3_71() { - if (jj_3R_95()) return true; - return false; - } - - final private boolean jj_3R_180() { - if (jj_3R_155()) return true; - return false; - } - - final private boolean jj_3R_179() { - if (jj_3R_102()) return true; - return false; - } - - final private boolean jj_3R_178() { - if (jj_3R_104()) return true; - return false; - } - - final private boolean jj_3R_64() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(112)) { - jj_scanpos = xsp; - if (jj_scan_token(113)) { - jj_scanpos = xsp; - if (jj_scan_token(114)) { - jj_scanpos = xsp; - if (jj_scan_token(115)) return true; - } - } - } - return false; - } - - final private boolean jj_3R_314() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_313() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_230()) return true; - return false; - } - - final private boolean jj_3R_306() { - Token xsp; - if (jj_3R_314()) return true; - while (true) { - xsp = jj_scanpos; - if (jj_3R_314()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_135() { - if (jj_3R_67()) return true; - if (jj_scan_token(COLONCOLON)) return true; - if (jj_3R_78()) return true; - return false; - } - - final private boolean jj_3R_78() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_135()) jj_scanpos = xsp; - if (jj_scan_token(ASSUME)) return true; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = (getToken(1).kind == ASSUME) - || ((getToken(2).kind == COLONCOLON) && - (getToken(3).kind == ASSUME) ); - lookingAhead = false; - if (!jj_semLA || jj_3R_136()) { - jj_scanpos = xsp; - if (jj_3R_137()) { - jj_scanpos = xsp; - if (jj_3_16()) return true; - } - } - while (true) { - xsp = jj_scanpos; - if (jj_3R_138()) { jj_scanpos = xsp; break; } - } - if (jj_scan_token(PROVE)) return true; - return false; - } - - final private boolean jj_3_73() { - if (jj_scan_token(NUMBER_LITERAL)) return true; - return false; - } - - final private boolean jj_3R_177() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(232)) { - jj_scanpos = xsp; - if (jj_scan_token(233)) return true; - } - return false; - } - - final private boolean jj_3_72() { - if (jj_3R_107()) return true; - return false; - } - - final private boolean jj_3R_176() { - if (jj_3R_67()) return true; - return false; - } - - final private boolean jj_3R_153() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_176()) { - jj_scanpos = xsp; - if (jj_3R_177()) { - jj_scanpos = xsp; - if (jj_3R_178()) { - jj_scanpos = xsp; - if (jj_3R_179()) { - jj_scanpos = xsp; - if (jj_3R_180()) return true; - } - } - } - } - xsp = jj_scanpos; - if (jj_3_71()) jj_scanpos = xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_232()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_91() { - if (jj_3R_146()) return true; - return false; - } - - final private boolean jj_3R_142() { - if (jj_3R_78()) return true; - return false; - } - - final private boolean jj_3R_152() { - if (jj_3R_175()) return true; - return false; - } - - final private boolean jj_3R_305() { - if (jj_scan_token(COLON)) return true; - if (jj_3R_230()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_313()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_294() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_305()) { - jj_scanpos = xsp; - if (jj_3R_306()) return true; - } - return false; - } - - final private boolean jj_3_46() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_91()) { - jj_scanpos = xsp; - if (jj_scan_token(229)) return true; - } - if (jj_scan_token(COLON)) return true; - return false; - } - - final private boolean jj_3_38() { - if (jj_3R_63()) return true; - return false; - } - - final private boolean jj_3R_151() { - if (jj_3R_107()) return true; - return false; - } - - final private boolean jj_3R_293() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_230()) return true; - return false; - } - - final private boolean jj_3_47() { - if (jj_3R_63()) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_294()) jj_scanpos = xsp; - return false; - } - - final private boolean jj_3R_98() { - Token xsp; - xsp = jj_scanpos; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_151()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = BStack.aboveReference( getToken(1).beginColumn); - lookingAhead = false; - if (!jj_semLA || jj_3R_152()) { - jj_scanpos = xsp; - if (jj_3R_153()) return true; - } - } - return false; - } - - final private boolean jj_3R_90() { - if (jj_3R_146()) return true; - return false; - } - - final private boolean jj_3R_141() { - if (jj_scan_token(SUFFICES)) return true; - return false; - } - - final private boolean jj_3_45() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_90()) { - jj_scanpos = xsp; - if (jj_scan_token(229)) return true; - } - if (jj_scan_token(COMMA)) return true; - return false; - } - - final private boolean jj_3R_82() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_141()) jj_scanpos = xsp; - xsp = jj_scanpos; - if (jj_3_38()) { - jj_scanpos = xsp; - lookingAhead = true; - jj_semLA = getToken(1).kind == ASSUME; - lookingAhead = false; - if (!jj_semLA || jj_3R_142()) return true; - } - return false; - } - - final private boolean jj_3R_94() { - if (jj_3R_63()) return true; - if (jj_scan_token(COLON)) return true; - if (jj_3R_230()) return true; - Token xsp; - while (true) { - xsp = jj_scanpos; - if (jj_3R_293()) { jj_scanpos = xsp; break; } - } - return false; - } - - final private boolean jj_3R_292() { - if (jj_scan_token(COMMA)) return true; - if (jj_3R_63()) return true; - return false; - } - - public TLAplusParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private Token jj_scanpos, jj_lastpos; - private int jj_la; - public boolean lookingAhead = false; - private boolean jj_semLA; - private int jj_gen; - final private int[] jj_la1 = new int[138]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static private int[] jj_la1_2; - static private int[] jj_la1_3; - static private int[] jj_la1_4; - static private int[] jj_la1_5; - static private int[] jj_la1_6; - static private int[] jj_la1_7; - static { - jj_la1_0(); - jj_la1_1(); - jj_la1_2(); - jj_la1_3(); - jj_la1_4(); - jj_la1_5(); - jj_la1_6(); - jj_la1_7(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0x0,0x0,0x0,0x0,0x4,0x80000,0x80000,0x100008,0x0,0x0,0x0,0x0,0x100008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x4000,0x408,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x400420,0x0,0x400420,0x400400,0x0,0x0,0x400000,0x400000,0x20,0x0,0x0,0x1000000,0x0,0x0,0x0,0x40000000,0x40000000,0x20000000,0x200000,0x0,0x200000,0x200000,0x0,0x200000,0x0,0x0,0x100,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2000000,0x2000000,0xc05a300,0x0,0x0,0x0,0x0,0x0,0x0,0xa000,0x0,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2000000,0x100000,0x100000,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc05a300,}; - } - private static void jj_la1_2() { - jj_la1_2 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x40000,0x1000,0x0,0x200000,0x200000,0x200000,0x200000,0x0,0x2000000,0x0,0x200000,0x0,0x0,0x200000,0x0,0x2000000,0x200000,0x2000000,0x8000000,0x200000,0x8000000,0x0,0x2000000,0x0,0x100000,0x0,0x0,0x80,0x0,0x20000000,0x0,0x46000,0x200000,0x46000,0x0,0x0,0x2000000,0x0,0x0,0x6000,0x2000000,0x0,0x2,0x200,0x60,0x200,0x0,0x0,0x20c,0x0,0x200000,0x0,0x0,0x200000,0x0,0x1,0x0,0x18110,0x0,0x200000,0x200000,0x0,0x200000,0x200000,0x200000,0x0,0x20000,0x8000000,0x48080000,0x48080000,0x0,0x0,0x8000000,0x0,0x0,0x200000,0x0,0x0,0x200000,0x200000,0x0,0x0,0x200000,0x200000,0x0,0x0,0x200000,0x600000,0x600000,0x200000,0x200000,0x200000,0x200000,0x600000,0x600000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x80200000,0x41000000,0x200000,0x41000000,0x200000,0x0,0x200000,0x0,0x0,0x48000000,0x80000,0x20001000,0x20001000,0x0,0x0,0x200000,0x0,0x48080000,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x400000,0x0,}; - } - private static void jj_la1_3() { - jj_la1_3 = new int[] {0x7fe00000,0x7ff00000,0x80000000,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800f0000,0x7ff00000,0x0,0x0,0x0,0x7ff00000,0x0,0x0,0x7ff00000,0x0,0x7ff00000,0x0,0x0,0x0,0x800f0000,0x7ff00000,0x0,0x0,0xffff0000,0xffff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7ff00000,0x0,0x0,0x0,0x7ff00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x2a,0xffef302a,0x0,0xffef3000,0x0,0x100,0xffef0000,0x0,0xffff0000,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x100,0x2a,0x0,0x0,0x0,0x0,0x20,0x0,0xffe00000,0x2a,0xffe00000,0x0,0x800f0000,0x100,0xffff0000,0xffff0000,0x0,0x10a0,0x0,}; - } - private static void jj_la1_4() { - jj_la1_4 = new int[] {0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,}; - } - private static void jj_la1_5() { - jj_la1_5 = new int[] {0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,}; - } - private static void jj_la1_6() { - jj_la1_6 = new int[] {0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0x0,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,}; - } - private static void jj_la1_7() { - jj_la1_7 = new int[] {0x0,0x0,0x1f,0x0,0x0,0x20,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f,0x20,0x0,0x0,0x0,0x0,0x0,0x20,0x20,0x0,0x20,0x0,0x0,0x0,0x1f,0x0,0x0,0x0,0x3f,0x3f,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x3f,0x0,0x3f,0x0,0x0,0x3f,0x0,0x1f,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x20,0x0,0x1f,0x0,0x1f,0x300,0x33f,0x0,0x33f,0x1f,0x0,0x0,0x0,}; - } - final private JJCalls[] jj_2_rtns = new JJCalls[77]; - private boolean jj_rescan = false; - private int jj_gc = 0; - - public TLAplusParser(java.io.InputStream stream) { - this(stream, null); - } - public TLAplusParser(java.io.InputStream stream, String encoding) { - try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source = new TLAplusParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - public void ReInit(java.io.InputStream stream, String encoding) { - try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public TLAplusParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new TLAplusParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public TLAplusParser(TLAplusParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(TLAplusParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 138; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns.length; i++) { - JJCalls c = jj_2_rtns[i]; - while (c != null) { - if (c.gen < jj_gen) c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - static private final class LookaheadSuccess extends java.lang.Error { } - final private LookaheadSuccess jj_ls = new LookaheadSuccess(); - final private boolean jj_scan_token(int kind) { - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos.next == null) { - jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos.next; - } - } else { - jj_scanpos = jj_scanpos.next; - } - if (jj_rescan) { - int i = 0; Token tok = token; - while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } - if (tok != null) jj_add_error_token(kind, i); - } - if (jj_scanpos.kind != kind) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; - return false; - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = lookingAhead ? jj_scanpos : token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector jj_expentries = new java.util.Vector(); - private int[] jj_expentry; - private int jj_kind = -1; - private int[] jj_lasttokens = new int[100]; - private int jj_endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new int[jj_endpos]; - for (int i = 0; i < jj_endpos; i++) { - jj_expentry[i] = jj_lasttokens[i]; - } - boolean exists = false; - for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) { - int[] oldentry = (int[])(e.nextElement()); - if (oldentry.length == jj_expentry.length) { - exists = true; - for (int i = 0; i < jj_expentry.length; i++) { - if (oldentry[i] != jj_expentry[i]) { - exists = false; - break; - } - } - if (exists) break; - } - } - if (!exists) jj_expentries.addElement(jj_expentry); - if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } - } - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[237]; - for (int i = 0; i < 237; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 138; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1<<j)) != 0) { - la1tokens[j] = true; - } - if ((jj_la1_1[i] & (1<<j)) != 0) { - la1tokens[32+j] = true; - } - if ((jj_la1_2[i] & (1<<j)) != 0) { - la1tokens[64+j] = true; - } - if ((jj_la1_3[i] & (1<<j)) != 0) { - la1tokens[96+j] = true; - } - if ((jj_la1_4[i] & (1<<j)) != 0) { - la1tokens[128+j] = true; - } - if ((jj_la1_5[i] & (1<<j)) != 0) { - la1tokens[160+j] = true; - } - if ((jj_la1_6[i] & (1<<j)) != 0) { - la1tokens[192+j] = true; - } - if ((jj_la1_7[i] & (1<<j)) != 0) { - la1tokens[224+j] = true; - } - } - } - } - for (int i = 0; i < 237; i++) { - if (la1tokens[i]) { - jj_expentry = new int[1]; - jj_expentry[0] = i; - jj_expentries.addElement(jj_expentry); - } - } - jj_endpos = 0; - jj_rescan_token(); - jj_add_error_token(0, 0); - int[][] exptokseq = new int[jj_expentries.size()][]; - for (int i = 0; i < jj_expentries.size(); i++) { - exptokseq[i] = (int[])jj_expentries.elementAt(i); - } - return new ParseException(token, exptokseq, tokenImage); - } - - final public void enable_tracing() { - } - - final public void disable_tracing() { - } - - final private void jj_rescan_token() { - jj_rescan = true; - for (int i = 0; i < 77; i++) { - try { - JJCalls p = jj_2_rtns[i]; - do { - if (p.gen > jj_gen) { - jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; - switch (i) { - case 0: jj_3_1(); break; - case 1: jj_3_2(); break; - case 2: jj_3_3(); break; - case 3: jj_3_4(); break; - case 4: jj_3_5(); break; - case 5: jj_3_6(); break; - case 6: jj_3_7(); break; - case 7: jj_3_8(); break; - case 8: jj_3_9(); break; - case 9: jj_3_10(); break; - case 10: jj_3_11(); break; - case 11: jj_3_12(); break; - case 12: jj_3_13(); break; - case 13: jj_3_14(); break; - case 14: jj_3_15(); break; - case 15: jj_3_16(); break; - case 16: jj_3_17(); break; - case 17: jj_3_18(); break; - case 18: jj_3_19(); break; - case 19: jj_3_20(); break; - case 20: jj_3_21(); break; - case 21: jj_3_22(); break; - case 22: jj_3_23(); break; - case 23: jj_3_24(); break; - case 24: jj_3_25(); break; - case 25: jj_3_26(); break; - case 26: jj_3_27(); break; - case 27: jj_3_28(); break; - case 28: jj_3_29(); break; - case 29: jj_3_30(); break; - case 30: jj_3_31(); break; - case 31: jj_3_32(); break; - case 32: jj_3_33(); break; - case 33: jj_3_34(); break; - case 34: jj_3_35(); break; - case 35: jj_3_36(); break; - case 36: jj_3_37(); break; - case 37: jj_3_38(); break; - case 38: jj_3_39(); break; - case 39: jj_3_40(); break; - case 40: jj_3_41(); break; - case 41: jj_3_42(); break; - case 42: jj_3_43(); break; - case 43: jj_3_44(); break; - case 44: jj_3_45(); break; - case 45: jj_3_46(); break; - case 46: jj_3_47(); break; - case 47: jj_3_48(); break; - case 48: jj_3_49(); break; - case 49: jj_3_50(); break; - case 50: jj_3_51(); break; - case 51: jj_3_52(); break; - case 52: jj_3_53(); break; - case 53: jj_3_54(); break; - case 54: jj_3_55(); break; - case 55: jj_3_56(); break; - case 56: jj_3_57(); break; - case 57: jj_3_58(); break; - case 58: jj_3_59(); break; - case 59: jj_3_60(); break; - case 60: jj_3_61(); break; - case 61: jj_3_62(); break; - case 62: jj_3_63(); break; - case 63: jj_3_64(); break; - case 64: jj_3_65(); break; - case 65: jj_3_66(); break; - case 66: jj_3_67(); break; - case 67: jj_3_68(); break; - case 68: jj_3_69(); break; - case 69: jj_3_70(); break; - case 70: jj_3_71(); break; - case 71: jj_3_72(); break; - case 72: jj_3_73(); break; - case 73: jj_3_74(); break; - case 74: jj_3_75(); break; - case 75: jj_3_76(); break; - case 76: jj_3_77(); break; - } - } - p = p.next; - } while (p != null); - } catch(LookaheadSuccess ls) { } - } - jj_rescan = false; - } - - final private void jj_save(int index, int xla) { - JJCalls p = jj_2_rtns[index]; - while (p.gen > jj_gen) { - if (p.next == null) { p = p.next = new JJCalls(); break; } - p = p.next; - } - p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; - } - - static final class JJCalls { - int gen; - Token first; - int arg; - JJCalls next; - } - -} diff --git a/tlatools/src-gen/TLAplusParserConstants.java b/tlatools/src-gen/TLAplusParserConstants.java deleted file mode 100644 index d4255ca1c4b3cdd19fac2103a3c86c7af9da3974..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/TLAplusParserConstants.java +++ /dev/null @@ -1,477 +0,0 @@ -/* Generated By:55&JavaCC: Do not edit this line. TLAplusParserConstants.java */ -package tla2sany.parser; - -public interface TLAplusParserConstants { - - int EOF = 0; - int BEGIN_MODULE = 1; - int BEGIN_PRAGMA = 2; - int _BM1 = 3; - int CASE0 = 5; - int CASE1 = 6; - int CASE1b = 7; - int CASE1c = 8; - int CASE2 = 9; - int CASE2b = 10; - int CASE2c = 11; - int CASE3 = 12; - int CASE6 = 13; - int CASE6b = 14; - int CASE6c = 15; - int CASEN = 16; - int LETTER = 17; - int DIGIT = 18; - int NUMBER = 19; - int _BM2 = 20; - int _BM0 = 34; - int SEPARATOR = 35; - int END_MODULE = 36; - int ACTION = 37; - int ASSUME = 38; - int ASSUMPTION = 39; - int CASE = 40; - int CHOOSE = 41; - int CONSTANT = 42; - int ELSE = 43; - int EXCEPT = 44; - int EXISTS = 45; - int EXTENDS = 46; - int FORALL = 47; - int IF = 48; - int INSTANCE = 49; - int LET = 50; - int LETIN = 51; - int LOCAL = 52; - int MODULE = 53; - int NEW = 54; - int OTHER = 55; - int PROPOSITION = 56; - int SF = 57; - int T_EXISTS = 58; - int T_FORALL = 59; - int THEN = 60; - int BY = 61; - int ONLY = 62; - int DEFINE = 63; - int DF = 64; - int THEOREM = 65; - int USE = 66; - int HIDE = 67; - int HAVE = 68; - int OBVIOUS = 69; - int OMITTED = 70; - int LAMBDA = 71; - int TAKE = 72; - int PROOF = 73; - int PROVE = 74; - int QED = 75; - int RECURSIVE = 76; - int STATE = 77; - int TEMPORAL = 78; - int PICK = 79; - int WITNESS = 80; - int SUFFICES = 81; - int VARIABLE = 82; - int WF = 83; - int WITH = 84; - int COMMA = 85; - int COLON = 86; - int COLONCOLON = 87; - int DOT = 88; - int US = 89; - int DEF = 90; - int LBR = 91; - int RBR = 92; - int DEFBREAK = 93; - int LSB = 94; - int ARSB = 95; - int RSB = 96; - int LWB = 97; - int RWB = 98; - int LBC = 99; - int RBC = 100; - int LAB = 101; - int ARAB = 102; - int RAB = 103; - int BANG = 104; - int ARROW = 105; - int SUBSTITUTE = 106; - int MAPTO = 107; - int NUMBER_LITERAL = 108; - int STRING_LITERAL = 109; - int BAND = 110; - int BOR = 111; - int op_57 = 112; - int op_68 = 113; - int op_69 = 114; - int op_70 = 115; - int op_76 = 116; - int op_26 = 117; - int op_29 = 118; - int op_58 = 119; - int CASESEP = 120; - int op_61 = 121; - int op_112 = 122; - int op_113 = 123; - int op_114 = 124; - int op_115 = 125; - int op_116 = 126; - int op_1 = 127; - int AND = 128; - int op_3 = 129; - int op_4 = 130; - int OR = 131; - int op_6 = 132; - int op_7 = 133; - int op_8 = 134; - int op_9 = 135; - int op_10 = 136; - int op_11 = 137; - int op_12 = 138; - int op_13 = 139; - int op_14 = 140; - int op_15 = 141; - int op_16 = 142; - int op_17 = 143; - int op_18 = 144; - int op_19 = 145; - int IN = 146; - int op_21 = 147; - int op_22 = 148; - int op_23 = 149; - int op_24 = 150; - int op_25 = 151; - int op_27 = 152; - int op_30 = 153; - int op_31 = 154; - int op_32 = 155; - int op_33 = 156; - int op_34 = 157; - int op_35 = 158; - int op_36 = 159; - int op_37 = 160; - int op_38 = 161; - int op_39 = 162; - int op_40 = 163; - int op_41 = 164; - int op_42 = 165; - int op_43 = 166; - int op_44 = 167; - int op_45 = 168; - int op_46 = 169; - int op_47 = 170; - int op_48 = 171; - int op_49 = 172; - int op_50 = 173; - int op_51 = 174; - int op_52 = 175; - int op_53 = 176; - int op_54 = 177; - int op_55 = 178; - int op_56 = 179; - int op_59 = 180; - int op_62 = 181; - int op_63 = 182; - int op_64 = 183; - int EQUALS = 184; - int op_66 = 185; - int op_67 = 186; - int op_71 = 187; - int op_72 = 188; - int op_73 = 189; - int op_74 = 190; - int op_75 = 191; - int op_77 = 192; - int op_78 = 193; - int op_79 = 194; - int op_80 = 195; - int op_81 = 196; - int op_82 = 197; - int op_83 = 198; - int op_84 = 199; - int op_85 = 200; - int op_86 = 201; - int op_87 = 202; - int op_88 = 203; - int op_89 = 204; - int op_90 = 205; - int op_91 = 206; - int op_92 = 207; - int op_93 = 208; - int op_94 = 209; - int op_95 = 210; - int op_96 = 211; - int op_97 = 212; - int op_98 = 213; - int op_100 = 214; - int op_101 = 215; - int op_102 = 216; - int op_103 = 217; - int op_104 = 218; - int op_105 = 219; - int op_106 = 220; - int op_107 = 221; - int op_108 = 222; - int op_109 = 223; - int op_110 = 224; - int op_111 = 225; - int op_117 = 226; - int op_118 = 227; - int op_119 = 228; - int IDENTIFIER = 229; - int ProofLevelLexeme = 230; - int ProofImplicitLevelLexeme = 231; - int ProofStepLexeme = 232; - int ProofImplicitStepLexeme = 233; - int ProofStepDotLexeme = 234; - int BareLevelLexeme = 235; - int UnnumberedStepLexeme = 236; - - int DEFAULT = 0; - int PRAGMA = 1; - int SPEC = 2; - int IN_COMMENT = 3; - int EMBEDDED = 4; - int IN_EOL_COMMENT = 5; - - String[] tokenImage = { - "<EOF>", - "<BEGIN_MODULE>", - "\"--->\"", - "<_BM1>", - "<token of kind 4>", - "<CASE0>", - "<CASE1>", - "<CASE1b>", - "<CASE1c>", - "<CASE2>", - "<CASE2b>", - "<CASE2c>", - "<CASE3>", - "<CASE6>", - "<CASE6b>", - "<CASE6c>", - "<CASEN>", - "<LETTER>", - "<DIGIT>", - "<NUMBER>", - "<_BM2>", - "<token of kind 21>", - "\" \"", - "\"\\t\"", - "\"\\n\"", - "\"\\r\"", - "<token of kind 26>", - "\"\\\\*\"", - "<token of kind 28>", - "\"*)\"", - "\"*)\"", - "<token of kind 31>", - "<token of kind 32>", - "<token of kind 33>", - "<_BM0>", - "<SEPARATOR>", - "<END_MODULE>", - "<ACTION>", - "\"ASSUME\"", - "<ASSUMPTION>", - "\"CASE\"", - "\"CHOOSE\"", - "<CONSTANT>", - "\"ELSE\"", - "\"EXCEPT\"", - "<EXISTS>", - "\"EXTENDS\"", - "<FORALL>", - "\"IF\"", - "\"INSTANCE\"", - "\"LET\"", - "\"IN\"", - "\"LOCAL\"", - "\"MODULE\"", - "\"NEW\"", - "\"OTHER\"", - "<PROPOSITION>", - "\"SF_\"", - "\"\\\\EE\"", - "\"\\\\AA\"", - "\"THEN\"", - "\"BY\"", - "\"ONLY\"", - "\"DEFINE\"", - "<DF>", - "\"THEOREM\"", - "\"USE\"", - "\"HIDE\"", - "\"HAVE\"", - "\"OBVIOUS\"", - "\"OMITTED\"", - "\"LAMBDA\"", - "\"TAKE\"", - "\"PROOF\"", - "\"PROVE\"", - "\"QED\"", - "\"RECURSIVE\"", - "\"STATE\"", - "<TEMPORAL>", - "\"PICK\"", - "\"WITNESS\"", - "\"SUFFICES\"", - "<VARIABLE>", - "\"WF_\"", - "\"WITH\"", - "\",\"", - "\":\"", - "\"::\"", - "\".\"", - "\"_\"", - "\"==\"", - "\"(\"", - "\")\"", - "\"-|-\"", - "\"[\"", - "\"]_\"", - "\"]\"", - "\"{|\"", - "\"|}\"", - "\"{\"", - "\"}\"", - "\"<<\"", - "\">>_\"", - "\">>\"", - "\"!\"", - "\"->\"", - "\"<-\"", - "\"|->\"", - "<NUMBER_LITERAL>", - "<STRING_LITERAL>", - "<BAND>", - "<BOR>", - "\"\\\'\"", - "\"^+\"", - "\"^*\"", - "\"^#\"", - "\"-.\"", - "\"\\\\lnot\"", - "\"\\\\neg\"", - "\"~\"", - "\"[]\"", - "\"<>\"", - "\"ENABLED\"", - "\"UNCHANGED\"", - "\"SUBSET\"", - "\"UNION\"", - "\"DOMAIN\"", - "\"//\"", - "\"/\\\\\"", - "\"/=\"", - "\"/\"", - "\"\\\\/\"", - "\"\\\\approx\"", - "\"\\\\asymp\"", - "\"\\\\bigcirc\"", - "\"\\\\bullet\"", - "\"\\\\cap\"", - "\"\\\\cdot\"", - "\"\\\\circ\"", - "\"\\\\cong\"", - "\"\\\\cup\"", - "\"\\\\div\"", - "\"\\\\doteq\"", - "\"\\\\equiv\"", - "\"\\\\geq\"", - "\"\\\\gg\"", - "\"\\\\in\"", - "\"\\\\intersect\"", - "\"\\\\union\"", - "\"\\\\land\"", - "\"\\\\leq\"", - "\"\\\\ll\"", - "\"\\\\lor\"", - "\"\\\\o\"", - "\"\\\\odot\"", - "\"\\\\ominus\"", - "\"\\\\oplus\"", - "\"\\\\oslash\"", - "\"\\\\otimes\"", - "\"\\\\prec\"", - "\"\\\\preceq\"", - "\"\\\\propto\"", - "\"\\\\sim\"", - "\"\\\\simeq\"", - "\"\\\\sqcap\"", - "\"\\\\sqcup\"", - "\"\\\\sqsubset\"", - "\"\\\\sqsupset\"", - "\"\\\\sqsubseteq\"", - "\"\\\\sqsupseteq\"", - "\"\\\\star\"", - "\"\\\\subset\"", - "\"\\\\subseteq\"", - "\"\\\\succ\"", - "\"\\\\succeq\"", - "\"\\\\supset\"", - "\"\\\\supseteq\"", - "\"\\\\uplus\"", - "\"\\\\wr\"", - "\"\\\\\"", - "\"~>\"", - "\"=>\"", - "\"=<\"", - "\"=|\"", - "\"=\"", - "\"##\"", - "\"#\"", - "\"^^\"", - "\"^\"", - "\"--\"", - "\"-|\"", - "\"-+->\"", - "\"-\"", - "\"**\"", - "\"*\"", - "\"++\"", - "\"+\"", - "\"<=>\"", - "\"<:\"", - "\"<=\"", - "\"<\"", - "\">=\"", - "\">\"", - "\"...\"", - "\"..\"", - "\"||\"", - "\"|\"", - "\"|-\"", - "\"|=\"", - "\"&&\"", - "\"&\"", - "\"$$\"", - "\"$\"", - "\"??\"", - "\"%%\"", - "\"%\"", - "\"@@\"", - "\"!!\"", - "\":>\"", - "\":=\"", - "\"::=\"", - "\"(+)\"", - "\"(-)\"", - "\"(.)\"", - "\"(/)\"", - "\"(\\\\X)\"", - "\"\\\\notin\"", - "\"\\\\times\"", - "\"\\\\X\"", - "<IDENTIFIER>", - "<ProofLevelLexeme>", - "<ProofImplicitLevelLexeme>", - "<ProofStepLexeme>", - "<ProofImplicitStepLexeme>", - "<ProofStepDotLexeme>", - "<BareLevelLexeme>", - "<UnnumberedStepLexeme>", - }; - -} diff --git a/tlatools/src-gen/TLAplusParserTokenManager.java b/tlatools/src-gen/TLAplusParserTokenManager.java deleted file mode 100644 index 51f286252033b352a96add5a85aaaf0c736b19f8..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/TLAplusParserTokenManager.java +++ /dev/null @@ -1,4523 +0,0 @@ -/* Generated By:55&JavaCC: Do not edit this line. TLAplusParserTokenManager.java */ -package tla2sany.parser; -import tla2sany.st.ParseTree; -import tla2sany.st.TreeNode; -import tla2sany.utilities.Vector; -import tla2sany.utilities.Stack; -import tla2sany.utilities.Assert; -import util.UniqueString; -import util.ToolIO; - -public class TLAplusParserTokenManager implements TLAplusParserConstants -{ - static int bracketCount = 0; - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - case 0: - if ((active0 & 0x4L) != 0L) - return 10; - return -1; - case 1: - if ((active0 & 0x4L) != 0L) - return 9; - return -1; - case 2: - if ((active0 & 0x4L) != 0L) - return 0; - return -1; - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 45: - return jjMoveStringLiteralDfa1_0(0x4L); - default : - return jjMoveNfa_0(11, 0); - } -} -private final int jjMoveStringLiteralDfa1_0(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(0, active0); - return 1; - } - switch(curChar) - { - case 45: - return jjMoveStringLiteralDfa2_0(active0, 0x4L); - default : - break; - } - return jjStartNfa_0(0, active0); -} -private final int jjMoveStringLiteralDfa2_0(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_0(0, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(1, active0); - return 2; - } - switch(curChar) - { - case 45: - return jjMoveStringLiteralDfa3_0(active0, 0x4L); - default : - break; - } - return jjStartNfa_0(1, active0); -} -private final int jjMoveStringLiteralDfa3_0(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_0(1, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(2, active0); - return 3; - } - switch(curChar) - { - case 62: - if ((active0 & 0x4L) != 0L) - return jjStopAtPos(3, 2); - break; - default : - break; - } - return jjStartNfa_0(2, active0); -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 12; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 1: - if (curChar == 45) - jjCheckNAddStates(0, 2); - break; - case 2: - if (curChar == 32) - jjCheckNAddTwoStates(2, 8); - break; - case 9: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 0; - break; - case 10: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 9; - break; - case 11: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 10; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 3: - if (curChar == 69) - kind = 3; - break; - case 4: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 3; - break; - case 5: - if (curChar == 85) - jjstateSet[jjnewStateCnt++] = 4; - break; - case 6: - if (curChar == 68) - jjstateSet[jjnewStateCnt++] = 5; - break; - case 7: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 6; - break; - case 8: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 7; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 12 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_4(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_4(int pos, long active0) -{ - return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_4(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_4(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_4() -{ - switch(curChar) - { - case 42: - return jjMoveStringLiteralDfa1_4(0x40000000L); - default : - return jjMoveNfa_4(0, 0); - } -} -private final int jjMoveStringLiteralDfa1_4(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_4(0, active0); - return 1; - } - switch(curChar) - { - case 41: - if ((active0 & 0x40000000L) != 0L) - return jjStopAtPos(1, 30); - break; - default : - break; - } - return jjStartNfa_4(0, active0); -} -private final int jjMoveNfa_4(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 4; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (curChar == 40) - jjAddStates(3, 4); - break; - case 1: - if (curChar == 46) - kind = 31; - break; - case 2: - if (curChar == 42) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 3: - if (curChar == 42 && kind > 31) - kind = 31; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjMoveStringLiteralDfa0_1() -{ - return jjMoveNfa_1(0, 0); -} -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 58; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 19) - kind = 19; - jjCheckNAddStates(5, 13); - } - else if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 11; - if (curChar == 48) - { - if (kind > 19) - kind = 19; - } - break; - case 1: - case 2: - if (curChar == 45) - jjCheckNAddStates(14, 16); - break; - case 3: - if (curChar == 32) - jjCheckNAddTwoStates(3, 9); - break; - case 10: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 11: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 10; - break; - case 12: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 11; - break; - case 14: - if ((0x3ff000000000000L & l) != 0L) - jjAddStates(17, 18); - break; - case 16: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 16; - break; - case 18: - case 19: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(19); - break; - case 23: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 19) - kind = 19; - jjCheckNAddStates(5, 13); - break; - case 24: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 19) - kind = 19; - jjCheckNAdd(24); - break; - case 25: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(25, 28); - break; - case 27: - case 42: - case 52: - if (curChar == 47) - jjCheckNAdd(26); - break; - case 28: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 27; - break; - case 29: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(29, 32); - break; - case 30: - if (curChar == 47 && kind > 111) - kind = 111; - break; - case 32: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 31; - break; - case 33: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(33, 34); - break; - case 35: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 35; - break; - case 36: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(36, 37); - break; - case 38: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 38; - break; - case 40: - case 41: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(41, 43); - break; - case 43: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 42; - break; - case 44: - case 45: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(45, 47); - break; - case 47: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 46; - break; - case 48: - case 49: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(49); - break; - case 51: - if ((0x3ff000000000000L & l) != 0L) - jjAddStates(19, 20); - break; - case 53: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 52; - break; - case 54: - if ((0x3ff000000000000L & l) != 0L) - jjAddStates(21, 22); - break; - case 56: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 55; - break; - case 57: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 57; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x7fffffe0777fffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAddStates(23, 27); - } - else if ((0x880000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjAddStates(28, 30); - } - else if (curChar == 64) - { - if (kind > 229) - kind = 229; - } - else if (curChar == 95) - jjCheckNAddTwoStates(14, 15); - if (curChar == 83) - jjCheckNAdd(17); - else if (curChar == 87) - jjCheckNAdd(17); - break; - case 4: - if (curChar == 69 && kind > 20) - kind = 20; - break; - case 5: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 4; - break; - case 6: - if (curChar == 85) - jjstateSet[jjnewStateCnt++] = 5; - break; - case 7: - if (curChar == 68) - jjstateSet[jjnewStateCnt++] = 6; - break; - case 8: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 7; - break; - case 9: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 8; - break; - case 13: - if (curChar == 95) - jjCheckNAddTwoStates(14, 15); - break; - case 14: - if ((0x7fffffe87fffffeL & l) != 0L) - jjCheckNAddTwoStates(14, 15); - break; - case 15: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(16); - break; - case 16: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(16); - break; - case 17: - if (curChar != 70) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 18; - break; - case 18: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(19); - break; - case 19: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(19); - break; - case 20: - if (curChar == 87) - jjCheckNAdd(17); - break; - case 21: - if (curChar == 83) - jjCheckNAdd(17); - break; - case 22: - if (curChar == 64) - kind = 229; - break; - case 25: - if ((0x7fffffe07fffffeL & l) != 0L) - jjAddStates(31, 32); - break; - case 26: - if (curChar == 92 && kind > 110) - kind = 110; - break; - case 29: - if ((0x7fffffe07fffffeL & l) != 0L) - jjAddStates(33, 34); - break; - case 31: - case 46: - case 55: - if (curChar == 92) - jjCheckNAdd(30); - break; - case 33: - if ((0x7fffffe87fffffeL & l) != 0L) - jjAddStates(35, 36); - break; - case 34: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(35); - break; - case 35: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(35); - break; - case 37: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(38); - break; - case 38: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(38); - break; - case 39: - if ((0x880000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjAddStates(28, 30); - break; - case 40: - if ((0x7fffffe07ffffbeL & l) != 0L) - jjCheckNAddTwoStates(41, 43); - break; - case 41: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(41, 43); - break; - case 44: - if ((0x7fffffe07ffffbeL & l) != 0L) - jjCheckNAddTwoStates(45, 47); - break; - case 45: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(45, 47); - break; - case 48: - if ((0x7fffffe87ffffbeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(49); - break; - case 49: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(49); - break; - case 50: - if ((0x7fffffe0777fffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAddStates(23, 27); - break; - case 51: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(51, 53); - break; - case 54: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(54, 56); - break; - case 57: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(57); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 58 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjMoveStringLiteralDfa0_5() -{ - return jjMoveNfa_5(0, 0); -} -private final int jjMoveNfa_5(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 3; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x2400L & l) != 0L) - { - if (kind > 32) - kind = 32; - } - if (curChar == 13) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 1: - if (curChar == 10 && kind > 32) - kind = 32; - break; - case 2: - if (curChar == 13) - jjstateSet[jjnewStateCnt++] = 1; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_2(int pos, long active0, long active1, long active2, long active3) -{ - switch (pos) - { - case 0: - if ((active0 & 0x8000000000000000L) != 0L || (active1 & 0x4000000000000000L) != 0L) - { - jjmatchedKind = 229; - return 81; - } - if ((active1 & 0x4000000L) != 0L || (active2 & 0x1e0000000000000L) != 0L) - return 3; - if ((active1 & 0x200042000000000L) != 0L || (active3 & 0x1e0L) != 0L) - return 166; - if ((active0 & 0x60eb580000000000L) != 0L || (active1 & 0x2c0000000000187cL) != 0L) - { - jjmatchedKind = 229; - return 229; - } - if ((active0 & 0x200000000000000L) != 0L || (active1 & 0x10000000001b2000L) != 0L) - { - jjmatchedKind = 229; - return 146; - } - if ((active1 & 0x8000000L) != 0L || (active3 & 0x3e0000000L) != 0L) - return 87; - if ((active0 & 0x14000000000000L) != 0L || (active1 & 0x80L) != 0L) - { - jjmatchedKind = 229; - return 19; - } - if ((active0 & 0x30000000000L) != 0L) - { - jjmatchedKind = 229; - return 112; - } - if ((active1 & 0x10020020000000L) != 0L || (active2 & 0xe000000000000000L) != 0L || (active3 & 0x1L) != 0L) - return 100; - if ((active0 & 0xc00000008000000L) != 0L || (active1 & 0x60000000000000L) != 0L || (active2 & 0xffffffffffff8L) != 0L || (active3 & 0x1c00000000L) != 0L) - return 190; - if ((active3 & 0x1000000L) != 0L) - { - jjmatchedKind = 229; - return -1; - } - if ((active1 & 0x2000000L) != 0L) - return 230; - if ((active0 & 0x1000000000000000L) != 0L || (active1 & 0x102L) != 0L) - { - jjmatchedKind = 229; - return 70; - } - if ((active0 & 0x4000000000L) != 0L) - { - jjmatchedKind = 229; - return 209; - } - if ((active1 & 0x8600L) != 0L) - { - jjmatchedKind = 229; - return 14; - } - return -1; - case 1: - if ((active0 & 0x50f05b0000000000L) != 0L || (active1 & 0x6c000000000099feL) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 229; - } - if ((active1 & 0x4000000L) != 0L) - return 2; - if ((active0 & 0x400000000000000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 45; - jjmatchedPos = 1; - } - return -1; - } - if ((active0 & 0x200b000000000000L) != 0L) - return 229; - if ((active0 & 0x4000000000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 223; - } - if ((active2 & 0xc0L) != 0L) - return 44; - if ((active1 & 0x600L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 13; - } - if ((active0 & 0x800000000000000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 47; - jjmatchedPos = 1; - } - return -1; - } - if ((active2 & 0x7e000000L) != 0L) - return 42; - if ((active3 & 0x1000000L) != 0L) - { - if (jjmatchedPos == 0) - { - jjmatchedKind = 229; - jjmatchedPos = 0; - } - return -1; - } - if ((active0 & 0x8000000000000000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 80; - } - if ((active2 & 0x2000000000000000L) != 0L) - return 99; - if ((active1 & 0x1000000000132000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 231; - } - if ((active0 & 0x4000000000000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 18; - } - if ((active0 & 0x200000000000000L) != 0L || (active1 & 0x80000L) != 0L) - { - if (jjmatchedPos != 1) - { - jjmatchedKind = 229; - jjmatchedPos = 1; - } - return 35; - } - if ((active2 & 0x8000L) != 0L) - return 195; - return -1; - case 2: - if ((active0 & 0x800000000000000L) != 0L) - { - if (jjmatchedPos < 1) - { - jjmatchedKind = 47; - jjmatchedPos = 1; - } - return -1; - } - if ((active1 & 0x1000000000132000L) != 0L) - { - if (jjmatchedPos != 2) - { - jjmatchedKind = 229; - jjmatchedPos = 2; - } - return 231; - } - if ((active0 & 0x44000000000000L) != 0L || (active1 & 0x804L) != 0L) - return 229; - if ((active0 & 0x400000000000000L) != 0L) - { - if (jjmatchedPos < 1) - { - jjmatchedKind = 45; - jjmatchedPos = 1; - } - return -1; - } - if ((active0 & 0x4000000000L) != 0L) - { - if (jjmatchedPos != 2) - { - jjmatchedKind = 229; - jjmatchedPos = 2; - } - return 222; - } - if ((active1 & 0x600L) != 0L) - { - if (jjmatchedPos != 2) - { - jjmatchedKind = 229; - jjmatchedPos = 2; - } - return 12; - } - if ((active0 & 0x50b25b0000000000L) != 0L || (active1 & 0x6c000000000091faL) != 0L) - { - if (jjmatchedPos != 2) - { - jjmatchedKind = 229; - jjmatchedPos = 2; - } - return 229; - } - if ((active0 & 0x8000000000000000L) != 0L) - { - if (jjmatchedPos != 2) - { - jjmatchedKind = 64; - jjmatchedPos = 2; - } - return 82; - } - return -1; - case 3: - if ((active0 & 0x5000090000000000L) != 0L || (active1 & 0x8118L) != 0L) - return 229; - if ((active0 & 0x80b2520000000000L) != 0L || (active1 & 0x6c000000000016e2L) != 0L) - { - if (jjmatchedPos != 3) - { - jjmatchedKind = 229; - jjmatchedPos = 3; - } - return 229; - } - if ((active1 & 0x1000000000032000L) != 0L) - { - if (jjmatchedPos != 3) - { - jjmatchedKind = 229; - jjmatchedPos = 3; - } - return 231; - } - if ((active0 & 0x4000000000L) != 0L) - { - if (jjmatchedPos != 3) - { - jjmatchedKind = 229; - jjmatchedPos = 3; - } - return 221; - } - if ((active1 & 0x100000L) != 0L) - return 231; - return -1; - case 4: - if ((active0 & 0x8022520000000000L) != 0L || (active1 & 0x4c000000000010e2L) != 0L) - { - if (jjmatchedPos != 4) - { - jjmatchedKind = 229; - jjmatchedPos = 4; - } - return 229; - } - if ((active0 & 0x4000000000L) != 0L) - { - if (jjmatchedPos != 4) - { - jjmatchedKind = 229; - jjmatchedPos = 4; - } - return 220; - } - if ((active0 & 0x90000000000000L) != 0L || (active1 & 0x2000000000000600L) != 0L) - return 229; - if ((active1 & 0x1000000000030000L) != 0L) - { - if (jjmatchedPos != 4) - { - jjmatchedKind = 229; - jjmatchedPos = 4; - } - return 231; - } - if ((active1 & 0x2000L) != 0L) - return 231; - return -1; - case 5: - if ((active1 & 0x30000L) != 0L) - { - jjmatchedKind = 229; - jjmatchedPos = 5; - return 231; - } - if ((active0 & 0x8020124000000000L) != 0L || (active1 & 0x4000000000000080L) != 0L) - return 229; - if ((active0 & 0x2400000000000L) != 0L || (active1 & 0xc00000000001062L) != 0L) - { - jjmatchedKind = 229; - jjmatchedPos = 5; - return 229; - } - if ((active1 & 0x1000000000000000L) != 0L) - return 231; - return -1; - case 6: - if ((active0 & 0x2000000000000L) != 0L || (active1 & 0x800000000001000L) != 0L) - { - if (jjmatchedPos != 6) - { - jjmatchedKind = 229; - jjmatchedPos = 6; - } - return 229; - } - if ((active0 & 0x400000000000L) != 0L || (active1 & 0x400000000000062L) != 0L) - return 229; - if ((active1 & 0x20000L) != 0L) - { - if (jjmatchedPos != 6) - { - jjmatchedKind = 229; - jjmatchedPos = 6; - } - return 231; - } - if ((active1 & 0x10000L) != 0L) - return 231; - return -1; - case 7: - if ((active0 & 0x2000000000000L) != 0L) - return 229; - if ((active1 & 0x20000L) != 0L) - return 231; - if ((active1 & 0x800000000001000L) != 0L) - { - jjmatchedKind = 229; - jjmatchedPos = 7; - return 229; - } - return -1; - case 8: - if ((active1 & 0x800000000001000L) != 0L) - return 229; - return -1; - default : - return -1; - } -} -private final int jjStartNfa_2(int pos, long active0, long active1, long active2, long active3) -{ - return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0, active1, active2, active3), pos + 1); -} -private final int jjStartNfaWithStates_2(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_2(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_2() -{ - switch(curChar) - { - case 33: - jjmatchedKind = 104; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x2000000L); - case 35: - jjmatchedKind = 186; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x200000000000000L, 0x0L); - case 36: - jjmatchedKind = 212; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x80000L); - case 37: - jjmatchedKind = 215; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x400000L); - case 38: - jjmatchedKind = 210; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x20000L); - case 39: - return jjStopAtPos(0, 112); - case 40: - jjmatchedKind = 91; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x3e0000000L); - case 41: - return jjStopAtPos(0, 92); - case 42: - jjmatchedKind = 194; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x2L); - case 43: - jjmatchedKind = 196; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x8L); - case 44: - return jjStopAtPos(0, 85); - case 45: - jjmatchedKind = 192; - return jjMoveStringLiteralDfa1_2(0x0L, 0x10020020000000L, 0xe000000000000000L, 0x0L); - case 46: - jjmatchedKind = 88; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x1800L); - case 47: - jjmatchedKind = 130; - return jjMoveStringLiteralDfa1_2(0x0L, 0x8000000000000000L, 0x3L, 0x0L); - case 58: - jjmatchedKind = 86; - return jjMoveStringLiteralDfa1_2(0x0L, 0x800000L, 0x0L, 0x1c000000L); - case 60: - jjmatchedKind = 200; - return jjMoveStringLiteralDfa1_2(0x0L, 0x200042000000000L, 0x0L, 0xe0L); - case 61: - jjmatchedKind = 184; - return jjMoveStringLiteralDfa1_2(0x0L, 0x4000000L, 0xe0000000000000L, 0x0L); - case 62: - jjmatchedKind = 202; - return jjMoveStringLiteralDfa1_2(0x0L, 0xc000000000L, 0x0L, 0x200L); - case 63: - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x200000L); - case 64: - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x0L, 0x1000000L); - case 65: - return jjMoveStringLiteralDfa1_2(0x4000000000L, 0x0L, 0x0L, 0x0L); - case 66: - return jjMoveStringLiteralDfa1_2(0x2000000000000000L, 0x0L, 0x0L, 0x0L); - case 67: - return jjMoveStringLiteralDfa1_2(0x30000000000L, 0x0L, 0x0L, 0x0L); - case 68: - return jjMoveStringLiteralDfa1_2(0x8000000000000000L, 0x4000000000000000L, 0x0L, 0x0L); - case 69: - return jjMoveStringLiteralDfa1_2(0x580000000000L, 0x400000000000000L, 0x0L, 0x0L); - case 72: - return jjMoveStringLiteralDfa1_2(0x0L, 0x18L, 0x0L, 0x0L); - case 73: - return jjMoveStringLiteralDfa1_2(0xb000000000000L, 0x0L, 0x0L, 0x0L); - case 76: - return jjMoveStringLiteralDfa1_2(0x14000000000000L, 0x80L, 0x0L, 0x0L); - case 77: - return jjMoveStringLiteralDfa1_2(0x20000000000000L, 0x0L, 0x0L, 0x0L); - case 78: - return jjMoveStringLiteralDfa1_2(0x40000000000000L, 0x0L, 0x0L, 0x0L); - case 79: - return jjMoveStringLiteralDfa1_2(0x4080000000000000L, 0x60L, 0x0L, 0x0L); - case 80: - return jjMoveStringLiteralDfa1_2(0x0L, 0x8600L, 0x0L, 0x0L); - case 81: - return jjMoveStringLiteralDfa1_2(0x0L, 0x800L, 0x0L, 0x0L); - case 82: - return jjMoveStringLiteralDfa1_2(0x0L, 0x1000L, 0x0L, 0x0L); - case 83: - return jjMoveStringLiteralDfa1_2(0x200000000000000L, 0x1000000000022000L, 0x0L, 0x0L); - case 84: - return jjMoveStringLiteralDfa1_2(0x1000000000000000L, 0x102L, 0x0L, 0x0L); - case 85: - return jjMoveStringLiteralDfa1_2(0x0L, 0x2800000000000004L, 0x0L, 0x0L); - case 87: - return jjMoveStringLiteralDfa1_2(0x0L, 0x190000L, 0x0L, 0x0L); - case 91: - jjmatchedKind = 94; - return jjMoveStringLiteralDfa1_2(0x0L, 0x100000000000000L, 0x0L, 0x0L); - case 92: - jjmatchedKind = 179; - return jjMoveStringLiteralDfa1_2(0xc00000008000000L, 0x60000000000000L, 0x7fffffffffff8L, 0x1c00000000L); - case 93: - jjmatchedKind = 96; - return jjMoveStringLiteralDfa1_2(0x0L, 0x80000000L, 0x0L, 0x0L); - case 94: - jjmatchedKind = 188; - return jjMoveStringLiteralDfa1_2(0x0L, 0xe000000000000L, 0x800000000000000L, 0x0L); - case 95: - return jjStartNfaWithStates_2(0, 89, 230); - case 123: - jjmatchedKind = 99; - return jjMoveStringLiteralDfa1_2(0x0L, 0x200000000L, 0x0L, 0x0L); - case 124: - jjmatchedKind = 206; - return jjMoveStringLiteralDfa1_2(0x0L, 0x80400000000L, 0x0L, 0x1a000L); - case 125: - return jjStopAtPos(0, 100); - case 126: - jjmatchedKind = 119; - return jjMoveStringLiteralDfa1_2(0x0L, 0x0L, 0x10000000000000L, 0x0L); - default : - return jjMoveNfa_2(4, 0); - } -} -private final int jjMoveStringLiteralDfa1_2(long active0, long active1, long active2, long active3) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(0, active0, active1, active2, active3); - return 1; - } - switch(curChar) - { - case 33: - if ((active3 & 0x2000000L) != 0L) - return jjStopAtPos(1, 217); - break; - case 35: - if ((active1 & 0x8000000000000L) != 0L) - return jjStopAtPos(1, 115); - else if ((active2 & 0x200000000000000L) != 0L) - return jjStopAtPos(1, 185); - break; - case 36: - if ((active3 & 0x80000L) != 0L) - return jjStopAtPos(1, 211); - break; - case 37: - if ((active3 & 0x400000L) != 0L) - return jjStopAtPos(1, 214); - break; - case 38: - if ((active3 & 0x20000L) != 0L) - return jjStopAtPos(1, 209); - break; - case 42: - if ((active0 & 0x8000000L) != 0L) - return jjStopAtPos(1, 27); - else if ((active1 & 0x4000000000000L) != 0L) - return jjStopAtPos(1, 114); - else if ((active3 & 0x2L) != 0L) - return jjStopAtPos(1, 193); - break; - case 43: - if ((active1 & 0x2000000000000L) != 0L) - return jjStopAtPos(1, 113); - else if ((active3 & 0x8L) != 0L) - return jjStopAtPos(1, 195); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x8000000000000000L, active3, 0x20000000L); - case 45: - if ((active1 & 0x40000000000L) != 0L) - return jjStopAtPos(1, 106); - else if ((active2 & 0x2000000000000000L) != 0L) - return jjStartNfaWithStates_2(1, 189, 99); - else if ((active3 & 0x8000L) != 0L) - { - jjmatchedKind = 207; - jjmatchedPos = 1; - } - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x80000000000L, active2, 0L, active3, 0x40000000L); - case 46: - if ((active1 & 0x10000000000000L) != 0L) - return jjStopAtPos(1, 116); - else if ((active3 & 0x1000L) != 0L) - { - jjmatchedKind = 204; - jjmatchedPos = 1; - } - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x80000800L); - case 47: - if ((active1 & 0x8000000000000000L) != 0L) - return jjStopAtPos(1, 127); - else if ((active2 & 0x8L) != 0L) - return jjStopAtPos(1, 131); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x100000000L); - case 58: - if ((active1 & 0x800000L) != 0L) - { - jjmatchedKind = 87; - jjmatchedPos = 1; - } - else if ((active3 & 0x40L) != 0L) - return jjStopAtPos(1, 198); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x10000000L); - case 60: - if ((active1 & 0x2000000000L) != 0L) - return jjStopAtPos(1, 101); - else if ((active2 & 0x40000000000000L) != 0L) - return jjStopAtPos(1, 182); - break; - case 61: - if ((active1 & 0x4000000L) != 0L) - return jjStartNfaWithStates_2(1, 90, 2); - else if ((active2 & 0x2L) != 0L) - return jjStopAtPos(1, 129); - else if ((active3 & 0x80L) != 0L) - { - jjmatchedKind = 199; - jjmatchedPos = 1; - } - else if ((active3 & 0x200L) != 0L) - return jjStopAtPos(1, 201); - else if ((active3 & 0x10000L) != 0L) - return jjStopAtPos(1, 208); - else if ((active3 & 0x8000000L) != 0L) - return jjStopAtPos(1, 219); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x20L); - case 62: - if ((active1 & 0x8000000000L) != 0L) - { - jjmatchedKind = 103; - jjmatchedPos = 1; - } - else if ((active1 & 0x20000000000L) != 0L) - return jjStopAtPos(1, 105); - else if ((active1 & 0x200000000000000L) != 0L) - return jjStopAtPos(1, 121); - else if ((active2 & 0x10000000000000L) != 0L) - return jjStopAtPos(1, 180); - else if ((active2 & 0x20000000000000L) != 0L) - return jjStopAtPos(1, 181); - else if ((active3 & 0x4000000L) != 0L) - return jjStopAtPos(1, 218); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x4000000000L, active2, 0L, active3, 0L); - case 63: - if ((active3 & 0x200000L) != 0L) - return jjStopAtPos(1, 213); - break; - case 64: - if ((active3 & 0x1000000L) != 0L) - return jjStopAtPos(1, 216); - break; - case 65: - return jjMoveStringLiteralDfa2_2(active0, 0x800010000000000L, active1, 0x190L, active2, 0L, active3, 0L); - case 66: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x20L, active2, 0L, active3, 0L); - case 69: - return jjMoveStringLiteralDfa2_2(active0, 0x8444000000000000L, active1, 0x1800L, active2, 0L, active3, 0L); - case 70: - if ((active0 & 0x1000000000000L) != 0L) - return jjStartNfaWithStates_2(1, 48, 229); - return jjMoveStringLiteralDfa2_2(active0, 0x200000000000000L, active1, 0x80000L, active2, 0L, active3, 0L); - case 72: - return jjMoveStringLiteralDfa2_2(active0, 0x1000020000000000L, active1, 0x2L, active2, 0L, active3, 0L); - case 73: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x118008L, active2, 0L, active3, 0L); - case 76: - return jjMoveStringLiteralDfa2_2(active0, 0x80000000000L, active1, 0L, active2, 0L, active3, 0L); - case 77: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x40L, active2, 0L, active3, 0L); - case 78: - if ((active0 & 0x8000000000000L) != 0L) - { - jjmatchedKind = 51; - jjmatchedPos = 1; - } - return jjMoveStringLiteralDfa2_2(active0, 0x4002000000000000L, active1, 0x2c00000000000000L, active2, 0L, active3, 0L); - case 79: - return jjMoveStringLiteralDfa2_2(active0, 0x30000000000000L, active1, 0x4000000000000000L, active2, 0L, active3, 0L); - case 82: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x600L, active2, 0L, active3, 0L); - case 83: - return jjMoveStringLiteralDfa2_2(active0, 0x4000000000L, active1, 0x4L, active2, 0L, active3, 0L); - case 84: - return jjMoveStringLiteralDfa2_2(active0, 0x80000000000000L, active1, 0x2000L, active2, 0L, active3, 0L); - case 85: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x1000000000020000L, active2, 0L, active3, 0L); - case 88: - if ((active3 & 0x1000000000L) != 0L) - return jjStopAtPos(1, 228); - return jjMoveStringLiteralDfa2_2(active0, 0x500000000000L, active1, 0L, active2, 0L, active3, 0L); - case 89: - if ((active0 & 0x2000000000000000L) != 0L) - return jjStartNfaWithStates_2(1, 61, 229); - break; - case 92: - if ((active2 & 0x1L) != 0L) - return jjStopAtPos(1, 128); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x200000000L); - case 93: - if ((active1 & 0x100000000000000L) != 0L) - return jjStopAtPos(1, 120); - break; - case 94: - if ((active2 & 0x800000000000000L) != 0L) - return jjStopAtPos(1, 187); - break; - case 95: - if ((active1 & 0x80000000L) != 0L) - return jjStopAtPos(1, 95); - break; - case 97: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x30L, active3, 0L); - case 98: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0xc0L, active3, 0L); - case 99: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x1f00L, active3, 0L); - case 100: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x6000L, active3, 0L); - case 101: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x8000L, active3, 0L); - case 103: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x30000L, active3, 0L); - case 105: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0xc0000L, active3, 0L); - case 108: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x20000000000000L, active2, 0x1e00000L, active3, 0L); - case 110: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x40000000000000L, active2, 0L, active3, 0x400000000L); - case 111: - if ((active2 & 0x2000000L) != 0L) - { - jjmatchedKind = 153; - jjmatchedPos = 1; - } - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x7c000000L, active3, 0L); - case 112: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x380000000L, active3, 0L); - case 115: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x1fffc00000000L, active3, 0L); - case 116: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x800000000L); - case 117: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x2000000100000L, active3, 0L); - case 119: - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0L, active2, 0x4000000000000L, active3, 0L); - case 124: - if ((active1 & 0x200000000L) != 0L) - return jjStopAtPos(1, 97); - else if ((active2 & 0x80000000000000L) != 0L) - return jjStopAtPos(1, 183); - else if ((active2 & 0x4000000000000000L) != 0L) - { - jjmatchedKind = 190; - jjmatchedPos = 1; - } - else if ((active3 & 0x2000L) != 0L) - return jjStopAtPos(1, 205); - return jjMoveStringLiteralDfa2_2(active0, 0L, active1, 0x20000000L, active2, 0L, active3, 0L); - case 125: - if ((active1 & 0x400000000L) != 0L) - return jjStopAtPos(1, 98); - break; - default : - break; - } - return jjStartNfa_2(0, active0, active1, active2, active3); -} -private final int jjMoveStringLiteralDfa2_2(long old0, long active0, long old1, long active1, long old2, long active2, long old3, long active3) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2) | (active3 &= old3)) == 0L) - return jjStartNfa_2(0, old0, old1, old2, old3); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(1, active0, active1, active2, active3); - return 2; - } - switch(curChar) - { - case 41: - if ((active3 & 0x20000000L) != 0L) - return jjStopAtPos(2, 221); - else if ((active3 & 0x40000000L) != 0L) - return jjStopAtPos(2, 222); - else if ((active3 & 0x80000000L) != 0L) - return jjStopAtPos(2, 223); - else if ((active3 & 0x100000000L) != 0L) - return jjStopAtPos(2, 224); - break; - case 45: - if ((active1 & 0x20000000L) != 0L) - return jjStopAtPos(2, 93); - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x8000000000000000L, active3, 0L); - case 46: - if ((active3 & 0x800L) != 0L) - return jjStopAtPos(2, 203); - break; - case 61: - if ((active3 & 0x10000000L) != 0L) - return jjStopAtPos(2, 220); - break; - case 62: - if ((active1 & 0x80000000000L) != 0L) - return jjStopAtPos(2, 107); - else if ((active3 & 0x20L) != 0L) - return jjStopAtPos(2, 197); - break; - case 65: - if ((active0 & 0x800000000000000L) != 0L) - return jjStopAtPos(2, 59); - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x400000000002000L, active2, 0L, active3, 0L); - case 66: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x1000000000000000L, active2, 0L, active3, 0L); - case 67: - return jjMoveStringLiteralDfa3_2(active0, 0x10100000000000L, active1, 0x800000000009000L, active2, 0L, active3, 0L); - case 68: - if ((active1 & 0x800L) != 0L) - return jjStartNfaWithStates_2(2, 75, 229); - return jjMoveStringLiteralDfa3_2(active0, 0x20000000000000L, active1, 0x8L, active2, 0L, active3, 0L); - case 69: - if ((active0 & 0x400000000000000L) != 0L) - return jjStopAtPos(2, 58); - else if ((active1 & 0x4L) != 0L) - return jjStartNfaWithStates_2(2, 66, 229); - return jjMoveStringLiteralDfa3_2(active0, 0x1000000000000000L, active1, 0x2L, active2, 0L, active3, 0L); - case 70: - return jjMoveStringLiteralDfa3_2(active0, 0x8000000000000000L, active1, 0x20000L, active2, 0L, active3, 0L); - case 72: - return jjMoveStringLiteralDfa3_2(active0, 0x80000000000000L, active1, 0L, active2, 0L, active3, 0L); - case 73: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x2000000000000040L, active2, 0L, active3, 0L); - case 75: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x100L, active2, 0L, active3, 0L); - case 76: - return jjMoveStringLiteralDfa3_2(active0, 0x4000000000000000L, active1, 0L, active2, 0L, active3, 0L); - case 77: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x4000000000000080L, active2, 0L, active3, 0L); - case 79: - return jjMoveStringLiteralDfa3_2(active0, 0x20000000000L, active1, 0x600L, active2, 0L, active3, 0L); - case 83: - return jjMoveStringLiteralDfa3_2(active0, 0x2094000000000L, active1, 0L, active2, 0L, active3, 0L); - case 84: - if ((active0 & 0x4000000000000L) != 0L) - return jjStartNfaWithStates_2(2, 50, 229); - return jjMoveStringLiteralDfa3_2(active0, 0x400000000000L, active1, 0x110000L, active2, 0L, active3, 0L); - case 86: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x30L, active2, 0L, active3, 0L); - case 87: - if ((active0 & 0x40000000000000L) != 0L) - return jjStartNfaWithStates_2(2, 54, 229); - break; - case 88: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0L, active3, 0x200000000L); - case 95: - if ((active0 & 0x200000000000000L) != 0L) - return jjStopAtPos(2, 57); - else if ((active1 & 0x80000L) != 0L) - return jjStopAtPos(2, 83); - else if ((active1 & 0x4000000000L) != 0L) - return jjStopAtPos(2, 102); - break; - case 97: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x200100L, active3, 0L); - case 100: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x4000200L, active3, 0L); - case 101: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x40000000000000L, active2, 0x410000L, active3, 0L); - case 103: - if ((active2 & 0x20000L) != 0L) - return jjStopAtPos(2, 145); - break; - case 105: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0xc00002440L, active3, 0x800000000L); - case 108: - if ((active2 & 0x800000L) != 0L) - return jjStopAtPos(2, 151); - break; - case 109: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x8000000L, active3, 0L); - case 110: - if ((active2 & 0x40000L) != 0L) - { - jjmatchedKind = 146; - jjmatchedPos = 2; - } - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0x20000000000000L, active2, 0x180000L, active3, 0L); - case 111: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x1004800L, active3, 0x400000000L); - case 112: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x2000010000010L, active3, 0L); - case 113: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x3f000008000L, active3, 0L); - case 114: - if ((active2 & 0x4000000000000L) != 0L) - return jjStopAtPos(2, 178); - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x380000000L, active3, 0L); - case 115: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x20000020L, active3, 0L); - case 116: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x40040000000L, active3, 0L); - case 117: - return jjMoveStringLiteralDfa3_2(active0, 0L, active1, 0L, active2, 0x1f80000001080L, active3, 0L); - default : - break; - } - return jjStartNfa_2(1, active0, active1, active2, active3); -} -private final int jjMoveStringLiteralDfa3_2(long old0, long active0, long old1, long active1, long old2, long active2, long old3, long active3) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2) | (active3 &= old3)) == 0L) - return jjStartNfa_2(1, old0, old1, old2, old3); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(2, active0, active1, active2, active3); - return 3; - } - switch(curChar) - { - case 41: - if ((active3 & 0x200000000L) != 0L) - return jjStopAtPos(3, 225); - break; - case 62: - if ((active2 & 0x8000000000000000L) != 0L) - return jjStopAtPos(3, 191); - break; - case 65: - return jjMoveStringLiteralDfa4_2(active0, 0x10000000000000L, active1, 0x4000000000000000L, active2, 0L, active3, 0L); - case 66: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x400000000000080L, active2, 0L, active3, 0L); - case 69: - if ((active0 & 0x10000000000L) != 0L) - return jjStartNfaWithStates_2(3, 40, 229); - else if ((active0 & 0x80000000000L) != 0L) - return jjStartNfaWithStates_2(3, 43, 229); - else if ((active1 & 0x8L) != 0L) - return jjStartNfaWithStates_2(3, 67, 229); - else if ((active1 & 0x10L) != 0L) - return jjStartNfaWithStates_2(3, 68, 229); - else if ((active1 & 0x100L) != 0L) - return jjStartNfaWithStates_2(3, 72, 229); - return jjMoveStringLiteralDfa4_2(active0, 0x80500000000000L, active1, 0L, active2, 0L, active3, 0L); - case 70: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x20000L, active2, 0L, active3, 0L); - case 72: - if ((active1 & 0x100000L) != 0L) - return jjStartNfaWithStates_2(3, 84, 231); - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x800000000000000L, active2, 0L, active3, 0L); - case 73: - return jjMoveStringLiteralDfa4_2(active0, 0x8000000000000000L, active1, 0x20L, active2, 0L, active3, 0L); - case 75: - if ((active1 & 0x8000L) != 0L) - return jjStartNfaWithStates_2(3, 79, 229); - break; - case 78: - if ((active0 & 0x1000000000000000L) != 0L) - return jjStartNfaWithStates_2(3, 60, 229); - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x10000L, active2, 0L, active3, 0L); - case 79: - return jjMoveStringLiteralDfa4_2(active0, 0x20000000000L, active1, 0x2000000000000202L, active2, 0L, active3, 0L); - case 83: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x1000000000000000L, active2, 0L, active3, 0L); - case 84: - return jjMoveStringLiteralDfa4_2(active0, 0x2000000000000L, active1, 0x2040L, active2, 0L, active3, 0L); - case 85: - return jjMoveStringLiteralDfa4_2(active0, 0x20004000000000L, active1, 0x1000L, active2, 0L, active3, 0L); - case 86: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x400L, active2, 0L, active3, 0L); - case 89: - if ((active0 & 0x4000000000000000L) != 0L) - return jjStartNfaWithStates_2(3, 62, 229); - break; - case 97: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x40000000000L, active3, 0L); - case 98: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x180000000000L, active3, 0L); - case 99: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x603000000000L, active3, 0L); - case 101: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x180000000L, active3, 0L); - case 103: - if ((active1 & 0x40000000000000L) != 0L) - return jjStopAtPos(3, 118); - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x40L, active3, 0L); - case 105: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x48100000L, active3, 0L); - case 108: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x2000030000080L, active3, 0L); - case 109: - if ((active2 & 0x400000000L) != 0L) - { - jjmatchedKind = 162; - jjmatchedPos = 3; - } - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x800000000L, active3, 0x800000000L); - case 110: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x200800L, active3, 0L); - case 111: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0x20000000000000L, active2, 0x204000200L, active3, 0L); - case 112: - if ((active2 & 0x100L) != 0L) - return jjStopAtPos(3, 136); - else if ((active2 & 0x1000L) != 0L) - return jjStopAtPos(3, 140); - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x1800000000010L, active3, 0L); - case 113: - if ((active2 & 0x10000L) != 0L) - return jjStopAtPos(3, 144); - else if ((active2 & 0x400000L) != 0L) - return jjStopAtPos(3, 150); - break; - case 114: - if ((active2 & 0x1000000L) != 0L) - return jjStopAtPos(3, 152); - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x400L, active3, 0L); - case 115: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x3c000000000L, active3, 0L); - case 116: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x84000L, active3, 0x400000000L); - case 117: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x8000L, active3, 0L); - case 118: - if ((active2 & 0x2000L) != 0L) - return jjStopAtPos(3, 141); - break; - case 121: - return jjMoveStringLiteralDfa4_2(active0, 0L, active1, 0L, active2, 0x20L, active3, 0L); - default : - break; - } - return jjStartNfa_2(2, active0, active1, active2, active3); -} -private final int jjMoveStringLiteralDfa4_2(long old0, long active0, long old1, long active1, long old2, long active2, long old3, long active3) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2) | (active3 &= old3)) == 0L) - return jjStartNfa_2(2, old0, old1, old2, old3); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(3, active0, active1, active2, active3); - return 4; - } - switch(curChar) - { - case 65: - return jjMoveStringLiteralDfa5_2(active0, 0x2000000000000L, active1, 0x800000000000000L, active2, 0L, active3, 0L); - case 68: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x80L, active2, 0L, active3, 0L); - case 69: - if ((active1 & 0x400L) != 0L) - return jjStartNfaWithStates_2(4, 74, 229); - else if ((active1 & 0x2000L) != 0L) - return jjStartNfaWithStates_2(4, 77, 231); - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x1000000000010000L, active2, 0L, active3, 0L); - case 70: - if ((active1 & 0x200L) != 0L) - return jjStartNfaWithStates_2(4, 73, 229); - break; - case 73: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x4000000000020000L, active2, 0L, active3, 0L); - case 76: - if ((active0 & 0x10000000000000L) != 0L) - return jjStartNfaWithStates_2(4, 52, 229); - return jjMoveStringLiteralDfa5_2(active0, 0x20000000000000L, active1, 0x400000000000000L, active2, 0L, active3, 0L); - case 77: - return jjMoveStringLiteralDfa5_2(active0, 0x4000000000L, active1, 0L, active2, 0L, active3, 0L); - case 78: - if ((active1 & 0x2000000000000000L) != 0L) - return jjStartNfaWithStates_2(4, 125, 229); - return jjMoveStringLiteralDfa5_2(active0, 0x8000400000000000L, active1, 0L, active2, 0L, active3, 0L); - case 79: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x20L, active2, 0L, active3, 0L); - case 80: - return jjMoveStringLiteralDfa5_2(active0, 0x100000000000L, active1, 0L, active2, 0L, active3, 0L); - case 82: - if ((active0 & 0x80000000000000L) != 0L) - return jjStartNfaWithStates_2(4, 55, 229); - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x1002L, active2, 0L, active3, 0L); - case 83: - return jjMoveStringLiteralDfa5_2(active0, 0x20000000000L, active1, 0L, active2, 0L, active3, 0L); - case 84: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0x40L, active2, 0L, active3, 0L); - case 97: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x1020000000L, active3, 0L); - case 99: - if ((active2 & 0x400L) != 0L) - return jjStopAtPos(4, 138); - else if ((active2 & 0x80000000L) != 0L) - { - jjmatchedKind = 159; - jjmatchedPos = 4; - } - else if ((active2 & 0x200000000000L) != 0L) - { - jjmatchedKind = 173; - jjmatchedPos = 4; - } - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x400100000040L, active3, 0L); - case 100: - if ((active2 & 0x200000L) != 0L) - return jjStopAtPos(4, 149); - break; - case 101: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x800084000L, active3, 0x800000000L); - case 103: - if ((active2 & 0x800L) != 0L) - return jjStopAtPos(4, 139); - break; - case 105: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x8000L, active3, 0x400000000L); - case 108: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x80L, active3, 0L); - case 109: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x40000020L, active3, 0L); - case 110: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x8000000L, active3, 0L); - case 111: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x100000L, active3, 0L); - case 112: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x200000000L, active3, 0L); - case 114: - if ((active2 & 0x40000000000L) != 0L) - return jjStopAtPos(4, 170); - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x10L, active3, 0L); - case 115: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x1980000000000L, active3, 0L); - case 116: - if ((active1 & 0x20000000000000L) != 0L) - return jjStopAtPos(4, 117); - else if ((active2 & 0x200L) != 0L) - return jjStopAtPos(4, 137); - else if ((active2 & 0x4000000L) != 0L) - return jjStopAtPos(4, 154); - break; - case 117: - return jjMoveStringLiteralDfa5_2(active0, 0L, active1, 0L, active2, 0x203e010000000L, active3, 0L); - default : - break; - } - return jjStartNfa_2(3, active0, active1, active2, active3); -} -private final int jjMoveStringLiteralDfa5_2(long old0, long active0, long old1, long active1, long old2, long active2, long old3, long active3) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2) | (active3 &= old3)) == 0L) - return jjStartNfa_2(3, old0, old1, old2, old3); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(4, active0, active1, active2, active3); - return 5; - } - switch(curChar) - { - case 65: - if ((active1 & 0x80L) != 0L) - return jjStartNfaWithStates_2(5, 71, 229); - break; - case 67: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0x20000L, active2, 0L, active3, 0L); - case 68: - return jjMoveStringLiteralDfa6_2(active0, 0x400000000000L, active1, 0L, active2, 0L, active3, 0L); - case 69: - if ((active0 & 0x4000000000L) != 0L) - return jjStartNfaWithStates_2(5, 38, 229); - else if ((active0 & 0x20000000000L) != 0L) - return jjStartNfaWithStates_2(5, 41, 229); - else if ((active0 & 0x20000000000000L) != 0L) - return jjStartNfaWithStates_2(5, 53, 229); - else if ((active0 & 0x8000000000000000L) != 0L) - return jjStartNfaWithStates_2(5, 63, 229); - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0x400000000000042L, active2, 0L, active3, 0L); - case 78: - if ((active1 & 0x4000000000000000L) != 0L) - return jjStartNfaWithStates_2(5, 126, 229); - return jjMoveStringLiteralDfa6_2(active0, 0x2000000000000L, active1, 0x800000000000000L, active2, 0L, active3, 0L); - case 83: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0x11000L, active2, 0L, active3, 0L); - case 84: - if ((active0 & 0x100000000000L) != 0L) - return jjStartNfaWithStates_2(5, 44, 229); - else if ((active1 & 0x1000000000000000L) != 0L) - return jjStartNfaWithStates_2(5, 124, 231); - break; - case 85: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0x20L, active2, 0L, active3, 0L); - case 98: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x14000000000L, active3, 0L); - case 101: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x1d80140000080L, active3, 0L); - case 105: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x40L, active3, 0L); - case 110: - if ((active2 & 0x100000L) != 0L) - return jjStopAtPos(5, 148); - else if ((active3 & 0x400000000L) != 0L) - return jjStopAtPos(5, 226); - break; - case 111: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x10L, active3, 0L); - case 112: - if ((active2 & 0x20L) != 0L) - return jjStopAtPos(5, 133); - else if ((active2 & 0x1000000000L) != 0L) - return jjStopAtPos(5, 164); - else if ((active2 & 0x2000000000L) != 0L) - return jjStopAtPos(5, 165); - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x28000000000L, active3, 0L); - case 113: - if ((active2 & 0x4000L) != 0L) - return jjStopAtPos(5, 142); - else if ((active2 & 0x800000000L) != 0L) - return jjStopAtPos(5, 163); - break; - case 114: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x80000L, active3, 0L); - case 115: - if ((active2 & 0x10000000L) != 0L) - return jjStopAtPos(5, 156); - else if ((active2 & 0x2000000000000L) != 0L) - return jjStopAtPos(5, 177); - else if ((active3 & 0x800000000L) != 0L) - return jjStopAtPos(5, 227); - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x20000000L, active3, 0L); - case 116: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x200000000L, active3, 0L); - case 117: - return jjMoveStringLiteralDfa6_2(active0, 0L, active1, 0L, active2, 0x8000000L, active3, 0L); - case 118: - if ((active2 & 0x8000L) != 0L) - return jjStopAtPos(5, 143); - break; - default : - break; - } - return jjStartNfa_2(4, active0, active1, active2, active3); -} -private final int jjMoveStringLiteralDfa6_2(long old0, long active0, long old1, long active1, long old2, long active2, long old3, long active3) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2) | (active3 &= old3)) == 0L) - return jjStartNfa_2(4, old0, old1, old2, old3); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(5, active0, active1, active2, 0L); - return 6; - } - switch(curChar) - { - case 67: - return jjMoveStringLiteralDfa7_2(active0, 0x2000000000000L, active1, 0L, active2, 0L); - case 68: - if ((active1 & 0x40L) != 0L) - return jjStartNfaWithStates_2(6, 70, 229); - else if ((active1 & 0x400000000000000L) != 0L) - return jjStartNfaWithStates_2(6, 122, 229); - break; - case 69: - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0x20000L, active2, 0L); - case 71: - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0x800000000000000L, active2, 0L); - case 73: - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0x1000L, active2, 0L); - case 77: - if ((active1 & 0x2L) != 0L) - return jjStartNfaWithStates_2(6, 65, 229); - break; - case 83: - if ((active0 & 0x400000000000L) != 0L) - return jjStartNfaWithStates_2(6, 46, 229); - else if ((active1 & 0x20L) != 0L) - return jjStartNfaWithStates_2(6, 69, 229); - else if ((active1 & 0x10000L) != 0L) - return jjStartNfaWithStates_2(6, 80, 231); - break; - case 104: - if ((active2 & 0x20000000L) != 0L) - return jjStopAtPos(6, 157); - break; - case 111: - if ((active2 & 0x200000000L) != 0L) - return jjStopAtPos(6, 161); - break; - case 113: - if ((active2 & 0x100000000L) != 0L) - return jjStopAtPos(6, 160); - else if ((active2 & 0x400000000000L) != 0L) - return jjStopAtPos(6, 174); - break; - case 114: - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0L, active2, 0x40L); - case 115: - if ((active2 & 0x8000000L) != 0L) - return jjStopAtPos(6, 155); - else if ((active2 & 0x40000000L) != 0L) - return jjStopAtPos(6, 158); - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0L, active2, 0x3c000080000L); - case 116: - if ((active2 & 0x80L) != 0L) - return jjStopAtPos(6, 135); - else if ((active2 & 0x80000000000L) != 0L) - { - jjmatchedKind = 171; - jjmatchedPos = 6; - } - else if ((active2 & 0x800000000000L) != 0L) - { - jjmatchedKind = 175; - jjmatchedPos = 6; - } - return jjMoveStringLiteralDfa7_2(active0, 0L, active1, 0L, active2, 0x1100000000000L); - case 120: - if ((active2 & 0x10L) != 0L) - return jjStopAtPos(6, 132); - break; - default : - break; - } - return jjStartNfa_2(5, active0, active1, active2, 0L); -} -private final int jjMoveStringLiteralDfa7_2(long old0, long active0, long old1, long active1, long old2, long active2) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2)) == 0L) - return jjStartNfa_2(5, old0, old1, old2, 0L); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(6, active0, active1, active2, 0L); - return 7; - } - switch(curChar) - { - case 69: - if ((active0 & 0x2000000000000L) != 0L) - return jjStartNfaWithStates_2(7, 49, 229); - return jjMoveStringLiteralDfa8_2(active0, 0L, active1, 0x800000000000000L, active2, 0L); - case 83: - if ((active1 & 0x20000L) != 0L) - return jjStartNfaWithStates_2(7, 81, 231); - break; - case 86: - return jjMoveStringLiteralDfa8_2(active0, 0L, active1, 0x1000L, active2, 0L); - case 99: - if ((active2 & 0x40L) != 0L) - return jjStopAtPos(7, 134); - break; - case 101: - return jjMoveStringLiteralDfa8_2(active0, 0L, active1, 0L, active2, 0x113c000080000L); - default : - break; - } - return jjStartNfa_2(6, active0, active1, active2, 0L); -} -private final int jjMoveStringLiteralDfa8_2(long old0, long active0, long old1, long active1, long old2, long active2) -{ - if (((active0 &= old0) | (active1 &= old1) | (active2 &= old2)) == 0L) - return jjStartNfa_2(6, old0, old1, old2, 0L); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(7, 0L, active1, active2, 0L); - return 8; - } - switch(curChar) - { - case 68: - if ((active1 & 0x800000000000000L) != 0L) - return jjStartNfaWithStates_2(8, 123, 229); - break; - case 69: - if ((active1 & 0x1000L) != 0L) - return jjStartNfaWithStates_2(8, 76, 229); - break; - case 99: - return jjMoveStringLiteralDfa9_2(active1, 0L, active2, 0x80000L); - case 113: - if ((active2 & 0x100000000000L) != 0L) - return jjStopAtPos(8, 172); - else if ((active2 & 0x1000000000000L) != 0L) - return jjStopAtPos(8, 176); - break; - case 116: - if ((active2 & 0x4000000000L) != 0L) - { - jjmatchedKind = 166; - jjmatchedPos = 8; - } - else if ((active2 & 0x8000000000L) != 0L) - { - jjmatchedKind = 167; - jjmatchedPos = 8; - } - return jjMoveStringLiteralDfa9_2(active1, 0L, active2, 0x30000000000L); - default : - break; - } - return jjStartNfa_2(7, 0L, active1, active2, 0L); -} -private final int jjMoveStringLiteralDfa9_2(long old1, long active1, long old2, long active2) -{ - if (((active1 &= old1) | (active2 &= old2)) == 0L) - return jjStartNfa_2(7, 0L, old1, old2, 0L); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(8, 0L, 0L, active2, 0L); - return 9; - } - switch(curChar) - { - case 101: - return jjMoveStringLiteralDfa10_2(active2, 0x30000000000L); - case 116: - if ((active2 & 0x80000L) != 0L) - return jjStopAtPos(9, 147); - break; - default : - break; - } - return jjStartNfa_2(8, 0L, 0L, active2, 0L); -} -private final int jjMoveStringLiteralDfa10_2(long old2, long active2) -{ - if (((active2 &= old2)) == 0L) - return jjStartNfa_2(8, 0L, 0L, old2, 0L); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_2(9, 0L, 0L, active2, 0L); - return 10; - } - switch(curChar) - { - case 113: - if ((active2 & 0x10000000000L) != 0L) - return jjStopAtPos(10, 168); - else if ((active2 & 0x20000000000L) != 0L) - return jjStopAtPos(10, 169); - break; - default : - break; - } - return jjStartNfa_2(9, 0L, 0L, active2, 0L); -} -static final long[] jjbitVec0 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_2(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 229; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 166: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(181, 182); - else if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(182); - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(178, 179); - else if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(179); - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(173, 174); - else if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(174); - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(167, 168); - else if ((0xc0000000000L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 171; - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 230) - kind = 230; - jjCheckNAdd(165); - } - else if ((0xc0000000000L & l) != 0L) - { - if (kind > 231) - kind = 231; - } - break; - case 146: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - } - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(151, 153); - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 230: - case 31: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(31, 32); - break; - case 80: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 4: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 108) - kind = 108; - jjCheckNAddStates(37, 45); - } - else if (curChar == 60) - jjCheckNAddStates(46, 55); - else if (curChar == 45) - jjAddStates(56, 57); - else if (curChar == 40) - jjAddStates(58, 59); - else if (curChar == 34) - jjCheckNAddStates(60, 63); - else if (curChar == 61) - jjstateSet[jjnewStateCnt++] = 3; - if (curChar == 48) - { - if (kind > 108) - kind = 108; - } - break; - case 220: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 223: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 12: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 18: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 70: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 112: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 87: - if (curChar == 42) - { - if (kind > 26) - kind = 26; - } - if (curChar == 42) - jjstateSet[jjnewStateCnt++] = 86; - break; - case 99: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 101; - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 90; - break; - case 229: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 221: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 82: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 13: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 19: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 209: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 100: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 103; - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 99; - break; - case 81: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 222: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 14: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 231: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - } - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 152; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(151, 153); - else if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 148; - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 0: - case 1: - if (curChar != 61) - break; - if (kind > 36) - kind = 36; - jjCheckNAdd(1); - break; - case 2: - if (curChar == 61) - jjstateSet[jjnewStateCnt++] = 0; - break; - case 3: - if (curChar == 61) - jjstateSet[jjnewStateCnt++] = 2; - break; - case 21: - if (curChar == 48 && kind > 108) - kind = 108; - break; - case 22: - case 28: - if (curChar == 34) - jjCheckNAddStates(60, 63); - break; - case 23: - if ((0xfffffffbffffdbffL & l) != 0L) - jjCheckNAddStates(60, 63); - break; - case 25: - if ((0xffffff7fffffffffL & l) != 0L) - jjAddStates(64, 65); - break; - case 26: - if (curChar == 39) - jjCheckNAddStates(60, 63); - break; - case 29: - if (curChar == 34 && kind > 109) - kind = 109; - break; - case 33: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 33; - break; - case 35: - case 36: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(36); - break; - case 42: - if ((0xff000000000000L & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjstateSet[jjnewStateCnt++] = 42; - break; - case 44: - if ((0x3000000000000L & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjstateSet[jjnewStateCnt++] = 44; - break; - case 46: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjstateSet[jjnewStateCnt++] = 46; - break; - case 85: - if (curChar == 40) - jjAddStates(58, 59); - break; - case 86: - if (curChar == 46 && kind > 26) - kind = 26; - break; - case 88: - if (curChar == 42 && kind > 26) - kind = 26; - break; - case 89: - if (curChar == 45) - jjAddStates(56, 57); - break; - case 90: - case 91: - if (curChar == 45) - jjCheckNAddStates(66, 68); - break; - case 92: - if (curChar == 32) - jjCheckNAddTwoStates(92, 98); - break; - case 101: - case 102: - if (curChar != 45) - break; - if (kind > 35) - kind = 35; - jjCheckNAdd(102); - break; - case 103: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 101; - break; - case 104: - if (curChar == 45) - jjstateSet[jjnewStateCnt++] = 103; - break; - case 129: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjCheckNAddStates(37, 45); - break; - case 130: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjCheckNAdd(130); - break; - case 131: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(131, 134); - break; - case 133: - case 148: - case 158: - if (curChar == 47) - jjCheckNAdd(132); - break; - case 134: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 133; - break; - case 135: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(135, 138); - break; - case 136: - if (curChar == 47 && kind > 111) - kind = 111; - break; - case 138: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 137; - break; - case 139: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(139, 140); - break; - case 141: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 141; - break; - case 142: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(142, 143); - break; - case 144: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 144; - break; - case 147: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 149: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 148; - break; - case 150: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(151, 153); - break; - case 151: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(151, 153); - break; - case 153: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 152; - break; - case 154: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - break; - case 155: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - break; - case 157: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 159: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 158; - break; - case 160: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(160, 162); - break; - case 162: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 161; - break; - case 163: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - break; - case 164: - if (curChar == 60) - jjCheckNAddStates(46, 55); - break; - case 165: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 230) - kind = 230; - jjCheckNAdd(165); - break; - case 167: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(167, 168); - break; - case 168: - if (curChar == 62) - jjCheckNAdd(169); - break; - case 169: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 232) - kind = 232; - jjCheckNAdd(169); - break; - case 170: - if ((0xc0000000000L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 171; - break; - case 171: - if (curChar == 62) - jjCheckNAdd(172); - break; - case 172: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 233) - kind = 233; - jjCheckNAdd(172); - break; - case 173: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(173, 174); - break; - case 174: - if (curChar == 62) - jjCheckNAdd(175); - break; - case 175: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(175, 176); - break; - case 176: - if (curChar != 46) - break; - if (kind > 234) - kind = 234; - jjCheckNAdd(176); - break; - case 177: - if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(174); - break; - case 178: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(178, 179); - break; - case 179: - if (curChar == 62 && kind > 235) - kind = 235; - break; - case 180: - if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(179); - break; - case 181: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(181, 182); - break; - case 182: - if (curChar == 62) - jjCheckNAddStates(69, 71); - break; - case 183: - if (curChar != 42) - break; - if (kind > 236) - kind = 236; - jjCheckNAdd(184); - break; - case 184: - if (curChar != 46) - break; - if (kind > 236) - kind = 236; - jjCheckNAdd(184); - break; - case 185: - if (curChar != 45) - break; - if (kind > 236) - kind = 236; - jjCheckNAdd(186); - break; - case 186: - if (curChar != 46) - break; - if (kind > 236) - kind = 236; - jjCheckNAdd(186); - break; - case 187: - if (curChar != 46) - break; - if (kind > 236) - kind = 236; - jjCheckNAdd(187); - break; - case 188: - if ((0xc0000000000L & l) != 0L) - jjCheckNAdd(182); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 146: - if ((0x7fffffe87ffffbeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - } - else if (curChar == 70) - { - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 35; - } - if ((0x7fffffe07ffffbeL & l) != 0L) - jjCheckNAddTwoStates(151, 153); - if ((0x7fffffe07ffffbeL & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 230: - if ((0x7fffffe87fffffeL & l) != 0L) - jjCheckNAddTwoStates(31, 32); - if ((0x7fffffe07fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(33); - } - break; - case 80: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 70) - jjstateSet[jjnewStateCnt++] = 82; - if (curChar == 70) - { - if (kind > 64) - kind = 64; - } - break; - case 4: - if ((0x7fffffe0777fffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAddStates(72, 76); - } - else if ((0x880000L & l) != 0L) - { - if (kind > 229) - kind = 229; - jjAddStates(77, 79); - } - else if (curChar == 92) - jjAddStates(80, 83); - else if (curChar == 64) - { - if (kind > 229) - kind = 229; - } - else if (curChar == 95) - jjCheckNAddTwoStates(31, 32); - if (curChar == 65) - jjAddStates(84, 87); - else if (curChar == 67) - jjAddStates(88, 90); - else if (curChar == 68) - jjAddStates(91, 92); - else if (curChar == 84) - jjAddStates(93, 94); - else if (curChar == 86) - jjAddStates(95, 96); - else if (curChar == 92) - jjAddStates(97, 99); - else if (curChar == 83) - jjCheckNAdd(34); - else if (curChar == 87) - jjCheckNAdd(34); - else if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 19; - else if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 14; - break; - case 220: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 219; - break; - case 223: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 222; - break; - case 12: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 11; - break; - case 18: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 17; - break; - case 70: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 77; - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 69; - break; - case 112: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 127; - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 119; - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 111; - break; - case 190: - if ((0x10000000100L & l) != 0L) - jjCheckNAdd(46); - else if ((0x400000004L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 44; - else if ((0x800000008000L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 42; - else if (curChar == 102) - jjstateSet[jjnewStateCnt++] = 202; - else if (curChar == 65) - { - if (kind > 47) - kind = 47; - } - else if (curChar == 101) - jjstateSet[jjnewStateCnt++] = 195; - else if (curChar == 69) - { - if (kind > 45) - kind = 45; - } - break; - case 229: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 221: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 220; - break; - case 82: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 83) - { - if (kind > 64) - kind = 64; - } - break; - case 13: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 12; - break; - case 19: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 18; - break; - case 209: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 88) - jjstateSet[jjnewStateCnt++] = 227; - else if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 223; - else if (curChar == 67) - jjstateSet[jjnewStateCnt++] = 214; - if (curChar == 67) - jjstateSet[jjnewStateCnt++] = 208; - break; - case 81: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 83; - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 80; - break; - case 222: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 85) - jjstateSet[jjnewStateCnt++] = 221; - break; - case 14: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 13; - break; - case 231: - if ((0x7fffffe87fffffeL & l) != 0L) - { - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - } - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(151, 153); - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 5: - if (curChar == 78 && kind > 56) - kind = 56; - break; - case 6: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 5; - break; - case 7: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 6; - break; - case 8: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 7; - break; - case 9: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 8; - break; - case 10: - if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 9; - break; - case 11: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 10; - break; - case 15: - if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 14; - break; - case 16: - if (curChar == 65 && kind > 56) - kind = 56; - break; - case 17: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 16; - break; - case 20: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 19; - break; - case 23: - if ((0xfffffffeefffffffL & l) != 0L) - jjCheckNAddStates(60, 63); - break; - case 24: - if (curChar == 96) - jjCheckNAddTwoStates(25, 26); - break; - case 25: - jjCheckNAddTwoStates(25, 26); - break; - case 27: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 28; - break; - case 28: - if ((0x14404010000000L & l) != 0L) - jjCheckNAddStates(60, 63); - break; - case 30: - if (curChar == 95) - jjCheckNAddTwoStates(31, 32); - break; - case 31: - if ((0x7fffffe87fffffeL & l) != 0L) - jjCheckNAddTwoStates(31, 32); - break; - case 32: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(33); - break; - case 33: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(33); - break; - case 34: - if (curChar != 70) - break; - if (kind > 229) - kind = 229; - jjstateSet[jjnewStateCnt++] = 35; - break; - case 35: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(36); - break; - case 36: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(36); - break; - case 37: - if (curChar == 87) - jjCheckNAdd(34); - break; - case 38: - if (curChar == 83) - jjCheckNAdd(34); - break; - case 39: - if (curChar == 64 && kind > 229) - kind = 229; - break; - case 40: - if (curChar == 92) - jjAddStates(97, 99); - break; - case 41: - if ((0x800000008000L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 42; - break; - case 43: - if ((0x400000004L & l) != 0L) - jjstateSet[jjnewStateCnt++] = 44; - break; - case 45: - if ((0x10000000100L & l) != 0L) - jjCheckNAdd(46); - break; - case 46: - if ((0x7e0000007eL & l) == 0L) - break; - if (kind > 108) - kind = 108; - jjCheckNAdd(46); - break; - case 47: - if (curChar == 86) - jjAddStates(95, 96); - break; - case 48: - if (curChar == 69 && kind > 82) - kind = 82; - break; - case 49: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 48; - break; - case 50: - if (curChar == 66) - jjstateSet[jjnewStateCnt++] = 49; - break; - case 51: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 50; - break; - case 52: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 51; - break; - case 53: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 52; - break; - case 54: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 53; - break; - case 55: - if (curChar == 83 && kind > 82) - kind = 82; - break; - case 56: - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 55; - break; - case 57: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 56; - break; - case 58: - if (curChar == 66) - jjstateSet[jjnewStateCnt++] = 57; - break; - case 59: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 58; - break; - case 60: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 59; - break; - case 61: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 60; - break; - case 62: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 61; - break; - case 63: - if (curChar == 84) - jjAddStates(93, 94); - break; - case 64: - if (curChar == 76 && kind > 78) - kind = 78; - break; - case 65: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 64; - break; - case 66: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 65; - break; - case 67: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 66; - break; - case 68: - if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 67; - break; - case 69: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 68; - break; - case 71: - if (curChar == 83 && kind > 78) - kind = 78; - break; - case 72: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 71; - break; - case 73: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 72; - break; - case 74: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 73; - break; - case 75: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 74; - break; - case 76: - if (curChar == 80) - jjstateSet[jjnewStateCnt++] = 75; - break; - case 77: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 76; - break; - case 78: - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 77; - break; - case 79: - if (curChar == 68) - jjAddStates(91, 92); - break; - case 83: - if (curChar == 70) - jjstateSet[jjnewStateCnt++] = 82; - break; - case 84: - if (curChar == 69) - jjstateSet[jjnewStateCnt++] = 83; - break; - case 93: - if (curChar == 69 && kind > 34) - kind = 34; - break; - case 94: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 93; - break; - case 95: - if (curChar == 85) - jjstateSet[jjnewStateCnt++] = 94; - break; - case 96: - if (curChar == 68) - jjstateSet[jjnewStateCnt++] = 95; - break; - case 97: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 96; - break; - case 98: - if (curChar == 77) - jjstateSet[jjnewStateCnt++] = 97; - break; - case 105: - if (curChar == 67) - jjAddStates(88, 90); - break; - case 106: - if (curChar == 84 && kind > 42) - kind = 42; - break; - case 107: - if (curChar == 78) - jjstateSet[jjnewStateCnt++] = 106; - break; - case 108: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 107; - break; - case 109: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 108; - break; - case 110: - if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 109; - break; - case 111: - if (curChar == 78) - jjstateSet[jjnewStateCnt++] = 110; - break; - case 113: - if (curChar == 83 && kind > 42) - kind = 42; - break; - case 114: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 113; - break; - case 115: - if (curChar == 78) - jjstateSet[jjnewStateCnt++] = 114; - break; - case 116: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 115; - break; - case 117: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 116; - break; - case 118: - if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 117; - break; - case 119: - if (curChar == 78) - jjstateSet[jjnewStateCnt++] = 118; - break; - case 120: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 119; - break; - case 121: - if (curChar == 89 && kind > 56) - kind = 56; - break; - case 122: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 121; - break; - case 123: - if (curChar == 65) - jjstateSet[jjnewStateCnt++] = 122; - break; - case 124: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 123; - break; - case 125: - if (curChar == 76) - jjstateSet[jjnewStateCnt++] = 124; - break; - case 126: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 125; - break; - case 127: - if (curChar == 82) - jjstateSet[jjnewStateCnt++] = 126; - break; - case 128: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 127; - break; - case 131: - if ((0x7fffffe07fffffeL & l) != 0L) - jjAddStates(100, 101); - break; - case 132: - if (curChar == 92 && kind > 110) - kind = 110; - break; - case 135: - if ((0x7fffffe07fffffeL & l) != 0L) - jjAddStates(102, 103); - break; - case 137: - case 152: - case 161: - if (curChar == 92) - jjCheckNAdd(136); - break; - case 139: - if ((0x7fffffe87fffffeL & l) != 0L) - jjAddStates(104, 105); - break; - case 140: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(141); - break; - case 141: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(141); - break; - case 143: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(144); - break; - case 144: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(144); - break; - case 145: - if ((0x880000L & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjAddStates(77, 79); - break; - case 147: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(147, 149); - break; - case 150: - if ((0x7fffffe07ffffbeL & l) != 0L) - jjCheckNAddTwoStates(151, 153); - break; - case 151: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(151, 153); - break; - case 154: - if ((0x7fffffe87ffffbeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - break; - case 155: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(155); - break; - case 156: - if ((0x7fffffe0777fffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAddStates(72, 76); - break; - case 157: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(157, 159); - break; - case 160: - if ((0x7fffffe07fffffeL & l) != 0L) - jjCheckNAddTwoStates(160, 162); - break; - case 163: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 229) - kind = 229; - jjCheckNAdd(163); - break; - case 169: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 232) - kind = 232; - jjstateSet[jjnewStateCnt++] = 169; - break; - case 172: - if ((0x7fffffe07fffffeL & l) == 0L) - break; - if (kind > 233) - kind = 233; - jjstateSet[jjnewStateCnt++] = 172; - break; - case 175: - if ((0x7fffffe07fffffeL & l) != 0L) - jjAddStates(106, 107); - break; - case 189: - if (curChar == 92) - jjAddStates(80, 83); - break; - case 191: - if (curChar == 115 && kind > 45) - kind = 45; - break; - case 192: - if (curChar == 116) - jjstateSet[jjnewStateCnt++] = 191; - break; - case 193: - if (curChar == 115) - jjstateSet[jjnewStateCnt++] = 192; - break; - case 194: - if (curChar == 105) - jjstateSet[jjnewStateCnt++] = 193; - break; - case 195: - if (curChar == 120) - jjstateSet[jjnewStateCnt++] = 194; - break; - case 196: - if (curChar == 101) - jjstateSet[jjnewStateCnt++] = 195; - break; - case 197: - if (curChar == 65 && kind > 47) - kind = 47; - break; - case 198: - if (curChar == 108 && kind > 47) - kind = 47; - break; - case 199: - if (curChar == 108) - jjstateSet[jjnewStateCnt++] = 198; - break; - case 200: - if (curChar == 97) - jjstateSet[jjnewStateCnt++] = 199; - break; - case 201: - if (curChar == 114) - jjstateSet[jjnewStateCnt++] = 200; - break; - case 202: - if (curChar == 111) - jjstateSet[jjnewStateCnt++] = 201; - break; - case 203: - if (curChar == 102) - jjstateSet[jjnewStateCnt++] = 202; - break; - case 204: - if (curChar == 65) - jjAddStates(84, 87); - break; - case 205: - if (curChar == 78 && kind > 37) - kind = 37; - break; - case 206: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 205; - break; - case 207: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 206; - break; - case 208: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 207; - break; - case 210: - if (curChar == 83 && kind > 37) - kind = 37; - break; - case 211: - if (curChar == 78) - jjstateSet[jjnewStateCnt++] = 210; - break; - case 212: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 211; - break; - case 213: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 212; - break; - case 214: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 213; - break; - case 215: - if (curChar == 67) - jjstateSet[jjnewStateCnt++] = 214; - break; - case 216: - if (curChar == 78 && kind > 39) - kind = 39; - break; - case 217: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 216; - break; - case 218: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 217; - break; - case 219: - if (curChar == 84) - jjstateSet[jjnewStateCnt++] = 218; - break; - case 224: - if (curChar == 83) - jjstateSet[jjnewStateCnt++] = 223; - break; - case 225: - if (curChar == 77 && kind > 39) - kind = 39; - break; - case 226: - if (curChar == 79) - jjstateSet[jjnewStateCnt++] = 225; - break; - case 227: - if (curChar == 73) - jjstateSet[jjnewStateCnt++] = 226; - break; - case 228: - if (curChar == 88) - jjstateSet[jjnewStateCnt++] = 227; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 23: - if ((jjbitVec0[i2] & l2) != 0L) - jjAddStates(60, 63); - break; - case 25: - if ((jjbitVec0[i2] & l2) != 0L) - jjAddStates(64, 65); - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 229 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_3(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} -private final int jjStartNfa_3(int pos, long active0) -{ - return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_3(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_3(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_3() -{ - switch(curChar) - { - case 42: - return jjMoveStringLiteralDfa1_3(0x20000000L); - default : - return jjMoveNfa_3(0, 0); - } -} -private final int jjMoveStringLiteralDfa1_3(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_3(0, active0); - return 1; - } - switch(curChar) - { - case 41: - if ((active0 & 0x20000000L) != 0L) - return jjStopAtPos(1, 29); - break; - default : - break; - } - return jjStartNfa_3(0, active0); -} -private final int jjMoveNfa_3(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 4; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if (curChar == 40) - jjAddStates(3, 4); - break; - case 1: - if (curChar == 46) - kind = 28; - break; - case 2: - if (curChar == 42) - jjstateSet[jjnewStateCnt++] = 1; - break; - case 3: - if (curChar == 42 && kind > 28) - kind = 28; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { - 1, 2, 8, 2, 3, 24, 25, 28, 29, 32, 33, 34, 36, 37, 2, 3, - 9, 14, 15, 51, 53, 54, 56, 51, 53, 54, 56, 57, 40, 44, 48, 25, - 28, 29, 32, 33, 34, 130, 131, 134, 135, 138, 139, 140, 142, 143, 165, 166, - 167, 170, 173, 177, 178, 180, 181, 188, 100, 104, 87, 88, 23, 24, 27, 29, - 25, 26, 91, 92, 98, 183, 185, 187, 157, 159, 160, 162, 163, 146, 150, 154, - 190, 196, 197, 203, 209, 215, 224, 228, 112, 120, 128, 81, 84, 70, 78, 54, - 62, 41, 43, 45, 131, 134, 135, 138, 139, 140, 175, 176, -}; -public static final String[] jjstrLiteralImages = { -"", null, "\55\55\55\76", null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, null, null, null, null, null, null, null, null, null, null, null, null, null, -null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "PRAGMA", - "SPEC", - "IN_COMMENT", - "EMBEDDED", - "IN_EOL_COMMENT", -}; -public static final int[] jjnewLexState = { - -1, -1, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, - -1, 3, 5, 4, 2, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0xfffffffc0018000dL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0x1f3fffffffffL, -}; -static final long[] jjtoSkip = { - 0x1f3e00010L, 0x0L, 0x0L, 0x0L, -}; -static final long[] jjtoSpecial = { - 0x1f0000000L, 0x0L, 0x0L, 0x0L, -}; -static final long[] jjtoMore = { - 0x20c000000L, 0x0L, 0x0L, 0xc000000000L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[229]; -private final int[] jjstateSet = new int[458]; -StringBuffer image; -int jjimageLen; -int lengthOfMatch; -protected char curChar; -public TLAplusParserTokenManager(SimpleCharStream stream){ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public TLAplusParserTokenManager(SimpleCharStream stream, int lexState){ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 229; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 6 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - return matchedToken; - } - image = null; - jjimageLen = 0; - - for (;;) - { - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - if (jjmatchedPos == 0 && jjmatchedKind > 4) - { - jjmatchedKind = 4; - } - break; - case 1: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - if (jjmatchedPos == 0 && jjmatchedKind > 21) - { - jjmatchedKind = 21; - } - break; - case 2: - try { input_stream.backup(0); - while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) - curChar = input_stream.BeginToken(); - } - catch (java.io.IOException e1) { continue EOFLoop; } - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_2(); - break; - case 3: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_3(); - if (jjmatchedPos == 0 && jjmatchedKind > 33) - { - jjmatchedKind = 33; - } - break; - case 4: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_4(); - if (jjmatchedPos == 0 && jjmatchedKind > 33) - { - jjmatchedKind = 33; - } - break; - case 5: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_5(); - if (jjmatchedPos == 0 && jjmatchedKind > 33) - { - jjmatchedKind = 33; - } - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - matchedToken.specialToken = specialToken; - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (specialToken == null) - specialToken = matchedToken; - else - { - matchedToken.specialToken = specialToken; - specialToken = (specialToken.next = matchedToken); - } - SkipLexicalActions(matchedToken); - } - else - SkipLexicalActions(null); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - jjimageLen += jjmatchedPos + 1; - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - curPos = 0; - jjmatchedKind = 0x7fffffff; - try { - curChar = input_stream.readChar(); - continue; - } - catch (java.io.IOException e1) { } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } -} - -void SkipLexicalActions(Token matchedToken) -{ - switch(jjmatchedKind) - { - case 28 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - bracketCount++; - break; - case 30 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - bracketCount--; if (bracketCount == 0) SwitchTo( IN_COMMENT ); - break; - case 31 : - if (image == null) - image = new StringBuffer(); - image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1))); - bracketCount++; - break; - default : - break; - } -} -} diff --git a/tlatools/src-gen/Token.java b/tlatools/src-gen/Token.java deleted file mode 100644 index 98d52deed3f6c211bdb0b96d562545ffbd438933..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/Token.java +++ /dev/null @@ -1,81 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -package tla2sany.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} diff --git a/tlatools/src-gen/TokenMgrError.java b/tlatools/src-gen/TokenMgrError.java deleted file mode 100644 index c84b74accd6e35307a785ade19be820b94868a38..0000000000000000000000000000000000000000 --- a/tlatools/src-gen/TokenMgrError.java +++ /dev/null @@ -1,133 +0,0 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -package tla2sany.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} diff --git a/tlatools/src/model/ModelInJar.java b/tlatools/src/model/ModelInJar.java index d823fda2e6e6aac46ce612d1ab8161be0aae3aa1..7edca84c2eacdae890e5f56e661874b3c54cc9d3 100644 --- a/tlatools/src/model/ModelInJar.java +++ b/tlatools/src/model/ModelInJar.java @@ -1,7 +1,11 @@ package model; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Enumeration; import java.util.Properties; @@ -12,6 +16,21 @@ public abstract class ModelInJar { return ModelInJar.class.getResource("/model/MC.tla") != null; } + public static boolean hasCfg() { + return ModelInJar.class.getResource("/model/MC.cfg") != null; + } + + public static File getCfg() { + try { + final InputStream source = ModelInJar.class.getResourceAsStream("/model/MC.cfg"); + Path target = Files.createTempFile("MC", ".cfg"); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + return target.toFile(); + } catch (IOException notExpectedToHappen) { + return new File(""); + } + } + public static boolean loadProperties() { InputStream in = ModelInJar.class .getResourceAsStream("/model/generated.properties"); diff --git a/tlatools/src/pcal/ParseAlgorithm.java b/tlatools/src/pcal/ParseAlgorithm.java index 3f8d7bd28890ff0aa99086e4ed4d65bf89b47d29..18849103fa924cf6451c5288d1c44bd5fefcebd1 100644 --- a/tlatools/src/pcal/ParseAlgorithm.java +++ b/tlatools/src/pcal/ParseAlgorithm.java @@ -108,11 +108,11 @@ package pcal; import java.util.Hashtable; import java.util.Vector; + import pcal.exception.ParseAlgorithmException; import pcal.exception.TLAExprException; import pcal.exception.TokenizerException; import pcal.exception.UnrecoverableException; -import tla2sany.parser.ParseError; import tla2tex.Debug; @@ -314,7 +314,8 @@ public class ParseAlgorithm * should be set to the position of the PcalParams.BeginAlg string by * * whatever method finds that string and calls GetAlgorithm. * **********************************************************************/ - { Init(charR) ; + { try { + Init(charR) ; if (fairAlgorithm) { String nextToken = GetAlgToken() ; if (!nextToken.equals(PcalParams.BeginFairAlg2)) { @@ -545,6 +546,14 @@ public class ParseAlgorithm GetLastLocationEnd())) ; return uniproc ; } + } catch (final RuntimeException e) { + // Catch generic/unhandled errors (ArrayIndexOutOfbounds/NullPointers/...) that + // the nested code might throw at us. Not converting them into a + // ParseAlgorithmException means the Toolbox silently fails to translate an + // algorithm (see Github issue at https://github.com/tlaplus/tlaplus/issues/313) + ParsingError("Unknown error at or before"); + return null; + } } /** @@ -954,6 +963,8 @@ public class ParseAlgorithm } else { result.unlabDo = GetCStmt() ; } ; + if (result.unlabDo.size() == 0) + { ParsingError("Missing body of while statement at"); } result.labDo = new Vector() ; /****************************************************************** * For historical reasons, some methods expect a labDo field to * diff --git a/tlatools/src/pcal/PcalParams.java b/tlatools/src/pcal/PcalParams.java index 7244b30ee741aaf0860f00e9ae5a42af1df8a5a3..2fc3b9087359b4e9c973cffefd000a5c3b44c0d6 100644 --- a/tlatools/src/pcal/PcalParams.java +++ b/tlatools/src/pcal/PcalParams.java @@ -18,8 +18,8 @@ public final class PcalParams /** * Parameters to be updated on each new release. */ - public static final String modDate = "16 May 2016"; - public static final String version = "1.8"; + public static final String modDate = "10 July 2019"; + public static final String version = "1.9"; /** * SZ Mar 9, 2009: * Added re-initialization method. Since PcalParams class diff --git a/tlatools/src/pcal/PcalTLAGen.java b/tlatools/src/pcal/PcalTLAGen.java index 02e72dd47d2c90d53b2464cf5384c33c4d585b76..9fa7e5f5b6b7c1c5bfa1e0dec10c08eecf2f36ae 100644 --- a/tlatools/src/pcal/PcalTLAGen.java +++ b/tlatools/src/pcal/PcalTLAGen.java @@ -5,7 +5,6 @@ import java.util.Vector; import pcal.AST.VarDecl; import pcal.exception.PcalTLAGenException; import pcal.exception.TLAExprException; -import tla2tex.Debug; /**************************************************************************** * Given an exploded and disambiguated AST, generate the equivalent TLA+. @@ -2715,7 +2714,65 @@ public class PcalTLAGen Vector nextS = new Vector(); StringBuffer sb = new StringBuffer(); int max, col; - + + if (! (PcalParams.NoDoneDisjunct || ParseAlgorithm.omitStutteringWhenDone)) + { +// tlacode.addElement(sb.toString()); + sb.append("(* Allow infinite stuttering to prevent deadlock on termination. *)"); + addOneLineOfTLA(sb.toString()); + + sb = new StringBuffer("Terminating == "); + if (mp) { + /************************************************************ + * Bug fix by LL on 6 Sep 2007. Added parentheses to * + * change * + * * + * (*) \A self \in ProcSet: ... /\ UNCHANGED vars * + * * + * to * + * * + * (**) (\A self \in ProcSet: ...) /\ UNCHANGED vars * + * * + * thus moving the UNCHANGED vars outside the quantifier. * + * Since self does not appear in UNCHANGED vars, the two * + * expressions are equivalent except when ProcSet is the * + * empty set, in which case (*) equals TRUE and (**) equals * + * UNCHANGED vars. * + ************************************************************/ + /************************************************************ + * Changed by MK on 19 Jun 2019 into a conjunct list * + * after modifying GenNext to generate an explicit * + * Terminating action before Next instead of the old * + * implicit disjunct-to-prevent-deadlock-on-termination. * + * This change also entailed to copy this if-block from the * + * end of GenNext here modifying the original one to * + * generate a call to Terminating. * + * * + * The rational for this change results from the recently * + * introduced TLC profiler. The profiler reports the number * + * of distinct successor states per action. * + * A terminating PlusCal algorithm has the implicit * + * disjunct-to-prevent-deadlock-on-termination sub-action of * + * the Next next-state action. Since the sub-action has no * + * identifier, the profiler has to report Next as generating * + * no successor states (which is bogus). With this change, * + * the profiler will report the Terminating sub-action to * + * generate no (distinct) successor states instead, which * + * is perfectly correct and easy to understand. * + ************************************************************/ + sb.append("/\\ \\A self \\in ProcSet: pc[self] = \"Done\""); + addOneLineOfTLA(sb.toString()); + sb = new StringBuffer(NSpaces("Terminating == ".length())); + sb.append("/\\ UNCHANGED vars"); + } else { + sb.append("pc = \"Done\" /\\ UNCHANGED vars"); +// tlacode.addElement(sb.toString()); + } + addOneLineOfTLA(sb.toString()); + addOneLineOfTLA(""); + } ; + sb = new StringBuffer(); + // Steps with no parameter max = wrapColumn - ("Next == \\/ ".length()); for (int i = 0; i < nextStep.size(); i++) @@ -2838,33 +2895,9 @@ public class PcalTLAGen sb = new StringBuffer(NSpaces(col) + " \\/ "); } if (! (PcalParams.NoDoneDisjunct || ParseAlgorithm.omitStutteringWhenDone)) - { sb.append("(* Disjunct to prevent deadlock on termination *)"); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col + 4)); - if (mp) - /************************************************************ - * Bug fix by LL on 6 Sep 2007. Added parentheses to * - * change * - * * - * (*) \A self \in ProcSet: ... /\ UNCHANGED vars * - * * - * to * - * * - * (**) (\A self \in ProcSet: ...) /\ UNCHANGED vars * - * * - * thus moving the UNCHANGED vars outside the quantifier. * - * Since self does not appear in UNCHANGED vars, the two * - * expressions are equivalent except when ProcSet is the * - * empty set, in which case (*) equals TRUE and (**) equals * - * UNCHANGED vars. * - ************************************************************/ - sb.append("((\\A self \\in ProcSet: pc[self] = \"Done\") /\\ " + "UNCHANGED vars)"); - else - sb.append("(pc = \"Done\" /\\ UNCHANGED vars)"); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - } ; + { + addOneLineOfTLA(sb.append("Terminating").toString()); + } addOneLineOfTLA(""); // tlacode.addElement(""); } diff --git a/tlatools/src/pcal/Region.java b/tlatools/src/pcal/Region.java index 548681978b01fba42469c74408e11ec4b5c58a17..5089e3c441c400a19770e6ebac4a75d8f39f6be2 100644 --- a/tlatools/src/pcal/Region.java +++ b/tlatools/src/pcal/Region.java @@ -55,11 +55,6 @@ public class Region implements Serializable { } public String toString() { -// return "[begin |-> " + begin.toString() + ", end |-> " -// + end.toString() + "]"; - if (this == null) { - return "null"; - } return "[" + begin.toString() + "-" + end.toString() + "]"; } diff --git a/tlatools/src/pcal/Tokenize.java b/tlatools/src/pcal/Tokenize.java index d81c982c210c75e442a98c31648261b607e29861..45a071c408c8fc51e59deb99459437af583c1218 100644 --- a/tlatools/src/pcal/Tokenize.java +++ b/tlatools/src/pcal/Tokenize.java @@ -814,6 +814,7 @@ public class Tokenize || tok.equals("procedure") || tok.equals("define") || tok.equals("process") + || tok.equals("fair") ) ; } diff --git a/tlatools/src/pcal/Translator.java b/tlatools/src/pcal/Translator.java index 5e118d7cb069e2f2148a5de4105b22f29b9c798b..ea3e62a8d3fea48f6ff7e37d52baba0906265a10 100644 --- a/tlatools/src/pcal/Translator.java +++ b/tlatools/src/pcal/Translator.java @@ -63,16 +63,21 @@ public class Translator */ public boolean translate() { final Vector<String> in = new Vector<String>(); - final String[] lines = input.split(System.getProperty("line.separator")); + // The input .tla file might have unix or windows line ending. If we fail to + // properly split the input (a line per array cell), the pcal translator will + // silently fail as well. + final String[] lines = input.split("\\r?\\n"); for (String line : lines) { in.add(line); } - final Vector<String> out = trans.runMe(in, PcalParams.tlaPcalMapping); + final Vector<String> out = trans.runMe(in); if (out != null) { final StringBuffer buf = new StringBuffer(out.size()); for (String line : out) { buf.append(line); + // The output .tla file will use the OS's line ending which is in line with the + // the translator's legacy behavior. buf.append(System.getProperty("line.separator")); } output = buf.toString(); diff --git a/tlatools/src/pcal/trans.java b/tlatools/src/pcal/trans.java index 31c9fe976e875c0b79d818a1647c81e1966c163a..a68c1a835f5fb40b43d31f14aaeff333eeb4f509 100644 --- a/tlatools/src/pcal/trans.java +++ b/tlatools/src/pcal/trans.java @@ -114,6 +114,14 @@ import util.ToolIO; * - Removed the unnecessary CASE in the pc = ... clause of * * the Init predicate when there is only a single process * * statement. * +* Version 1.9: (10 July 2019) * +* - Change translation to generate an explicit * +* Terminating action instead of the implicit one which * +* is the disjunct of the next-state relation. * +* - Support in-memory only translation for better * +* Toolbox integration (old file based translation was * +* racy). * +* - Minor changes related to better error reporting. * * ----------------------------------------------------------------- * * * * This is the main method of the +CAL to TLA+ translation program. * @@ -274,7 +282,7 @@ class trans /** Status indicating no errors and successful process */ static final int STATUS_OK = 1; /** Status of no errors, but abort of the translation */ - private static final int STATUS_EXIT_WITHOUT_ERROR = 0; + static final int STATUS_EXIT_WITHOUT_ERROR = 0; /** Status of present errors and abort of the translation */ static final int STATUS_EXIT_WITH_ERRORS = -1; @@ -298,16 +306,7 @@ class trans * value was not being used.) If the translation fails, it returns * null. */ - /** - * @param args - * @return - */ - /** - * @param args - * @return - */ -// public static int runMe(String[] args) - public static TLAtoPCalMapping runMe(String[] args) // added for testing + public static int runMe(String[] args) { /********************************************************************* * Get and print version number. * @@ -335,20 +334,11 @@ class trans /********************************************************************* * Get and process arguments. *********************************************************************/ - - /** - * Create the new TLAtoPCalMapping object, call it mapping - * here and set PcalParams.tlaPcalMapping to point to it. - */ - TLAtoPCalMapping mapping = new TLAtoPCalMapping() ; - PcalParams.tlaPcalMapping = mapping; - int status = parseAndProcessArguments(args); if (status != STATUS_OK) { -// return exitWithStatus(status); - return new TLAtoPCalMapping() ; // added for testing + return exitWithStatus(status); } /********************************************************************* @@ -363,8 +353,7 @@ class trans } catch (FileToStringVectorException e) { PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } /********************************************************************* @@ -372,9 +361,9 @@ class trans * which was not always the case in the aborted version 1.31. * *********************************************************************/ // Vector outputVec = PcalParams.fromPcalFile ? new Vector() : inputVec; - final Vector<String> outputVec = runMe(inputVec, mapping); + final Vector<String> outputVec = runMe(inputVec); if (outputVec == null) { - return null; + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } /********************************************************************* @@ -398,8 +387,7 @@ class trans { PcalDebug.reportError("Could not rename input file " + PcalParams.TLAInputFile + ".tla" + " to " + PcalParams.TLAInputFile + ".old"); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } ; // } @@ -439,8 +427,7 @@ class trans } catch (StringVectorToFileException e) { PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".tla" + " written."); @@ -461,8 +448,7 @@ class trans } catch (FileToStringVectorException e) { PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } } else { @@ -570,18 +556,23 @@ class trans } catch (StringVectorToFileException e) { PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return exitWithStatus(STATUS_EXIT_WITH_ERRORS); } PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".cfg" + " written."); } ; -// return exitWithStatus(STATUS_EXIT_WITHOUT_ERROR); - return PcalParams.tlaPcalMapping ; // added for testing + return exitWithStatus(STATUS_EXIT_WITHOUT_ERROR); } // END main - public static Vector<String> runMe(final Vector<String> inputVec, final TLAtoPCalMapping mapping) { + public static Vector<String> runMe(final Vector<String> inputVec) { + /** + * Create the new TLAtoPCalMapping object, call it mapping + * here and set PcalParams.tlaPcalMapping to point to it. + */ + final TLAtoPCalMapping mapping = new TLAtoPCalMapping() ; + PcalParams.tlaPcalMapping = mapping; + /********************************************************************* * Set untabInputVec to be the vector of strings obtained from * * inputVec by replacing tabs with spaces. * @@ -691,7 +682,6 @@ class trans if (endTranslationLine == -1) { PcalDebug.reportError("No line containing `" + PcalParams.EndXlation1 + " " + PcalParams.EndXlation2); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); return null; } @@ -741,8 +731,7 @@ class trans if (!foundBegin) { PcalDebug.reportError("Beginning of algorithm string " + PcalParams.BeginAlg + " not found."); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return null; } ; @@ -831,8 +820,7 @@ class trans if (notFound) { PcalDebug.reportError("Algorithm not in properly terminated comment"); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return null; } // Report an error if there's something else on the line that doesn't begin with "\*". This is probably @@ -841,8 +829,7 @@ class trans if (!endStuff.equals("") && !endStuff.startsWith("\\*")) { PcalDebug.reportError("Text on same line following `*)' that ends the \n comment containing the algorithm."); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing + return null ; } ; inputVec.insertElementAt("\\* BEGIN TRANSLATION", ecLine+1) ; @@ -1003,7 +990,6 @@ class trans * If run in the system mode, exits the program, in tool mode returns the status * @param status */ - @SuppressWarnings("unused") private static int exitWithStatus(int status) { if (ToolIO.getMode() == ToolIO.SYSTEM) diff --git a/tlatools/src/tla2sany/configuration/ASCII_CharStream.java b/tlatools/src/tla2sany/configuration/ASCII_CharStream.java index 3bbbdc33c62fe04d8607cddbcb981a66c6ae4c7a..71e03c7b21f9c766d9afad93ec142b73cc8f1bb7 100644 --- a/tlatools/src/tla2sany/configuration/ASCII_CharStream.java +++ b/tlatools/src/tla2sany/configuration/ASCII_CharStream.java @@ -284,7 +284,7 @@ public final class ASCII_CharStream public ASCII_CharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } public ASCII_CharStream(java.io.InputStream dstream, int startline, @@ -296,7 +296,7 @@ public final class ASCII_CharStream static public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } static public void ReInit(java.io.InputStream dstream, int startline, diff --git a/tlatools/src/tla2sany/drivers/SANY.java b/tlatools/src/tla2sany/drivers/SANY.java index 9ce89d8765e1d429b7a557732907bc11ec47af8e..d27b042086fa6c832d6809d5c4a5c6ee56b86d19 100644 --- a/tlatools/src/tla2sany/drivers/SANY.java +++ b/tlatools/src/tla2sany/drivers/SANY.java @@ -114,7 +114,7 @@ public class SANY { * processing--those are reported in the returned specification * object, which must be checked as described above. */ - public static final void frontEndMain( + public static final int frontEndMain( SpecObj spec, String fileName, PrintStream syserr) throws FrontEndException { @@ -130,20 +130,20 @@ public class SANY { {frontEndSemanticAnalysis(spec, syserr, doLevelChecking);} ; } catch (InitException ie) { - return; + return -1; } catch (ParseException pe) { - return; + return -1; } catch (SemanticException se) { - return; + return -1; } catch (Exception e) { // e.printStackTrace(syserr); syserr.println(e.toString()); throw new FrontEndException(e); } - return; + return 0; } /** @@ -436,13 +436,16 @@ public class SANY { if (FileUtil.createNamedInputStream(args[i], spec.getResolver()) != null) { try { - frontEndMain(spec, args[i], ToolIO.out); + int ret = frontEndMain(spec, args[i], ToolIO.out); + if (ret != 0) { + System.exit(ret); + } } catch (FrontEndException fe) { // For debugging fe.printStackTrace(); ToolIO.out.println(fe); - return; + System.exit(-1); } // Compile operator usage stats @@ -452,13 +455,14 @@ public class SANY { // Run the Semantic Graph Exploration tool Explorer explorer = new Explorer(spec.getExternalModuleTable()); try { - explorer.main(); + explorer.main(args); } catch (ExplorerQuitException e) { /*do nothing*/ } } } else { ToolIO.out.println("Cannot find the specified file " + args[i] + "."); + System.exit(-1); } } } diff --git a/tlatools/src/tla2sany/explorer/DotExplorerVisitor.java b/tlatools/src/tla2sany/explorer/DotExplorerVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..dfd828dc4732f5ed78ed3630fe8fb22e58543041 --- /dev/null +++ b/tlatools/src/tla2sany/explorer/DotExplorerVisitor.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tla2sany.explorer; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import tla2sany.semantic.Context; +import tla2sany.semantic.FormalParamNode; +import tla2sany.semantic.LetInNode; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDeclNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.Subst; +import util.FileUtil; + +public class DotExplorerVisitor extends ExplorerVisitor { + + private static final Map<Class<? extends SemanticNode>, String> type2format = new HashMap<>(); + + static { + type2format.put(OpDefNode.class, " [style=filled,shape=diamond,fillcolor=\"red\","); + type2format.put(OpApplNode.class, " [color=\"green\","); + type2format.put(OpDeclNode.class, " [shape=square,color=\"yellow\","); + type2format.put(LetInNode.class, " [color=\"orange\","); + } + + private final ModuleNode rootModule; + private final Hashtable<Integer, ExploreNode> table; + private final PrintWriter writer; + private final Deque<ExploreNode> stack = new ArrayDeque<>(); + private final boolean includeLineNumbers = Boolean.getBoolean(DotExplorerVisitor.class.getName() + ".includeLineNumbers"); + + public DotExplorerVisitor(final ModuleNode rootModule) { + this.rootModule = rootModule; + this.table = new NoopTable<>(); + try { + this.writer = new PrintWriter(FileUtil.newBFOS(rootModule.getName() + ".dot")); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + this.writer.append("strict digraph DiskGraph {\n"); // strict removes redundant edges + } + + @Override + public void preVisit(ExploreNode exploreNode) { + if (skipNode(exploreNode)) { + return; + } + + final ExploreNode parent = stack.peek(); + if (exploreNode == this.rootModule) { + assert parent == null; + + final ModuleNode mn = (ModuleNode) exploreNode; + this.writer.append(Integer.toString(mn.hashCode())); + this.writer.append(" [label=\""); + this.writer.append(mn.getName().toString()); + this.writer.append("\",style = filled]"); + this.writer.append(";\n"); + + stack.push(exploreNode); + } else { + final SemanticNode sn = (SemanticNode) exploreNode; + this.writer.append(Integer.toString(sn.hashCode())); + this.writer.append(type2format.getOrDefault(exploreNode.getClass(), " [") + "label=\""); + if (exploreNode instanceof OpDefNode) { + this.writer.append(toDot(((OpDefNode) sn).getName().toString())); + } else { + this.writer.append(toDot(sn.getTreeNode().getHumanReadableImage())); + } + if (includeLineNumbers) { + // Wrap location for more compact nodes in dot output. + final String loc = sn.getLocation().toString(); + this.writer.append("\n"); + this.writer.append(loc.replace("of module", "\n")); + } + this.writer.append("\"]"); + this.writer.append(";\n"); + + this.writer.append(Integer.toString(parent.hashCode())); + this.writer.append(" -> "); + this.writer.append(Integer.toString(sn.hashCode())); + this.writer.append("\n"); + + stack.push(sn); + } + } + + @Override + public void postVisit(final ExploreNode exploreNode) { + if (skipNode(exploreNode)) { + return; + } + final ExploreNode pop = stack.pop(); + assert pop == exploreNode; + } + + public void done() { + this.writer.append("}"); + this.writer.close(); + } + + public Hashtable<Integer, ExploreNode> getTable() { + return table; + } + + private static String toDot(final String sn) { + return sn.replace("\\", "\\\\").replace("\"", "\\\"").trim().replace("\n", "\\n"); + } + + private static boolean skipNode(final ExploreNode exploreNode) { + if (exploreNode instanceof Context || exploreNode instanceof FormalParamNode) { + return true; + } + if (exploreNode instanceof Subst) { + return true; + } + if (Context.isBuiltIn(exploreNode)) { + return true; + } + if (exploreNode instanceof SemanticNode) { + return ((SemanticNode) exploreNode).isStandardModule(); + } + return false; + } + + @SuppressWarnings("serial") + private class NoopTable<K, V> extends Hashtable<K, V> { + @Override + public V get(Object key) { + // Return null here to visit an OpDefNode D multiple times if D is "called" from + // multiple OpApplNodes. However, stop endless recursion if D is a RECURSIVE + // operator. + final V v = super.get(key); + if (v instanceof OpDefNode) { + final OpDefNode odn = (OpDefNode) v; + if (odn.getInRecursive()) { + if (stack.contains(odn)) { + // RECURSIVE operators + return v; + } + } + } + return null; + } + } +} diff --git a/tlatools/src/tla2sany/explorer/ExploreNode.java b/tlatools/src/tla2sany/explorer/ExploreNode.java index 8598632c5381e3d4f9bc67516e1052dd4dbf05d9..f3eb734631ebc0ed9ae9f6cf46a91a6b88cfdc74 100644 --- a/tlatools/src/tla2sany/explorer/ExploreNode.java +++ b/tlatools/src/tla2sany/explorer/ExploreNode.java @@ -22,13 +22,13 @@ public interface ExploreNode { ***********************************************************************/ public String levelDataToString(); - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, final ExplorerVisitor visitor); /*********************************************************************** * This method is apparently supposed to insert an entry in * * semNodesTable for itself and every descendant in the semantic tree * * by executing * * * - * Integer uid = new Integer(myUID); * + * Integer uid = Integer.valueOf(myUID); * * if (semNodesTable.get(uid) != null) return; * * semNodesTable.put(uid, this); * * * diff --git a/tlatools/src/tla2sany/explorer/Explorer.java b/tlatools/src/tla2sany/explorer/Explorer.java index 6fec0b6fc9946f0c3c467203c97f56f121b94885..04d2e7a28585ac79ad14213d2853417f9a6da7f1 100644 --- a/tlatools/src/tla2sany/explorer/Explorer.java +++ b/tlatools/src/tla2sany/explorer/Explorer.java @@ -4,15 +4,16 @@ * 2 Mar 2007: enum <- Enum * ***************************************************************************/ - package tla2sany.explorer; import java.io.EOFException; import java.io.IOException; import java.io.InputStreamReader; +import java.util.Arrays; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; +import java.util.List; import java.util.StringTokenizer; import tla2sany.semantic.ExternalModuleTable; @@ -38,383 +39,399 @@ import util.UniqueString; public class Explorer { - public Generator generator; - - // Next three vars used in reading commands from keyboard - private InputStreamReader inStream = new InputStreamReader(System.in); - private final int inCapacity = 100; - private StringBuffer input = new StringBuffer(inCapacity); - private int lineLength; - - // semNodesTable contains various nodes in the semantic graph keyed - // by their UIDs - private Hashtable semNodesTable = new Hashtable(); - - // variables used in parsing commands - private int ntokens; - private StringTokenizer inputTokens; - private String inputString; - private String firstToken,secondToken; - private Integer icmd,icmd2 = null; - private ExploreNode obj; - - private ExternalModuleTable mt; + public Generator generator; + // Next three vars used in reading commands from keyboard + private final InputStreamReader inStream = new InputStreamReader(System.in); + private final int inCapacity = 100; + private StringBuffer input = new StringBuffer(inCapacity); + private int lineLength; - // Constructor - public Explorer (ExternalModuleTable mtarg) { + // semNodesTable contains various nodes in the semantic graph keyed + // by their UIDs + private final Hashtable<Integer, ExploreNode> semNodesTable = new Hashtable<>(); - mt = mtarg; + // variables used in parsing commands + private int ntokens; + private StringTokenizer inputTokens; + private String firstToken, secondToken; + private Integer icmd, icmd2 = null; + private ExploreNode obj; - } + private ExternalModuleTable mt; + // Constructor + public Explorer(ExternalModuleTable mtarg) { - /* Reads one line from "inStream" into "input". - Returns "false" if there is an EOF; "true" otherwise - */ + mt = mtarg; - private boolean getLine() { - try { - lineLength=0; - input.setLength(inCapacity); - do { - input.setCharAt(lineLength,(char)inStream.read()); - lineLength++; } - while (input.charAt(lineLength-1) != '\n' & lineLength < inCapacity ); - input.setLength(lineLength); - } - catch (EOFException e) { - return false; - } - catch (IOException e) { - System.out.println("***I/O exception on keyboard input; " + e); - System.exit(-1); - } - if (lineLength >= inCapacity) { - System.out.println("Input line too long; line limited to " + inCapacity - + " chars. Line ignored."); - input.setLength(0); - } - - return true; - } - - - - // Integer command - private void printNode(int depth) { - - // See if the object requested is already in the table - if ((obj = (ExploreNode)semNodesTable.get(icmd)) != null) { - //Print tree to depth of icmd2 - System.out.println(((ExploreNode)obj).toString(depth)); - System.out.print("\n" + ((ExploreNode)obj).levelDataToString()); - } else { - // object requested is not in semNodesTable - System.out.println("No such node encountered yet"); - } - } // end method - - - private void lookUpAndPrintSyntaxTree(String symbName) { - - Vector symbolVect = new Vector(8); // Initial room for 8 symbols with same name - - - // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == symbName - - for ( Enumeration Enum = semNodesTable.elements(); Enum.hasMoreElements(); ) { - - Object semNode = Enum.nextElement(); - - if ( semNode instanceof SymbolNode && - ((SymbolNode)semNode).getName() == UniqueString.uniqueStringOf(symbName) ) { - - symbolVect.addElement(semNode); - } - } - - // Print them all - for (int i = 0; i < symbolVect.size(); i++ ) { - SymbolNode sym = (SymbolNode)(symbolVect.elementAt(i)); - ((SemanticNode)(sym)).getTreeNode().printST(0); - System.out.println(); - } + /* + * Reads one line from "inStream" into "input". Returns "false" if there is an + * EOF; "true" otherwise + */ + + private boolean getLine() { + try { + lineLength = 0; + input.setLength(inCapacity); + do { + input.setCharAt(lineLength, (char) inStream.read()); + lineLength++; + } while (input.charAt(lineLength - 1) != '\n' & lineLength < inCapacity); + input.setLength(lineLength); + } catch (EOFException e) { + return false; + } catch (IOException e) { + System.out.println("***I/O exception on keyboard input; " + e); + System.exit(-1); + } + if (lineLength >= inCapacity) { + System.out.println("Input line too long; line limited to " + inCapacity + " chars. Line ignored."); + input.setLength(0); + } + + return true; + } - } + // Integer command + private void printNode(int depth) { + // See if the object requested is already in the table + if ((obj = (ExploreNode) semNodesTable.get(icmd)) != null) { + // Print tree to depth of icmd2 + System.out.println(((ExploreNode) obj).toString(depth)); + System.out.print("\n" + ((ExploreNode) obj).levelDataToString()); + } else { + // object requested is not in semNodesTable + System.out.println("No such node encountered yet"); + } + } // end method - private void lookUpAndPrintDef(String symbName) { + private void lookUpAndPrintSyntaxTree(String symbName) { - Vector symbolVect = new Vector(8); // Initial room for 8 symbols with same name + Vector<SymbolNode> symbolVect = new Vector<>(8); // Initial room for 8 symbols with same name + // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == + // symbName - // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == symbName + for (Enumeration<ExploreNode> Enum = semNodesTable.elements(); Enum.hasMoreElements();) { - for ( Enumeration Enum = semNodesTable.elements(); Enum.hasMoreElements(); ) { + ExploreNode semNode = Enum.nextElement(); - Object semNode = Enum.nextElement(); + if (semNode instanceof SymbolNode + && ((SymbolNode) semNode).getName() == UniqueString.uniqueStringOf(symbName)) { - if ( semNode instanceof SymbolNode && - ((SymbolNode)semNode).getName() == UniqueString.uniqueStringOf(symbName) ) { + symbolVect.addElement((SymbolNode) semNode); - symbolVect.addElement(semNode); + } + } - } - } + // Print them all + for (int i = 0; i < symbolVect.size(); i++) { + SymbolNode sym = (SymbolNode) (symbolVect.elementAt(i)); + ((SemanticNode) (sym)).getTreeNode().printST(0); + System.out.println(); + } - // Print them all - for (int i = 0; i < symbolVect.size(); i++ ) { - SymbolNode sym = (SymbolNode)(symbolVect.elementAt(i)); - if (sym instanceof OpDefOrDeclNode) { - if ( ((OpDefOrDeclNode)sym).getOriginallyDefinedInModuleNode() != null ) { - System.out.print( "Module: " + ((OpDefOrDeclNode)sym).getOriginallyDefinedInModuleNode().getName() + "\n" ); - } else { - System.out.print( "Module: " + "null" + "\n"); - } - } else if (sym instanceof FormalParamNode) { - System.out.print( "Module: " + ((FormalParamNode)sym).getModuleNode().getName() ); } - System.out.println( ((ExploreNode)(symbolVect.elementAt(i))).toString(100) ); - System.out.println(); - } - - } - private void levelDataPrint(String symbName) { + private void lookUpAndPrintDef(String symbName) { - Vector symbolVect = new Vector(8); // Initial room for 8 symbols with same name + Vector<SymbolNode> symbolVect = new Vector<>(8); // Initial room for 8 symbols with same name + // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == + // symbName - // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == symbName + for (Enumeration<ExploreNode> Enum = semNodesTable.elements(); Enum.hasMoreElements();) { - for ( Enumeration Enum = semNodesTable.elements(); Enum.hasMoreElements(); ) { + ExploreNode semNode = Enum.nextElement(); - Object semNode = Enum.nextElement(); + if (semNode instanceof SymbolNode + && ((SymbolNode) semNode).getName() == UniqueString.uniqueStringOf(symbName)) { - if ( semNode instanceof SymbolNode && - ((SymbolNode)semNode).getName() == UniqueString.uniqueStringOf(symbName) ) { + symbolVect.addElement((SymbolNode) semNode); - symbolVect.addElement(semNode); + } + } - } - } + // Print them all + for (int i = 0; i < symbolVect.size(); i++) { + SymbolNode sym = (SymbolNode) (symbolVect.elementAt(i)); + if (sym instanceof OpDefOrDeclNode) { + if (((OpDefOrDeclNode) sym).getOriginallyDefinedInModuleNode() != null) { + System.out.print( + "Module: " + ((OpDefOrDeclNode) sym).getOriginallyDefinedInModuleNode().getName() + "\n"); + } else { + System.out.print("Module: " + "null" + "\n"); + } + } else if (sym instanceof FormalParamNode) { + System.out.print("Module: " + ((FormalParamNode) sym).getModuleNode().getName()); + } + System.out.println(((ExploreNode) (symbolVect.elementAt(i))).toString(100)); + System.out.println(); + } - // Print them all - for (int i = 0; i < symbolVect.size(); i++ ) { - SymbolNode sym = (SymbolNode)(symbolVect.elementAt(i)); - if (sym instanceof OpDefOrDeclNode) { - if ( ((OpDefOrDeclNode)sym).getOriginallyDefinedInModuleNode() != null ) { - System.out.print( "Module: " + ((OpDefOrDeclNode)sym).getOriginallyDefinedInModuleNode().getName() + "\n" ); - } else { - System.out.print( "Module: " + "null" + "\n" ); - } - } else if (sym instanceof FormalParamNode) { - System.out.print( "Module: " + ((FormalParamNode)sym).getModuleNode().getName() + "\n" ); } - System.out.println( ((ExploreNode)(sym)).levelDataToString() ); - System.out.println(); - } - - } - - - private void executeCommand() throws ExplorerQuitException { - - // At this point icmd (firsToken) may be null, but icmd2 - // (second token) is always non-null - - // Integers as commands start printing at the node having icmd == UID; - // non-integer commands do something else - - if (icmd != null) { // first token is an integer - printNode(icmd2.intValue()); + private void levelDataPrint(String symbName) { - } else { // the first token is not an integer - - // non-integer commands - if (firstToken.toLowerCase().startsWith("qu")) { - // "quit" command - throw new ExplorerQuitException(); - - } else if (firstToken.toLowerCase().equals("mt")) { - - // Print the semantic graph, rooted in the Module Table - // excluding built-ins and ops defined in module Naturals - if (icmd2 != null) { - mt.printExternalModuleTable(icmd2.intValue(),false); - } else { - mt.printExternalModuleTable(2, false); - } + Vector<SymbolNode> symbolVect = new Vector<>(8); // Initial room for 8 symbols with same name - } else if (firstToken.toLowerCase().equals("mt*")) { + // Collect in Vector symbols all SymbolNodes in the semNodesTable whose name == + // symbName - // Print the semantic graph, rooted in the Module Table - // including builtins and ops defined in Naturals - if (icmd2 != null) { - mt.printExternalModuleTable(icmd2.intValue(),true); - } else { - mt.printExternalModuleTable(2,true); - } + for (Enumeration<ExploreNode> Enum = semNodesTable.elements(); Enum.hasMoreElements();) { - } else if (firstToken.toLowerCase().startsWith("cst")) { - printSyntaxTree(); + ExploreNode semNode = Enum.nextElement(); - } else if (firstToken.toLowerCase().startsWith("s")) { - if (secondToken != null) { - lookUpAndPrintSyntaxTree(secondToken); - } else { - System.out.println("***Error: You must indicate what name you want to print the syntax tree of."); - } + if (semNode instanceof SymbolNode + && ((SymbolNode) semNode).getName() == UniqueString.uniqueStringOf(symbName)) { - } else if (firstToken.toLowerCase().startsWith("d")) { - if (secondToken != null) { - lookUpAndPrintDef(secondToken); - } else { - System.out.println("***Error: You must indicate what name you want to print the definition of."); - } + symbolVect.addElement((SymbolNode) semNode); - } else if (firstToken.toLowerCase().startsWith("l")) { - if (secondToken != null) { - levelDataPrint(secondToken); - } else { - System.out.println("***Error: You must indicate what name you want to print the level data of."); - } + } + } - } else { - // unknown command - System.out.println("Unknown command: " + firstToken.toString()); - return; - } + // Print them all + for (int i = 0; i < symbolVect.size(); i++) { + SymbolNode sym = (SymbolNode) (symbolVect.elementAt(i)); + if (sym instanceof OpDefOrDeclNode) { + if (((OpDefOrDeclNode) sym).getOriginallyDefinedInModuleNode() != null) { + System.out.print( + "Module: " + ((OpDefOrDeclNode) sym).getOriginallyDefinedInModuleNode().getName() + "\n"); + } else { + System.out.print("Module: " + "null" + "\n"); + } + } else if (sym instanceof FormalParamNode) { + System.out.print("Module: " + ((FormalParamNode) sym).getModuleNode().getName() + "\n"); + } + System.out.println(((ExploreNode) (sym)).levelDataToString()); + System.out.println(); + } - } // end else - - } - - - private void parseAndExecuteCommand() throws ExplorerQuitException { - - icmd = null; - icmd2 = null; - ntokens = 0; - - // Do nothing if cmd line contains no tokens - if (!inputTokens.hasMoreElements()) return; + } - // Process first token - ntokens++; - firstToken = (String)(inputTokens.nextElement()); + private void executeCommand() throws ExplorerQuitException { - // Try parsing first token as an Integer - try { - icmd = Integer.valueOf(firstToken); - } - catch (Exception e) { } + // At this point icmd (firsToken) may be null, but icmd2 + // (second token) is always non-null - //Process second token (if present) - if (inputTokens.hasMoreElements()) { - ntokens++; - secondToken = (String)(inputTokens.nextElement()); + // Integers as commands start printing at the node having icmd == UID; + // non-integer commands do something else - // Try parsing second token as an Integer - try { - icmd2 = Integer.valueOf(secondToken); - } - catch (Exception e) { } - } + if (icmd != null) { // first token is an integer - // A single token command defaults the depth to 20, except for - // "mt" command, which defaults to 2 - if (ntokens < 2 || (icmd2 != null && icmd2.intValue() < 0)) { - if (firstToken.toLowerCase().startsWith("mt")) { - icmd2 = new Integer(2); - } else { - icmd2 = new Integer(4); - } - } + printNode(icmd2.intValue()); - if (inputTokens.hasMoreElements()) { - System.out.println("Command has too many tokens"); - return; - } + } else { // the first token is not an integer - executeCommand(); + // non-integer commands + if (firstToken.toLowerCase().startsWith("qu")) { + // "quit" command + throw new ExplorerQuitException(); - } // end method + } else if (firstToken.toLowerCase().equals("mt")) { + // Print the semantic graph, rooted in the Module Table + // excluding built-ins and ops defined in module Naturals + if (icmd2 != null) { + mt.printExternalModuleTable(icmd2.intValue(), false); + } else { + mt.printExternalModuleTable(2, false); + } - public void printSyntaxTree () { + } else if (firstToken.toLowerCase().equals("mt*")) { - Integer key; + // Print the semantic graph, rooted in the Module Table + // including builtins and ops defined in Naturals + if (icmd2 != null) { + mt.printExternalModuleTable(icmd2.intValue(), true); + } else { + mt.printExternalModuleTable(2, true); + } - // Prepare to iterate over ExternalModuleTable entries - Iterator modules = mt.moduleHashTable.values().iterator(); - ExternalModuleTable.ExternalModuleTableEntry mte; + } else if (firstToken.equalsIgnoreCase("dot")) { + dotSemanticGraph(); + } else if (firstToken.toLowerCase().startsWith("cst")) { + printSyntaxTree(); - // For each entry ExternalModuleTableEntry mte in the ExternalModuleTable mt ... - while (modules.hasNext()) { - key = new Integer(-1); + } else if (firstToken.toLowerCase().startsWith("s")) { + if (secondToken != null) { + lookUpAndPrintSyntaxTree(secondToken); + } else { + System.out.println("***Error: You must indicate what name you want to print the syntax tree of."); + } - mte = (ExternalModuleTable.ExternalModuleTableEntry)(modules.next()); + } else if (firstToken.toLowerCase().startsWith("d")) { + if (secondToken != null) { + lookUpAndPrintDef(secondToken); + } else { + System.out.println("***Error: You must indicate what name you want to print the definition of."); + } - // Did the module parse correctly? - if (mte != null) { - if (mte.getModuleNode() != null ) { - key = new Integer(mte.getModuleNode().getUid()); + } else if (firstToken.toLowerCase().startsWith("l")) { + if (secondToken != null) { + levelDataPrint(secondToken); + } else { + System.out.println("***Error: You must indicate what name you want to print the level data of."); + } - // Make an entry in the semNodesTable for this ModuleNode - semNodesTable.put(key,mte.getModuleNode()); + } else { + // unknown command + System.out.println("Unknown command: " + firstToken.toString()); + return; + } - // Print the concrete syntax tree for this ExternalModuleTableEntry - System.out.println("\n*** Concrete Syntax Tree for Module " + key); + } // end else - tla2sany.st.TreeNode stn = mte.getModuleNode().getTreeNode(); - stn.printST(0); // Zero indentation level + } - System.out.println("\n*** End of concrete syntax tree for Module " - + key); - } else { - System.out.println("\n*** Null ExternalModuleTableEntry. " + - "\n*** Next module did not parse, and cannot be printed."); - } - } else { - System.out.println("*** Null SemanticNode in ExternalModuleTableEntry. " + - "/n*** Next module did not parse, and cannot be printed."); - } + private void parseAndExecuteCommand() throws ExplorerQuitException { + + icmd = null; + icmd2 = null; + ntokens = 0; + + // Do nothing if cmd line contains no tokens + if (!inputTokens.hasMoreElements()) + return; + + // Process first token + ntokens++; + firstToken = (String) (inputTokens.nextElement()); + + // Try parsing first token as an Integer + try { + icmd = Integer.valueOf(firstToken); + } catch (Exception e) { + } + + // Process second token (if present) + if (inputTokens.hasMoreElements()) { + ntokens++; + secondToken = (String) (inputTokens.nextElement()); + + // Try parsing second token as an Integer + try { + icmd2 = Integer.valueOf(secondToken); + } catch (Exception e) { + } + } + + // A single token command defaults the depth to 20, except for + // "mt" command, which defaults to 2 + if (ntokens < 2 || (icmd2 != null && icmd2.intValue() < 0)) { + if (firstToken.toLowerCase().startsWith("mt")) { + icmd2 = new Integer(2); + } else { + icmd2 = new Integer(4); + } + } + + if (inputTokens.hasMoreElements()) { + System.out.println("Command has too many tokens"); + return; + } + + executeCommand(); + + } // end method + + public void dotSemanticGraph() { + final DotExplorerVisitor visitor = new DotExplorerVisitor(mt.getRootModule()); + mt.getRootModule().walkGraph(visitor.getTable(), visitor); + visitor.done(); + } - } - } + public void printSyntaxTree() { + int key; - public void main() throws ExplorerQuitException { + // Prepare to iterate over ExternalModuleTable entries + Iterator<ExternalModuleTable.ExternalModuleTableEntry> modules = mt.moduleHashTable.values().iterator(); + ExternalModuleTable.ExternalModuleTableEntry mte; - if (mt==null) { - System.out.println("*** module table == null in Explorer.main() ***"); - return; - } + // For each entry ExternalModuleTableEntry mte in the ExternalModuleTable mt ... + while (modules.hasNext()) { + key = -1; - // Get all semNodes in semNodeTable - mt.walkGraph(semNodesTable); + mte = modules.next(); - // Print initial user input prompt - System.out.println("\n\n*** TLA+ semantic graph exploration tool v 1.0 (DRJ)"); - System.out.print("\n>>"); + // Did the module parse correctly? + if (mte != null) { + if (mte.getModuleNode() != null) { + key = mte.getModuleNode().getUid(); - // Main command interpreter loop - while (getLine()) { + // Make an entry in the semNodesTable for this ModuleNode + semNodesTable.put(key, mte.getModuleNode()); - inputTokens = new StringTokenizer(input.toString()); + // Print the concrete syntax tree for this ExternalModuleTableEntry + System.out.println("\n*** Concrete Syntax Tree for Module " + key); - parseAndExecuteCommand(); + tla2sany.st.TreeNode stn = mte.getModuleNode().getTreeNode(); + stn.printST(0); // Zero indentation level - // Print next user prompt - System.out.print("\n>>"); + System.out.println("\n*** End of concrete syntax tree for Module " + key); + } else { + System.out.println("\n*** Null ExternalModuleTableEntry. " + + "\n*** Next module did not parse, and cannot be printed."); + } + } else { + System.out.println("*** Null SemanticNode in ExternalModuleTableEntry. " + + "/n*** Next module did not parse, and cannot be printed."); + } - } // end while + } + } - } // end main() method + public void main(final String[] args) throws ExplorerQuitException { + + if (mt == null) { + System.out.println("*** module table == null in Explorer.main() ***"); + return; + } + + final List<String> asList = Arrays.asList(args); + // Passing single token commands as command line parameter skips Explorer's + // interpreter mode. + if (asList.contains("cst")) { + inputTokens = new StringTokenizer("cst"); + parseAndExecuteCommand(); + System.exit(0); + } else if (asList.contains("dot")) { + inputTokens = new StringTokenizer("dot"); + parseAndExecuteCommand(); + System.exit(0); + } else if (asList.contains("mt")) { + inputTokens = new StringTokenizer("mt"); + parseAndExecuteCommand(); + System.exit(0); + } else if (asList.contains("mt*")) { + inputTokens = new StringTokenizer("mt*"); + parseAndExecuteCommand(); + System.exit(0); + } else { + // Get all semNodes in semNodeTable + mt.walkGraph(semNodesTable); + + // Print initial user input prompt + System.out.println("\n\n*** TLA+ semantic graph exploration tool v 1.0 (DRJ)"); + System.out.print("\n>>"); + // Main command interpreter loop + while (getLine()) { + + inputTokens = new StringTokenizer(input.toString()); + + parseAndExecuteCommand(); + + // Print next user prompt + System.out.print("\n>>"); + + } // end while + } + + } // end main() method } // end class diff --git a/tlatools/src/tla2sany/explorer/ExplorerVisitor.java b/tlatools/src/tla2sany/explorer/ExplorerVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..bc714a92f944fe791136e405db4a4470d0c44e00 --- /dev/null +++ b/tlatools/src/tla2sany/explorer/ExplorerVisitor.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tla2sany.explorer; + +public class ExplorerVisitor { + + public static final ExplorerVisitor NoopVisitor = new ExplorerVisitor(); + + public void preVisit(final ExploreNode exploreNode) { + } + + public void postVisit(final ExploreNode exploreNode) { + } +} diff --git a/tlatools/src/tla2sany/modanalyzer/SpecObj.java b/tlatools/src/tla2sany/modanalyzer/SpecObj.java index 95139ba6083fb9b43677761ca4aaf63af56a905f..e701e708d1f66558ea38189d17aadc2031ad5a31 100644 --- a/tlatools/src/tla2sany/modanalyzer/SpecObj.java +++ b/tlatools/src/tla2sany/modanalyzer/SpecObj.java @@ -30,7 +30,7 @@ public class SpecObj // The raw file name for the root (top) module, unprocessed by adding // ".tla" or by prepending the full file system path to it) - ExternalModuleTable externalModuleTable = new ExternalModuleTable(); + final ExternalModuleTable externalModuleTable = new ExternalModuleTable(); // This is the one ExternalModuleTable for the entire specification; // it includes ModuleNode's for the root module, and for all modules // that it depends on directly or indirectly by EXTENDS or INSTANCE diff --git a/tlatools/src/tla2sany/parser/ParseException.java b/tlatools/src/tla2sany/parser/ParseException.java index 614bc91e5ea1008f25b66bab19a6a9bbd02bfe03..9eb892e8598c6300e5ba6e0ab6087c4f669e676f 100644 --- a/tlatools/src/tla2sany/parser/ParseException.java +++ b/tlatools/src/tla2sany/parser/ParseException.java @@ -111,8 +111,9 @@ public class ParseException extends Exception { // retval += add_escapes(tok.image); tok = tok.next; } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - return retval; + retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn + + " and token \"" + add_escapes(currentToken.image) + "\" "; + return retval; } /** diff --git a/tlatools/src/tla2sany/parser/TLAplusParser.java b/tlatools/src/tla2sany/parser/TLAplusParser.java index eea79546f5945da3ca22bf3847c2d39db4587ef6..2a54587334b1a1575f90468452dccb5d3dbf1d39 100644 --- a/tlatools/src/tla2sany/parser/TLAplusParser.java +++ b/tlatools/src/tla2sany/parser/TLAplusParser.java @@ -3,13 +3,12 @@ package tla2sany.parser; import tla2sany.st.ParseTree; import tla2sany.st.TreeNode; -import tlc2.output.EC; - -import tla2sany.utilities.Vector; import tla2sany.utilities.Stack; +import tla2sany.utilities.Vector; +import tlc2.output.EC; import util.Assert; -import util.UniqueString; import util.ToolIO; +import util.UniqueString; public class TLAplusParser implements tla2sany.st.SyntaxTreeConstants, ParseTree, TLAplusParserConstants { diff --git a/tlatools/src/tla2sany/parser/TLAplusParserTokenManager.java b/tlatools/src/tla2sany/parser/TLAplusParserTokenManager.java index 2e9e7763c596838edbaa4b65b4c16fada72aad62..fadad65d8564ceaea2f5c189115325a3d2a433ac 100644 --- a/tlatools/src/tla2sany/parser/TLAplusParserTokenManager.java +++ b/tlatools/src/tla2sany/parser/TLAplusParserTokenManager.java @@ -1,13 +1,5 @@ /* Generated By:23&JavaCC: Do not edit this line. TLAplusParserTokenManager.java */ package tla2sany.parser; -import tla2sany.st.ParseTree; -import tla2sany.st.TreeNode; -import tlc2.output.EC; -import tla2sany.utilities.Vector; -import tla2sany.utilities.Stack; -import util.Assert; -import util.UniqueString; -import util.ToolIO; public class TLAplusParserTokenManager implements TLAplusParserConstants { diff --git a/tlatools/src/tla2sany/semantic/APSubstInNode.java b/tlatools/src/tla2sany/semantic/APSubstInNode.java index eb9a2dc6339fa8779a18e648e34ec97a61a47dda..4b804c6f8ff96b671e44e19cd90a29793c11589a 100644 --- a/tlatools/src/tla2sany/semantic/APSubstInNode.java +++ b/tlatools/src/tla2sany/semantic/APSubstInNode.java @@ -21,16 +21,17 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class APSubstInNode extends LevelNode { /** * For a APSubstInNode object s that has the WITH clause @@ -435,18 +436,20 @@ public class APSubstInNode extends LevelNode { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (this.substs != null) { for (int i = 0; i < this.substs.length; i++) { - if (this.substs[i] != null) this.substs[i].walkGraph(semNodesTable); + if (this.substs[i] != null) this.substs[i].walkGraph(semNodesTable, visitor); } } - if (this.body != null) this.body.walkGraph(semNodesTable); + if (this.body != null) this.body.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); return; } diff --git a/tlatools/src/tla2sany/semantic/AssumeNode.java b/tlatools/src/tla2sany/semantic/AssumeNode.java index 040ff65ca1fee049a605b83ceacf5d27c0c281f6..66aa37736f0c48c7b971dfd345beb60cd8f70cf0 100644 --- a/tlatools/src/tla2sany/semantic/AssumeNode.java +++ b/tlatools/src/tla2sany/semantic/AssumeNode.java @@ -5,13 +5,15 @@ package tla2sany.semantic; import java.util.HashSet; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; /** * This class represents an assumption about the constants in a module. @@ -184,13 +186,15 @@ public AssumeNode(TreeNode stn, ExprNode expr, ModuleNode mn, * Explorer tool. */ @Override - public final void walkGraph (Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph (Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); - if (assumeExpr != null) {assumeExpr.walkGraph(semNodesTable);} ; + visitor.preVisit(this); + if (assumeExpr != null) {assumeExpr.walkGraph(semNodesTable, visitor);} ; + visitor.postVisit(this); } /* MR: This is the same as SymbolNode.exportDefinition. Exports the actual theorem content, not only a reference. diff --git a/tlatools/src/tla2sany/semantic/AssumeProveNode.java b/tlatools/src/tla2sany/semantic/AssumeProveNode.java index fda59621bcd30291d4d4e0e800c1ad1c321c179e..28d0f6541b6641fab7bcf54c6beddeda7c34f1b7 100644 --- a/tlatools/src/tla2sany/semantic/AssumeProveNode.java +++ b/tlatools/src/tla2sany/semantic/AssumeProveNode.java @@ -6,14 +6,15 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * An assume prove node represents something like * * * @@ -351,16 +352,18 @@ public class AssumeProveNode extends LevelNode { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> h) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> h, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (h.get(uid) != null) return; h.put(uid, this); + visitor.preVisit(this); int i = 0 ; while (i < assumes.length) { - assumes[i].walkGraph(h) ; + assumes[i].walkGraph(h, visitor) ; i = i+1; } ; - prove.walkGraph(h) ; + prove.walkGraph(h, visitor) ; + visitor.postVisit(this); } // end walkGraph() diff --git a/tlatools/src/tla2sany/semantic/AtNode.java b/tlatools/src/tla2sany/semantic/AtNode.java index 90aee12b081063bf0607ac581c4411d0033e8658..2a673d779722fed014cb8314f131435962e58774 100644 --- a/tlatools/src/tla2sany/semantic/AtNode.java +++ b/tlatools/src/tla2sany/semantic/AtNode.java @@ -4,13 +4,14 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class AtNode extends ExprNode { private OpApplNode exceptRef; // reference to OpApplNode for the innermost @@ -151,7 +152,7 @@ public class AtNode extends ExprNode { * and inserts them in the Hashtable semNodesTable for use by the Explorer tool. */ @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> h) { + public final void walkGraph(Hashtable<Integer, ExploreNode> h, ExplorerVisitor visitor) { // Empty because there are no nodes reachable through an AtNode that are not // reachable by other paths through the semantic graph. } // end walkGraph() diff --git a/tlatools/src/tla2sany/semantic/Context.java b/tlatools/src/tla2sany/semantic/Context.java index 78e7cd418e5cf26ddff14437fafa92c8d0144be0..a178f2ae58db10521d76f82dd2558eca9d5ffaf8 100644 --- a/tlatools/src/tla2sany/semantic/Context.java +++ b/tlatools/src/tla2sany/semantic/Context.java @@ -8,18 +8,17 @@ package tla2sany.semantic; +import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.Location; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - // A context contains def/declNodes only. // Implements a simple context for symbol decls and defs. Also // supports the intial (or global) context of built-in operators. @@ -90,23 +89,23 @@ public class Context implements ExploreNode { public class InitialSymbolEnumeration { - Enumeration e = initialContext.content(); + Enumeration<Pair> e = initialContext.content(); public boolean hasMoreElements() { return e.hasMoreElements(); } public SymbolNode nextElement() { - return (SymbolNode)(((Pair)(e.nextElement())).getSymbol()); + return e.nextElement().getSymbol(); } } public class ContextSymbolEnumeration { - Enumeration e = Context.this.content(); + Enumeration<Pair> e = Context.this.content(); public boolean hasMoreElements() { return e.hasMoreElements(); } public SymbolNode nextElement() { - return ((Pair)(e.nextElement())).getSymbol(); + return e.nextElement().getSymbol(); } /* public Element export(Document doc) { @@ -132,7 +131,7 @@ public class Context implements ExploreNode { // belongs to is null for global contex shared by all modules. private Errors errors; // Object in which to register errors - private Hashtable table; // Mapping from symbol name to Pair's that include SymbolNode's + private Hashtable<Object, Pair> table; // Mapping from symbol name to Pair's that include SymbolNode's private Pair lastPair; // Pair added last to the this.table /** @@ -140,7 +139,7 @@ public class Context implements ExploreNode { * SymbolTable this Context is part of (or null). */ public Context(ExternalModuleTable mt, Errors errs) { - table = new Hashtable(); + table = new Hashtable<>(); this.exMT = mt; this.errors = errs; this.lastPair = null; @@ -163,6 +162,16 @@ public class Context implements ExploreNode { public static Context getGlobalContext() { return initialContext; } + + public static boolean isBuiltIn(final ExploreNode exploreNode) { + final Collection<Pair> pairs = initialContext.table.values(); + for (Pair p : pairs) { + if (exploreNode == p.info) { + return true; + } + } + return false; + } public Errors getErrors() { return errors; } @@ -232,11 +241,11 @@ public class Context implements ExploreNode { * Returns a Vector of those SymbolNodes in this Context that are * instances of class "template" (or one of its subclasses) */ - public Vector getByClass( Class template ) { - Vector result = new Vector(); - Enumeration list = table.elements(); + public Vector<SymbolNode> getByClass( Class template ) { + Vector<SymbolNode> result = new Vector<>(); + Enumeration<Pair> list = table.elements(); while (list.hasMoreElements()) { - Pair elt = (Pair)list.nextElement(); + Pair elt = list.nextElement(); if (template.isInstance(elt.info)) { result.addElement( elt.info ); } @@ -249,12 +258,12 @@ public class Context implements ExploreNode { * instances of class OpDefNode and that are NOT of kind BuiltInKind * or ModuleInstanceKind */ - public Vector getOpDefs() { + public Vector<OpDefNode> getOpDefs() { // SZ Apr 21, 2009: not used instance // Class template = OpDefNode.class; Pair nextPair = lastPair; - Vector result = new Vector(); + Vector<OpDefNode> result = new Vector<>(); while (nextPair != null) { if ( nextPair.info instanceof OpDefNode && // true for superclasses too. ((OpDefNode)nextPair.info).getKind() != ASTConstants.ModuleInstanceKind && @@ -270,12 +279,12 @@ public class Context implements ExploreNode { * instances of class ThmOrAssumpDefNode or ModuleInstanceKind * * Code copied from getOpDefs(). * *************************************************************************/ - public Vector getThmOrAssDefs() { + public Vector<ThmOrAssumpDefNode> getThmOrAssDefs() { // SZ Apr 21, 2009: not used instance // Class template = ThmOrAssumpDefNode.class; Pair nextPair = lastPair; - Vector result = new Vector(); + Vector<ThmOrAssumpDefNode> result = new Vector<>(); while (nextPair != null) { if ( nextPair.info instanceof ThmOrAssumpDefNode) { result.addElement( (ThmOrAssumpDefNode)(nextPair.info) );} ; @@ -287,13 +296,13 @@ public class Context implements ExploreNode { /** * Returns vector of OpDeclNodes that represent CONSTANT declarations */ - public Vector getConstantDecls() { - Class templateClass = OpDeclNode.class; - Enumeration list = table.elements(); + public Vector<SemanticNode> getConstantDecls() { + Class<? extends SemanticNode> templateClass = OpDeclNode.class; + Enumeration<Pair> list = table.elements(); - Vector result = new Vector(); + Vector<SemanticNode> result = new Vector<>(); while (list.hasMoreElements()) { - Pair elt = (Pair)list.nextElement(); + Pair elt = list.nextElement(); if (templateClass.isInstance(elt.info) && // true for superclasses too. ((OpDeclNode)elt.info).getKind() == ASTConstants.ConstantDeclKind ) result.addElement( (SemanticNode)(elt.info) ); @@ -303,13 +312,13 @@ public class Context implements ExploreNode { } /* Returns vector of OpDeclNodes that represent CONSTANT declarations */ - public Vector getVariableDecls() { - Class templateClass = OpDeclNode.class; - Enumeration list = table.elements(); + public Vector<SemanticNode> getVariableDecls() { + Class<? extends SemanticNode> templateClass = OpDeclNode.class; + Enumeration<Pair> list = table.elements(); - Vector result = new Vector(); + Vector<SemanticNode> result = new Vector<>(); while (list.hasMoreElements()) { - Pair elt = (Pair)list.nextElement(); + Pair elt = list.nextElement(); if (templateClass.isInstance(elt.info) && // true for superclasses too. ((OpDeclNode)elt.info).getKind() == ASTConstants.VariableDeclKind ) result.addElement( (SemanticNode)(elt.info) ); @@ -321,13 +330,13 @@ public class Context implements ExploreNode { * Returns a Vector of those SymbolNodes in this Context that are * instances of class ModuleNode */ - public Vector getModDefs() { - Class template = ModuleNode.class; - Enumeration list = table.elements(); + public Vector<SemanticNode> getModDefs() { + Class<? extends SemanticNode> template = ModuleNode.class; + Enumeration<Pair> list = table.elements(); - Vector result = new Vector(); + Vector<SemanticNode> result = new Vector<>(); while (list.hasMoreElements()) { - Pair elt = (Pair)list.nextElement(); + Pair elt = list.nextElement(); if (template.isInstance(elt.info)) // true for superclasses too. result.addElement( (SemanticNode)(elt.info) ); } @@ -471,8 +480,8 @@ public class Context implements ExploreNode { * comment in the walkGraph method of this file for a bit more * * information. * *************************************************************************/ - public Vector getContextEntryStringVector(int depth, boolean b) { - Vector ctxtEntries = new Vector(100); // vector of Strings + public Vector<String> getContextEntryStringVector(int depth, boolean b) { + Vector<String> ctxtEntries = new Vector<>(100); // vector of Strings Context naturalsContext = exMT.getContext(UniqueString.uniqueStringOf("Naturals")); @@ -496,7 +505,7 @@ public class Context implements ExploreNode { } // Reverse the order of elements in the vector so they print properly - Object obj; + String obj; int n = ctxtEntries.size(); for (int i = 0; i < n/2; i++) { obj = ctxtEntries.elementAt(i); @@ -506,7 +515,8 @@ public class Context implements ExploreNode { return ctxtEntries; } - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + visitor.preVisit(this); UniqueString key; Enumeration<?> e = table.keys(); @@ -533,8 +543,9 @@ public class Context implements ExploreNode { } else { key = (UniqueString) next; - ((Pair)table.get(key)).info.walkGraph(semNodesTable); + ((Pair)table.get(key)).info.walkGraph(semNodesTable, visitor); } ; + visitor.postVisit(this); } } diff --git a/tlatools/src/tla2sany/semantic/DecimalNode.java b/tlatools/src/tla2sany/semantic/DecimalNode.java index b767ee0850624aec769bf0cc4989333f9c7e0639..22db04ecd4b140c17acb9ff17d0c2c9a67046eec 100644 --- a/tlatools/src/tla2sany/semantic/DecimalNode.java +++ b/tlatools/src/tla2sany/semantic/DecimalNode.java @@ -5,13 +5,14 @@ package tla2sany.semantic; import java.math.BigDecimal; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * Describes a decimal like 1347.052. This number is represented by the * values @@ -114,11 +115,13 @@ public class DecimalNode extends ExprNode { * Explorer tool. */ @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } /** diff --git a/tlatools/src/tla2sany/semantic/DefStepNode.java b/tlatools/src/tla2sany/semantic/DefStepNode.java index a17463c1da92f06e85058c41dbedde45a6001fde..2bba6d019525992375be96767c3a6d688c1ea385 100644 --- a/tlatools/src/tla2sany/semantic/DefStepNode.java +++ b/tlatools/src/tla2sany/semantic/DefStepNode.java @@ -3,15 +3,16 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * This class represents definition step of a proof, which consists of a * * sequence of operator-, function-, or module-definition steps. (A * @@ -59,13 +60,15 @@ public class DefStepNode extends LevelNode { } @Override - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); for (int i = 0; i < defs.length; i++) { - defs[i].walkGraph(semNodesTable); + defs[i].walkGraph(semNodesTable, visitor); } ; + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/ExternalModuleTable.java b/tlatools/src/tla2sany/semantic/ExternalModuleTable.java index 446c1f086955827aca0247c9d8e32bc8b0f562a0..10835c4c439706e2ff39d34f57acffb205e95021 100644 --- a/tlatools/src/tla2sany/semantic/ExternalModuleTable.java +++ b/tlatools/src/tla2sany/semantic/ExternalModuleTable.java @@ -12,6 +12,7 @@ import java.util.Enumeration; import java.util.Hashtable; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import util.UniqueString; @@ -49,9 +50,9 @@ public class ExternalModuleTable implements ExploreNode { */ public String levelDataToString() { return "Dummy level string"; } - public void walkGraph(Hashtable<Integer, ExploreNode> moduleNodesTable) { - if (moduleNode != null) moduleNode.walkGraph(moduleNodesTable); - if (ctxt != null) ctxt.walkGraph(moduleNodesTable); + public void walkGraph(Hashtable<Integer, ExploreNode> moduleNodesTable, ExplorerVisitor visitor) { + if (moduleNode != null) moduleNode.walkGraph(moduleNodesTable, visitor); + if (ctxt != null) ctxt.walkGraph(moduleNodesTable, visitor); } // end walkGraph() public String toString(int depth) { @@ -80,21 +81,21 @@ public class ExternalModuleTable implements ExploreNode { * moduleHashTable, and that each of its entries has a moduleName as the * * key and a value that's an ExternalModuleTableEntry object. * *************************************************************************/ - public Hashtable moduleHashTable; + public Hashtable<UniqueString, ExternalModuleTableEntry> moduleHashTable; // Vector moduleVector contains ModuleNodes (the same ones as // moduleHashTable), but preserves the order in which they were // inserted. If module A depends on module B, then A has a HIGHER // index than B. - public Vector moduleNodeVector; + public Vector<ModuleNode> moduleNodeVector; // The nodule node of the root module public ModuleNode rootModule; // Constructor public ExternalModuleTable() { - moduleHashTable = new Hashtable(); - moduleNodeVector = new Vector(); + moduleHashTable = new Hashtable<>(); + moduleNodeVector = new Vector<>(); } // Set and get the rootModule field @@ -102,11 +103,15 @@ public class ExternalModuleTable implements ExploreNode { public void setRootModule(ModuleNode mn) { rootModule = mn; } public final Context getContext( UniqueString key ) { - ExternalModuleTableEntry p = (ExternalModuleTableEntry)moduleHashTable.get(key); + ExternalModuleTableEntry p = moduleHashTable.get(key); if (p == null) return null; return p.ctxt; } + public final Context getContextForRootModule() { + return getContext(getRootModule().getName()); + } + /** * Returns a vector of ModuleNodes, one for each outer module (i.e. not * inner modules) in the specification. InnerModules can be obtained @@ -124,13 +129,13 @@ public class ExternalModuleTable implements ExploreNode { } public final ModuleNode getModuleNode( UniqueString key ) { - ExternalModuleTableEntry p = (ExternalModuleTableEntry)moduleHashTable.get(key); + ExternalModuleTableEntry p = moduleHashTable.get(key); if (p == null) return null; return p.moduleNode; } public final void put( UniqueString key, Context ctxt, ModuleNode moduleNode ) { - ExternalModuleTableEntry c = (ExternalModuleTableEntry)moduleHashTable.get( key ); + ExternalModuleTableEntry c = moduleHashTable.get( key ); if (c == null) { moduleHashTable.put( key, new ExternalModuleTableEntry(ctxt, moduleNode) ); moduleNodeVector.addElement(moduleNode); @@ -139,11 +144,11 @@ public class ExternalModuleTable implements ExploreNode { @Override public String toString() { - Enumeration Enum = moduleHashTable.elements(); + Enumeration<ExternalModuleTableEntry> Enum = moduleHashTable.elements(); String ret = ""; - for (int i=1; Enum.hasMoreElements(); i++) { - ExternalModuleTableEntry mte = (ExternalModuleTableEntry)Enum.nextElement(); + while (Enum.hasMoreElements()) { + ExternalModuleTableEntry mte = Enum.nextElement(); ret = ret + mte.toString(); } return "\nModule Table:" + Strings.indent(2,ret); @@ -153,7 +158,7 @@ public class ExternalModuleTable implements ExploreNode { System.out.print("\nExternal Module Table:"); for (int i = 0; i < moduleNodeVector.size(); i++) { - ModuleNode mn = (ModuleNode)moduleNodeVector.elementAt(i); + ModuleNode mn = moduleNodeVector.elementAt(i); if (mn != null) { System.out.print(Strings.indent(2, "\nModule: ")); @@ -188,11 +193,15 @@ public class ExternalModuleTable implements ExploreNode { } public void walkGraph(Hashtable<Integer, ExploreNode> moduleNodesTable) { - Enumeration Enum = moduleHashTable.elements(); + walkGraph(moduleNodesTable, ExplorerVisitor.NoopVisitor); + } + + public void walkGraph(Hashtable<Integer, ExploreNode> moduleNodesTable, ExplorerVisitor visitor) { + Enumeration<ExternalModuleTableEntry> Enum = moduleHashTable.elements(); while ( Enum.hasMoreElements() ) { - ExternalModuleTableEntry mte = (ExternalModuleTableEntry)Enum.nextElement(); - mte.walkGraph(moduleNodesTable); + ExternalModuleTableEntry mte = Enum.nextElement(); + mte.walkGraph(moduleNodesTable, visitor); } } diff --git a/tlatools/src/tla2sany/semantic/FormalParamNode.java b/tlatools/src/tla2sany/semantic/FormalParamNode.java index eff6a45af42ad5c7637c520541b8f8031132d795..46f0756e9073d9fe90172350d7fc37c8028de0a7 100644 --- a/tlatools/src/tla2sany/semantic/FormalParamNode.java +++ b/tlatools/src/tla2sany/semantic/FormalParamNode.java @@ -4,14 +4,15 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * A FormalParamNode represents a formal parameter in a user * definition--for example, p and q in @@ -115,11 +116,13 @@ public class FormalParamNode extends SymbolNode { // } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/Generator.java b/tlatools/src/tla2sany/semantic/Generator.java index d5917ac6bc0282566037012cb4221f6a14b3a6e8..9561f00c6b68eb2c329b7b3313d5ced9d66fcde2 100644 --- a/tlatools/src/tla2sany/semantic/Generator.java +++ b/tlatools/src/tla2sany/semantic/Generator.java @@ -33,8 +33,6 @@ import tlc2.output.MP; import util.UniqueString; import util.WrongInvocationException; - - // This class generates a semantic graph from a parse tree. It also uses // the list of modules to access contexts to instantiate or extend. @@ -49,469 +47,435 @@ import util.WrongInvocationException; // are working from the inside. /*************************************************************************** -* Only one object of class Generator is ever created--namely, the object * -* gen in drivers/SANY.java. So it seems like all fields and methods of * -* this class could have been made static. * -***************************************************************************/ - -public class Generator implements ASTConstants, SyntaxTreeConstants, - LevelConstants, TLAplusParserConstants { - - private Context context; // current context, not very useful. - private SymbolTable symbolTable; // symbol table used throughout the spec. - // except for embedded modules - /*********************************************************************** - * A SymbolTable is actually a stack of contexts, where a context is a * - * mapping from symbols to their meanings. Elements are looked up in * - * a SymbolTable by going through the stack of contexts from the top * - * down. * - * * - * symbolTable appears to contain the definitions and declarations of * - * all symbols that are currently defined or declared. When a * - * construct containing local definitions or declarations is * - * entered--for example, when constructing the ExprNode for a LET/IN, * - * a new context is pushed onto symbolTable to hold those local defs * - * or decls. It appears that after the complete semantic ModuleNode * - * has been created, symbolTable should contain only a single context, * - * which becomes the ModuleNode's context. * - * * - * symbolTable entries are made for SymbolNode objects (objects * - * belonging to a subclass of SymbolNode). It appears that all of * - * those objects are added (to the context at the top of the stack) * - * symbolTable by the SymbolNode object's constructor. * - ***********************************************************************/ - - private ExternalModuleTable moduleTable; - public Errors errors; - private Stack excStack; // Holds stack of OpApplNodes for $Except - // operators; used for @ - private Stack excSpecStack; // Holds stack of OpApplNode for @Pair - // operators representing ExceptSpecs; - // also used for @ - - // dummy definitions; used during the creation of the "-- TLA+ BUILTINS --" phony module, - // before real modules are processed; also used somewhat inconsistently to avoid returning - // null values, and to allow semantic analysis to proceed when an error is detected - private SubstInNode nullSubstIn; - private FormalParamNode[] nullParam; - private OpDefNode nullODN; - protected OpApplNode nullOAN; - protected LabelNode nullLabelNode; - /*********************************************************************** - * This is a special OpApplNode that gets returned in various places * - * when an error is detected. This allows semantic analysis to * - * continue, presumably by preventing a NullPointerException. * - ***********************************************************************/ - protected OpArgNode nullOpArg; - - private final static UniqueString S_e = UniqueString.uniqueStringOf("\\E"); - private final static UniqueString S_ex = UniqueString.uniqueStringOf("\\exists"); - private final static UniqueString S_f = UniqueString.uniqueStringOf("\\A"); - private final static UniqueString S_fx = UniqueString.uniqueStringOf("\\always"); - private final static UniqueString S_te = UniqueString.uniqueStringOf("\\EE"); - private final static UniqueString S_tf = UniqueString.uniqueStringOf("\\AA"); - private final static UniqueString S_a = UniqueString.uniqueStringOf("<<"); - private final static UniqueString S_brack = UniqueString.uniqueStringOf("["); - private final static UniqueString S_sf = UniqueString.uniqueStringOf("SF_"); - private final static UniqueString S_wf = UniqueString.uniqueStringOf("WF_"); - private final static UniqueString S_at = UniqueString.uniqueStringOf("@"); - private final static UniqueString S_lambda = - UniqueString.uniqueStringOf("LAMBDA"); - private final static UniqueString S_subexpression = - UniqueString.uniqueStringOf("$Subexpression"); - - class Function { - /*********************************************************************** - * The only object of this class ever created is `functions', declared * - * right after the class definition. So, I don't know why this * - * class's methods weren't just made ordinary methods of the Generator * - * class. Perhaps this was done so the subclass `pair' could be * - * defined within it without interfering with any other subclass by * - * that name. However, there is no other subclass by that name in the * - * Generator class. * - * * - * See the comments attached to the `functions' object for the class's * - * explanation. * - ***********************************************************************/ - class pair{ - UniqueString a; - OpApplNode b; - - pair(UniqueString uniqueString, OpApplNode oan) { a = uniqueString; b = oan; } - UniqueString uniqueString() { return a; } - OpApplNode oan() { return b; } - } - - Stack funcStack = new Stack(); - - void push(UniqueString uniqueString, OpApplNode oan) { - funcStack.push( new pair(uniqueString, oan) ); - } - - void pop() { funcStack.pop(); } - - // If same function found farther down on stack, then this is a recursive - // function definition--change the operator to indicate so. - boolean recursionCheck(UniqueString uniqueString) { - for (int lvi = funcStack.size()-1; lvi>=0; lvi-- ) { - if (uniqueString.equals( ((pair)funcStack.elementAt( lvi )).uniqueString())) { - // OA-rfs = recursive func spec - ((pair)funcStack.elementAt(lvi)).oan().resetOperator(OP_rfs); - return true; - } - } - return false; - } - - } // end class Function - - // This is the only instance of class Function - - Function functions = new Function(); - /*********************************************************************** - * This object is used to detect that a function definition is * - * recursive. It is a stack of <<UniqueString, OpApplNode>> pairs. * - * An element <<f, opAp>> in the stack indicates that the current node * - * being processed is inside the body of a function definition of the * - * form f[...] == body. The current context assigns to f an OpDefNode * - * whose body is the OpApplNode opAp whose operator is either * - * $RecursiveFcnSpec or $NonRecursiveFcnSpec having (an OpDeclNode * - * for) the bound identifier f and having the body of the definition * - * as its operand. The following methods can be applied: * - * * - * functions.push(UniqueString us, OpApplNode oan) * - * Pushes <<us, oan>> onto the stack. * - * * - * functions.pop() * - * Pops the last element off the stack. * - * * - * recursionCheck(UniqueString us) * - * If there is a pair <<us, oan>> on the stack, then the * - * operator of oan is set to $RecursiveFcnSpec. * - * * - * An entry for f is pushed on the stack before processing the body * - * f's definition, and popped upon return. * - * * - * When processing a FcnAppl syntax nodefor an expression f[...], * - * functions.recursionCheck is called to see the node occurs in the * - * body of the definition of f, in which case the definition body's * - * OpApplNode's operator is changed to indicate that f's definition is * - * recursive. * - ***********************************************************************/ - - - - // This class represents a generalized identifier, e.g. a syntactic - // phrase such as A(2)!B(x,y)!C!D(u,v,w) In this case the compoundID - // would be A!B!C!D and the args array would contain [2,x,y] - // (i.e. not including u,v,and w, because they are - // args to the main operator, and not part of the GenID - private class GenID { - - private TreeNode treeNode; - // The syntax tree node holding this GenID - private StringBuffer compoundID; - // The string name of the compound op, with "!"'s, if any - private Vector argsVector = new Vector(); - // Vector of arguments (ExprNodes and OpArgNodes) - // that are embedded in the generalized identifier - - // The next three fields are null until the finalAppend - // method has been called - private UniqueString compoundIDUS; - // UniqueString version of compoundID - private SymbolNode fullyQualifiedOp; - // SymbolNode for compoundID - private ExprOrOpArgNode[] args; - // Array with same contents as argsVector - - // Constructor - public GenID(TreeNode node) { - treeNode = node; - compoundID = new StringBuffer(""); - compoundIDUS = null; - fullyQualifiedOp = null; - args = null; - } - - public final UniqueString getCompoundIDUS() { return compoundIDUS;} - - public final SymbolNode getFullyQualifiedOp() { return fullyQualifiedOp; } - - public final ExprOrOpArgNode[] getArgs() { return args; } - - public final Vector getArgsVector() { return argsVector; } - - /** Append a new segment to the compound name of the operator */ - public final void append(String s) { - compoundID.append(s); - } - - /** Add a new argument to the vector of arguments being constructed */ - public final void addArg(ExprOrOpArgNode arg) { - argsVector.addElement(arg); - } - - /** - * Appends the final element of the fully-qualified name to the - * GenID that has been being built using addArg() and - * append(). Since it signals the completion of the construction - * of the name, this method converts the name from StringBuffer to - * UniqueString, resolves it to a SymbolNode, and converts the - * argument list from vector to array form. - */ - public final void finalAppend(String s, boolean unaryNegKludge) { - // append the final segment of the compound name - if (unaryNegKludge && s.equals("-")) { - compoundID.append("-."); - } - else { - compoundID.append(s); - } - - // convert the full name to a UniqueString - compoundIDUS = UniqueString.uniqueStringOf(compoundID.toString()); - - // look up the full name in the SymbolTable (may return null) - fullyQualifiedOp = symbolTable.resolveSymbol(Operators.resolveSynonym(compoundIDUS)); - - if (fullyQualifiedOp == null && compoundIDUS != S_at) { - // if not in the symbol table and not "@", then it is an unresolved symbol - errors.addError(treeNode.getLocation(), - "Could not find declaration or definition of symbol '" + - UniqueString.uniqueStringOf(compoundID.toString()) + "'."); - } - } - - public final void finalizeID() { - // copy argsVector contents into args array - args = new ExprOrOpArgNode[argsVector.size()]; - - for (int i = 0; i < args.length; i++) { - args[i] = (ExprOrOpArgNode)argsVector.elementAt(i); - } - } - - /** - * Special kluge to append a "." to the name of this ID; - * should be used ONLY to change unary "-" to "-." - */ - public final void appendDot() { - compoundIDUS = UniqueString.uniqueStringOf(compoundIDUS.toString() + "."); - } - - public final String toString(int n) { - String ret = "compound ID: " + compoundID.toString() + "\nargs: " + args.length + "\n"; - for (int i = 0; i < args.length; i++) { - ret += Strings.indent(2,args[i].toString(n)); - } - return ret; - } - - } // end GenID - - - final UniqueString AtUS = UniqueString.uniqueStringOf("@") ; - /*********************************************************************** - * This is needed in a couple of places. (I didn't notice that this * - * is already defined to equal S_at.) * - ***********************************************************************/ - - /************************************************************************* - * An object of subclass Selector is used to represent a the translation * - * of a GeneralId or an OpApplication whose operator is a GeneralId. It * - * contains the data represented in the Subexpression +cal algorithm by * - * the arrays ops and args. For example, the user expression * - * * - * Foo(a,b)!:!(c) * - * * - * produces the following in Subexpression algorithm: * - * * - * ops = << "Foo", ":", "null" >> * - * args = << <<a, b>>, << >>, << <<c>> >>, * - * * - * This is represented by a Selector object with four arrays of * - * length 3. The first is: * - * * - * int[] ops with ops[0] = NameSel * - * ops[1] = ColonSel * - * ops[2] = NullSel * - * * - * The set of all possible values of ops[i] are: * - * * - * An integer i >= 0 // Represents the i of "!i". * - * * - * One of the following integers < 0. * - *************************************************************************/ - - final int NameSel = -1 ; // A name like "Foo" ; - final int NullSel = -2 ; // A "(...)" selector ; - final int GGSel = -3 ; // ">>" ; - final int LLSel = -4 ; // "<<" ; - final int ColonSel = -5 ; // ":" ; - final int AtSel = -6 ; // "@" ; - - /************************************************************************* - * The remaining three arrays are: * - * * - * SyntaxTreeNode[] opsSTN with values equal to the syntax tree * - * nodes for the corresponding element * - * of ops. * - * * - * UniqueString[] opNames with opNames[0] = "Foo" * - * opNames[1] = ":" * - * opNames[2] = null * - * * - * SyntaxTreeNode[] args with args[0] = "(a, b)" * - * args[1] = null * - * args[2] = "(c)" * - * * - * Note: we can't turn the arguments into semantic nodes yet because we * - * want to use generateExprOrOpArg to do that, which requires that we * - * know the operator of which they're the arguments. Hence, that * - * computation has to be folded into the Subexpression algorithm. * - * * - * These arrays are initialized by the finish method, which is called * - * after all calls of addSelector have been issued. * - *************************************************************************/ - private class Selector { - /********************************************************************** - * A single field for the syntax tree node of the entire selector. * - **********************************************************************/ - SyntaxTreeNode selSTN ; - - /********************************************************************** - * The fields modified by addSelector: * - **********************************************************************/ - private Vector opVec = new Vector(); // of SyntaxTreeNode ; - private Vector argVec = new Vector(); // of SyntaxTreeNode ; - - /********************************************************************** - * The fields set from opVec and argVec by finalize. * - **********************************************************************/ - int[] ops = null ; - UniqueString[] opNames = null ; - SyntaxTreeNode[] opsSTN = null ; - SyntaxTreeNode[] args = null ; - - /********************************************************************** - * Constants not needed elsewhere. * - **********************************************************************/ - final UniqueString GGUS = UniqueString.uniqueStringOf(">>") ; - final UniqueString LLUS = UniqueString.uniqueStringOf("<<") ; - final UniqueString ColonUS = UniqueString.uniqueStringOf(":") ; - - /********************************************************************** - * The constructor. * - **********************************************************************/ - - Selector(SyntaxTreeNode tn) { - selSTN = tn ; - } - void addSelector(SyntaxTreeNode stn, SyntaxTreeNode opargs) { - /******************************************************************** - * opargs is the args entry. * - * * - * stn is the syntax tree node representing the ops entry. If * - * there are no arguments, it should be null. For a NullSel entry * - * it should be the OpArgs node (the "(arg1, ... , argN)") that is * - * used as the second argument. * - ********************************************************************/ - opVec.addElement(stn) ; - argVec.addElement(opargs) ; - } // addSelector - - void finish() throws AbortException { - int arrayLen = opVec.size() ; - ops = new int[arrayLen] ; - opNames = new UniqueString[arrayLen] ; - opsSTN = new SyntaxTreeNode[arrayLen] ; - args = new SyntaxTreeNode[arrayLen] ; - for (int i = 0; i < arrayLen; i++) { - args[i] = (SyntaxTreeNode) argVec.elementAt(i) ; - SyntaxTreeNode stn = (SyntaxTreeNode) opVec.elementAt(i) ; - opsSTN[i] = stn ; - opNames[i] = stn.getUS() ; - switch (stn.getKind()) { - case IDENTIFIER: - case N_InfixOp: - case N_NonExpPrefixOp: - case N_PostfixOp: - case N_PrefixOp: - case ProofStepLexeme: + * Only one object of class Generator is ever created--namely, the object * gen + * in drivers/SANY.java. So it seems like all fields and methods of * this class + * could have been made static. * + ***************************************************************************/ + +public class Generator implements ASTConstants, SyntaxTreeConstants, LevelConstants, TLAplusParserConstants { + + private Context context; // current context, not very useful. + private SymbolTable symbolTable; // symbol table used throughout the spec. + // except for embedded modules + /*********************************************************************** + * A SymbolTable is actually a stack of contexts, where a context is a * mapping + * from symbols to their meanings. Elements are looked up in * a SymbolTable by + * going through the stack of contexts from the top * down. * * symbolTable + * appears to contain the definitions and declarations of * all symbols that are + * currently defined or declared. When a * construct containing local + * definitions or declarations is * entered--for example, when constructing the + * ExprNode for a LET/IN, * a new context is pushed onto symbolTable to hold + * those local defs * or decls. It appears that after the complete semantic + * ModuleNode * has been created, symbolTable should contain only a single + * context, * which becomes the ModuleNode's context. * * symbolTable entries + * are made for SymbolNode objects (objects * belonging to a subclass of + * SymbolNode). It appears that all of * those objects are added (to the context + * at the top of the stack) * symbolTable by the SymbolNode object's + * constructor. * + ***********************************************************************/ + + private ExternalModuleTable moduleTable; + public Errors errors; + private Stack excStack; // Holds stack of OpApplNodes for $Except + // operators; used for @ + private Stack excSpecStack; // Holds stack of OpApplNode for @Pair + // operators representing ExceptSpecs; + // also used for @ + + // dummy definitions; used during the creation of the "-- TLA+ BUILTINS --" + // phony module, + // before real modules are processed; also used somewhat inconsistently to avoid + // returning + // null values, and to allow semantic analysis to proceed when an error is + // detected + private SubstInNode nullSubstIn; + private FormalParamNode[] nullParam; + private OpDefNode nullODN; + protected OpApplNode nullOAN; + protected LabelNode nullLabelNode; + /*********************************************************************** + * This is a special OpApplNode that gets returned in various places * when an + * error is detected. This allows semantic analysis to * continue, presumably by + * preventing a NullPointerException. * + ***********************************************************************/ + protected OpArgNode nullOpArg; + + private final static UniqueString S_e = UniqueString.uniqueStringOf("\\E"); + private final static UniqueString S_ex = UniqueString.uniqueStringOf("\\exists"); + private final static UniqueString S_f = UniqueString.uniqueStringOf("\\A"); + private final static UniqueString S_fx = UniqueString.uniqueStringOf("\\always"); + private final static UniqueString S_te = UniqueString.uniqueStringOf("\\EE"); + private final static UniqueString S_tf = UniqueString.uniqueStringOf("\\AA"); + private final static UniqueString S_a = UniqueString.uniqueStringOf("<<"); + private final static UniqueString S_brack = UniqueString.uniqueStringOf("["); + private final static UniqueString S_sf = UniqueString.uniqueStringOf("SF_"); + private final static UniqueString S_wf = UniqueString.uniqueStringOf("WF_"); + private final static UniqueString S_at = UniqueString.uniqueStringOf("@"); + private final static UniqueString S_lambda = UniqueString.uniqueStringOf("LAMBDA"); + private final static UniqueString S_subexpression = UniqueString.uniqueStringOf("$Subexpression"); + + class Function { + /*********************************************************************** + * The only object of this class ever created is `functions', declared * right + * after the class definition. So, I don't know why this * class's methods + * weren't just made ordinary methods of the Generator * class. Perhaps this was + * done so the subclass `pair' could be * defined within it without interfering + * with any other subclass by * that name. However, there is no other subclass + * by that name in the * Generator class. * * See the comments attached to the + * `functions' object for the class's * explanation. * + ***********************************************************************/ + class pair { + UniqueString a; + OpApplNode b; + + pair(UniqueString uniqueString, OpApplNode oan) { + a = uniqueString; + b = oan; + } + + UniqueString uniqueString() { + return a; + } + + OpApplNode oan() { + return b; + } + } + + Stack funcStack = new Stack(); + + void push(UniqueString uniqueString, OpApplNode oan) { + funcStack.push(new pair(uniqueString, oan)); + } + + void pop() { + funcStack.pop(); + } + + // If same function found farther down on stack, then this is a recursive + // function definition--change the operator to indicate so. + boolean recursionCheck(UniqueString uniqueString) { + for (int lvi = funcStack.size() - 1; lvi >= 0; lvi--) { + if (uniqueString.equals(((pair) funcStack.elementAt(lvi)).uniqueString())) { + // OA-rfs = recursive func spec + ((pair) funcStack.elementAt(lvi)).oan().resetOperator(OP_rfs); + return true; + } + } + return false; + } + + } // end class Function + + // This is the only instance of class Function + + Function functions = new Function(); + + /*********************************************************************** + * This object is used to detect that a function definition is * recursive. It + * is a stack of <<UniqueString, OpApplNode>> pairs. * An element <<f, opAp>> in + * the stack indicates that the current node * being processed is inside the + * body of a function definition of the * form f[...] == body. The current + * context assigns to f an OpDefNode * whose body is the OpApplNode opAp whose + * operator is either * $RecursiveFcnSpec or $NonRecursiveFcnSpec having (an + * OpDeclNode * for) the bound identifier f and having the body of the + * definition * as its operand. The following methods can be applied: * * + * functions.push(UniqueString us, OpApplNode oan) * Pushes <<us, oan>> onto the + * stack. * * functions.pop() * Pops the last element off the stack. * * + * recursionCheck(UniqueString us) * If there is a pair <<us, oan>> on the + * stack, then the * operator of oan is set to $RecursiveFcnSpec. * * An entry + * for f is pushed on the stack before processing the body * f's definition, and + * popped upon return. * * When processing a FcnAppl syntax nodefor an + * expression f[...], * functions.recursionCheck is called to see the node + * occurs in the * body of the definition of f, in which case the definition + * body's * OpApplNode's operator is changed to indicate that f's definition is + * * recursive. * + ***********************************************************************/ + + // This class represents a generalized identifier, e.g. a syntactic + // phrase such as A(2)!B(x,y)!C!D(u,v,w) In this case the compoundID + // would be A!B!C!D and the args array would contain [2,x,y] + // (i.e. not including u,v,and w, because they are + // args to the main operator, and not part of the GenID + private class GenID { + + private TreeNode treeNode; + // The syntax tree node holding this GenID + private StringBuffer compoundID; + // The string name of the compound op, with "!"'s, if any + private Vector argsVector = new Vector(); + // Vector of arguments (ExprNodes and OpArgNodes) + // that are embedded in the generalized identifier + + // The next three fields are null until the finalAppend + // method has been called + private UniqueString compoundIDUS; + // UniqueString version of compoundID + private SymbolNode fullyQualifiedOp; + // SymbolNode for compoundID + private ExprOrOpArgNode[] args; + // Array with same contents as argsVector + + // Constructor + public GenID(TreeNode node) { + treeNode = node; + compoundID = new StringBuffer(""); + compoundIDUS = null; + fullyQualifiedOp = null; + args = null; + } + + public final UniqueString getCompoundIDUS() { + return compoundIDUS; + } + + public final SymbolNode getFullyQualifiedOp() { + return fullyQualifiedOp; + } + + public final ExprOrOpArgNode[] getArgs() { + return args; + } + + public final Vector getArgsVector() { + return argsVector; + } + + /** Append a new segment to the compound name of the operator */ + public final void append(String s) { + compoundID.append(s); + } + + /** Add a new argument to the vector of arguments being constructed */ + public final void addArg(ExprOrOpArgNode arg) { + argsVector.addElement(arg); + } + + /** + * Appends the final element of the fully-qualified name to the GenID that has + * been being built using addArg() and append(). Since it signals the completion + * of the construction of the name, this method converts the name from + * StringBuffer to UniqueString, resolves it to a SymbolNode, and converts the + * argument list from vector to array form. + */ + public final void finalAppend(String s, boolean unaryNegKludge) { + // append the final segment of the compound name + if (unaryNegKludge && s.equals("-")) { + compoundID.append("-."); + } else { + compoundID.append(s); + } + + // convert the full name to a UniqueString + compoundIDUS = UniqueString.uniqueStringOf(compoundID.toString()); + + // look up the full name in the SymbolTable (may return null) + fullyQualifiedOp = symbolTable.resolveSymbol(Operators.resolveSynonym(compoundIDUS)); + + if (fullyQualifiedOp == null && compoundIDUS != S_at) { + // if not in the symbol table and not "@", then it is an unresolved symbol + errors.addError(treeNode.getLocation(), "Could not find declaration or definition of symbol '" + + UniqueString.uniqueStringOf(compoundID.toString()) + "'."); + } + } + + public final void finalizeID() { + // copy argsVector contents into args array + args = new ExprOrOpArgNode[argsVector.size()]; + + for (int i = 0; i < args.length; i++) { + args[i] = (ExprOrOpArgNode) argsVector.elementAt(i); + } + } + + /** + * Special kluge to append a "." to the name of this ID; should be used ONLY to + * change unary "-" to "-." + */ + public final void appendDot() { + compoundIDUS = UniqueString.uniqueStringOf(compoundIDUS.toString() + "."); + } + + public final String toString(int n) { + String ret = "compound ID: " + compoundID.toString() + "\nargs: " + args.length + "\n"; + for (int i = 0; i < args.length; i++) { + ret += Strings.indent(2, args[i].toString(n)); + } + return ret; + } + + } // end GenID + + final UniqueString AtUS = UniqueString.uniqueStringOf("@"); + /*********************************************************************** + * This is needed in a couple of places. (I didn't notice that this * is already + * defined to equal S_at.) * + ***********************************************************************/ + + /************************************************************************* + * An object of subclass Selector is used to represent a the translation * of a + * GeneralId or an OpApplication whose operator is a GeneralId. It * contains + * the data represented in the Subexpression +cal algorithm by * the arrays ops + * and args. For example, the user expression * * Foo(a,b)!:!(c) * * produces + * the following in Subexpression algorithm: * * ops = << "Foo", ":", "null" >> + * * args = << <<a, b>>, << >>, << <<c>> >>, * * This is represented by a + * Selector object with four arrays of * length 3. The first is: * * int[] ops + * with ops[0] = NameSel * ops[1] = ColonSel * ops[2] = NullSel * * The set of + * all possible values of ops[i] are: * * An integer i >= 0 // Represents the i + * of "!i". * * One of the following integers < 0. * + *************************************************************************/ + + final int NameSel = -1; // A name like "Foo" ; + final int NullSel = -2; // A "(...)" selector ; + final int GGSel = -3; // ">>" ; + final int LLSel = -4; // "<<" ; + final int ColonSel = -5; // ":" ; + final int AtSel = -6; // "@" ; + + /************************************************************************* + * The remaining three arrays are: * * SyntaxTreeNode[] opsSTN with values equal + * to the syntax tree * nodes for the corresponding element * of ops. * * + * UniqueString[] opNames with opNames[0] = "Foo" * opNames[1] = ":" * + * opNames[2] = null * * SyntaxTreeNode[] args with args[0] = "(a, b)" * args[1] + * = null * args[2] = "(c)" * * Note: we can't turn the arguments into semantic + * nodes yet because we * want to use generateExprOrOpArg to do that, which + * requires that we * know the operator of which they're the arguments. Hence, + * that * computation has to be folded into the Subexpression algorithm. * * + * These arrays are initialized by the finish method, which is called * after + * all calls of addSelector have been issued. * + *************************************************************************/ + private class Selector { + /********************************************************************** + * A single field for the syntax tree node of the entire selector. * + **********************************************************************/ + SyntaxTreeNode selSTN; + + /********************************************************************** + * The fields modified by addSelector: * + **********************************************************************/ + private Vector opVec = new Vector(); // of SyntaxTreeNode ; + private Vector argVec = new Vector(); // of SyntaxTreeNode ; + + /********************************************************************** + * The fields set from opVec and argVec by finalize. * + **********************************************************************/ + int[] ops = null; + UniqueString[] opNames = null; + SyntaxTreeNode[] opsSTN = null; + SyntaxTreeNode[] args = null; + + /********************************************************************** + * Constants not needed elsewhere. * + **********************************************************************/ + final UniqueString GGUS = UniqueString.uniqueStringOf(">>"); + final UniqueString LLUS = UniqueString.uniqueStringOf("<<"); + final UniqueString ColonUS = UniqueString.uniqueStringOf(":"); + + /********************************************************************** + * The constructor. * + **********************************************************************/ + + Selector(SyntaxTreeNode tn) { + selSTN = tn; + } + + void addSelector(SyntaxTreeNode stn, SyntaxTreeNode opargs) { + /******************************************************************** + * opargs is the args entry. * * stn is the syntax tree node representing the + * ops entry. If * there are no arguments, it should be null. For a NullSel + * entry * it should be the OpArgs node (the "(arg1, ... , argN)") that is * + * used as the second argument. * + ********************************************************************/ + opVec.addElement(stn); + argVec.addElement(opargs); + } // addSelector + + void finish() throws AbortException { + int arrayLen = opVec.size(); + ops = new int[arrayLen]; + opNames = new UniqueString[arrayLen]; + opsSTN = new SyntaxTreeNode[arrayLen]; + args = new SyntaxTreeNode[arrayLen]; + for (int i = 0; i < arrayLen; i++) { + args[i] = (SyntaxTreeNode) argVec.elementAt(i); + SyntaxTreeNode stn = (SyntaxTreeNode) opVec.elementAt(i); + opsSTN[i] = stn; + opNames[i] = stn.getUS(); + switch (stn.getKind()) { + case IDENTIFIER: + case N_InfixOp: + case N_NonExpPrefixOp: + case N_PostfixOp: + case N_PrefixOp: + case ProofStepLexeme: // xyz: following case added by LL on 13 Oct 2007 // - case ProofImplicitStepLexeme: - ops[i] = NameSel ; - break ; - - - - case N_StructOp: - if (stn.heirs().length > 0) { - /************************************************************ - * This is a number. * - ************************************************************/ - TreeNode numNode = stn.heirs()[0].heirs()[0] ; - ops[i] = Integer.parseInt(numNode.getImage()) ; - } - else { - /************************************************************ - * This is not a number, so it is ">>", "<<", "@", or ":". * - ************************************************************/ - UniqueString us = stn.getUS() ; - if (us == GGUS) {ops[i] = GGSel ;} - else if (us == LLUS) {ops[i] = LLSel ;} - else if (us == ColonUS) {ops[i] = ColonSel ;} - else if (us == AtUS) {ops[i] = AtSel ; } - else { errors.addAbort( - stn.getLocation(), - "Internal error: Unexpected selector `" + - stn.getImage() + "'.") ;} - } // if stn.heirs().length > 0 - break ; - - case N_OpArgs: - ops[i] = NullSel ; - break ; - - default: - /*************************************************************** - * This error occurs on silly input like * - * * - * USE DEF <<1, 2>> * - * * - * It therefore seems better to report a mysterious error and * - * let processing continue in the hopes that it will generate * - * a later, more useful error. * - ***************************************************************/ + case ProofImplicitStepLexeme: + ops[i] = NameSel; + break; + + case N_StructOp: + if (stn.heirs().length > 0) { + /************************************************************ + * This is a number. * + ************************************************************/ + TreeNode numNode = stn.heirs()[0].heirs()[0]; + ops[i] = Integer.parseInt(numNode.getImage()); + } else { + /************************************************************ + * This is not a number, so it is ">>", "<<", "@", or ":". * + ************************************************************/ + UniqueString us = stn.getUS(); + if (us == GGUS) { + ops[i] = GGSel; + } else if (us == LLUS) { + ops[i] = LLSel; + } else if (us == ColonUS) { + ops[i] = ColonSel; + } else if (us == AtUS) { + ops[i] = AtSel; + } else { + errors.addAbort(stn.getLocation(), + "Internal error: Unexpected selector `" + stn.getImage() + "'."); + } + } // if stn.heirs().length > 0 + break; + + case N_OpArgs: + ops[i] = NullSel; + break; + + default: + /*************************************************************** + * This error occurs on silly input like * * USE DEF <<1, 2>> * * It therefore + * seems better to report a mysterious error and * let processing continue in + * the hopes that it will generate * a later, more useful error. * + ***************************************************************/ // errors.addAbort( - errors.addError( - stn.getLocation(), + errors.addError(stn.getLocation(), // "Internal error: Selector had unexpected node kind " + // stn.getKind()) ; - "Unexpected token found." ) ; - break ; - } ; - } // for - } - - public String toString() { - /******************************************************************** - * For debugging. * - ********************************************************************/ - String retval = "Selector object:\n" ; - for (int i = 0; i < ops.length; i++) { - retval = retval + " elt " + i + " : ops = " + ops[i] + - ", opNames = " + opNames[i].toString() + - ", opsSTN.kind = " + opsSTN[i].getKind() + - ", args.kind = " + - ((args[i] == null)?"null":(args[i].getKind()+" ")) + "\n" ; - } - return retval ; - } - - } // class Selector + "Unexpected token found."); + break; + } + ; + } // for + } + + public String toString() { + /******************************************************************** + * For debugging. * + ********************************************************************/ + String retval = "Selector object:\n"; + for (int i = 0; i < ops.length; i++) { + retval = retval + " elt " + i + " : ops = " + ops[i] + ", opNames = " + opNames[i].toString() + + ", opsSTN.kind = " + opsSTN[i].getKind() + ", args.kind = " + + ((args[i] == null) ? "null" : (args[i].getKind() + " ")) + "\n"; + } + return retval; + } + + } // class Selector // private ExprOrOpArgNode[] opArgsToArray(SyntaxTreeNode opArgNode) // /*********************************************************************** @@ -530,3993 +494,3743 @@ public class Generator implements ASTConstants, SyntaxTreeConstants, // } // for // } // opArgsToArray - private Selector genIdToSelector(SyntaxTreeNode genId) - throws AbortException { - /*********************************************************************** - * Constructs a selector in which all the addSelector calls to * - * translate the GeneralId node genId have been made and finish has * - * been called. * - * * - * See the commments in tla+.jj before the OpOrExpr() production to * - * see what the tree structure of a GeneralId node looks like. * - ***********************************************************************/ - Selector retval = new Selector(genId) ; - TreeNode prefix = genId.heirs()[0] ; - TreeNode[] prefixElts = prefix.heirs() ; - SyntaxTreeNode lastOp = (SyntaxTreeNode) genId.heirs()[1] ; - for (int i = 0 ; i < prefixElts.length; i++) { - TreeNode[] pe = prefixElts[i].heirs(); - if (pe.length == 0) { - /******************************************************************* - * We reach this point when processing the nonsensical input * - * HIDE DEF X' * - * So we report a not very helpful error in the hopes that further * - * processing will produce a more useful error message. * - *******************************************************************/ - errors.addError(genId.getLocation(), - "Was expecting a GeneralId."); - break ;} ; - SyntaxTreeNode thisPrefix = (SyntaxTreeNode) pe[0] ; - switch (thisPrefix.getKind()) { - case N_OpArgs: - retval.addSelector(thisPrefix, thisPrefix) ; - break; - case N_StructOp: - retval.addSelector(thisPrefix, null) ; - break; - default: - /***************************************************************** - * This must be an identifier or operator. It may or may not * - * have arguments. * - *****************************************************************/ - if (prefixElts[i].heirs().length == 2) { - /*************************************************************** - * There are no arguments (the 2nd heir is the "!"). * - ***************************************************************/ - retval.addSelector(thisPrefix, null) ; - } - else { - /*************************************************************** - * There are arguments, which are heirs()[1]. * - ***************************************************************/ - if (prefixElts[i].heirs().length != 3) { - // Note added 13 April 2015 by LL: - // This error is caused by the spurious "(x)" in the leaf proof - // BY ... DEF A!foo(x) - // It would be nice if this produced a more helpful error - // message, but I have no idea if there are other bad inputs - // that can cause it. - errors.addAbort( - prefixElts[i].getLocation(), - "Internal error: " + - "IdPrefixElement has other than 2 or 3 heirs.") ; - } ; - retval.addSelector(thisPrefix, - (SyntaxTreeNode) prefixElts[i].heirs()[1]) ; - } // if} - break ; - } // switch - }; // for i - - if (lastOp.getKind() == N_OpArgs) {retval.addSelector(lastOp, lastOp) ;} - else {retval.addSelector(lastOp, null) ;} ; - - retval.finish() ; - return retval ; - } // genIdToSelector - - - /*********************************************************************** - * Constants for use in selectorToNode. * - ***********************************************************************/ - private final int FindingOpName = 11 ; - private final int FollowingLabels = 22 ; - private final int FindingSubExpr = 33 ; - - private final int ArgNum(int op, int arity) { - /*********************************************************************** - * This is the implementation of ArgNum in Subexpression.tla. Beware * - * that this is the human argument number (where the first argument is * - * argument 1), not the Java argument number. * - ***********************************************************************/ - if (op > 0) {if (op <= arity) {return op;} ; - return -1 ; - } ; - if (op == LLSel) {return (arity > 0) ? 1 : -1 ;} ; - if (op == GGSel) {// if (arity == 1) {return 1;} ; - /************************************************** - * Commented out on 9 Mar 2010 by LL. Apparently, * - * I once thought it was a good idea to let !>> * - * refer to the argument of a unary operator. I * - * no longer think so. * - **************************************************/ - if (arity == 2) {return 2;} ; - } ; - return -1; - } // ArgNum - - LevelNode selectorToNode(Selector sel, // The selector. - int expectedArity, - boolean isFact, // true if looking for a fact - boolean isDef, // true if looking for a DEF - // clause item. - ModuleNode cm ) // The current module. - throws AbortException { - /*********************************************************************** - * This is an implementation of the +cal algorithm in module * - * Subexpression.tla, which is attached as a comment to the end of * - * this file. If expectedArity >= 0, then it returns an * - * ExprOrOpArgNode, otherwise it returns an OpDefNode or a * - * ThmOrAssumpDefNode. On an error, it returns nullOAN which will * - * allow semantic analysis to continue. * - * * - * The +cal algorithm describes only the case isFact = false and isDef * - * = false. It should be updated to include the other case as well. * - * It also doesn't mention the case of a NumberedProofStepKind OpDef * - * node. * - * * - * This code was modified on 15 Oct 2007 by LL to allow the use of a * - * ModuleInstanceKind node (the M in "M == INSTANCE ...") as a fact or * - * a DEF in a BY, USE, or HIDE. Parameterized instances can be used in * - * a DEF (without the parameters), but only a non-parameterized module * - * instance can be used as a fact. * - * * - * It appears that, if an error has occurred, a call with * - * expectedArity>0 can return something other than an OpArgNode * - * (probably an OpApplNode). This caused a problem in one * - * place--namely, in generateOpArg. I didn't try figuring out whether * - * this is actually a bug in selectorToNode. Instead, I just kludged * - * something to handle that case. * - ***********************************************************************/ - Vector substInPrefix = new Vector() ; // of SubstInNode - Vector params = new Vector() ; // of FormalParamNode - Vector allArgs = new Vector() ; // of ExprOrOpArgNode - - /*********************************************************************** - * Local algorithm variables. * - ***********************************************************************/ - UniqueString curName = null ; - UniqueString newName = null ; // Initial value set to make Eclipse happy. - SemanticNode curNode = null ; - SemanticNode newNode ; - - int idx = 0 ; - /********************************************************************* - * We use the Java convention of counting from 0 instead of the * - * human convention of couunting from 1. * - *********************************************************************/ - int mode = FindingOpName ; - int prevMode = -999 ; - /********************************************************************* - * The compiler is too dumb to figure out that it always gets set * - * before it's used. * - *********************************************************************/ - Context letInContext = null ; - /********************************************************************* - * This implements the algorithm's curContext variable when that * - * context is a LET/IN node's context. When mode = FindingOpName, * - * letInContext is null iff this is the first time that mode is * - * entered--i.e., for the name that is the initial part of the * - * selector. In this case, the algorithm's curContext is * - * represented by the method's "global variable" symbolTable, since * - * any name legal in that context can be referred to. When mode is * - * subsequently set to FindingOpName, it means that the name being * - * sought is from a LET/IN node. In that case, letInContext will * - * contain the Context that implements the algorithm's curContext * - * variable. * - *********************************************************************/ - int opDefArityFound = 0 ; - Vector opDefArgs = new Vector() ; // of ExprOrOpArgNode objects - boolean firstFindingOpName = true; - SymbolNode subExprOf = null; - - boolean inAPsuffices = false ; - /********************************************************************* - * Added 16 Feb 2009. An AssumeProveNode with suffices field true * - * represents SUFFICE ASSUME / PROVE, and the SUFFICES is treated as * - * if it were a 1-argument operator. This flag is set true when the * - * node is first encountered. * - *********************************************************************/ - - while (idx < sel.args.length) { - /********************************************************************* - * Check the one part of the algorithm's assert that should not * - * automatically hold -- the first conjunct of the last conjunct -- * - * for i = idx: * - *********************************************************************/ - if ( ( ( (sel.ops[idx] != NameSel) - && (sel.ops[idx] != NullSel)) - || (expectedArity != 0) ) - && (sel.args[idx] != null)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selector `" + selectorItemToString(sel, idx) + - "' should not have argument(s).") ; - return nullOAN ; - } // if (sel.ops[idx] == NameSel) ... ; - - /********************************************************************* - * Check that, if sel.args[idx] != null, then it is an OpArgs node. * - *********************************************************************/ - if ( (sel.args[idx] != null) - && (sel.args[idx].getKind() != N_OpArgs) ) { - errors.addAbort( - sel.args[idx].getLocation(), - "Internal error: Unexpected syntax node kind."); - } ; - - switch (mode) { - case FindingOpName : - // Following code changed on 23 Sep 2009 to fix bug, and corrected - // on 9 Nov 2009. See description in Subexpression.tla. - SymbolNode newSymbolNode = null; - Vector tempArgs = new Vector() ; - // a vector of SyntaxTreeNode objects, one for each argument - // found for an undefined operator name in the following loop - - while (newSymbolNode == null && idx < sel.args.length) { - /****************************************************************** - * +cal: newName := IF IsName(ops[idx]) ... ELSE null ; * - ******************************************************************/ - if (sel.ops[idx] == NameSel) { - if (curName == null) { - newName = Operators.resolveSynonym(sel.opNames[idx]) ; - /************************************************************ - * Need to call resolveSynonym so things like (+), aka * - * \oplus, are handled properly. * - ************************************************************/ - } - else { newName = - UniqueString.uniqueStringOf( - curName.toString() + "!" + - Operators.resolveSynonym(sel.opNames[idx]).toString()) ; - } ; - } // if (sel.ops[idx] = NameSel) - else { newName = null ; } ; - - if ( (curName == null) - && (sel.ops[idx] != NameSel)) { - if (idx == 0) { errors.addError( - sel.opsSTN[idx].getLocation(), - "Need name or step number here, not `" + - sel.opNames[idx] + "'.") ; - return nullOAN ; } - else {errors.addAbort(sel.opsSTN[idx].getLocation(), - "Internal error: should have name here.") ; - } ; - } ; // if (curName == null) ... ; - if (newName != null) { - if (letInContext == null) { - /*************************************************************** - * See the comments for the declaration of letInContext. * - ***************************************************************/ - newSymbolNode = symbolTable.resolveSymbol(newName) ; - } - else { - newSymbolNode = letInContext.getSymbol(newName) ; - } ; - } ; // if (newName != null) - if (newSymbolNode == null) { - curName = newName; - if (sel.args[idx] != null) { - // sel.args[idx].heirs() is the array of SyntaxTreeNode objects - // representing: - // "(" "arg1" "," ... "," "arg_n" ")" - // We add these SyntaxTreeNode objects to tempArgs. - int numOfOpArgs = (sel.args[idx].heirs().length - 1) / 2 ; - for (int i = 0 ; i < numOfOpArgs; i++) { - tempArgs.addElement(sel.args[idx].heirs()[2*i+1]); - } - } - idx++; - } - } // while (newNode == null) - - if (newSymbolNode == null) { - int eidx = (idx < sel.args.length) ? idx : (sel.args.length-1); - errors.addError( - sel.opsSTN[eidx].getLocation(), - "Unknown operator: `" + - selectorItemToString(sel, eidx) + "'.") ; - return nullOAN ; - } ; - - if (newSymbolNode.getKind() == ModuleKind) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Module name (" + sel.opNames[idx].toString() + - ") not allowed here.") ; - return nullOAN ; - } ; // if - - curNode = newSymbolNode ; - SymbolNode curSymbolNode = newSymbolNode ; - /**************************************************************** - * A version of curNode "cast" as a SymbolNode. * - ****************************************************************/ - curName = newName ; - switch (curSymbolNode.getKind()) { - case ConstantDeclKind: - case VariableDeclKind: - case FormalParamKind: - case BuiltInKind: - case NewConstantKind: - case NewVariableKind: - case NewStateKind: - case NewActionKind: - case NewTemporalKind: - case NumberedProofStepKind: - /************************************************************** - * This last case added by LL on 17 Aug 2007. I think it * - * fits in here nicely, but I wouldn't swear to it. * - **************************************************************/ - if (idx != 0) { - errors.addAbort( - sel.selSTN.getLocation(), - "Internal error: impossible naming of declaration.") ; - } - else if (sel.ops.length != 1) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Cannot take subexpression of `" + curName.toString() - + "'.") ; - return nullOAN ; - } // ; - - /**************************************************************** - * Warning: horrible Java programming hack. There is * - * deliberately no break here, so this case "joins" the * - * following case. * - ****************************************************************/ - //$FALL-THROUGH$ - case UserDefinedOpKind: - case ThmOrAssumpDefKind: - case ModuleInstanceKind: - /************************************************************** - * +cal: nodeArity := Arity(curNode) ; * - **************************************************************/ - int nodeArity = curSymbolNode.getArity() ; - /************************************************************** - * +cal: if expectedArity = 0 * - **************************************************************/ - if (expectedArity == 0) { - SyntaxTreeNode opArgs = sel.args[idx] ; - int numOfOpArgs = 0 ; - if (opArgs != null) { - // if there are arguments, add them to tempArgs. - /********************************************************** - * The heirs of an oparg node are * - * * - * "(" "arg1" "," ... "," "arg_n" ")" * - **********************************************************/ - numOfOpArgs = (opArgs.heirs().length - 1) / 2 ; - for (int i = 0 ; i < numOfOpArgs; i++) { - tempArgs.addElement(sel.args[idx].heirs()[2*i+1]); - } ; - - }; - /************************************************************** - * +cal then if opDefArityFound + Len(tempArgs) # nodeArity * - **************************************************************/ - if (opDefArityFound + tempArgs.size() != nodeArity) { - errors.addError( - (opArgs == null)? sel.selSTN.getLocation() : - sel.args[idx].getLocation(), - "The operator " + curName.toString() + " requires " + - (nodeArity - opDefArityFound) + " arguments.") ; - return nullOAN ; - } ; // if - ExprOrOpArgNode[] opArgNodes = - new ExprOrOpArgNode[tempArgs.size()] ; - /********************************************************** - * The array of semantic nodes generated by the arguments. * - **********************************************************/ - for (int i = 0 ; i < tempArgs.size(); i++) { - /********************************************************** - * Call generateExprOrOpArg to generate the semantic * - * nodes for the arguments and add them to the vector * - * opDefArgs. Note that curSymbolNode is used as the * - * argument to generateExprOrOpArg that specifies the * - * operator to which the arguments are being given. (The * - * comments for that method assumes that the operator * - * arguments appear in an OpApplication node, but the * - * method doesn't really care; it just uses that operator * - * to check the arity of the arguments.) Note that * - * argument number i of sel.args[idx] represents argument * - * number i + opDefArityFound of the operator described * - * by curSymbolNode. * - **********************************************************/ - opDefArgs.addElement( - generateExprOrOpArg( - curSymbolNode, - sel.opsSTN[idx], - i + opDefArityFound, - (TreeNode) tempArgs.elementAt(i), - cm)); - } ; // end for - - } // if expectedArity = 0 - /************************************************************** - * +cal: else if expectedArity > 0) * - **************************************************************/ - else { - if (expectedArity > 0) { - /********************************************************** - * Subexpression.tla has a test to report an error if a * - * higher-order operator is specified, since such an * - * operator can't be used as an operator argument. That * - * test is eliminated here because this error should be * - * caught by the caller of the selectorToNode method. * - **********************************************************/ - } - } ; // else [expectedArity != 0] - opDefArityFound = nodeArity ; - - if (curNode.getKind() == ModuleInstanceKind) { - if ((idx == sel.ops.length - 1) && ! (isDef || isFact)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Operator name " + curName.toString() + " is incomplete."); - return nullOAN ; - }; - } - else { - /************************************************************** - * curNode.getKind() \in * - * {UserDefinedOpKind, ThmOrAssumpDefKind, * - * ConstantDeclKind, VariableDeclKind, FormalParamKind, * - * BuiltInKind, BoundSymbolKind, NumberedProofStepKind} * - **************************************************************/ - /************************************************************** - * +cal: then if /\ curNode.kind = UserDefinedOpKind ... * - **************************************************************/ - if ( (curNode.getKind() == UserDefinedOpKind) - && ( ! ((OpDefNode) curNode).isDefined ) - && (sel.ops.length != 1)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Subexpression of `" + curName.toString() + - "' used inside the operator's definition."); - return nullOAN ; - } ; - - /************************************************************** - * +cal: if /\ firstFindingOpName ... * - **************************************************************/ - if ( firstFindingOpName - && ( (curNode.getKind() == UserDefinedOpKind) - || (curNode.getKind() == ThmOrAssumpDefKind))) { - subExprOf = (SymbolNode) curNode; - } - /************************************************************** - * +cal: idx # Len(ops) * - **************************************************************/ - if (idx != sel.ops.length - 1) { - FormalParamNode[] opParams ; - if (curNode.getKind() == UserDefinedOpKind) { - opParams = ((OpDefNode) curNode).getParams() ; - newNode = ((OpDefNode) curNode).getBody() ; - } // if - else { // curNode.getKind() == ThmOrAssumpDefKind - opParams = ((ThmOrAssumpDefNode) curNode).getParams() ; - newNode = ((ThmOrAssumpDefNode) curNode).getBody() ; - } ; - for (int i = 0 ; i < opParams.length ; i++) { - params.addElement(opParams[i]) ; - } ; // for - curName = null ; - if (sel.ops[idx+1] == NameSel) {mode = FollowingLabels; } - else {mode = FindingSubExpr ;} ; - for (int i = 0 ; i < opDefArgs.size() ; i++) { - allArgs.addElement(opDefArgs.elementAt(i)) ; - } ; // for - opDefArityFound = 0; - opDefArgs = new Vector() ; - - /************************************************************ - * If newNode = null, then I think there's an error. It * - * should be caught later. * - ************************************************************/ - if (newNode != null) { - while (newNode.getKind() == SubstInKind) { - substInPrefix.addElement(newNode) ; - newNode = ((SubstInNode) newNode).getBody() ; - }; // while - while (newNode.getKind() == APSubstInKind) { - substInPrefix.addElement(newNode) ; - newNode = ((APSubstInNode) newNode).getBody() ; - }; // while - } ; - if (mode == FindingSubExpr) { - curNode = newNode ; - } ; - } // if (idx != sel.ops.length - 1) - } // else curNode.getKind() \in {UserDefinedOpKind, ...} - prevMode = FindingOpName ; - break ; - - default: - errors.addAbort(sel.opsSTN[idx].getLocation(), - "Internal error: unexpected node kind.") ; - break ; - } ; // switch (curSymbolNode.getKind()) - - break ; // case FindingOpName - - - case FollowingLabels : - /****************************************************************** - * Invariant: sel.ops[idx] = NameSel * - ******************************************************************/ - if ( ( (prevMode == FindingOpName) - && (curNode.getKind() != UserDefinedOpKind) - && (curNode.getKind() != ThmOrAssumpDefKind)) - || ( (prevMode != FindingOpName) - && (curNode.getKind() != LabelKind))) { - errors.addAbort(sel.selSTN.getLocation(), - "Unexpected node kind in FollowingLabels mode.") ; - } ; - - LabelNode newLabelNode = - ((OpDefOrLabelNode) curNode).getLabel(sel.opNames[idx]) ; - - if (newLabelNode == null) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Cannot find label `" + sel.opNames[idx].toString() + "'."); - return nullOAN ; - } ; - - curNode = newLabelNode ; - - if (illegalLabelRef(newLabelNode, sel.opsSTN[idx])) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Accessing subexpression labeled `" + - sel.opNames[idx].toString() + - "' of ASSUME/PROVE clause within the scope of " + - "a declaration\n from outside that declaration's scope."); - return nullOAN ; - } ; - - if (expectedArity == 0) { - - /**************************************************************** - * Check that label has right number of arguments. * - ****************************************************************/ - if (newLabelNode.getArity() != - ((sel.args[idx] == null) - ? 0 - : (sel.args[idx].heirs().length-1)/2)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Label `" + sel.opNames[idx].toString() - + "' used with wrong number of arguments."); - return nullOAN ; - } ; - for (int i = 0; i < newLabelNode.getArity(); i++) { - allArgs.addElement(generateExpression( - sel.args[idx].heirs()[2 * i + 1] , cm)) ; - } ; - }; // if (expectedArity == 0) - - for (int i = 0; i < newLabelNode.getArity(); i++) { - FormalParamNode pdecl = newLabelNode.params[i] ; - params.addElement(pdecl); - } ; - - if ((idx < sel.ops.length - 1) && (sel.ops[idx+1] != NameSel)) { - mode = FindingSubExpr ; - } ; - - if ((mode == FindingSubExpr) || (idx == sel.ops.length)) { - curNode = newLabelNode.getBody() ; - } ; - - prevMode = FollowingLabels ; - break ; // case FollowingLabels - - case FindingSubExpr: - if (sel.ops[idx] == ColonSel) { - if ( (prevMode == FindingSubExpr) - || ! ( ( (idx == sel.ops.length - 1) - && (prevMode == FindingOpName)) - || ( (idx < sel.ops.length - 1) - && (sel.ops[idx+1] == NameSel)))) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "`!:' can be used only after a name and either at the " + - "end after an\noperator name or before an operator name."); - return nullOAN ; - } // if ( (prevMode == FindingSubExpr) ...) - } // if (sel.ops[idx] == ColonSel) - else if (curNode == null) { - errors.addError(sel.opsSTN[idx].getLocation(), - "Subexpression selection failed, probably due to " + - "an error in the selected expression."); - return nullOAN ; - } - else if (curNode.getKind() == LetInKind) { - if (ArgNum(sel.ops[idx], 1) == 1) { - curNode = ((LetInNode) curNode).getBody() ; - } else { - errors.addError(sel.opsSTN[idx].getLocation(), - "A LET/IN expression has only one operand."); - return nullOAN ; - } ; - } // else if (curNode.getKind() == LetInKind) - - else if (curNode.getKind() == OpApplKind) { - OpApplNode curOpApplNode = (OpApplNode) curNode ; - ExprOrOpArgNode[] curArgs = curOpApplNode.getArgs() ; - SymbolNode opNode = curOpApplNode.getOperator(); - if ( (opNode.getKind() == FormalParamKind) - || (opNode.getKind() == ConstantDeclKind) - || (opNode.getKind() == UserDefinedOpKind)) { - int temp = ArgNum(sel.ops[idx], opNode.getArity()) ; - if (temp == -1) { - reportSelectorError(sel, idx) ; + private Selector genIdToSelector(SyntaxTreeNode genId) throws AbortException { + /*********************************************************************** + * Constructs a selector in which all the addSelector calls to * translate the + * GeneralId node genId have been made and finish has * been called. * * See the + * commments in tla+.jj before the OpOrExpr() production to * see what the tree + * structure of a GeneralId node looks like. * + ***********************************************************************/ + Selector retval = new Selector(genId); + TreeNode prefix = genId.heirs()[0]; + TreeNode[] prefixElts = prefix.heirs(); + SyntaxTreeNode lastOp = (SyntaxTreeNode) genId.heirs()[1]; + for (int i = 0; i < prefixElts.length; i++) { + TreeNode[] pe = prefixElts[i].heirs(); + if (pe.length == 0) { + /******************************************************************* + * We reach this point when processing the nonsensical input * HIDE DEF X' * So + * we report a not very helpful error in the hopes that further * processing + * will produce a more useful error message. * + *******************************************************************/ + errors.addError(genId.getLocation(), "Was expecting a GeneralId."); + break; + } + ; + SyntaxTreeNode thisPrefix = (SyntaxTreeNode) pe[0]; + switch (thisPrefix.getKind()) { + case N_OpArgs: + retval.addSelector(thisPrefix, thisPrefix); + break; + case N_StructOp: + retval.addSelector(thisPrefix, null); + break; + default: + /***************************************************************** + * This must be an identifier or operator. It may or may not * have arguments. * + *****************************************************************/ + if (prefixElts[i].heirs().length == 2) { + /*************************************************************** + * There are no arguments (the 2nd heir is the "!"). * + ***************************************************************/ + retval.addSelector(thisPrefix, null); + } else { + /*************************************************************** + * There are arguments, which are heirs()[1]. * + ***************************************************************/ + if (prefixElts[i].heirs().length != 3) { + // Note added 13 April 2015 by LL: + // This error is caused by the spurious "(x)" in the leaf proof + // BY ... DEF A!foo(x) + // It would be nice if this produced a more helpful error + // message, but I have no idea if there are other bad inputs + // that can cause it. + errors.addAbort(prefixElts[i].getLocation(), + "Internal error: " + "IdPrefixElement has other than 2 or 3 heirs."); + } + ; + retval.addSelector(thisPrefix, (SyntaxTreeNode) prefixElts[i].heirs()[1]); + } // if} + break; + } // switch + } + ; // for i + + if (lastOp.getKind() == N_OpArgs) { + retval.addSelector(lastOp, lastOp); + } else { + retval.addSelector(lastOp, null); + } + ; + + retval.finish(); + return retval; + } // genIdToSelector + + /*********************************************************************** + * Constants for use in selectorToNode. * + ***********************************************************************/ + private final int FindingOpName = 11; + private final int FollowingLabels = 22; + private final int FindingSubExpr = 33; + + private final int ArgNum(int op, int arity) { + /*********************************************************************** + * This is the implementation of ArgNum in Subexpression.tla. Beware * that this + * is the human argument number (where the first argument is * argument 1), not + * the Java argument number. * + ***********************************************************************/ + if (op > 0) { + if (op <= arity) { + return op; + } + ; + return -1; + } + ; + if (op == LLSel) { + return (arity > 0) ? 1 : -1; + } + ; + if (op == GGSel) {// if (arity == 1) {return 1;} ; + /************************************************** + * Commented out on 9 Mar 2010 by LL. Apparently, * I once thought it was a good + * idea to let !>> * refer to the argument of a unary operator. I * no longer + * think so. * + **************************************************/ + if (arity == 2) { + return 2; + } + ; + } + ; + return -1; + } // ArgNum + + LevelNode selectorToNode(Selector sel, // The selector. + int expectedArity, boolean isFact, // true if looking for a fact + boolean isDef, // true if looking for a DEF + // clause item. + ModuleNode cm) // The current module. + throws AbortException { + /*********************************************************************** + * This is an implementation of the +cal algorithm in module * + * Subexpression.tla, which is attached as a comment to the end of * this file. + * If expectedArity >= 0, then it returns an * ExprOrOpArgNode, otherwise it + * returns an OpDefNode or a * ThmOrAssumpDefNode. On an error, it returns + * nullOAN which will * allow semantic analysis to continue. * * The +cal + * algorithm describes only the case isFact = false and isDef * = false. It + * should be updated to include the other case as well. * It also doesn't + * mention the case of a NumberedProofStepKind OpDef * node. * * This code was + * modified on 15 Oct 2007 by LL to allow the use of a * ModuleInstanceKind node + * (the M in "M == INSTANCE ...") as a fact or * a DEF in a BY, USE, or HIDE. + * Parameterized instances can be used in * a DEF (without the parameters), but + * only a non-parameterized module * instance can be used as a fact. * * It + * appears that, if an error has occurred, a call with * expectedArity>0 can + * return something other than an OpArgNode * (probably an OpApplNode). This + * caused a problem in one * place--namely, in generateOpArg. I didn't try + * figuring out whether * this is actually a bug in selectorToNode. Instead, I + * just kludged * something to handle that case. * + ***********************************************************************/ + Vector substInPrefix = new Vector(); // of SubstInNode + Vector params = new Vector(); // of FormalParamNode + Vector allArgs = new Vector(); // of ExprOrOpArgNode + + /*********************************************************************** + * Local algorithm variables. * + ***********************************************************************/ + UniqueString curName = null; + UniqueString newName = null; // Initial value set to make Eclipse happy. + SemanticNode curNode = null; + SemanticNode newNode; + + int idx = 0; + /********************************************************************* + * We use the Java convention of counting from 0 instead of the * human + * convention of couunting from 1. * + *********************************************************************/ + int mode = FindingOpName; + int prevMode = -999; + /********************************************************************* + * The compiler is too dumb to figure out that it always gets set * before it's + * used. * + *********************************************************************/ + Context letInContext = null; + /********************************************************************* + * This implements the algorithm's curContext variable when that * context is a + * LET/IN node's context. When mode = FindingOpName, * letInContext is null iff + * this is the first time that mode is * entered--i.e., for the name that is the + * initial part of the * selector. In this case, the algorithm's curContext is * + * represented by the method's "global variable" symbolTable, since * any name + * legal in that context can be referred to. When mode is * subsequently set to + * FindingOpName, it means that the name being * sought is from a LET/IN node. + * In that case, letInContext will * contain the Context that implements the + * algorithm's curContext * variable. * + *********************************************************************/ + int opDefArityFound = 0; + Vector opDefArgs = new Vector(); // of ExprOrOpArgNode objects + boolean firstFindingOpName = true; + SymbolNode subExprOf = null; + + boolean inAPsuffices = false; + /********************************************************************* + * Added 16 Feb 2009. An AssumeProveNode with suffices field true * represents + * SUFFICE ASSUME / PROVE, and the SUFFICES is treated as * if it were a + * 1-argument operator. This flag is set true when the * node is first + * encountered. * + *********************************************************************/ + + while (idx < sel.args.length) { + /********************************************************************* + * Check the one part of the algorithm's assert that should not * automatically + * hold -- the first conjunct of the last conjunct -- * for i = idx: * + *********************************************************************/ + if ((((sel.ops[idx] != NameSel) && (sel.ops[idx] != NullSel)) || (expectedArity != 0)) + && (sel.args[idx] != null)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Selector `" + selectorItemToString(sel, idx) + "' should not have argument(s)."); + return nullOAN; + } // if (sel.ops[idx] == NameSel) ... ; + + /********************************************************************* + * Check that, if sel.args[idx] != null, then it is an OpArgs node. * + *********************************************************************/ + if ((sel.args[idx] != null) && (sel.args[idx].getKind() != N_OpArgs)) { + errors.addAbort(sel.args[idx].getLocation(), "Internal error: Unexpected syntax node kind."); + } + ; + + switch (mode) { + case FindingOpName: + // Following code changed on 23 Sep 2009 to fix bug, and corrected + // on 9 Nov 2009. See description in Subexpression.tla. + SymbolNode newSymbolNode = null; + Vector tempArgs = new Vector(); + // a vector of SyntaxTreeNode objects, one for each argument + // found for an undefined operator name in the following loop + + while (newSymbolNode == null && idx < sel.args.length) { + /****************************************************************** + * +cal: newName := IF IsName(ops[idx]) ... ELSE null ; * + ******************************************************************/ + if (sel.ops[idx] == NameSel) { + if (curName == null) { + newName = Operators.resolveSynonym(sel.opNames[idx]); + /************************************************************ + * Need to call resolveSynonym so things like (+), aka * \oplus, are handled + * properly. * + ************************************************************/ + } else { + newName = UniqueString.uniqueStringOf( + curName.toString() + "!" + Operators.resolveSynonym(sel.opNames[idx]).toString()); + } + ; + } // if (sel.ops[idx] = NameSel) + else { + newName = null; + } + ; + + if ((curName == null) && (sel.ops[idx] != NameSel)) { + if (idx == 0) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Need name or step number here, not `" + sel.opNames[idx] + "'."); + return nullOAN; + } else { + errors.addAbort(sel.opsSTN[idx].getLocation(), "Internal error: should have name here."); + } + ; + } + ; // if (curName == null) ... ; + if (newName != null) { + if (letInContext == null) { + /*************************************************************** + * See the comments for the declaration of letInContext. * + ***************************************************************/ + newSymbolNode = symbolTable.resolveSymbol(newName); + } else { + newSymbolNode = letInContext.getSymbol(newName); + } + ; + } + ; // if (newName != null) + if (newSymbolNode == null) { + curName = newName; + if (sel.args[idx] != null) { + // sel.args[idx].heirs() is the array of SyntaxTreeNode objects + // representing: + // "(" "arg1" "," ... "," "arg_n" ")" + // We add these SyntaxTreeNode objects to tempArgs. + int numOfOpArgs = (sel.args[idx].heirs().length - 1) / 2; + for (int i = 0; i < numOfOpArgs; i++) { + tempArgs.addElement(sel.args[idx].heirs()[2 * i + 1]); + } + } + idx++; + } + } // while (newNode == null) + + if (newSymbolNode == null) { + int eidx = (idx < sel.args.length) ? idx : (sel.args.length - 1); + errors.addError(sel.opsSTN[eidx].getLocation(), + "Unknown operator: `" + selectorItemToString(sel, eidx) + "'."); + return nullOAN; + } + ; + + if (newSymbolNode.getKind() == ModuleKind) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Module name (" + sel.opNames[idx].toString() + ") not allowed here."); + return nullOAN; + } + ; // if + + curNode = newSymbolNode; + SymbolNode curSymbolNode = newSymbolNode; + /**************************************************************** + * A version of curNode "cast" as a SymbolNode. * + ****************************************************************/ + curName = newName; + switch (curSymbolNode.getKind()) { + case ConstantDeclKind: + case VariableDeclKind: + case FormalParamKind: + case BuiltInKind: + case NewConstantKind: + case NewVariableKind: + case NewStateKind: + case NewActionKind: + case NewTemporalKind: + case NumberedProofStepKind: + /************************************************************** + * This last case added by LL on 17 Aug 2007. I think it * fits in here nicely, + * but I wouldn't swear to it. * + **************************************************************/ + if (idx != 0) { + errors.addAbort(sel.selSTN.getLocation(), "Internal error: impossible naming of declaration."); + } else if (sel.ops.length != 1) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Cannot take subexpression of `" + curName.toString() + "'."); + return nullOAN; + } // ; + + /**************************************************************** + * Warning: horrible Java programming hack. There is * deliberately no break + * here, so this case "joins" the * following case. * + ****************************************************************/ + //$FALL-THROUGH$ + case UserDefinedOpKind: + case ThmOrAssumpDefKind: + case ModuleInstanceKind: + /************************************************************** + * +cal: nodeArity := Arity(curNode) ; * + **************************************************************/ + int nodeArity = curSymbolNode.getArity(); + /************************************************************** + * +cal: if expectedArity = 0 * + **************************************************************/ + if (expectedArity == 0) { + SyntaxTreeNode opArgs = sel.args[idx]; + int numOfOpArgs = 0; + if (opArgs != null) { + // if there are arguments, add them to tempArgs. + /********************************************************** + * The heirs of an oparg node are * * "(" "arg1" "," ... "," "arg_n" ")" * + **********************************************************/ + numOfOpArgs = (opArgs.heirs().length - 1) / 2; + for (int i = 0; i < numOfOpArgs; i++) { + tempArgs.addElement(sel.args[idx].heirs()[2 * i + 1]); + } + ; + + } + ; + /************************************************************** + * +cal then if opDefArityFound + Len(tempArgs) # nodeArity * + **************************************************************/ + if (opDefArityFound + tempArgs.size() != nodeArity) { + errors.addError((opArgs == null) ? sel.selSTN.getLocation() : sel.args[idx].getLocation(), + "The operator " + curName.toString() + " requires " + (nodeArity - opDefArityFound) + + " arguments."); + return nullOAN; + } + ; // if + ExprOrOpArgNode[] opArgNodes = new ExprOrOpArgNode[tempArgs.size()]; + /********************************************************** + * The array of semantic nodes generated by the arguments. * + **********************************************************/ + for (int i = 0; i < tempArgs.size(); i++) { + /********************************************************** + * Call generateExprOrOpArg to generate the semantic * nodes for the arguments + * and add them to the vector * opDefArgs. Note that curSymbolNode is used as + * the * argument to generateExprOrOpArg that specifies the * operator to which + * the arguments are being given. (The * comments for that method assumes that + * the operator * arguments appear in an OpApplication node, but the * method + * doesn't really care; it just uses that operator * to check the arity of the + * arguments.) Note that * argument number i of sel.args[idx] represents + * argument * number i + opDefArityFound of the operator described * by + * curSymbolNode. * + **********************************************************/ + opDefArgs.addElement(generateExprOrOpArg(curSymbolNode, sel.opsSTN[idx], + i + opDefArityFound, (TreeNode) tempArgs.elementAt(i), cm)); + } + ; // end for + + } // if expectedArity = 0 + /************************************************************** + * +cal: else if expectedArity > 0) * + **************************************************************/ + else { + if (expectedArity > 0) { + /********************************************************** + * Subexpression.tla has a test to report an error if a * higher-order operator + * is specified, since such an * operator can't be used as an operator argument. + * That * test is eliminated here because this error should be * caught by the + * caller of the selectorToNode method. * + **********************************************************/ + } + } + ; // else [expectedArity != 0] + opDefArityFound = nodeArity; + + if (curNode.getKind() == ModuleInstanceKind) { + if ((idx == sel.ops.length - 1) && !(isDef || isFact)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Operator name " + curName.toString() + " is incomplete."); + return nullOAN; + } + ; + } else { + /************************************************************** + * curNode.getKind() \in * {UserDefinedOpKind, ThmOrAssumpDefKind, * + * ConstantDeclKind, VariableDeclKind, FormalParamKind, * BuiltInKind, + * BoundSymbolKind, NumberedProofStepKind} * + **************************************************************/ + /************************************************************** + * +cal: then if /\ curNode.kind = UserDefinedOpKind ... * + **************************************************************/ + if ((curNode.getKind() == UserDefinedOpKind) && (!((OpDefNode) curNode).isDefined) + && (sel.ops.length != 1)) { + errors.addError(sel.opsSTN[idx].getLocation(), "Subexpression of `" + curName.toString() + + "' used inside the operator's definition."); + return nullOAN; + } + ; + + /************************************************************** + * +cal: if /\ firstFindingOpName ... * + **************************************************************/ + if (firstFindingOpName && ((curNode.getKind() == UserDefinedOpKind) + || (curNode.getKind() == ThmOrAssumpDefKind))) { + subExprOf = (SymbolNode) curNode; + } + /************************************************************** + * +cal: idx # Len(ops) * + **************************************************************/ + if (idx != sel.ops.length - 1) { + FormalParamNode[] opParams; + if (curNode.getKind() == UserDefinedOpKind) { + opParams = ((OpDefNode) curNode).getParams(); + newNode = ((OpDefNode) curNode).getBody(); + } // if + else { // curNode.getKind() == ThmOrAssumpDefKind + opParams = ((ThmOrAssumpDefNode) curNode).getParams(); + newNode = ((ThmOrAssumpDefNode) curNode).getBody(); + } + ; + for (int i = 0; i < opParams.length; i++) { + params.addElement(opParams[i]); + } + ; // for + curName = null; + if (sel.ops[idx + 1] == NameSel) { + mode = FollowingLabels; + } else { + mode = FindingSubExpr; + } + ; + for (int i = 0; i < opDefArgs.size(); i++) { + allArgs.addElement(opDefArgs.elementAt(i)); + } + ; // for + opDefArityFound = 0; + opDefArgs = new Vector(); + + /************************************************************ + * If newNode = null, then I think there's an error. It * should be caught + * later. * + ************************************************************/ + if (newNode != null) { + while (newNode.getKind() == SubstInKind) { + substInPrefix.addElement(newNode); + newNode = ((SubstInNode) newNode).getBody(); + } + ; // while + while (newNode.getKind() == APSubstInKind) { + substInPrefix.addElement(newNode); + newNode = ((APSubstInNode) newNode).getBody(); + } + ; // while + } + ; + if (mode == FindingSubExpr) { + curNode = newNode; + } + ; + } // if (idx != sel.ops.length - 1) + } // else curNode.getKind() \in {UserDefinedOpKind, ...} + prevMode = FindingOpName; + break; + + default: + errors.addAbort(sel.opsSTN[idx].getLocation(), "Internal error: unexpected node kind."); + break; + } + ; // switch (curSymbolNode.getKind()) + + break; // case FindingOpName + + case FollowingLabels: + /****************************************************************** + * Invariant: sel.ops[idx] = NameSel * + ******************************************************************/ + if (((prevMode == FindingOpName) && (curNode.getKind() != UserDefinedOpKind) + && (curNode.getKind() != ThmOrAssumpDefKind)) + || ((prevMode != FindingOpName) && (curNode.getKind() != LabelKind))) { + errors.addAbort(sel.selSTN.getLocation(), "Unexpected node kind in FollowingLabels mode."); + } + ; + + LabelNode newLabelNode = ((OpDefOrLabelNode) curNode).getLabel(sel.opNames[idx]); + + if (newLabelNode == null) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Cannot find label `" + sel.opNames[idx].toString() + "'."); + return nullOAN; + } + ; + + curNode = newLabelNode; + + if (illegalLabelRef(newLabelNode, sel.opsSTN[idx])) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Accessing subexpression labeled `" + sel.opNames[idx].toString() + + "' of ASSUME/PROVE clause within the scope of " + + "a declaration\n from outside that declaration's scope."); + return nullOAN; + } + ; + + if (expectedArity == 0) { + + /**************************************************************** + * Check that label has right number of arguments. * + ****************************************************************/ + if (newLabelNode + .getArity() != ((sel.args[idx] == null) ? 0 : (sel.args[idx].heirs().length - 1) / 2)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Label `" + sel.opNames[idx].toString() + "' used with wrong number of arguments."); + return nullOAN; + } + ; + for (int i = 0; i < newLabelNode.getArity(); i++) { + allArgs.addElement(generateExpression(sel.args[idx].heirs()[2 * i + 1], cm)); + } + ; + } + ; // if (expectedArity == 0) + + for (int i = 0; i < newLabelNode.getArity(); i++) { + FormalParamNode pdecl = newLabelNode.params[i]; + params.addElement(pdecl); + } + ; + + if ((idx < sel.ops.length - 1) && (sel.ops[idx + 1] != NameSel)) { + mode = FindingSubExpr; + } + ; + + if ((mode == FindingSubExpr) || (idx == sel.ops.length)) { + curNode = newLabelNode.getBody(); + } + ; + + prevMode = FollowingLabels; + break; // case FollowingLabels + + case FindingSubExpr: + if (sel.ops[idx] == ColonSel) { + if ((prevMode == FindingSubExpr) || !(((idx == sel.ops.length - 1) && (prevMode == FindingOpName)) + || ((idx < sel.ops.length - 1) && (sel.ops[idx + 1] == NameSel)))) { + errors.addError(sel.opsSTN[idx].getLocation(), + "`!:' can be used only after a name and either at the " + + "end after an\noperator name or before an operator name."); + return nullOAN; + } // if ( (prevMode == FindingSubExpr) ...) + } // if (sel.ops[idx] == ColonSel) + else if (curNode == null) { + errors.addError(sel.opsSTN[idx].getLocation(), "Subexpression selection failed, probably due to " + + "an error in the selected expression."); + return nullOAN; + } else if (curNode.getKind() == LetInKind) { + if (ArgNum(sel.ops[idx], 1) == 1) { + curNode = ((LetInNode) curNode).getBody(); + } else { + errors.addError(sel.opsSTN[idx].getLocation(), "A LET/IN expression has only one operand."); + return nullOAN; + } + ; + } // else if (curNode.getKind() == LetInKind) + + else if (curNode.getKind() == OpApplKind) { + OpApplNode curOpApplNode = (OpApplNode) curNode; + ExprOrOpArgNode[] curArgs = curOpApplNode.getArgs(); + SymbolNode opNode = curOpApplNode.getOperator(); + if ((opNode.getKind() == FormalParamKind) || (opNode.getKind() == ConstantDeclKind) + || (opNode.getKind() == UserDefinedOpKind)) { + int temp = ArgNum(sel.ops[idx], opNode.getArity()); + if (temp == -1) { + reportSelectorError(sel, idx); // errors.addError(sel.opsSTN[idx].getLocation(), // "NoNexistent operand specified by `" // + sel.opNames[idx].toString() + "'."); - return nullOAN ; - } ; - curNode = curArgs[temp-1] ; - } // if (opNode.getKind() == FormalParamKind) || ... - - else if (opNode.getKind() == BuiltInKind) { - if ( (opNode.getName() == OP_rc) // $RcdConstructor - || (opNode.getName() == OP_sor)){ // $SetOfRcds - - int temp = ArgNum(sel.ops[idx], curArgs.length) ; - if (temp == -1) { + return nullOAN; + } + ; + curNode = curArgs[temp - 1]; + } // if (opNode.getKind() == FormalParamKind) || ... + + else if (opNode.getKind() == BuiltInKind) { + if ((opNode.getName() == OP_rc) // $RcdConstructor + || (opNode.getName() == OP_sor)) { // $SetOfRcds + + int temp = ArgNum(sel.ops[idx], curArgs.length); + if (temp == -1) { // errors.addError(sel.opsSTN[idx].getLocation(), // "NonExistent operand specified by `" // + sel.opNames[idx].toString() + "'."); - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - curOpApplNode = (OpApplNode) curArgs[temp-1] ; - if (curOpApplNode.getOperator().getName() != OP_pair) { - errors.addAbort( - sel.opsSTN[idx].getLocation(), - "Internal error: Expecting $Pair and didn't find it.") ; - } ; - curNode = curOpApplNode.getArgs()[1] ; - } // if opNode.name == $RcdConstructor or $SetOfRcds - - else if (opNode.getName() == OP_case) { //$Case - if (idx == sel.ops.length - 1) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Subexpression of CASE must have form !i!j."); - return nullOAN ; - } ; - int temp = ArgNum(sel.ops[idx], curArgs.length) ; - if (temp == -1) { - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - curOpApplNode = (OpApplNode) curArgs[temp-1] ; - if (curOpApplNode.getOperator().getName() != OP_pair) { - errors.addAbort( - sel.opsSTN[idx].getLocation(), - "Internal error: Expecting $Pair and didn't find it.") ; - } ; - idx = idx + 1; - temp = ArgNum(sel.ops[idx], 2) ; - if (temp == -1) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Second selector for CASE subexpression must specify " - + " one of two operands."); - return nullOAN ; - } ; - curNode = curOpApplNode.getArgs()[temp-1] ; - if (curNode == null) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selecting OTHER in a CASE statement."); - return nullOAN ; - } ; - } // if opNode.name = $Case - - else if (opNode.getName() == OP_exc) { //$Except - /************************************************************ - * In an $Except node representing * - * * - * [exp_1 ELSE !... = exp_2, ..., !... = exp_n] * - * * - * operand i names exp_i. * - ************************************************************/ - int temp = ArgNum(sel.ops[idx], curArgs.length) ; - if (temp == -1) { - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - /************************************************************ - * Selection of subexpressions of EXCEPT have been outlawed * - * because they may contain a dangling "@". This doesn't * - * seem to be worth fixing because it's unlikely that * - * anyone will actually want to refer to such a * - * subexpression. * - * Change made 25 Oct 2007. * - ************************************************************/ - if (temp > 1) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selecting subexpression of an " + - "EXCEPT not yet implemented."); - return nullOAN ; - } ; - curNode = curArgs[temp-1]; - if (isNullSelection(curNode, sel, idx)) - { return nullOAN ; } ; - if (temp > 1) { - curOpApplNode = (OpApplNode) curNode ; - if (curOpApplNode.getOperator().getName() != OP_pair) { - errors.addAbort( - sel.opsSTN[idx].getLocation(), - "Internal error: Expecting $Pair and didn't find it.") ; - } ; - curNode = curOpApplNode.getArgs()[1] ; - }; // if (temp > 1) - } // if opNode.name = $Except - - else { // Handled by standard procedure - if ( (curOpApplNode.getNumberOfBoundedBoundSymbols() == 0) - && ( (curOpApplNode.getUnbdedQuantSymbols() == null) - || (curOpApplNode.getUnbdedQuantSymbols().length - == 0) ) - /***************************************************** - * I'm not sure getUnbdedQuantSymbols always returns * - * null if there are no such symbols. * - *****************************************************/ - ) { - /********************************************************** - * Current subexpression has no bound variables. * - **********************************************************/ - int temp = ArgNum(sel.ops[idx], - curOpApplNode.getArgs().length) ; - if (temp == -1) { - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - curNode = curOpApplNode.getArgs()[temp-1] ; - } // if current subexpression has no bound variables - else { - /********************************************************** - * Current subexpression has bound variables. * - **********************************************************/ - if ( (sel.ops[idx] == NullSel) - || (sel.ops[idx] == AtSel)) { - /******************************************************** - * Set temp to the array of FormalParamNodes for the * - * parameters. * - ********************************************************/ - FormalParamNode[] temp ; - if (curOpApplNode.getNumberOfBoundedBoundSymbols() > 0) { - FormalParamNode[][] symbs = - curOpApplNode.getBdedQuantSymbolLists() ; - int numSymbs = 0 ; - for (int i = 0 ; i < symbs.length ; i++) { - numSymbs = numSymbs + symbs[i].length ; - }; // for - temp = new FormalParamNode[numSymbs] ; - int k = 0 ; - for (int i = 0 ; i < symbs.length ; i++) { - for (int j = 0 ; j < symbs[i].length ; j++) { - temp[k] = symbs[i][j] ; - k++; - }; // for j - }; // for i - } // if (curOpApplNode.getNumberOf... > 0) - else { - temp = curOpApplNode.getUnbdedQuantSymbols() ; - } ; // else not (curOpApplNode.getNumberOf... > 0) - - /******************************************************* - * Add the elements of temp to the params vector. * - *******************************************************/ - for (int i = 0 ; i < temp.length ; i++) { - params.addElement(temp[i]) ; - } ; // for i - - if (sel.ops[idx] == NullSel) { - /***************************************************** - * Add the arguments to allArgs, checking if there * - * are the right number. * - *****************************************************/ - int numOfArgs = (sel.args[idx].heirs().length-1)/2 ; - if ( temp.length != numOfArgs) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selector with " + numOfArgs + - " argument(s) used for quantifier with " + - temp.length + " bound identifier(s)."); - return nullOAN ; - } ; - for (int i = 0; i < numOfArgs; i++) { - allArgs.addElement( - generateExpression( - sel.args[idx].heirs()[2 * i + 1] , cm)) ; - } ; // for i - } ; // if (sel.ops[idx] == NullSel) - curNode = curOpApplNode.getArgs()[0] ; - } // if (sel.ops[idx] == NullSel) || ... - else { - int temp = ArgNum( - sel.ops[idx], - curOpApplNode.getBdedQuantBounds().length); - if (temp == -1) { - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - curNode = curOpApplNode.getBdedQuantBounds()[temp-1] ; - }; // else - }; // else Current subexpression has bound variables - }; // Handled by standard procedure - } // else if (opNode.getKind() == BuiltInKind) - - else { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Choosing operand `" + selectorItemToString(sel, idx) + - "' of subexpression with no operands." ); - return nullOAN ; - } ; - - } // else if ((curNode.getKind() == OpApplKind) - - else if (curNode.getKind() == AssumeProveKind) { - AssumeProveNode curAPNode = (AssumeProveNode) curNode; - - /**************************************************************** - * 16 Feb 2009: Case of curAPNode.suffices true added. * - ****************************************************************/ - if ( (curAPNode.isSuffices()) - && (! inAPsuffices) ) { - /************************************************************** - * In this case, the selector must be 1, and the curNode is * - * left equal to the AssumeProve, but with inAPsuffices set * - * to true. * - **************************************************************/ - if (ArgNum(sel.ops[idx], 1) != 1) { - errors.addError(sel.opsSTN[idx].getLocation(), - "Accessing non-existent subexpression of " + - "a SUFFICES"); - return nullOAN ; - }; - inAPsuffices = true ; - } // if (curAPNode.isSuffices()) - else { - inAPsuffices = false; - /************************************************************ - * Added 16 Feb 2009 by LL. * - ************************************************************/ - int temp = ArgNum(sel.ops[idx], - 1 + curAPNode.getAssumes().length); - if (temp == -1) { - reportSelectorError(sel, idx) ; - return nullOAN ; - } ; - - if (illegalAPPosRef(curAPNode, temp)){ - errors.addError(sel.opsSTN[idx].getLocation(), - "Accessing ASSUME/PROVE clause within the scope of " + - "a declaration\n from outside that declaration's scope."); - return nullOAN ; - } ; - if (temp <= curAPNode.getAssumes().length) { - curNode = curAPNode.getAssumes()[temp-1] ; - if (isNullSelection(curNode, sel, idx)) { return nullOAN; } ; - if ( (curNode.getKind() == NewSymbKind) - && (idx != sel.args.length-1)) { - /************************************************************ - * Extra conjunct added to if test to allow selection of a * - * NEW clause as a fact. * - ************************************************************/ - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selected a subexpression of a NEW clause of an ASSUME."); - return nullOAN ; - } - } - else { - curNode = curAPNode.getProve() ; - }; - } // else if (curAPNode.isSuffices()) - } // else if (curNode.getKind() == AssumeProveKind) - - else if (curNode.getKind() == OpArgKind) { - SymbolNode opNode = ((OpArgNode) curNode).getOp() ; - if ( (opNode.getKind() != UserDefinedOpKind) - || (opNode.getName() !=S_lambda)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Trying to select subexpression of an operator argument."); - return nullOAN ; - } ; - OpDefNode opDefOpNode = (OpDefNode) opNode ; - if ( (sel.ops[idx] != NullSel) - && (sel.ops[idx] != AtSel)) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Cannot use !" + sel.opNames[idx].toString() + - " to select subexpression of a LAMBDA."); - return nullOAN ; - } ; - if (sel.ops[idx] == NullSel) { - int numOfArgs = (sel.args[idx].heirs().length-1)/2 ; - if (opDefOpNode.getArity() != numOfArgs) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selector with " + numOfArgs + - "arguments used for LAMBDA expression taking " + - opDefOpNode.getArity() + " arguments."); - return nullOAN ; - } ; - for (int i = 0; i < numOfArgs; i++) { - allArgs.addElement(generateExpression( - sel.args[idx].heirs()[2 * i + 1] , cm)) ; - } ; - } ; // if (sel.ops[idx] == NullSel) - for (int i = 0; i < opDefOpNode.getArity(); i++) { - params.addElement(opDefOpNode.getParams()[i]) ; - } ; - curNode = opDefOpNode.getBody() ; - } // else if (curNode.getKind() == OpArgKind) - - else if ( (curNode.getKind() == UserDefinedOpKind) - || (curNode.getKind() == BuiltInKind) - || (curNode.getKind() == NumberedProofStepKind)) { - errors.addAbort( - sel.opsSTN[idx].getLocation(), - "Internal error: " + - " Should not have been able to select this node.") ; - } // else if (curNode.getKind() == UserDefinedOpKind) || ... - - else if ( (curNode.getKind() == AtNodeKind) - || (curNode.getKind() == DecimalKind) - || (curNode.getKind() == NumeralKind) - || (curNode.getKind() == StringKind) - || (curNode.getKind() == FormalParamKind) - || (curNode.getKind() == ConstantDeclKind) - || (curNode.getKind() == VariableDeclKind) - || (curNode.getKind() == BoundSymbolKind) ) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "Selecting subexpression of expression that has none.") ; - return nullOAN ; - } // else if (curNode.getKind() == AtNodeKind) || ... - - else if (curNode.getKind() == LabelKind) { - curNode = ((LabelNode) curNode).getBody() ; - idx = idx - 1; - } // else if (curNode.getKind() == LabelKind) - - else { - errors.addAbort( - sel.opsSTN[idx].getLocation(), - "Internal error: " + - " Unknown node kind.") ; - } ; // end last else of if sel.ops[idx] != ColonSel - - if (isNullSelection(curNode, sel, idx)) { return nullOAN; } ; - - if (idx != sel.ops.length - 1) { - if (sel.ops[idx+1] == NameSel) { - while (curNode.getKind() == LabelKind) { - curNode = ((LabelNode) curNode).getBody(); - if (isNullSelection(curNode, sel, idx)) { return nullOAN; } ; - }; // while - if (curNode.getKind() == LetInKind) { - letInContext = ((LetInNode) curNode).context ; - mode = FindingOpName ; - firstFindingOpName = false; - } - else { - errors.addError( - sel.opsSTN[idx].getLocation(), - "A name selector here must be from a LET clause.") ; - return nullOAN ; - } - } // if (sel.ops[idx+1] == NameSel) - else if (sel.ops[idx+1] == ColonSel) { - errors.addError( - sel.opsSTN[idx].getLocation(), - "!: should not follow an operand selector.") ; - return nullOAN ; - } - } ; // if (idx != sel.ops.length - 1) - - prevMode = FindingSubExpr ; - break ; // case FindingSubExpr - - default: - errors.addAbort(sel.selSTN.getLocation(), - "Internal error: Unexpected mode") ; - } // switch (mode) - idx++ ; - } // while idx < - /********************************************************************** - * +cal: end while ; * - **********************************************************************/ - - /*********************************************************************** - * +cal: if curNode.kind = AssumeProveKind ... end if * - * * - * Modified 17 Feb 2009 by LL to allow ASSUME/PROVE to be used as a * - * fact. This seems to have been a bug in the original. * - * * - * Not corrected in the PlusCal code because that code doesn't talk * - * about the isFact case. * - ***********************************************************************/ - if (curNode.getKind() == AssumeProveKind) { - if (isFact) { return (AssumeProveNode) curNode ; }; - errors.addError( - sel.selSTN.getLocation(), - "Selected ASSUME/PROVE instead of expression.") ; - return nullOAN ; - } ; - - /*********************************************************************** - * The following added to allow naming of NEW constructs of an * - * ASSUME/PROVE in facts. * - ***********************************************************************/ - if (curNode.getKind() == NewSymbKind) { - if (isFact) { return (LevelNode) curNode ; } ; - errors.addError( - sel.selSTN.getLocation(), - "Selected a NEW declaration as an expression or operator.") ; - return nullOAN ; - } ; - - /*********************************************************************** - * +cal: if expectedArity < 0 ... end if; * - ***********************************************************************/ - if (expectedArity < 0) { - if ( (prevMode != FindingOpName) - || !( (curNode.getKind() == UserDefinedOpKind) - || (curNode.getKind() == ThmOrAssumpDefKind) - || (curNode.getKind() == NumberedProofStepKind) - || // This clause added by LL 15 Oct 2007, not in +cal code - ( (curNode.getKind() == ModuleInstanceKind) - && isDef))) { - errors.addError( - sel.selSTN.getLocation(), - "DEF clause entry should describe a defined operator.") ; - return nullOAN ; - } ; - if ( (curNode.getKind() == NumberedProofStepKind) - && (((OpDefNode) curNode).getStepNode().getKind() != DefStepKind)) { - errors.addError( - sel.selSTN.getLocation(), - "DEF clause entry refers to a non-definition step.") ; - return nullOAN ; - } - return (LevelNode) curNode; - }; // if (expectedArity < 0) - - if (curNode.getKind() == NumberedProofStepKind) { - errors.addError( - sel.selSTN.getLocation(), - isFact ? "Step number of non-fact used as a fact" - : "Step number of non-expression step used as an expression.") ; - return nullOAN ; - } - - /*********************************************************************** - * +cal: if expectedArity > 0 ... end if * - ***********************************************************************/ - if (expectedArity > 0) { - int temp = params.size() ; - if (curNode.getKind() == OpArgKind) { - temp = temp + ((OpArgNode) curNode).getArity(); - } - else if (prevMode == FindingOpName) { - temp = temp + ((SymbolNode) curNode).getArity(); - } ; - - if (expectedArity != temp) { - errors.addError( - sel.selSTN.getLocation(), - "Expected arity " + expectedArity + - " but found operator of arity " + temp + ".") ; - return nullOAN ; - } ; - }; // if (expectedArity > 0) - - /*********************************************************************** - * If opDefArgs is non-empty, we will need to convert it to an array, * - * so we might as well do it here. * - ***********************************************************************/ - ExprOrOpArgNode[] opDefArgArray = - new ExprOrOpArgNode[opDefArgs.size()] ; - for (int i = 0 ; i < opDefArgs.size() ; i++) { - opDefArgArray[i] = (ExprOrOpArgNode) opDefArgs.elementAt(i) ; - } ; // for - - /*********************************************************************** - * +cal: if /\ prevMode = "FindingOpName" ... end if; * - ***********************************************************************/ - if ( (prevMode == FindingOpName) - && (params.size() + substInPrefix.size() > 0)) { - - /********************************************************************* - * Set nodeParams to the +cal program's curNode.params value. * - *********************************************************************/ - FormalParamNode[] nodeParams = null ; - if (curNode.getKind() == UserDefinedOpKind) { - nodeParams = ((OpDefNode) curNode).getParams(); - } - else { - if (curNode.getKind() != ThmOrAssumpDefKind) { - errors.addAbort( - sel.opsSTN[sel.opsSTN.length-1].getLocation(), - "Internal Error: " + - " Found unexpected node kind after FindingOpName") ; - } ; - nodeParams = ((ThmOrAssumpDefNode) curNode).getParams(); - } ; - - for (int i = 0 ; i < opDefArgs.size() ; i++) { - allArgs.addElement(opDefArgArray[i]) ; - } ; // for - - ExprOrOpArgNode[] temp = new ExprOrOpArgNode[nodeParams.length] ; - for (int i = 0; i < nodeParams.length; i++) { - FormalParamNode pm = nodeParams[i] ; - /******************************************************************* - * Set newpm to a "clone" of pm. * - *******************************************************************/ - FormalParamNode newpm = new FormalParamNode(pm.getName(), - pm.getArity(), - pm.stn, - null, - cm) ; - - /******************************************************************* - * Set eoag to the ExprOrOpArgNode constructed from newpm. * - *******************************************************************/ - ExprOrOpArgNode eoag = null ; - if (pm.getArity() == 0) { - /***************************************************************** - * Formal parameter eoag is an ordinary (non-operator) parameter. * - *****************************************************************/ - eoag = new OpApplNode(newpm, - new ExprNode[0], - sel.selSTN, - cm) ; - } - else { - /***************************************************************** - * Formal parameter eoag is an operator parameter. * - *****************************************************************/ - eoag = new OpArgNode(newpm, sel.selSTN, cm) ; - } ; - temp[i] = eoag ; - params.addElement(newpm) ; - } ; // for - SymbolNode curSymNode = (SymbolNode) curNode ; - curNode = new OpApplNode(curSymNode, - temp, // opDefArgArray, - sel.selSTN, // TreeNode - cm ); - - } ;// if (prevMode == FindingOpName) ... - - - /*********************************************************************** - * +cal: if curNode.kind = OpArgKind * - ***********************************************************************/ - if (curNode.getKind() == OpArgKind) { - OpArgNode curOpArgNode = (OpArgNode) curNode ; - - /********************************************************************* - * +cal: if expectedArity = 0 then ... elsif * - *********************************************************************/ - if (expectedArity == 0) { - errors.addError( - sel.selSTN.getLocation(), - "Selected operator argument when expression expected.") ; - return nullOAN ; - } ; - - /********************************************************************* - * +cal: elsif expectedArity # Len(params) + ... else * - *********************************************************************/ - int temp = params.size() + curOpArgNode.getArity() ; - if (expectedArity != temp) { - errors.addError( - sel.selSTN.getLocation(), - "Expected operator of arity " + expectedArity + - " but selected operator has arity " + temp + ".") ; - return nullOAN ; - }; - - /********************************************************************* - * +cal: else ... end if * - *********************************************************************/ - if (params.size() + substInPrefix.size() > 0) { - FormalParamNode[] temp2 = - new FormalParamNode[curOpArgNode.getArity()]; - for (int i = 0; i < temp2.length; i++) { - UniqueString temp3 = UniqueString.uniqueStringOf( - "NewParam" + i) ; - temp2[i] = new FormalParamNode( - temp3, // name - 0, // arity - new SyntaxTreeNode(temp3), // syntax tree node - null, // symbol table - cm) ; // module - params.addElement(temp2[i]) ; - } ; // for - curNode = new OpApplNode(curOpArgNode.getOp(), - opDefArgArray, - sel.selSTN, // TreeNode - cm ); - } ; // if (params.size() + ...) - - }; // if (curNode.getKind() == OpArgKind) - - /*********************************************************************** - * This code doesn't seem to be present in the +cal code. I forget * - * why not; perhaps I added it without correcting the +cal. * - * * - * Modified 19 May 2008 by LL because of addition of labeled * - * ASSUME/PROVE nodes. * - ***********************************************************************/ - if ( ! isFact - && ( ( (curNode.getKind() == ThmOrAssumpDefKind) - && ( ((ThmOrAssumpDefNode) curNode).getBody().getKind() - == AssumeProveKind)) - /*********************************************************** - * curNode is an ASSUME/PROVE theorem. * - ***********************************************************/ - || ( (curNode.getKind() == LabelKind) - && (((LabelNode) curNode).isAssumeProve))) - /*********************************************************** - * curNode is a LabelNode naming an ASSUME/PROVE. * - ***********************************************************/ - ) { - errors.addError( - sel.selSTN.getLocation(), - "ASSUME/PROVE used where an expression is required.") ; - return nullOAN ; - }; - - /*********************************************************************** - * The following code added 18 Oct 2007 to check if a * - * pseudo-expression like "HAVE P" or "PICK ..." was used as an * - * expression. * - ***********************************************************************/ - if ( (! isFact) - && (curNode.getKind() == ThmOrAssumpDefKind) - && (((ThmOrAssumpDefNode) curNode).getBody().getKind() - == OpApplKind)) { - UniqueString opName = - ((OpApplNode) ((ThmOrAssumpDefNode) - curNode).getBody()).getOperator().getName() ; - String exprType = null ; - if (opName == OP_qed) { exprType = "QED step" ;} - else if (opName == OP_pfcase) { exprType = "CASE" ;} - else if (opName == OP_have) { exprType = "HAVE" ;} - else if (opName == OP_take) { exprType = "TAKE" ;} - else if (opName == OP_pick) { exprType = "PICK" ;} - else if (opName == OP_witness) { exprType = "WITNESS" ;} - else if (opName == OP_suffices) { exprType = "SUFFICES" ;}; - /******************************************************************* - * OP_suffices added by LL 16 Feb 2009. * - *******************************************************************/ - if (exprType != null) { - errors.addError( - sel.selSTN.getLocation(), - exprType + " proof step selected instead of expression."); - return nullOAN ; - } ; - } // if - - - /*********************************************************************** - * +cal: if curNode.kind \in {UserDefinedOpKind, ConstantDeclKind... * - ***********************************************************************/ - if ( (curNode.getKind() == UserDefinedOpKind) - || (curNode.getKind() == ConstantDeclKind) - || (curNode.getKind() == VariableDeclKind) - || (curNode.getKind() == FormalParamKind) - || (curNode.getKind() == BuiltInKind) - || (curNode.getKind() == BoundSymbolKind) - || (curNode.getKind() == ThmOrAssumpDefKind) - || (curNode.getKind() == NewConstantKind) - || (curNode.getKind() == NewVariableKind) - || (curNode.getKind() == NewStateKind) - || (curNode.getKind() == NewActionKind) - || (curNode.getKind() == NewTemporalKind)) { - SymbolNode curSymbolNode = (SymbolNode) curNode ; - if (expectedArity > 0) { - return new OpArgNode(curSymbolNode, sel.selSTN, cm) ; - } - - /********************************************************************* - * +cal: elsif expectedArity = 0 then * - *********************************************************************/ - else { - /******************************************************************* - * expectedArity = 0 * - *******************************************************************/ - OpApplNode oan = new OpApplNode(curSymbolNode, - opDefArgArray, - sel.selSTN, - cm ) ; - oan.subExpressionOf = subExprOf; - return oan; - } // if (expectedArity > 0) - } ; // if (curNode.getKind() == UserDefinedOpKind) - - /*********************************************************************** - * +cal: elsif curNode.kind = OpArgKind then * - ***********************************************************************/ - if (curNode.getKind() == OpArgKind) { return (OpArgNode) curNode; } ; - - /*********************************************************************** - * +cal: else * - ***********************************************************************/ - - /*********************************************************************** - * The following test is not in Subexpression.tla and should not be, * - * having been added to allow the use of a ModuleInstanceKind as a * - * Fact or Def. The else case should not occur because if it would be * - * the case, then the error should have been caught earlier (I think). * - ***********************************************************************/ - if (curNode.getKind() == ModuleInstanceKind) { - if (isFact || isDef) { - return (OpDefNode) curNode; - } - else { - errors.addError( - sel.selSTN.getLocation(), - "Module instantiation selected instead of expression."); - return nullOAN ; - } - } ; - /*********************************************************************** - * curNode should be an expression node. * - ***********************************************************************/ - if (!(curNode instanceof ExprNode)) { - errors.addAbort(sel.selSTN.getLocation(), - "Internal error: Expected expression node.") ; - } ; - ExprNode curExprNode = (ExprNode) curNode ; - int temp = substInPrefix.size() ; - - /*********************************************************************** - * +cal: while temp > 0 do ... end while * - ***********************************************************************/ - while (temp > 0) { - // Modified on 13 Nov 2009 by LL to handle the case of a subexpression - // of a Theorem or Assumption. - Object substOb = substInPrefix.elementAt(temp-1) ; - if (substOb instanceof SubstInNode) { - SubstInNode subst = (SubstInNode) substOb; - curExprNode = new SubstInNode(subst.stn, - subst.getSubsts(), - curExprNode, - subst.getInstantiatingModule(), - subst.getInstantiatedModule() - ); - } else { - APSubstInNode subst = (APSubstInNode) substOb; - curExprNode = new SubstInNode(subst.stn, - subst.getSubsts(), - curExprNode, - subst.getInstantiatingModule(), - subst.getInstantiatedModule() - ); - - } - temp = temp - 1; - }; // while - - /*********************************************************************** - * Will need params as an array. * - ***********************************************************************/ - FormalParamNode[] paramsArray = new FormalParamNode[params.size()] ; - for (int i = 0; i < params.size(); i++) { - paramsArray[i] = (FormalParamNode) params.elementAt(i) ; - } ; - - /*********************************************************************** - * If there are params, will need a Lambda operator. * - ***********************************************************************/ - OpDefNode newLambda = null ; - if (paramsArray.length > 0) { - newLambda = - new OpDefNode(S_lambda, // The operator name is "LAMBDA" - UserDefinedOpKind, // The node kind - paramsArray, // the array of formal parameters - false , // localness, which is meaningless - curExprNode, // the body - cm, // the module - null, // the symbol table - sel.selSTN, // syntax-tree node - true, // Is defined. - null ) ; // Source - } ; - - /*********************************************************************** - * +cal: if expectedArity > 0 * - ***********************************************************************/ - if (expectedArity > 0) { - if (paramsArray.length != expectedArity) { - errors.addError( - sel.selSTN.getLocation(), - "Expected operator argument with arity " + expectedArity + - " but found one of arity " + paramsArray.length + ".") ; - return nullOAN ; - } ; - return new OpArgNode(newLambda, sel.selSTN, cm) ; - } // if (expectedArity > 0) - - /*********************************************************************** - * expectedArity = 0 * - * +cal: else if Len(params) # Len(allArgs) * - ***********************************************************************/ - if (paramsArray.length != allArgs.size()) { - errors.addError( - sel.selSTN.getLocation(), - "Expected " + paramsArray.length + " arguments but found " + - allArgs.size() + ".") ; - return nullOAN ; - } ; - /*********************************************************************** - * +cal: if Len(params) = 0 then * - ***********************************************************************/ - if (paramsArray.length == 0) { - /********************************************************************* - * In this case, we don't have to construct a new LAMBDA or OpAppl * - * node. However, we want to have a new node to which to attach the * - * SyntaxTree node. So, we create an OpApplNode with the dummy * - * builtin operator $Nop and return it. * - *********************************************************************/ - ExprOrOpArgNode[] args = new ExprOrOpArgNode[1] ; - args[0] = curExprNode ; - OpApplNode ln = new OpApplNode(OP_nop, args, sel.selSTN, cm) ; - ln.subExpressionOf = subExprOf ; - return ln;} - - /*********************************************************************** - * +cal: else * - ***********************************************************************/ - /*********************************************************************** - * Will need allArgs as an array. * - ***********************************************************************/ - ExprOrOpArgNode[] allArgsArray = new ExprOrOpArgNode[allArgs.size()] ; - for (int i = 0; i < allArgs.size(); i++) { - allArgsArray[i] = (ExprOrOpArgNode) allArgs.elementAt(i) ; - } ; - - OpApplNode oan = - new OpApplNode (newLambda, allArgsArray, sel.selSTN, cm) ; - oan.subExpressionOf = subExprOf ; - return oan ; - - } // selectorToNode - - private static String selectorItemToString(Selector sel, int idx) { - String selStr = sel.opNames[idx].toString() ; - if (selStr.equals("N_StructOp")) { - selStr = "argument selector " + - sel.opsSTN[idx].heirs()[0].heirs()[0].getImage() ; - } - else if (selStr.equals("N_OpArgs")) { - selStr = "!(...)" ; - }; - return selStr ; - } - - private void reportSelectorError(Selector sel, int idx) { - /*********************************************************************** - * Just a method to perform error reporting when an error is detected * - * when executing selectorToNode. * - ***********************************************************************/ - errors.addError(sel.opsSTN[idx].getLocation(), - "Nonexistent operand specified by `" - + selectorItemToString(sel, idx) + "'."); - } - - private boolean isNullSelection(SemanticNode node, Selector sel, int idx) { - /*********************************************************************** - * A method for use in selectorToNode to test if a a null node has * - * been selected. This should happen only if the null node was * - * created as a result of a previous error. If the node is null, then * - * an error is reported and true is returned. * - ***********************************************************************/ - boolean val = (node == null) ; - if (val) { - errors.addError(sel.opsSTN[idx].getLocation(), - "An unexpected null node specified by " - + selectorItemToString(sel, idx) + "'." - + "\nThis is probably due to a previous error."); - }; - return val ; - } - - // Constructor - public Generator(ExternalModuleTable moduleTable, Errors errs) { - nullParam = new FormalParamNode[0]; - nullODN = new OpDefNode(UniqueString.uniqueStringOf("nullODN")); - nullOAN = new OpApplNode(nullODN); - nullOpArg = new OpArgNode(UniqueString.uniqueStringOf("nullOpArg")); - nullLabelNode = new LabelNode(nullOAN) ; - this.errors = errs; - this.moduleTable = moduleTable; - this.symbolTable = new SymbolTable(moduleTable, errors); - this.excStack = new Stack(); - this.excSpecStack = new Stack(); - } - - public final SymbolTable getSymbolTable() { return symbolTable; } - - public final ModuleNode generate(TreeNode treeNode) throws AbortException { - /************************************************************************* - * This is the method called to generate the semantic graph for a module. * - *************************************************************************/ + reportSelectorError(sel, idx); + return nullOAN; + } + ; + curOpApplNode = (OpApplNode) curArgs[temp - 1]; + if (curOpApplNode.getOperator().getName() != OP_pair) { + errors.addAbort(sel.opsSTN[idx].getLocation(), + "Internal error: Expecting $Pair and didn't find it."); + } + ; + curNode = curOpApplNode.getArgs()[1]; + } // if opNode.name == $RcdConstructor or $SetOfRcds + + else if (opNode.getName() == OP_case) { // $Case + if (idx == sel.ops.length - 1) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Subexpression of CASE must have form !i!j."); + return nullOAN; + } + ; + int temp = ArgNum(sel.ops[idx], curArgs.length); + if (temp == -1) { + reportSelectorError(sel, idx); + return nullOAN; + } + ; + curOpApplNode = (OpApplNode) curArgs[temp - 1]; + if (curOpApplNode.getOperator().getName() != OP_pair) { + errors.addAbort(sel.opsSTN[idx].getLocation(), + "Internal error: Expecting $Pair and didn't find it."); + } + ; + idx = idx + 1; + temp = ArgNum(sel.ops[idx], 2); + if (temp == -1) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Second selector for CASE subexpression must specify " + + " one of two operands."); + return nullOAN; + } + ; + curNode = curOpApplNode.getArgs()[temp - 1]; + if (curNode == null) { + errors.addError(sel.opsSTN[idx].getLocation(), "Selecting OTHER in a CASE statement."); + return nullOAN; + } + ; + } // if opNode.name = $Case + + else if (opNode.getName() == OP_exc) { // $Except + /************************************************************ + * In an $Except node representing * * [exp_1 ELSE !... = exp_2, ..., !... = + * exp_n] * * operand i names exp_i. * + ************************************************************/ + int temp = ArgNum(sel.ops[idx], curArgs.length); + if (temp == -1) { + reportSelectorError(sel, idx); + return nullOAN; + } + ; + /************************************************************ + * Selection of subexpressions of EXCEPT have been outlawed * because they may + * contain a dangling "@". This doesn't * seem to be worth fixing because it's + * unlikely that * anyone will actually want to refer to such a * subexpression. + * * Change made 25 Oct 2007. * + ************************************************************/ + if (temp > 1) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Selecting subexpression of an " + "EXCEPT not yet implemented."); + return nullOAN; + } + ; + curNode = curArgs[temp - 1]; + if (isNullSelection(curNode, sel, idx)) { + return nullOAN; + } + ; + if (temp > 1) { + curOpApplNode = (OpApplNode) curNode; + if (curOpApplNode.getOperator().getName() != OP_pair) { + errors.addAbort(sel.opsSTN[idx].getLocation(), + "Internal error: Expecting $Pair and didn't find it."); + } + ; + curNode = curOpApplNode.getArgs()[1]; + } + ; // if (temp > 1) + } // if opNode.name = $Except + + else { // Handled by standard procedure + if ((curOpApplNode.getNumberOfBoundedBoundSymbols() == 0) + && ((curOpApplNode.getUnbdedQuantSymbols() == null) + || (curOpApplNode.getUnbdedQuantSymbols().length == 0)) + /***************************************************** + * I'm not sure getUnbdedQuantSymbols always returns * null if there are no such + * symbols. * + *****************************************************/ + ) { + /********************************************************** + * Current subexpression has no bound variables. * + **********************************************************/ + int temp = ArgNum(sel.ops[idx], curOpApplNode.getArgs().length); + if (temp == -1) { + reportSelectorError(sel, idx); + return nullOAN; + } + ; + curNode = curOpApplNode.getArgs()[temp - 1]; + } // if current subexpression has no bound variables + else { + /********************************************************** + * Current subexpression has bound variables. * + **********************************************************/ + if ((sel.ops[idx] == NullSel) || (sel.ops[idx] == AtSel)) { + /******************************************************** + * Set temp to the array of FormalParamNodes for the * parameters. * + ********************************************************/ + FormalParamNode[] temp; + if (curOpApplNode.getNumberOfBoundedBoundSymbols() > 0) { + FormalParamNode[][] symbs = curOpApplNode.getBdedQuantSymbolLists(); + int numSymbs = 0; + for (int i = 0; i < symbs.length; i++) { + numSymbs = numSymbs + symbs[i].length; + } + ; // for + temp = new FormalParamNode[numSymbs]; + int k = 0; + for (int i = 0; i < symbs.length; i++) { + for (int j = 0; j < symbs[i].length; j++) { + temp[k] = symbs[i][j]; + k++; + } + ; // for j + } + ; // for i + } // if (curOpApplNode.getNumberOf... > 0) + else { + temp = curOpApplNode.getUnbdedQuantSymbols(); + } + ; // else not (curOpApplNode.getNumberOf... > 0) + + /******************************************************* + * Add the elements of temp to the params vector. * + *******************************************************/ + for (int i = 0; i < temp.length; i++) { + params.addElement(temp[i]); + } + ; // for i + + if (sel.ops[idx] == NullSel) { + /***************************************************** + * Add the arguments to allArgs, checking if there * are the right number. * + *****************************************************/ + int numOfArgs = (sel.args[idx].heirs().length - 1) / 2; + if (temp.length != numOfArgs) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Selector with " + numOfArgs + + " argument(s) used for quantifier with " + temp.length + + " bound identifier(s)."); + return nullOAN; + } + ; + for (int i = 0; i < numOfArgs; i++) { + allArgs.addElement( + generateExpression(sel.args[idx].heirs()[2 * i + 1], cm)); + } + ; // for i + } + ; // if (sel.ops[idx] == NullSel) + curNode = curOpApplNode.getArgs()[0]; + } // if (sel.ops[idx] == NullSel) || ... + else { + int temp = ArgNum(sel.ops[idx], curOpApplNode.getBdedQuantBounds().length); + if (temp == -1) { + reportSelectorError(sel, idx); + return nullOAN; + } + ; + curNode = curOpApplNode.getBdedQuantBounds()[temp - 1]; + } + ; // else + } + ; // else Current subexpression has bound variables + } + ; // Handled by standard procedure + } // else if (opNode.getKind() == BuiltInKind) + + else { + errors.addError(sel.opsSTN[idx].getLocation(), "Choosing operand `" + + selectorItemToString(sel, idx) + "' of subexpression with no operands."); + return nullOAN; + } + ; + + } // else if ((curNode.getKind() == OpApplKind) + + else if (curNode.getKind() == AssumeProveKind) { + AssumeProveNode curAPNode = (AssumeProveNode) curNode; + + /**************************************************************** + * 16 Feb 2009: Case of curAPNode.suffices true added. * + ****************************************************************/ + if ((curAPNode.isSuffices()) && (!inAPsuffices)) { + /************************************************************** + * In this case, the selector must be 1, and the curNode is * left equal to the + * AssumeProve, but with inAPsuffices set * to true. * + **************************************************************/ + if (ArgNum(sel.ops[idx], 1) != 1) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Accessing non-existent subexpression of " + "a SUFFICES"); + return nullOAN; + } + ; + inAPsuffices = true; + } // if (curAPNode.isSuffices()) + else { + inAPsuffices = false; + /************************************************************ + * Added 16 Feb 2009 by LL. * + ************************************************************/ + int temp = ArgNum(sel.ops[idx], 1 + curAPNode.getAssumes().length); + if (temp == -1) { + reportSelectorError(sel, idx); + return nullOAN; + } + ; + + if (illegalAPPosRef(curAPNode, temp)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Accessing ASSUME/PROVE clause within the scope of " + + "a declaration\n from outside that declaration's scope."); + return nullOAN; + } + ; + if (temp <= curAPNode.getAssumes().length) { + curNode = curAPNode.getAssumes()[temp - 1]; + if (isNullSelection(curNode, sel, idx)) { + return nullOAN; + } + ; + if ((curNode.getKind() == NewSymbKind) && (idx != sel.args.length - 1)) { + /************************************************************ + * Extra conjunct added to if test to allow selection of a * NEW clause as a + * fact. * + ************************************************************/ + errors.addError(sel.opsSTN[idx].getLocation(), + "Selected a subexpression of a NEW clause of an ASSUME."); + return nullOAN; + } + } else { + curNode = curAPNode.getProve(); + } + ; + } // else if (curAPNode.isSuffices()) + } // else if (curNode.getKind() == AssumeProveKind) + + else if (curNode.getKind() == OpArgKind) { + SymbolNode opNode = ((OpArgNode) curNode).getOp(); + if ((opNode.getKind() != UserDefinedOpKind) || (opNode.getName() != S_lambda)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Trying to select subexpression of an operator argument."); + return nullOAN; + } + ; + OpDefNode opDefOpNode = (OpDefNode) opNode; + if ((sel.ops[idx] != NullSel) && (sel.ops[idx] != AtSel)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Cannot use !" + sel.opNames[idx].toString() + " to select subexpression of a LAMBDA."); + return nullOAN; + } + ; + if (sel.ops[idx] == NullSel) { + int numOfArgs = (sel.args[idx].heirs().length - 1) / 2; + if (opDefOpNode.getArity() != numOfArgs) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Selector with " + numOfArgs + "arguments used for LAMBDA expression taking " + + opDefOpNode.getArity() + " arguments."); + return nullOAN; + } + ; + for (int i = 0; i < numOfArgs; i++) { + allArgs.addElement(generateExpression(sel.args[idx].heirs()[2 * i + 1], cm)); + } + ; + } + ; // if (sel.ops[idx] == NullSel) + for (int i = 0; i < opDefOpNode.getArity(); i++) { + params.addElement(opDefOpNode.getParams()[i]); + } + ; + curNode = opDefOpNode.getBody(); + } // else if (curNode.getKind() == OpArgKind) + + else if ((curNode.getKind() == UserDefinedOpKind) || (curNode.getKind() == BuiltInKind) + || (curNode.getKind() == NumberedProofStepKind)) { + errors.addAbort(sel.opsSTN[idx].getLocation(), + "Internal error: " + " Should not have been able to select this node."); + } // else if (curNode.getKind() == UserDefinedOpKind) || ... + + else if ((curNode.getKind() == AtNodeKind) || (curNode.getKind() == DecimalKind) + || (curNode.getKind() == NumeralKind) || (curNode.getKind() == StringKind) + || (curNode.getKind() == FormalParamKind) || (curNode.getKind() == ConstantDeclKind) + || (curNode.getKind() == VariableDeclKind) || (curNode.getKind() == BoundSymbolKind)) { + errors.addError(sel.opsSTN[idx].getLocation(), + "Selecting subexpression of expression that has none."); + return nullOAN; + } // else if (curNode.getKind() == AtNodeKind) || ... + + else if (curNode.getKind() == LabelKind) { + curNode = ((LabelNode) curNode).getBody(); + idx = idx - 1; + } // else if (curNode.getKind() == LabelKind) + + else { + errors.addAbort(sel.opsSTN[idx].getLocation(), "Internal error: " + " Unknown node kind."); + } + ; // end last else of if sel.ops[idx] != ColonSel + + if (isNullSelection(curNode, sel, idx)) { + return nullOAN; + } + ; + + if (idx != sel.ops.length - 1) { + if (sel.ops[idx + 1] == NameSel) { + while (curNode.getKind() == LabelKind) { + curNode = ((LabelNode) curNode).getBody(); + if (isNullSelection(curNode, sel, idx)) { + return nullOAN; + } + ; + } + ; // while + if (curNode.getKind() == LetInKind) { + letInContext = ((LetInNode) curNode).context; + mode = FindingOpName; + firstFindingOpName = false; + } else { + errors.addError(sel.opsSTN[idx].getLocation(), + "A name selector here must be from a LET clause."); + return nullOAN; + } + } // if (sel.ops[idx+1] == NameSel) + else if (sel.ops[idx + 1] == ColonSel) { + errors.addError(sel.opsSTN[idx].getLocation(), "!: should not follow an operand selector."); + return nullOAN; + } + } + ; // if (idx != sel.ops.length - 1) + + prevMode = FindingSubExpr; + break; // case FindingSubExpr + + default: + errors.addAbort(sel.selSTN.getLocation(), "Internal error: Unexpected mode"); + } // switch (mode) + idx++; + } // while idx < + /********************************************************************** + * +cal: end while ; * + **********************************************************************/ + + /*********************************************************************** + * +cal: if curNode.kind = AssumeProveKind ... end if * * Modified 17 Feb 2009 + * by LL to allow ASSUME/PROVE to be used as a * fact. This seems to have been a + * bug in the original. * * Not corrected in the PlusCal code because that code + * doesn't talk * about the isFact case. * + ***********************************************************************/ + if (curNode.getKind() == AssumeProveKind) { + if (isFact) { + return (AssumeProveNode) curNode; + } + ; + errors.addError(sel.selSTN.getLocation(), "Selected ASSUME/PROVE instead of expression."); + return nullOAN; + } + ; + + /*********************************************************************** + * The following added to allow naming of NEW constructs of an * ASSUME/PROVE in + * facts. * + ***********************************************************************/ + if (curNode.getKind() == NewSymbKind) { + if (isFact) { + return (LevelNode) curNode; + } + ; + errors.addError(sel.selSTN.getLocation(), "Selected a NEW declaration as an expression or operator."); + return nullOAN; + } + ; + + /*********************************************************************** + * +cal: if expectedArity < 0 ... end if; * + ***********************************************************************/ + if (expectedArity < 0) { + if ((prevMode != FindingOpName) || !((curNode.getKind() == UserDefinedOpKind) + || (curNode.getKind() == ThmOrAssumpDefKind) || (curNode.getKind() == NumberedProofStepKind) || // This + // clause + // added + // by + // LL + // 15 + // Oct + // 2007, + // not + // in + // +cal + // code + ((curNode.getKind() == ModuleInstanceKind) && isDef))) { + errors.addError(sel.selSTN.getLocation(), "DEF clause entry should describe a defined operator."); + return nullOAN; + } + ; + if ((curNode.getKind() == NumberedProofStepKind) + && (((OpDefNode) curNode).getStepNode().getKind() != DefStepKind)) { + errors.addError(sel.selSTN.getLocation(), "DEF clause entry refers to a non-definition step."); + return nullOAN; + } + return (LevelNode) curNode; + } + ; // if (expectedArity < 0) + + if (curNode.getKind() == NumberedProofStepKind) { + errors.addError(sel.selSTN.getLocation(), isFact ? "Step number of non-fact used as a fact" + : "Step number of non-expression step used as an expression."); + return nullOAN; + } + + /*********************************************************************** + * +cal: if expectedArity > 0 ... end if * + ***********************************************************************/ + if (expectedArity > 0) { + int temp = params.size(); + if (curNode.getKind() == OpArgKind) { + temp = temp + ((OpArgNode) curNode).getArity(); + } else if (prevMode == FindingOpName) { + temp = temp + ((SymbolNode) curNode).getArity(); + } + ; + + if (expectedArity != temp) { + errors.addError(sel.selSTN.getLocation(), + "Expected arity " + expectedArity + " but found operator of arity " + temp + "."); + return nullOAN; + } + ; + } + ; // if (expectedArity > 0) + + /*********************************************************************** + * If opDefArgs is non-empty, we will need to convert it to an array, * so we + * might as well do it here. * + ***********************************************************************/ + ExprOrOpArgNode[] opDefArgArray = new ExprOrOpArgNode[opDefArgs.size()]; + for (int i = 0; i < opDefArgs.size(); i++) { + opDefArgArray[i] = (ExprOrOpArgNode) opDefArgs.elementAt(i); + } + ; // for + + /*********************************************************************** + * +cal: if /\ prevMode = "FindingOpName" ... end if; * + ***********************************************************************/ + if ((prevMode == FindingOpName) && (params.size() + substInPrefix.size() > 0)) { + + /********************************************************************* + * Set nodeParams to the +cal program's curNode.params value. * + *********************************************************************/ + FormalParamNode[] nodeParams = null; + if (curNode.getKind() == UserDefinedOpKind) { + nodeParams = ((OpDefNode) curNode).getParams(); + } else { + if (curNode.getKind() != ThmOrAssumpDefKind) { + errors.addAbort(sel.opsSTN[sel.opsSTN.length - 1].getLocation(), + "Internal Error: " + " Found unexpected node kind after FindingOpName"); + } + ; + nodeParams = ((ThmOrAssumpDefNode) curNode).getParams(); + } + ; + + for (int i = 0; i < opDefArgs.size(); i++) { + allArgs.addElement(opDefArgArray[i]); + } + ; // for + + ExprOrOpArgNode[] temp = new ExprOrOpArgNode[nodeParams.length]; + for (int i = 0; i < nodeParams.length; i++) { + FormalParamNode pm = nodeParams[i]; + /******************************************************************* + * Set newpm to a "clone" of pm. * + *******************************************************************/ + FormalParamNode newpm = new FormalParamNode(pm.getName(), pm.getArity(), pm.stn, null, cm); + + /******************************************************************* + * Set eoag to the ExprOrOpArgNode constructed from newpm. * + *******************************************************************/ + ExprOrOpArgNode eoag = null; + if (pm.getArity() == 0) { + /***************************************************************** + * Formal parameter eoag is an ordinary (non-operator) parameter. * + *****************************************************************/ + eoag = new OpApplNode(newpm, new ExprNode[0], sel.selSTN, cm); + } else { + /***************************************************************** + * Formal parameter eoag is an operator parameter. * + *****************************************************************/ + eoag = new OpArgNode(newpm, sel.selSTN, cm); + } + ; + temp[i] = eoag; + params.addElement(newpm); + } + ; // for + SymbolNode curSymNode = (SymbolNode) curNode; + curNode = new OpApplNode(curSymNode, temp, // opDefArgArray, + sel.selSTN, // TreeNode + cm); + + } + ;// if (prevMode == FindingOpName) ... + + /*********************************************************************** + * +cal: if curNode.kind = OpArgKind * + ***********************************************************************/ + if (curNode.getKind() == OpArgKind) { + OpArgNode curOpArgNode = (OpArgNode) curNode; + + /********************************************************************* + * +cal: if expectedArity = 0 then ... elsif * + *********************************************************************/ + if (expectedArity == 0) { + errors.addError(sel.selSTN.getLocation(), "Selected operator argument when expression expected."); + return nullOAN; + } + ; + + /********************************************************************* + * +cal: elsif expectedArity # Len(params) + ... else * + *********************************************************************/ + int temp = params.size() + curOpArgNode.getArity(); + if (expectedArity != temp) { + errors.addError(sel.selSTN.getLocation(), "Expected operator of arity " + expectedArity + + " but selected operator has arity " + temp + "."); + return nullOAN; + } + ; + + /********************************************************************* + * +cal: else ... end if * + *********************************************************************/ + if (params.size() + substInPrefix.size() > 0) { + FormalParamNode[] temp2 = new FormalParamNode[curOpArgNode.getArity()]; + for (int i = 0; i < temp2.length; i++) { + UniqueString temp3 = UniqueString.uniqueStringOf("NewParam" + i); + temp2[i] = new FormalParamNode(temp3, // name + 0, // arity + new SyntaxTreeNode(temp3), // syntax tree node + null, // symbol table + cm); // module + params.addElement(temp2[i]); + } + ; // for + curNode = new OpApplNode(curOpArgNode.getOp(), opDefArgArray, sel.selSTN, // TreeNode + cm); + } + ; // if (params.size() + ...) + + } + ; // if (curNode.getKind() == OpArgKind) + + /*********************************************************************** + * This code doesn't seem to be present in the +cal code. I forget * why not; + * perhaps I added it without correcting the +cal. * * Modified 19 May 2008 by + * LL because of addition of labeled * ASSUME/PROVE nodes. * + ***********************************************************************/ + if (!isFact && (((curNode.getKind() == ThmOrAssumpDefKind) + && (((ThmOrAssumpDefNode) curNode).getBody().getKind() == AssumeProveKind)) + /*********************************************************** + * curNode is an ASSUME/PROVE theorem. * + ***********************************************************/ + || ((curNode.getKind() == LabelKind) && (((LabelNode) curNode).isAssumeProve))) + /*********************************************************** + * curNode is a LabelNode naming an ASSUME/PROVE. * + ***********************************************************/ + ) { + errors.addError(sel.selSTN.getLocation(), "ASSUME/PROVE used where an expression is required."); + return nullOAN; + } + ; + + /*********************************************************************** + * The following code added 18 Oct 2007 to check if a * pseudo-expression like + * "HAVE P" or "PICK ..." was used as an * expression. * + ***********************************************************************/ + if ((!isFact) && (curNode.getKind() == ThmOrAssumpDefKind) + && (((ThmOrAssumpDefNode) curNode).getBody().getKind() == OpApplKind)) { + UniqueString opName = ((OpApplNode) ((ThmOrAssumpDefNode) curNode).getBody()).getOperator().getName(); + String exprType = null; + if (opName == OP_qed) { + exprType = "QED step"; + } else if (opName == OP_pfcase) { + exprType = "CASE"; + } else if (opName == OP_have) { + exprType = "HAVE"; + } else if (opName == OP_take) { + exprType = "TAKE"; + } else if (opName == OP_pick) { + exprType = "PICK"; + } else if (opName == OP_witness) { + exprType = "WITNESS"; + } else if (opName == OP_suffices) { + exprType = "SUFFICES"; + } + ; + /******************************************************************* + * OP_suffices added by LL 16 Feb 2009. * + *******************************************************************/ + if (exprType != null) { + errors.addError(sel.selSTN.getLocation(), exprType + " proof step selected instead of expression."); + return nullOAN; + } + ; + } // if + + /*********************************************************************** + * +cal: if curNode.kind \in {UserDefinedOpKind, ConstantDeclKind... * + ***********************************************************************/ + if ((curNode.getKind() == UserDefinedOpKind) || (curNode.getKind() == ConstantDeclKind) + || (curNode.getKind() == VariableDeclKind) || (curNode.getKind() == FormalParamKind) + || (curNode.getKind() == BuiltInKind) || (curNode.getKind() == BoundSymbolKind) + || (curNode.getKind() == ThmOrAssumpDefKind) || (curNode.getKind() == NewConstantKind) + || (curNode.getKind() == NewVariableKind) || (curNode.getKind() == NewStateKind) + || (curNode.getKind() == NewActionKind) || (curNode.getKind() == NewTemporalKind)) { + SymbolNode curSymbolNode = (SymbolNode) curNode; + if (expectedArity > 0) { + return new OpArgNode(curSymbolNode, sel.selSTN, cm); + } + + /********************************************************************* + * +cal: elsif expectedArity = 0 then * + *********************************************************************/ + else { + /******************************************************************* + * expectedArity = 0 * + *******************************************************************/ + OpApplNode oan = new OpApplNode(curSymbolNode, opDefArgArray, sel.selSTN, cm); + oan.subExpressionOf = subExprOf; + return oan; + } // if (expectedArity > 0) + } + ; // if (curNode.getKind() == UserDefinedOpKind) + + /*********************************************************************** + * +cal: elsif curNode.kind = OpArgKind then * + ***********************************************************************/ + if (curNode.getKind() == OpArgKind) { + return (OpArgNode) curNode; + } + ; + + /*********************************************************************** + * +cal: else * + ***********************************************************************/ + + /*********************************************************************** + * The following test is not in Subexpression.tla and should not be, * having + * been added to allow the use of a ModuleInstanceKind as a * Fact or Def. The + * else case should not occur because if it would be * the case, then the error + * should have been caught earlier (I think). * + ***********************************************************************/ + if (curNode.getKind() == ModuleInstanceKind) { + if (isFact || isDef) { + return (OpDefNode) curNode; + } else { + errors.addError(sel.selSTN.getLocation(), "Module instantiation selected instead of expression."); + return nullOAN; + } + } + ; + /*********************************************************************** + * curNode should be an expression node. * + ***********************************************************************/ + if (!(curNode instanceof ExprNode)) { + errors.addAbort(sel.selSTN.getLocation(), "Internal error: Expected expression node."); + } + ; + ExprNode curExprNode = (ExprNode) curNode; + int temp = substInPrefix.size(); + + /*********************************************************************** + * +cal: while temp > 0 do ... end while * + ***********************************************************************/ + while (temp > 0) { + // Modified on 13 Nov 2009 by LL to handle the case of a subexpression + // of a Theorem or Assumption. + Object substOb = substInPrefix.elementAt(temp - 1); + if (substOb instanceof SubstInNode) { + SubstInNode subst = (SubstInNode) substOb; + curExprNode = new SubstInNode(subst.stn, subst.getSubsts(), curExprNode, subst.getInstantiatingModule(), + subst.getInstantiatedModule()); + } else { + APSubstInNode subst = (APSubstInNode) substOb; + curExprNode = new SubstInNode(subst.stn, subst.getSubsts(), curExprNode, subst.getInstantiatingModule(), + subst.getInstantiatedModule()); + + } + temp = temp - 1; + } + ; // while + + /*********************************************************************** + * Will need params as an array. * + ***********************************************************************/ + FormalParamNode[] paramsArray = new FormalParamNode[params.size()]; + for (int i = 0; i < params.size(); i++) { + paramsArray[i] = (FormalParamNode) params.elementAt(i); + } + ; + + /*********************************************************************** + * If there are params, will need a Lambda operator. * + ***********************************************************************/ + OpDefNode newLambda = null; + if (paramsArray.length > 0) { + newLambda = new OpDefNode(S_lambda, // The operator name is "LAMBDA" + UserDefinedOpKind, // The node kind + paramsArray, // the array of formal parameters + false, // localness, which is meaningless + curExprNode, // the body + cm, // the module + null, // the symbol table + sel.selSTN, // syntax-tree node + true, // Is defined. + null); // Source + } + ; + + /*********************************************************************** + * +cal: if expectedArity > 0 * + ***********************************************************************/ + if (expectedArity > 0) { + if (paramsArray.length != expectedArity) { + errors.addError(sel.selSTN.getLocation(), "Expected operator argument with arity " + expectedArity + + " but found one of arity " + paramsArray.length + "."); + return nullOAN; + } + ; + return new OpArgNode(newLambda, sel.selSTN, cm); + } // if (expectedArity > 0) + + /*********************************************************************** + * expectedArity = 0 * +cal: else if Len(params) # Len(allArgs) * + ***********************************************************************/ + if (paramsArray.length != allArgs.size()) { + errors.addError(sel.selSTN.getLocation(), + "Expected " + paramsArray.length + " arguments but found " + allArgs.size() + "."); + return nullOAN; + } + ; + /*********************************************************************** + * +cal: if Len(params) = 0 then * + ***********************************************************************/ + if (paramsArray.length == 0) { + /********************************************************************* + * In this case, we don't have to construct a new LAMBDA or OpAppl * node. + * However, we want to have a new node to which to attach the * SyntaxTree node. + * So, we create an OpApplNode with the dummy * builtin operator $Nop and return + * it. * + *********************************************************************/ + ExprOrOpArgNode[] args = new ExprOrOpArgNode[1]; + args[0] = curExprNode; + OpApplNode ln = new OpApplNode(OP_nop, args, sel.selSTN, cm); + ln.subExpressionOf = subExprOf; + return ln; + } + + /*********************************************************************** + * +cal: else * + ***********************************************************************/ + /*********************************************************************** + * Will need allArgs as an array. * + ***********************************************************************/ + ExprOrOpArgNode[] allArgsArray = new ExprOrOpArgNode[allArgs.size()]; + for (int i = 0; i < allArgs.size(); i++) { + allArgsArray[i] = (ExprOrOpArgNode) allArgs.elementAt(i); + } + ; + + OpApplNode oan = new OpApplNode(newLambda, allArgsArray, sel.selSTN, cm); + oan.subExpressionOf = subExprOf; + return oan; + + } // selectorToNode + + private static String selectorItemToString(Selector sel, int idx) { + String selStr = sel.opNames[idx].toString(); + if (selStr.equals("N_StructOp")) { + selStr = "argument selector " + sel.opsSTN[idx].heirs()[0].heirs()[0].getImage(); + } else if (selStr.equals("N_OpArgs")) { + selStr = "!(...)"; + } + ; + return selStr; + } + + private void reportSelectorError(Selector sel, int idx) { + /*********************************************************************** + * Just a method to perform error reporting when an error is detected * when + * executing selectorToNode. * + ***********************************************************************/ + errors.addError(sel.opsSTN[idx].getLocation(), + "Nonexistent operand specified by `" + selectorItemToString(sel, idx) + "'."); + } + + private boolean isNullSelection(SemanticNode node, Selector sel, int idx) { + /*********************************************************************** + * A method for use in selectorToNode to test if a a null node has * been + * selected. This should happen only if the null node was * created as a result + * of a previous error. If the node is null, then * an error is reported and + * true is returned. * + ***********************************************************************/ + boolean val = (node == null); + if (val) { + errors.addError(sel.opsSTN[idx].getLocation(), "An unexpected null node specified by " + + selectorItemToString(sel, idx) + "'." + "\nThis is probably due to a previous error."); + } + ; + return val; + } + + // Constructor + public Generator(ExternalModuleTable moduleTable, Errors errs) { + nullParam = new FormalParamNode[0]; + nullODN = new OpDefNode(UniqueString.uniqueStringOf("nullODN")); + nullOAN = new OpApplNode(nullODN); + nullOpArg = new OpArgNode(UniqueString.uniqueStringOf("nullOpArg")); + nullLabelNode = new LabelNode(nullOAN); + this.errors = errs; + this.moduleTable = moduleTable; + this.symbolTable = new SymbolTable(moduleTable, errors); + this.excStack = new Stack(); + this.excSpecStack = new Stack(); + } + + public final SymbolTable getSymbolTable() { + return symbolTable; + } + + public final ModuleNode generate(TreeNode treeNode) throws AbortException { + /************************************************************************* + * This is the method called to generate the semantic graph for a module. * + *************************************************************************/ //System.out.println("TRUE = " + symbolTable.resolveSymbol( // UniqueString.uniqueStringOf("TRUE"))) ; //System.out.println("$SetEnumerate = " + symbolTable.resolveSymbol( // UniqueString.uniqueStringOf("$SetEnumerate"))) ; - - if (treeNode.isKind( N_Module )) { - this.context = symbolTable.getContext(); - return this.generateModule(treeNode, null); - } - return null; - } - - private final Context getContext(UniqueString us) { - ModuleNode symbolNode = symbolTable.resolveModule(us); - - if (symbolNode == null) { - return moduleTable.getContext(us); - } - return symbolNode.getContext(); - } - - private final ModuleNode generateModule(TreeNode treeNode, ModuleNode parent) - throws AbortException { - moduleNestingLevel++ ; - TreeNode[] children = treeNode.heirs(); // Array of heirs of the module root - TreeNode[] definitions = null; - // Array of definitions in the module - /********************************************************************* - * Actually, the array of all syntactic nodes that are heirs of the * - * module's body node--that is, definitions, theorems, parameter * - * declarations, etc. * - *********************************************************************/ - TreeNode[] ss = children[0].heirs(); // Array of heirs of the module header - // ss[1] is always the module name - String moduleName = ss[1].getImage(); // the module name - ModuleNode currentModule = new ModuleNode(ss[1].getUS(), context, treeNode); - currentModule.nestingLevel = moduleNestingLevel ; - // if this is an internal module, add its ModuleNode to the end of - // the list of definitions for the parent - if (parent != null) { - parent.appendDef(currentModule); - } - - symbolTable.setModuleNode( currentModule ); - // children[1] == extends - // children[1] is always the Extend's list (even if none) - processExtendsList(children[1].heirs(), currentModule); - - // children[2] == body - // children[2] is always the module body note that this line - // redefines "children" to be the array of definitions in the - // module - definitions = children[2].heirs(); - - // for each declaration, op definition, etc. in the body... - for (int lvi = 0; lvi < definitions.length; lvi++) { - switch (definitions[lvi].getKind()) { - case N_VariableDeclaration : - checkIfInRecursiveSection(definitions[lvi], "A VARIABLE declaration") ; - processVariables(definitions[lvi].heirs(), currentModule); - break; - - case N_ParamDeclaration : - checkIfInRecursiveSection(definitions[lvi], "A declaration") ; - processParameters(definitions[lvi].heirs(), currentModule); - break; - - case N_OperatorDefinition : - processOperator(definitions[lvi], null, currentModule); - break; - - case N_FunctionDefinition : - processFunction(definitions[lvi], null, currentModule); - break; - - case N_ModuleDefinition : + if (treeNode.isKind(N_Module)) { + this.context = symbolTable.getContext(); + return this.generateModule(treeNode, null); + } + return null; + } + + private final Context getContext(UniqueString us) { + ModuleNode symbolNode = symbolTable.resolveModule(us); + + if (symbolNode == null) { + return moduleTable.getContext(us); + } + return symbolNode.getContext(); + } + + private final ModuleNode generateModule(TreeNode treeNode, ModuleNode parent) throws AbortException { + moduleNestingLevel++; + TreeNode[] children = treeNode.heirs(); // Array of heirs of the module root + TreeNode[] definitions = null; + // Array of definitions in the module + /********************************************************************* + * Actually, the array of all syntactic nodes that are heirs of the * module's + * body node--that is, definitions, theorems, parameter * declarations, etc. * + *********************************************************************/ + TreeNode[] ss = children[0].heirs(); // Array of heirs of the module header + // ss[1] is always the module name + String moduleName = ss[1].getImage(); // the module name + ModuleNode currentModule = new ModuleNode(ss[1].getUS(), context, treeNode); + currentModule.nestingLevel = moduleNestingLevel; + // if this is an internal module, add its ModuleNode to the end of + // the list of definitions for the parent + if (parent != null) { + parent.appendDef(currentModule); + } + + symbolTable.setModuleNode(currentModule); + // children[1] == extends + // children[1] is always the Extend's list (even if none) + processExtendsList(children[1].heirs(), currentModule); + + // children[2] == body + // children[2] is always the module body note that this line + // redefines "children" to be the array of definitions in the + // module + definitions = children[2].heirs(); + + // for each declaration, op definition, etc. in the body... + for (int lvi = 0; lvi < definitions.length; lvi++) { + switch (definitions[lvi].getKind()) { + case N_VariableDeclaration: + checkIfInRecursiveSection(definitions[lvi], "A VARIABLE declaration"); + processVariables(definitions[lvi].heirs(), currentModule); + break; + + case N_ParamDeclaration: + checkIfInRecursiveSection(definitions[lvi], "A declaration"); + processParameters(definitions[lvi].heirs(), currentModule); + break; + + case N_OperatorDefinition: + processOperator(definitions[lvi], null, currentModule); + break; + + case N_FunctionDefinition: + processFunction(definitions[lvi], null, currentModule); + break; + + case N_ModuleDefinition: // We now allow INSTANCEs in recursive sections. // checkIfInRecursiveSection(definitions[lvi], "An INSTANCE") ; - processModuleDefinition(definitions[lvi], null, null, currentModule); - break; - - case N_Module : - // Modules can be nested, but inner ones need to keep a - // separate SymbolTable of their own. - checkIfInRecursiveSection(definitions[lvi], "A MODULE ") ; - SymbolTable oldSt = symbolTable; - symbolTable = new SymbolTable(moduleTable, errors, oldSt); - context = new Context(moduleTable, errors); - symbolTable.pushContext(context); - ModuleNode mn = generateModule(definitions[lvi], currentModule); - symbolTable.popContext(); - symbolTable = oldSt; - - // Add the inner module's name to the context of the outer module - symbolTable.addModule(mn.getName(), mn); - - /******************************************************************* - * Append the opDefsInRecursiveSection field of the inner module * - * to that of the current module. * - *******************************************************************/ - for (int i = 0; i < mn.opDefsInRecursiveSection.size(); i++) { - currentModule.opDefsInRecursiveSection.addElement( - mn.opDefsInRecursiveSection.elementAt(i)); - } ; - // System.err.println(mn.getName() + " added to SymbolTable for " + currentModule.getName()); - break; - - case N_Instance : + processModuleDefinition(definitions[lvi], null, null, currentModule); + break; + + case N_Module: + // Modules can be nested, but inner ones need to keep a + // separate SymbolTable of their own. + checkIfInRecursiveSection(definitions[lvi], "A MODULE "); + SymbolTable oldSt = symbolTable; + symbolTable = new SymbolTable(moduleTable, errors, oldSt); + context = new Context(moduleTable, errors); + symbolTable.pushContext(context); + ModuleNode mn = generateModule(definitions[lvi], currentModule); + symbolTable.popContext(); + symbolTable = oldSt; + + // Add the inner module's name to the context of the outer module + symbolTable.addModule(mn.getName(), mn); + + /******************************************************************* + * Append the opDefsInRecursiveSection field of the inner module * to that of + * the current module. * + *******************************************************************/ + for (int i = 0; i < mn.opDefsInRecursiveSection.size(); i++) { + currentModule.opDefsInRecursiveSection.addElement(mn.opDefsInRecursiveSection.elementAt(i)); + } + ; + // System.err.println(mn.getName() + " added to SymbolTable for " + + // currentModule.getName()); + break; + + case N_Instance: // We now allow INSTANCEs in recursive sections. // checkIfInRecursiveSection(definitions[lvi], "An INSTANCE") ; - generateInstance(definitions[lvi], currentModule, true); - break; - - case N_Proof : - checkIfInRecursiveSection(definitions[lvi], "A proof") ; - break; - - case N_Theorem : - checkIfInRecursiveSection(definitions[lvi], "A THEOREM") ; - processTheorem(definitions[lvi], currentModule); - break; - - case N_Assumption : - checkIfInRecursiveSection(definitions[lvi], "An ASSUME"); - processAssumption(definitions[lvi], currentModule); - break; - - case N_UseOrHide : - checkIfInRecursiveSection(definitions[lvi], "A USE or HIDE"); - UseOrHideNode uohn = generateUseOrHide(definitions[lvi], - currentModule) ; - uohn.factCheck(); - // Added 4 Mar 2009. - if (uohn.facts.length + uohn.defs.length == 0) { - errors.addError(definitions[lvi].getLocation(), - "Empty USE or HIDE statement."); - }; - currentModule.addTopLevel(uohn) ; - break; - - case SEPARATOR : - /******************************************************************* - * This code was originally * - * * - * case 35 * - * // Intended to handle "---------". Kludge for a parser bug. * - * * - * I have no idea why 35 was used instead of SEPARATOR, and what * - * kind of parser bug mentioned was encountered. The original * - * code did not import parser.TLAplusParserConstants where * - * SEPARATOR was used, so perhaps there was some reason why this * - * class could not be imported. * - *******************************************************************/ - break; - - case N_Recursive : - processRecursive(definitions[lvi], currentModule); - break; - default : - errors.addAbort( - definitions[ lvi ].getLocation(), - "Internal error: Syntax node of kind " + - definitions[ lvi ].getKind() + " unsupported " + - definitions[ lvi ].getImage(), true); - break; - } - } - - checkForUndefinedRecursiveOps(currentModule) ; - -Vector vec = currentModule.recursiveOpDefNodes ; -for (int i = 0 ; i < vec.size() ; i++) { -OpDefNode node = (OpDefNode) vec.elementAt(i); + generateInstance(definitions[lvi], currentModule, true); + break; + + case N_Proof: + checkIfInRecursiveSection(definitions[lvi], "A proof"); + break; + + case N_Theorem: + checkIfInRecursiveSection(definitions[lvi], "A THEOREM"); + processTheorem(definitions[lvi], currentModule); + break; + + case N_Assumption: + checkIfInRecursiveSection(definitions[lvi], "An ASSUME"); + processAssumption(definitions[lvi], currentModule); + break; + + case N_UseOrHide: + checkIfInRecursiveSection(definitions[lvi], "A USE or HIDE"); + UseOrHideNode uohn = generateUseOrHide(definitions[lvi], currentModule); + uohn.factCheck(); + // Added 4 Mar 2009. + if (uohn.facts.length + uohn.defs.length == 0) { + errors.addError(definitions[lvi].getLocation(), "Empty USE or HIDE statement."); + } + ; + currentModule.addTopLevel(uohn); + break; + + case SEPARATOR: + /******************************************************************* + * This code was originally * * case 35 * // Intended to handle "---------". + * Kludge for a parser bug. * * I have no idea why 35 was used instead of + * SEPARATOR, and what * kind of parser bug mentioned was encountered. The + * original * code did not import parser.TLAplusParserConstants where * + * SEPARATOR was used, so perhaps there was some reason why this * class could + * not be imported. * + *******************************************************************/ + break; + + case N_Recursive: + processRecursive(definitions[lvi], currentModule); + break; + default: + errors.addAbort(definitions[lvi].getLocation(), "Internal error: Syntax node of kind " + + definitions[lvi].getKind() + " unsupported " + definitions[lvi].getImage(), true); + break; + } + } + + checkForUndefinedRecursiveOps(currentModule); + + Vector vec = currentModule.recursiveOpDefNodes; + for (int i = 0; i < vec.size(); i++) { + OpDefNode node = (OpDefNode) vec.elementAt(i); // System.out.println("symbol " + node.getName() + ": recSect = " // + node.recursiveSection + ", inRecSect = " // + node.inRecursiveSection + ", letInLevel = " // + node.letInLevel); - } ; - - moduleNestingLevel -- ; - return currentModule; - - } // generateModule - - // This method must be extended so that the Extends list hangs off of - // the ModuleNode to support a getExtends() method that might reasonably - // be in the API. - private final void processExtendsList(TreeNode treeNodes[], ModuleNode cm) - throws AbortException{ - Vector extendeeVector = new Vector(2); - - if (treeNodes != null) { - // module names in the EXTENDS list are separated by commas; hence incr by 2 - for (int lvi = 1; lvi < treeNodes.length; lvi += 2) { - // Try to find the ModuleNode for the module being EXTENDED in the symbolTable - UniqueString extendeeID = treeNodes[lvi].getUS(); - ModuleNode extendee = symbolTable.resolveModule(extendeeID); - - // It must be an external module if it isn't in the symbolTable; - // try to find it in moduleTable (it cannot be in both places) - if (extendee == null) { - extendee = moduleTable.getModuleNode(extendeeID); - if (extendee == null) { - errors.addAbort(treeNodes[lvi].getLocation(), - "Could not find module " + extendeeID, - false); - } - } - - extendeeVector.addElement(extendee); - - Context context = this.getContext(extendeeID); - if (context != null) { - symbolTable.getContext().mergeExtendContext(context); - } - else { - errors.addError(treeNodes[lvi].getLocation(), - "Couldn't find context for module `" + extendeeID - + "'."); - } - - // copy nonlocal Assumes and Theorems - cm.copyAssumes(extendee); - cm.copyTheorems(extendee); - cm.copyTopLevel(extendee); - } - } - cm.createExtendeeArray(extendeeVector); - } // processExtendsList - - // This method must be extended so that the variable declarations list - // hangs off of the module node to support the getVariableDecls method - // of the API. - private final void processVariables(TreeNode treeNodes[], ModuleNode cm) { - for (int lvi = 1; lvi < treeNodes.length; lvi += 2) { - UniqueString us = treeNodes[ lvi ].getUS(); - - if (us == S_at) { - errors.addError(treeNodes[lvi].getLocation(), - "Attempted to declare '@' as a variable."); - } - - // The next line has its side-effects in the constructor; in particular, - // the new OpDeclNode is placed in the symbolTble there. - new OpDeclNode(us, VariableDeclKind, 1, 0, cm, symbolTable, treeNodes[lvi]); - } - } - - - - private final OpDeclNode buildParameter(TreeNode treeNode, - int declKind, - int declLevel, - ModuleNode cm, - boolean declare) { - /*********************************************************************** - * This method was originally called only by the processParameters * - * method to build an OpDeclNode for a module-level CONSTANT * - * declaration. For a declaration "CONSTANT foo(_), _+_" it would be * - * called twice, once with treeNode the node for "foo(_)", and once * - * with it equal to the node for "_+_". The OpDeclNode is not returned * - * because its constructor adds the node to symbolTable. * - * * - * It was modified by LL on 22 Mar 2007 for use in the generateNewSymb * - * method as well. The modifications consisted of returning the * - * OpDeclNode and adding arguments to specify the kind and level of * - * the OpDeclNode. * - * * - * Further modified by LL on 6 Apr 2007 for use in the * - * processRecursive method as well. The modification consisted of * - * adding the declare argument. If true, it calls the OpDeclNode * - * constructor with symbol table symbolTable, so the symbol is added * - * to the current symbol table. If false, it calls the constructor * - * with a null symbol table, so nothing is declared. The * - * processRecursive method just uses the name and arity from the * - * returned OpDeclNode. * - ***********************************************************************/ - UniqueString us = null; - int arity = 0; - TreeNode[] ss = treeNode.heirs(); - - if ( treeNode.isKind( N_IdentDecl ) ) { - us = ss[0].getUS(); - arity = (ss.length - 1) / 2; - } - else if ( treeNode.isKind( N_PrefixDecl ) ) { - us = ss[0].getUS(); - arity = 1; - } - else if ( treeNode.isKind( N_InfixDecl ) ) { - us = ss[1].getUS(); - arity = 2; - } - else if ( treeNode.isKind( N_PostfixDecl ) ) { - us = ss[1].getUS(); - arity = 1; - } - else { - errors.addError(treeNode.getLocation(), - "Unknown parameter declaration `" + treeNode.getUS() - + "'."); - } + } + ; + + moduleNestingLevel--; + return currentModule; + + } // generateModule + + // This method must be extended so that the Extends list hangs off of + // the ModuleNode to support a getExtends() method that might reasonably + // be in the API. + private final void processExtendsList(TreeNode treeNodes[], ModuleNode cm) throws AbortException { + Vector extendeeVector = new Vector(2); + + if (treeNodes != null) { + // module names in the EXTENDS list are separated by commas; hence incr by 2 + for (int lvi = 1; lvi < treeNodes.length; lvi += 2) { + // Try to find the ModuleNode for the module being EXTENDED in the symbolTable + UniqueString extendeeID = treeNodes[lvi].getUS(); + ModuleNode extendee = symbolTable.resolveModule(extendeeID); + + // It must be an external module if it isn't in the symbolTable; + // try to find it in moduleTable (it cannot be in both places) + if (extendee == null) { + extendee = moduleTable.getModuleNode(extendeeID); + if (extendee == null) { + errors.addAbort(treeNodes[lvi].getLocation(), "Could not find module " + extendeeID, false); + } + } + + extendeeVector.addElement(extendee); + + Context context = this.getContext(extendeeID); + if (context != null) { + symbolTable.getContext().mergeExtendContext(context); + } else { + errors.addError(treeNodes[lvi].getLocation(), + "Couldn't find context for module `" + extendeeID + "'."); + } + + // copy nonlocal Assumes and Theorems + cm.copyAssumes(extendee); + cm.copyTheorems(extendee); + cm.copyTopLevel(extendee); + } + } + cm.createExtendeeArray(extendeeVector); + } // processExtendsList + + // This method must be extended so that the variable declarations list + // hangs off of the module node to support the getVariableDecls method + // of the API. + private final void processVariables(TreeNode treeNodes[], ModuleNode cm) { + for (int lvi = 1; lvi < treeNodes.length; lvi += 2) { + UniqueString us = treeNodes[lvi].getUS(); + + if (us == S_at) { + errors.addError(treeNodes[lvi].getLocation(), "Attempted to declare '@' as a variable."); + } + + // The next line has its side-effects in the constructor; in particular, + // the new OpDeclNode is placed in the symbolTble there. + new OpDeclNode(us, VariableDeclKind, 1, 0, cm, symbolTable, treeNodes[lvi]); + } + } + + private final OpDeclNode buildParameter(TreeNode treeNode, int declKind, int declLevel, ModuleNode cm, + boolean declare) { + /*********************************************************************** + * This method was originally called only by the processParameters * method to + * build an OpDeclNode for a module-level CONSTANT * declaration. For a + * declaration "CONSTANT foo(_), _+_" it would be * called twice, once with + * treeNode the node for "foo(_)", and once * with it equal to the node for + * "_+_". The OpDeclNode is not returned * because its constructor adds the node + * to symbolTable. * * It was modified by LL on 22 Mar 2007 for use in the + * generateNewSymb * method as well. The modifications consisted of returning + * the * OpDeclNode and adding arguments to specify the kind and level of * the + * OpDeclNode. * * Further modified by LL on 6 Apr 2007 for use in the * + * processRecursive method as well. The modification consisted of * adding the + * declare argument. If true, it calls the OpDeclNode * constructor with symbol + * table symbolTable, so the symbol is added * to the current symbol table. If + * false, it calls the constructor * with a null symbol table, so nothing is + * declared. The * processRecursive method just uses the name and arity from the + * * returned OpDeclNode. * + ***********************************************************************/ + UniqueString us = null; + int arity = 0; + TreeNode[] ss = treeNode.heirs(); + + if (treeNode.isKind(N_IdentDecl)) { + us = ss[0].getUS(); + arity = (ss.length - 1) / 2; + } else if (treeNode.isKind(N_PrefixDecl)) { + us = ss[0].getUS(); + arity = 1; + } else if (treeNode.isKind(N_InfixDecl)) { + us = ss[1].getUS(); + arity = 2; + } else if (treeNode.isKind(N_PostfixDecl)) { + us = ss[1].getUS(); + arity = 1; + } else { + errors.addError(treeNode.getLocation(), "Unknown parameter declaration `" + treeNode.getUS() + "'."); + } // SymbolNode symbolNode = - SymbolTable st = null ; - if (declare) {st = symbolTable;}; - - /********************************************************************** - * Changed us to Operators.resolveSynonym(us) in the following so * - * constant declarations work with any synonym for an operator--e.g., * - * with both (+) and \oplus. * - **********************************************************************/ - return new OpDeclNode(Operators.resolveSynonym(us), declKind, declLevel, arity, cm, - st, treeNode); - } - - private final void processParameters(TreeNode treeNodes[], ModuleNode cm) { - for (int lvi = 1; lvi < treeNodes.length; lvi +=2 ) { - if (treeNodes[lvi].getUS() == S_at) { - errors.addError(treeNodes[lvi].getLocation(), - "Attempted to declare '@' as a constant."); - } ; - OpDeclNode odn = - buildParameter(treeNodes[lvi], ConstantDeclKind, ConstantLevel, - cm, true); - /******************************************************************* - * We throw away the OpDeclNode because, when it was constructed, * - * it was added to symbolTable, whose top context should be the * - * top-level context of the module. * - *******************************************************************/ - } - } - - /** - * Processes the LHS of an operator definition, in several ways, - * depending on whether it is a prefix, infix, postfix, or a - * parameter-free or parameter-ful function-notation operator. Also - * creates context entries for the operator and its parameters. - */ - /************************************************************************ - * Processes a syntactic node of type N_OperatorDefinition. It is * - * called by generateModule (with defs = null) when processing an * - * outer-level definition and by processLetIn (with defs /= null) when * - * processing a LET definition. It creates an OpDef node and puts it * - * in ModuleNode cm's set of definitions. * - ************************************************************************/ - private final void processOperator(TreeNode treeNode, Vector defs, - ModuleNode cm) throws AbortException { - TreeNode syntaxTreeNode = treeNode; - UniqueString name = null; - int arity = 0; - boolean local = syntaxTreeNode.zero() != null; - TreeNode [] children = syntaxTreeNode.one(); - TreeNode [] ss = children[0].heirs(); - FormalParamNode [] params = null; - Context ctxt = new Context(moduleTable, errors); - boolean isRecursive = false ; - /********************************************************************* - * Will be set to true if this operator was declared in a RECURSIVE * - * statement. * - *********************************************************************/ - // New context needed because parameter symbols may have to be - // added if the operator being defined takes params - symbolTable.pushContext( ctxt ); - - // If the operator is an identifier (possibly with params), as - // opposed to a prefix, infix, or postfix symbol - if ( children[ 0 ].isKind( N_IdentLHS ) ) { - if ( ss.length > 2 ) { - // If the operator has arguments - params = new FormalParamNode[ (ss.length-2) / 2 ]; - for ( int lvi = 2; lvi < ss.length; lvi += 2 ) { - TreeNode sss[] = ss[ lvi ].heirs(); - if ( ss[ lvi ].isKind( N_IdentDecl ) ) { - // parameter is simple identifier - name = sss[0].getUS(); - arity = (sss.length - 1 )/ 2; - } - else if ( ss[ lvi ].isKind( N_InfixDecl ) ) { - // parameter is infix operator - // Call of Operators.resolveSynonym added by LL on 27 Mar 2013 - name = sss[1].getUS(); - - // Following added by LL on 27 Mar 2013 - // to handle parameters like _(+)_ - name = Operators.resolveSynonym(name); - - arity = 2; - } - else if ( ss[ lvi ].isKind( N_PrefixDecl ) ) { - // parameter is prefix operator - name = sss[0].getUS(); - arity = 1; - } - else { - // parameter must be postfix operator - // SZ Jul 13, 2009: added the message to the assert - if(! ss[ lvi ].isKind( N_PostfixDecl )) - { - throw new WrongInvocationException(MP.getMessage(EC.TLC_PARAMETER_MUST_BE_POSTFIX)); - } - name = sss[1].getUS(); - arity = 1; - } - params[ (lvi-2)/2 ] = - new FormalParamNode(name, arity, ss[lvi], symbolTable, cm); - } - } - else { - // The operator has no arguments - params = new FormalParamNode[0]; - } - name = ss[0].getUS(); - } - else if (children[ 0 ].isKind(N_PrefixLHS)) { // operator is a prefix operator - // Process the parameter - params = new FormalParamNode[1]; - params[0] = new FormalParamNode(ss[1].getUS(), 0, ss[1], symbolTable, cm); - - // Process the operator - name = Operators.resolveSynonym(ss[0].getUS()); - } - else if (children[ 0 ].isKind(N_InfixLHS)) { // operator is an infix operator - params = new FormalParamNode[2]; - // Process the first param - params[0] = new FormalParamNode(ss[0].getUS(), 0, ss[0], symbolTable, cm); - - // Process the second param - params[1] = new FormalParamNode(ss[2].getUS(), 0, ss[2], symbolTable, cm); - - // Process the operator - name = Operators.resolveSynonym(ss[1].getUS()); - } - else if (children[ 0 ].isKind(N_PostfixLHS)) { // operator is a postfix operator - // Process the parameter - params = new FormalParamNode[1]; - params[0] = new FormalParamNode(ss[0].getUS(), 0, ss[0], symbolTable, cm); - - // Process the operator - name = Operators.resolveSynonym(ss[1].getUS()); - } - else { - errors.addError(children[0].getLocation(), - "Unknown parameter declaration `" + - children[0].getUS() + "'."); - } - - /*********************************************************************** - * The following code added by LL on 1 April 2007 to handle * - * recursively defined operators. * - ***********************************************************************/ - OpDefNode odn = null ; - /*********************************************************************** - * Check if this operator has already been declared or defined. If * - * so, if it was declared in a RECURSIVE statement at this let/in * - * level and not yet defined, then set the OpDefNode's fields * - * appropriately, otherwise report an error. * - ***********************************************************************/ - SymbolNode symbolNode = symbolTable.resolveSymbol(name) ; - - if (symbolNode != null) { - /********************************************************************* - * The symbol has already been defined or declared. Check if it was * - * declared in a RECURSIVE statement. * - *********************************************************************/ - if (symbolNode instanceof OpDefNode) {odn = (OpDefNode) symbolNode;}; - if ( (odn != null) - && odn.inRecursive - && (! odn.isDefined) ) { - if (odn.letInLevel == curLevel) { - isRecursive = true; - - /***************************************************************** - * Check that the parameters of the definition match the ones in * - * the RECURSIVE declaration. * - *****************************************************************/ - boolean paramsMatch = (odn.getParams().length == params.length) ; - if (paramsMatch) { - for (int i = 0 ; i < params.length ; i++) { - paramsMatch = (params[i].getArity() == 0) ; - }; - }; // if - if (!paramsMatch) { - errors.addError(treeNode.getLocation(), - "Definition of " + odn.getName() + - " has different arity than " + - "its RECURSIVE declaration."); - }; - - odn.setParams(params) ; - /*************************************************************** - * Here's where the params field of the OpDefNode is set for an * - * operator declared in a RECURSIVE statement. * - ***************************************************************/ - } // if (odn.letInLevel == curLevel) - else {errors.addError(treeNode.getLocation(), - "Recursive operator " + name.toString() + - " defined at wrong LET/IN level.") ; - odn = null ; - } // else - } // if (odn != null) ... - else { errors.addError(treeNode.getLocation(), - "Operator " + name.toString() + - " already defined or declared.") ; - } - } // if (symbolNode != null) - - pushLS() ; - /********************************************************************* - * Start fresh processing of labels. * - *********************************************************************/ - // Generate expression that is the body of the operator - ExprNode exp = generateExpression( children[2], cm ); - - // Restore old context, popping off the context containing the parameters - symbolTable.popContext(); - - - if (isRecursive) {endOpDefNode(odn, exp, syntaxTreeNode) ; } - else { - // Create OpDefNode using symbolTable whose top context contains the - // parameter symbols - /******************************************************************** - * This comment appears to be incorrect, because it looks like the * - * parameter symbols were just popped off symbolTable. * - ********************************************************************/ - odn = new OpDefNode(name, UserDefinedOpKind, params, local, - exp, cm, symbolTable, syntaxTreeNode, true, null); - symbolNode = odn ; - /******************************************************************* - * Keeping symbolNode for historical reasons--I'm too lazy to * - * rearrange the code to get rid of the redundant identifier. * - *******************************************************************/ - - setOpDefNodeRecursionFields(odn, cm) ; - - } // else - - Hashtable ht = popLabelNodeSet() ; - /********************************************************************* - * Succeed or fail, we must execute popLabelNodeSet to match the * - * previous pushLS. * - *********************************************************************/ - if (odn != null) {odn.setLabels(ht);} ; - /********************************************************************* - * If there was no error, then odn is an OpDefNode and we must set * - * it labels field. * - *********************************************************************/ - cm.appendDef(symbolNode) ; - /******************************************************************* - * Add the new OpDefNode to the current module's set of * - * definitions. * - *******************************************************************/ - // defs is non-null iff this definition is in the Let part of a - // Let-In expression - if (defs != null) defs.addElement(symbolNode); - } // processOperator - - private final void processQuantBoundArgs( - TreeNode[]treeNodeA, // node whose children include - // the bounded quants - int offset, // nodes to skip to get to first - // "quantifier" - FormalParamNode[][] odna, - boolean []bt, // set to true if arg is a tuple; - // otherwise false - ExprNode[] ena, - ModuleNode cm) - /*********************************************************************** - * Despite the incoherent and/or incorrect comments, here's what I * - * think is going on: * - * * - * - odna, ena, and bt have the same length N. * - * * - * - treeNodeA is an array of nodes containing a subsequence of * - * N_QuantBound nodes of length N that starts at * - * treeNodeA[offset]. * - * * - * - odna, ena, and bt are set to the arguments for the OpApplNode * - * constructor that produces an OpApplNode for the operator * - * having this sequence of N_QuantBound nodes. * - ***********************************************************************/ - - throws AbortException { - // For each quantifier, evaluate the bound in the context of the - // current symbol table, i.e. before the quantified variables are - // added to the new context, since the quantified vars may not - // appear in the bounds. - for (int lvi = 0; lvi < bt.length; lvi++ ) { - // Make ss point to each N_QuantBound node in turn. - TreeNode[] ss = treeNodeA[offset + 2 * lvi].heirs(); - // the last element in ss is expression for the quantifier bound - ena[lvi] = generateExpression( ss[ ss.length - 1 ], cm ); - } - - // Now for each quantifier, process the variable names - for (int lvi = 0; lvi < bt.length; lvi++ ) { - TreeNode treeNode = treeNodeA[offset + 2 * lvi]; - - // The variable bound to the "quantifier" - TreeNode[] ss = treeNode.heirs(); - - if (ss[0].isKind(N_IdentifierTuple)) { // three elements only, go into node - bt[lvi] = true; - TreeNode[] sss = ss[0].heirs(); - odna[lvi] = new FormalParamNode[ sss.length / 2 ]; - - for (int lvj = 0; lvj < sss.length / 2; lvj++ ) { - odna[lvi][lvj] = new FormalParamNode( - sss[ 2*lvj+1 ].getUS(), 0, sss[ 2*lvj+1 ], - symbolTable, cm) ; - } - } - else { // gotta be N_Identifier - bt[lvi] = false; - odna[lvi] = new FormalParamNode[ (ss.length - 1)/2 ]; - - for ( int lvj = 0; lvj < (ss.length - 1)/2 ; lvj++ ) { - odna[lvi][lvj] = new FormalParamNode( - ss[ 2*lvj ].getUS(), 0, ss[ 2*lvj ], - symbolTable, cm); - } - } - } - } - - // Process a function definition - private final void processFunction(TreeNode treeNode, Vector defs, ModuleNode cm) - throws AbortException { - TreeNode syntaxTreeNode = treeNode; - boolean local = syntaxTreeNode.zero() != null; - TreeNode[] ss = syntaxTreeNode.one(); - // Heirs to N_FunctionDefinition node - int ql = (ss.length-4)/2; - // number of QuantBound's - OpApplNode oan; - OpDefNode odn = null; - FormalParamNode[][] quants = new FormalParamNode[ql][0]; - FormalParamNode[] fcnDeclForRecursion = new FormalParamNode[1]; - /********************************************************************* - * This is an array of length 1 instead of just an OpDeclNode * - * because it is needed in such an array to pass as an argument to * - * new OpApplNode. * - *********************************************************************/ - boolean [] tuples = new boolean[ql]; - ExprNode [] domains = new ExprNode[ql]; - ExprNode [] lhs = new ExprNode[1]; - Context newContext = new Context(moduleTable, errors); - boolean isRecursive = false ; - /********************************************************************* - * Will be set to true if this operator was declared in a RECURSIVE * - * statement. * - *********************************************************************/ - - // Fill arrays with quantifier-related information; must be called - // in scope of *new* context, since it adds parameter symbols to - // the context. - symbolTable.pushContext(newContext); - processQuantBoundArgs( ss, 2, quants, tuples, domains, cm ); - - UniqueString name = ss[0].getUS() ; - SymbolNode symbolNode = symbolTable.resolveSymbol(name) ; - - - // This is in anticipation of the possibility that the function is - // recursive. We are creating a new bound symbol of the same name - // as the function to stand in the body for the function. The - // arity of the bound symbol is 0 because a function formally has - // arity 0 as an operator, even if it has several arguments as a - // function. - /*********************************************************************** - * If the function name is already defined (which should happen only * - * if it was declared in a RECURSIVE statement, then there is no need * - * to add this OpDeclNode to the symbol table. As near as I can tell * - * (which might not be near enough), this OpDeclNode's entry in the * - * symbol table is needed only so the name will be declared in case * - * of a recursive call. The check for whether a function call in the * - * body actually is recursive is made by calling the recursionCheck * - * method of the Function subclass to see if the OpApplNode is in the * - * Function object's funcStack. * - ***********************************************************************/ - SymbolTable st = null ; - if (symbolNode == null) {st = symbolTable; } ; - fcnDeclForRecursion[0] = - new FormalParamNode(name, 0, treeNode, st, cm); - symbolTable.popContext(); - - // Create OpApplNode to hold the function body; type is assumed to - // be non-recursive function (OP_nrfs); if the body is recursive, - // this will be discovered during generateExpression() for the - // body - oan = new OpApplNode(OP_nrfs, fcnDeclForRecursion, new ExprNode[0], - quants, tuples, domains, syntaxTreeNode, cm); - // constructor 5 - - /*********************************************************************** - * The following code added by LL on 19 April 2007 to handle * - * recursively defined operators. * - ***********************************************************************/ - if (symbolNode == null) { - odn = new OpDefNode(ss[0].getUS(), UserDefinedOpKind, nullParam, local, - oan, cm, symbolTable, syntaxTreeNode, true, null); - setOpDefNodeRecursionFields(odn, cm) ; - } - else - { - /********************************************************************* - * The symbol has already been defined or declared. Check if it was * - * declared in a RECURSIVE statement. * - *********************************************************************/ - if (symbolNode instanceof OpDefNode) {odn = (OpDefNode) symbolNode;}; - if ( (odn != null) - && odn.inRecursive - && (! odn.isDefined) ) { - if (odn.letInLevel == curLevel) { - isRecursive = true; - /***************************************************************** - * Check that the RECURSIVE declaration had no paramters. * - *****************************************************************/ - if (odn.getArity() == 0) { - endOpDefNode(odn, oan, syntaxTreeNode) ; - } - else { - /************************************************************* - * RECURSIVE declaration had parameters. * - *************************************************************/ - errors.addError(treeNode.getLocation(), - "Function " + odn.getName() + - " has operator arguments in " + - "its RECURSIVE declaration."); - } ; - } // if (odn.letInLevel == curLevel) - else {errors.addError(treeNode.getLocation(), - "Recursive function " + name.toString() + - " defined at wrong LET/IN level.") ; - odn = null ; - } // else - } // if (odn != null) ... - else { errors.addError(treeNode.getLocation(), - "Function name `" + name.toString() + - "' already defined or declared.") ; - } - } // else (symbolNode != null) - - // Create OpDefNode to hold the function definition, including - // reference to the function body ("oan") - if (odn != null) { - /********************************************************************* - * There was no error, so the OpDefNode was created. * - *********************************************************************/ - cm.appendDef(odn); - - // defs is non-null iff this function definition is in the Let - // part of a Let-In expression. If so, then we have to accumulate - // these defs in a vector. - if (defs != null) defs.addElement(odn); - - // Function body must be processed in the scope of the new - // context, including the parms - symbolTable.pushContext( newContext ); - - }; // if (odn != null) - - // Keep stack of nested function defs to enable detection of recursion - functions.push( ss[0].getUS(), oan ); - - - // Create semantic graph function body in the inner context including parameters - pushLS() ; - pushFormalParams(flattenParams(quants)) ; - /********************************************************************* - * Push a new empty label set onto LS, and push the function * - * definition's formal parameters onto Last(LS).paramSeq for * - * processing the function body. * - *********************************************************************/ - lhs[0] = generateExpression( ss[ss.length - 1], cm ); - popFormalParams() ; - /********************************************************************* - * Pop the formal params from Last(LS).paramSeq, which should now be * - * empty. This isn't really necessary, since we're going to pop the * - * LS stack below, but I hate to have a push without a pop. * - *********************************************************************/ - Hashtable ht = popLabelNodeSet() ; - /********************************************************************* - * The matching pop for the pushLS above. * - *********************************************************************/ - if (odn != null) { odn.setLabels(ht); } ; - /********************************************************************* - * If there was no error and we created an OpDefNode, then set its * - * label set. * - *********************************************************************/ - functions.pop(); - - oan.setArgs( lhs ); - /*********************************************************************** - * Test for odn != null added 2 Jul 2009 to avoid bug that caused * - * popping of empty symbol table when the function name was * - * already declared to be a variable. * - ***********************************************************************/ - if (odn != null){ - // Restore old context - symbolTable.popContext(); - } - - // if the function body turned out to be non-recursive, then we - // should null-out the fcnDefForRecursion ref put in place above, - // since it is unnecessary for a nonrecursive func - if (oan.getOperator().getName() == OP_nrfs) { - oan.makeNonRecursive(); - } - } // end processFunction() - - private final ExprNode processLetIn(TreeNode treeNode, TreeNode[] children, - ModuleNode cm) - throws AbortException { - TreeNode[] syntaxTreeNode = children[1].heirs(); // extract LetDefinitions - Vector defVec = new Vector(4); - Vector instVec = new Vector(1); - - Context letCtxt = new Context(moduleTable, errors) ; - symbolTable.pushContext(letCtxt); - /********************************************************************* - * Create a new sub-Context for the IN expression, containing the * - * LET definitions * - *********************************************************************/ - - /*********************************************************************** - * Increment curLevel. * - ***********************************************************************/ - if (curLevel < MaxLetInLevel) { curLevel++ ; } - else { errors.addAbort(treeNode.getLocation(), - "LETs nested more than " + MaxLetInLevel + - " deep.") ; - } ; - unresolvedCnt[curLevel] = 0 ; - /********************************************************************* - * Will not have been initialized if we haven't yet reached this * - * LET/IN nesting depth. * - *********************************************************************/ - - for (int lvi = 0; lvi < syntaxTreeNode.length; lvi++) { - /********************************************************************* - * Note: LL changed from an "if" and a sequence of "elseif"s to a * - * switch statement on 7 Apr 2007 when adding the N_Recursive case. * - *********************************************************************/ - switch (syntaxTreeNode[lvi].getKind()) { - case N_OperatorDefinition : - processOperator(syntaxTreeNode[ lvi ], defVec, cm); - break ; - - case N_FunctionDefinition : - processFunction(syntaxTreeNode[ lvi ], defVec, cm ); - break ; - - case N_ModuleDefinition : - processModuleDefinition(syntaxTreeNode[lvi], defVec, instVec, cm); - break ; - - case N_Recursive : - processRecursive(syntaxTreeNode[ lvi ], cm) ; - break ; - - default : - errors.addAbort(syntaxTreeNode[ lvi ].getLocation(), - "Internal error: found unexpected syntax " + - "tree node in LET.") ; - } // switch - } // for - - checkForUndefinedRecursiveOps(cm) ; - - /*********************************************************************** - * Decrement curLevel. * - ***********************************************************************/ - curLevel -- ; - if (curLevel < 0) { curLevel = 0;} ; - - - ExprNode body = generateExpression(children[3], cm); - - /*********************************************************************** - * Convert from Vector to array of SymbolNode, whose elements may be * - * OpDefNode or ThmOrAssumpDefNode objects. * - ***********************************************************************/ - SymbolNode[] opDefs = new SymbolNode[defVec.size()]; - for (int i = 0; i < opDefs.length; i++) { - opDefs[i] = (SymbolNode)defVec.elementAt(i); - } - - InstanceNode[] insts = new InstanceNode[instVec.size()]; - for (int i = 0; i < insts.length; i++) { - insts[i] = (InstanceNode)instVec.elementAt(i); - } - LetInNode letIn = new LetInNode(treeNode, opDefs, insts, body, letCtxt); - symbolTable.popContext(); - return letIn; - } // end processLetIn - - private final ExprNode generateExpression(TreeNode treeNode, ModuleNode cm) - throws AbortException { - /*********************************************************************** - * Must return an ExprNode that represents an expression, and not a * - * labeled ASSUME/PROVE * - ***********************************************************************/ - return generateExpressionOrLAP(treeNode, cm, false) ; - } - - private final ExprNode generateExpressionOrLAP( - TreeNode treeNode, ModuleNode cm, boolean allowLabeledAP) - /*********************************************************************** - * Can return a LabelNode labeling an ASSUME/PROVE iff allowLabeledAP * - * = true. Otherwise, it can return only an ExprNode that represents * - * an expression. * - ***********************************************************************/ - throws AbortException { - TreeNode[] children = treeNode.heirs(); - TreeNode[] ss = null; // grandchildren - SymbolNode opn = null; - TreeNode op = null; - GenID genID; - ExprOrOpArgNode[] sns; // a ExprNode list used for arguments - - switch (treeNode.getKind()) { - - case N_Real : - return new DecimalNode(children[0].getImage(),children[2].getImage(), treeNode); - - case N_Number : - return new NumeralNode( children[0].getImage(), treeNode); - - case N_String : - return new StringNode( treeNode, true); - - case N_ParenExpr : - return generateExpression( children[1], cm ); - - case N_InfixExpr : - genID = generateGenID(children[1], cm); - - sns = new ExprOrOpArgNode[2]; - opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); - if ( opn == null ) { - errors.addError(treeNode.getLocation(), - "Couldn't resolve infix operator symbol `" + - genID.getCompoundIDUS() + "'." ); - return null; - } - - sns[0] = generateExpression( children[0], cm ); - sns[1] = generateExpression( children[2], cm ); - return new OpApplNode(opn, sns, treeNode, cm); - - case N_PrefixExpr : - // 1 get gen operator node - ss = children[0].heirs(); - - // 2 get rightmost part of the possibly compound Op itself; - op = ss[1]; - genID = generateGenID(children[0], cm, true); - sns = new ExprOrOpArgNode[1]; - opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); - - if ( opn == null ) { - errors.addError(treeNode.getLocation(), - "Couldn't resolve prefix operator symbol `" + - genID.getCompoundIDUS() + "'." ); - return null; - } - - sns[0] = generateExpression( children[1], cm ); - return new OpApplNode(opn, sns, treeNode, cm); // constructor 2 - - case N_PostfixExpr : - genID = generateGenID(children[1], cm); - - sns = new ExprNode[1]; - opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); - if ( opn == null ) { - errors.addError(treeNode.getLocation(), "Couldn't resolve postfix " + - "operator symbol `" + genID.getCompoundIDUS() + "'."); - return null; - } - - sns[0] = generateExpression( children[0], cm ); - return new OpApplNode(opn, sns, treeNode, cm); // constructor 2 - - case N_Times : // or cartesian product - sns = new ExprNode[ (children.length+1)/2 ]; - - for (int lvi = 0; lvi < sns.length; lvi ++ ) { - sns[ lvi ] = generateExpression( children[ 2 * lvi ], cm ); - } - return new OpApplNode(OP_cp, sns, treeNode, cm); // constructor 3 - - case N_SetEnumerate : - int size = (children.length-1) / 2; - sns = new ExprNode [size]; - for ( int lvi = 0; lvi < size; lvi++ ) { - sns[lvi] = generateExpression( children[ 2 * lvi + 1 ], cm ); - } - return new OpApplNode(OP_se, sns, treeNode, cm); // constructor 3 - - case N_GeneralId : - // This is a zero-ary operator; it should show in the syntax - // tree as an OpApp, but it does not. Hence, an OpApplication - // node with zero arguments must be constructed for it - // if we get here, the GeneralID really is an OpApplication with 0 - // primary arguments, but with any number of prefix arguments - - // process the generalized identifier, complete with its - // embedded argument lists (if any) - - /********************************************************************* - * If the N_GeneralId represents the identifier "@", then check for * - * errors and return an AtNode if none. * - *********************************************************************/ - SyntaxTreeNode sTreeNode = (SyntaxTreeNode) treeNode ; - if ( (sTreeNode.heirs()[1].getKind() == IDENTIFIER) - && (sTreeNode.heirs()[1].getUS() == AtUS) - && (((SyntaxTreeNode) sTreeNode.heirs()[0]).heirs().length == 0) ) { - if (excStack.empty() || excSpecStack.empty()) { - // if either stack is empty, then @ used in improper EXCEPT context - errors.addError(sTreeNode.getLocation(), - "@ used where its meaning is not defined."); - return nullOAN ; - } - else { - // So, the context for @ is proper, then construct the - // AtNode and return it - return new AtNode((OpApplNode)excStack.peek(), - (OpApplNode)excSpecStack.peek()); - } - } ; - - ExprNode retVal = - (ExprNode) selectorToNode(genIdToSelector(sTreeNode), - 0, false, false, cm) ; - - /********************************************************************* - * A function definition generates an OpDefNode whose body is an * - * OpApplNode whose operator is either $RecursiveFcnSpec or * - * $NonRecursiveFcnSpec, the latter when the definition is * - * recursive. However, in SANY1 the definition * - * * - * f[x \in S] == ... * - * * - * was found to be recursive only if a subexpression f[...] occurs * - * in the body. It was not marked as recursive if another instance * - * of f occurs, such as Foo(f). To fix this, we need to check if * - * this genID is actually the Identifier of a function currently * - * being defined. The following call to functions.recursionCheck * - * does that. * - *********************************************************************/ - if (retVal.getKind() == OpApplKind) { - functions.recursionCheck( - ((OpApplNode) retVal).getOperator().getName()) ; - } ; - - return retVal ; - /************************** old version - genID = generateGenID(treeNode, cm); - - // if the symbol is "@" then check for errors and - // return an AtNode if none. - if (genID.getCompoundIDUS() == S_at) { - if (excStack.empty() || excSpecStack.empty()) { - // if either stack is empty, then @ used in improper EXCEPT context - errors.addError(treeNode.getLocation(), - "@ used where its meaning is not defined."); - } - else { - // So, the context for @ is proper, then construct the - // AtNode and return it - return new AtNode((OpApplNode)excStack.peek(), - (OpApplNode)excSpecStack.peek()); - } - } - else if (genID.getFullyQualifiedOp() == null - || genID.getArgs() == null) { - // If it is not an "@" symbol, it may still be an unresolved symbol - return nullOAN; - } - else if (genID.getFullyQualifiedOp().getKind() == ModuleKind) { - errors.addError( - treeNode.getLocation(), - "Module name '" + genID.getFullyQualifiedOp().getName() + - "' used as operator."); - return nullOAN; - } - else { - // but if there are no problems then we are in a situation in - // which return the appropriate OpApplNode an N_GenID node in - // the syntax tree really stands for an OpApplication - -// ********************************************************************* -// * Modified on 20 Apr 2007 by LL to correct the following bug. * -// * * -// * A function definition generates an OpDefNode whose body is an * -// * OpApplNode whose operator is either $RecursiveFcnSpec or * -// * $NonRecursiveFcnSpec, the latter when the definition is * -// * recursive. However, the definition * -// * * -// * f[x \in S] == ... * -// * * -// * was found to be recursive only if a subexpression f[...] occurs * -// * in the body. It was not marked as recursive if another instance * -// * of f occurs, such as Foo(f). To fix this, we need to check if * -// * this genID is actually the Identifier of a function currently * -// * being defined. The call to functions.recursionCheck was added * -// * here to do that. * -// ********************************************************************* - SymbolNode symNode = genID.getFullyQualifiedOp() ; - - if (symNode.getKind() == ThmOrAssumpDefKind) { - errors.addError(treeNode.getLocation(), - "Theorem or Assumption name used as expression.") ; - }; - OpApplNode retVal = - // return - new OpApplNode(symNode, genID.getArgs(), - treeNode, cm); - functions.recursionCheck(symNode.getName()); - return retVal ; - } - - ******************************* old version ******************/ - case N_OpApplication: - // for an operator with arguments - // Note: in neither case can this be an operator passed as an argument; - // the opAppl argument forces the return of an Operator application - // operators passed as arguments generate OpArg nodes, and that - // can happen only in certain contexts, not in every context where an - // expression can occur, which is the context we are in here - - SyntaxTreeNode genIdNode = (SyntaxTreeNode) treeNode.heirs()[0] ; - SyntaxTreeNode opApplNode = (SyntaxTreeNode) treeNode.heirs()[1] ; - - /********************************************************************* - * First a check. It appears that the children of an OpApplication * - * node must be a GeneralId node and an OpArgs node, but let's be * - * sure. * - *********************************************************************/ - if ( (genIdNode.getKind() != N_GeneralId) - || (opApplNode.getKind() != N_OpArgs)) { - errors.addAbort( - treeNode.getLocation(), - "Internal error: OpAppl node with unexpected children.", - true); - } ; - - Selector sel = genIdToSelector(genIdNode) ; - sel.args[sel.args.length - 1] = opApplNode ; - sel.selSTN = (SyntaxTreeNode) treeNode ; - /******************************************************************* - * For error reporting, make the syntax tree node of the selector * - * include both the general ID node and its argument. * - *******************************************************************/ - return (ExprNode) selectorToNode(sel, 0, false, false, cm) ; - -/***************** old version ********************* - return generateOpAppl(treeNode, cm); -************************/ - - case N_Tuple : - size = (children.length - 1) / 2; - sns = new ExprNode [size]; - for ( int lvi = 0; lvi < size; lvi++ ) { - sns[lvi] = generateExpression( children[ 2 * lvi + 1 ], cm ); - } - return new OpApplNode(OP_tup, sns, treeNode, cm); // Constructor 3 - - case N_FcnAppl : // Apparent function application - // Number of arguments to the apparent func app - int numArgs = (children.length - 2) / 2; - - // Function appl involves two semantic nodes: 1 for function, - // and 1 for arg or args tuple. - sns = new ExprNode[2]; - - // Generate expression tree for the function itself - sns[0] = generateExpression( children[0], cm ); - - if (sns[0] == null) {return null;} ; - /******************************************************************* - * sns[0] can be null if the parsing the function generates an * - * error (which is the case if the function is missing). * - * Added by LL on 29 Feb 2008 * - *******************************************************************/ - - // If the function is an OpApplNode (and could it be otherwise?) - if (sns[0].getKind() == OpApplKind) { - // Note if this is a recursive function, and change the top level - functions.recursionCheck(((OpApplNode)sns[0]).getOperator().getName()); - } - - // We next check that the number of arguments to a user-defined - // function is correct, if possible. - - // Retrieve the expression that represents the function being - // applied, i.e. the 1st arg to $FcnApply - ExprOrOpArgNode fcn = sns[0]; - - // The entire next conditional is for one purpose: to make sure - // that a function symbol is applied to the right number of - // arguments, when it is possible to do that during semantic - // analysis. This means that if a function is declared with, - // say, 3 parameters, e.g. "f[a,b,c] == {a,b,c}", then it is - // never used with 2 or 4 arguments. However, it can appear - // with zero arguments as the expression "f" (not as "f[]"), and - // it can appear with one argument, as in "f[e]", because e - // might be a 3-tuple value. (Whether it always is or not - // cannot be determined at the time of semantic analysis.) - // Furthermore a function declared with exactly one parameter - // can appear with any number of argument expressions because, - // e.g. f[1,2,3,4] is considered just an alternate way of - // writing f[<<1,2,3,4>>], so there is really just one argument - // value. - - // If it is an OpApplNode (as opposed to, say, an OpDeclNode) - if ( fcn instanceof OpApplNode ) { - // Retrieve the function being applied - SymbolNode funcOperator = ((OpApplNode)fcn).getOperator(); - - // If the function being applied is a user-defined function - // (as opposed to OpDeclNode, FormalParamNode, builtin - // operator, or expression) - if (funcOperator instanceof OpDefNode && - funcOperator.getKind() == UserDefinedOpKind) { - // Retrieve the function body expression - ExprOrOpArgNode funcBody = ((OpDefNode)funcOperator).getBody(); - - // if the function body is an OpApplNode (as opposed to, - // say, NumeralNode, DecimalNode, etc.) - if (funcBody instanceof OpApplNode && - (((OpApplNode)funcBody).getOperator().getName()==OP_nrfs || - ((OpApplNode)funcBody).getOperator().getName()==OP_rfs )) { - - // find out how many arguments it is SUPPOSED to have - int numParms = ((OpApplNode)funcBody ).getNumberOfBoundedBoundSymbols(); - - // If the function appears with numArgs >= 2 argument - // expressions, it must be declared with exactly numArgs - // parameters; and a function with numParms parameters in - // its definition should be applied to exactly numParms - // expressions, or 1 expression (representing arguments in - // tuple form), or 0 expressions (representing the - // function itself). Note: one cannot define a function - // with 0 arguments in TLA+. - if ( numArgs >= 2 && numParms != numArgs ) { - errors.addError(treeNode.getLocation(), - "Function '" + - ((OpApplNode)sns[0]).getOperator().getName() + - "' is defined with " + numParms + - " parameters, but is applied to " + - numArgs + " arguments."); - return nullOAN; - } // end if - } // end if - } // end if - } // end if - - // Assert.check(numArgs > 0); - if (numArgs == 1) { - sns[1] = generateExpression(children[2], cm); - } - else { - // If there is more than one arg we have to create a tuple for the arguments. - ExprOrOpArgNode[] exprs = new ExprNode[ numArgs ]; // One for each of the arguments - - // For each argument... - for (int lvi = 0; lvi < numArgs; lvi++) { - // Create the expression for that argument - exprs[lvi] = generateExpression( children[ 2+2*lvi ], cm ); - } - // Create an application of $Tuple - sns[1] = new OpApplNode(OP_tup, exprs, treeNode, cm); - } - // Create the function application node. - return new OpApplNode(OP_fa, sns, treeNode, cm); - - case N_UnboundOrBoundChoose : - return processChoose(treeNode, children, cm ); - - case N_BoundQuant : - return processBoundQuant(treeNode, children, cm); - - case N_UnboundQuant : - return processUnboundQuant( treeNode, children, cm ); - - case N_IfThenElse : - sns = new ExprNode[3]; - sns[0] = generateExpression( children[1], cm ); - sns[1] = generateExpression( children[3], cm ); - sns[2] = generateExpression( children[5], cm ); - return new OpApplNode(OP_ite, sns, treeNode, cm); - - case N_Case : - return processCase(treeNode, children, cm); - - case N_DisjList: - case N_ConjList: - sns = new ExprNode[ children.length ]; - for (int lvi = 0; lvi< sns.length; lvi++ ) { - sns[lvi] = generateExpression( children[lvi].heirs()[1], cm ); - } - if ( treeNode.isKind(N_DisjList ) ) - return new OpApplNode(OP_dl, sns, treeNode, cm); - else - return new OpApplNode(OP_cl, sns, treeNode, cm); - - case N_RecordComponent : // really RcdSelect in the API - sns = new ExprNode[2]; - sns[0] = generateExpression( children[0], cm ); - sns[1] = new StringNode(children[2], false); - return new OpApplNode(OP_rs, sns, treeNode, cm); - - case N_SetOfFcns: /* [S -> T] */ - sns = new ExprNode[2]; - sns[0] = generateExpression( children[1], cm ); - sns[1] = generateExpression( children[3], cm ); - - return new OpApplNode(OP_sof, sns, treeNode, cm); - - case N_SubsetOf : - return processSubsetOf( treeNode, children, cm ); - - case N_SetOfAll : - return processSetOfAll( treeNode, children, cm ); - - case N_RcdConstructor: - return processRcdForms( OP_rc, treeNode, children, cm ); - - case N_SetOfRcds: - return processRcdForms( OP_sor, treeNode, children, cm ); - - case N_FcnConst: - return processFcnConst( treeNode, children, cm ); - - case N_ActionExpr: - case N_FairnessExpr: - return processAction( treeNode, children, cm ); - - case N_Except: - return processExcept( treeNode, children, cm ); - - case N_LetIn: - return processLetIn( treeNode, children, cm ); - - case N_Lambda: - errors.addError( - treeNode.getLocation(), - "LAMBDA expression used where an expression is required." ); - return null; - - case N_Label: - LabelNode ln = generateLabel(treeNode, cm); - if (ln.isAssumeProve && !allowLabeledAP) { - errors.addError( - treeNode.getLocation(), - "Labeled ASSUME/PROVE used where an expression is required." ); - } - return ln ; - - default: - errors.addError(treeNode.getLocation(), - "Unsupported expression type `" + - treeNode.getImage() + "'."); - return null; - - } // end switch - - } // end generateExpression() - -/*************************************************************************** -* The following variables are used in the processing of ASSUME/PROVE * -* nodes, and the labels that lie within them. * -***************************************************************************/ - private int assumeProveDepth = 0 ; - /*********************************************************************** - * The nesting depth of ASSUME/PROVEs within which the node corrently * - * being processed lies. In * - * * - * THEOREM ASSUME P PROVE Q * - * * - * the nodes for P and Q are at depth 1 (not 0). * - ***********************************************************************/ - - private ThmOrAssumpDefNode currentGoal = null ; - private int currentGoalClause ; - /*********************************************************************** - * currentGoal is the named theorem or proof-step node within * - * which lies the current node that is being processed, or null if * - * we're not inside such a step. If currentGoal != null, and we're * - * within an ASSUME/PROVE step (which is true iff assumeProveDepth > * - * 0), then then currentGoalClause equals the clause of within which * - * the node being processed lies. (If we're processing Q in ASSUME P * - * PROVE Q, then Q = 1.) * - ***********************************************************************/ - - private static final int maxAPDepth = 100 ; - /*********************************************************************** - * Maximum allowed nesting depth of ASSUME/PROVES. 100 ought to * - * suffice. * - ***********************************************************************/ - - private boolean[] inScopeOfAPDecl = new boolean[maxAPDepth] ; - /*********************************************************************** - * For all i \leq assumeProveDepth, inScopeOfAPDecl[i] = true iff the * - * node currently being processed lies within a declaration made at * - * assumeProveDepth = i. Thus in * - * * - * THEOREM ASSUME NEW x \in S, * - * P, * - * ASSUME R , ACTION A PROVE T * - * PROVE Q * - * * - * inScopeOfAPDecl[1] equals false when S is being processed and * - * equals true when P, Q, R, and T are being processed. * - * * - * inScopeOfAPDecl[2] equals false when R is being processed and true * - * when T is being processed. * - ***********************************************************************/ - - - private boolean noLabelsAllowed() { - /*********************************************************************** - * This returns true if we are inside an ASSUME/PROVE node where a * - * label is not allowed because we are in the scope of a declaration * - * from an inner ASSUME/PROVE. * - ***********************************************************************/ - for (int i = 2; i <= assumeProveDepth; i++) { - if (inScopeOfAPDecl[i]) { return true ; } ; - } ; - return false ; - } - - - private final boolean illegalLabelRef(LabelNode ln, SyntaxTreeNode stn) - throws AbortException { - /*********************************************************************** - * True iff we are currently in a point where a reference to this * - * label is illegal because it lies inside an ASSUME/PROVE clause from * - * outside the scope of a symbol it may contain. See the comments in * - * AssumeProveNode.java for an explanation of this method. * - ***********************************************************************/ - ThmOrAssumpDefNode goal = ln.goal ; - if (goal == null) { return false ; } ; - if ( (goal.getBody() == null) - || (goal.getBody().getKind() != AssumeProveKind)) { - errors.addAbort( - stn.getLocation(), - "Internal error: Expecting label to be in AssumeProveNode, " + - "but it's not.") ; - } ; - AssumeProveNode ap = (AssumeProveNode) goal.getBody() ; - return ap.inScopeOfDecl[ln.goalClause] - && (goal.isSuffices() == ap.inProof) ; - } // illegalLabelRef - - private final boolean illegalAPPosRef(AssumeProveNode ap, int pos) { - /*********************************************************************** - * True iff it is illegal for the node currently being processed to * - * access the clause number pos of AssumeProve node ap because it is * - * not in the scope of symbols declared in previous ASSUME clauses of * - * ap. See the comments in AssumeProveNode.java for an explanation of * - * this method. * - ***********************************************************************/ - return ap.inScopeOfDecl[pos-1] - && ( (ap.getGoal() == null) - || (ap.getGoal().isSuffices() == ap.inProof)) ; - } - + SymbolTable st = null; + if (declare) { + st = symbolTable; + } + ; + + /********************************************************************** + * Changed us to Operators.resolveSynonym(us) in the following so * constant + * declarations work with any synonym for an operator--e.g., * with both (+) and + * \oplus. * + **********************************************************************/ + return new OpDeclNode(Operators.resolveSynonym(us), declKind, declLevel, arity, cm, st, treeNode); + } + + private final void processParameters(TreeNode treeNodes[], ModuleNode cm) { + for (int lvi = 1; lvi < treeNodes.length; lvi += 2) { + if (treeNodes[lvi].getUS() == S_at) { + errors.addError(treeNodes[lvi].getLocation(), "Attempted to declare '@' as a constant."); + } + ; + OpDeclNode odn = buildParameter(treeNodes[lvi], ConstantDeclKind, ConstantLevel, cm, true); + /******************************************************************* + * We throw away the OpDeclNode because, when it was constructed, * it was added + * to symbolTable, whose top context should be the * top-level context of the + * module. * + *******************************************************************/ + } + } + + /** + * Processes the LHS of an operator definition, in several ways, depending on + * whether it is a prefix, infix, postfix, or a parameter-free or parameter-ful + * function-notation operator. Also creates context entries for the operator and + * its parameters. + */ + /************************************************************************ + * Processes a syntactic node of type N_OperatorDefinition. It is * called by + * generateModule (with defs = null) when processing an * outer-level definition + * and by processLetIn (with defs /= null) when * processing a LET definition. + * It creates an OpDef node and puts it * in ModuleNode cm's set of definitions. + * * + ************************************************************************/ + private final void processOperator(TreeNode treeNode, Vector defs, ModuleNode cm) throws AbortException { + TreeNode syntaxTreeNode = treeNode; + UniqueString name = null; + int arity = 0; + boolean local = syntaxTreeNode.zero() != null; + TreeNode[] children = syntaxTreeNode.one(); + TreeNode[] ss = children[0].heirs(); + FormalParamNode[] params = null; + Context ctxt = new Context(moduleTable, errors); + boolean isRecursive = false; + /********************************************************************* + * Will be set to true if this operator was declared in a RECURSIVE * statement. + * * + *********************************************************************/ + // New context needed because parameter symbols may have to be + // added if the operator being defined takes params + symbolTable.pushContext(ctxt); + + // If the operator is an identifier (possibly with params), as + // opposed to a prefix, infix, or postfix symbol + if (children[0].isKind(N_IdentLHS)) { + if (ss.length > 2) { + // If the operator has arguments + params = new FormalParamNode[(ss.length - 2) / 2]; + for (int lvi = 2; lvi < ss.length; lvi += 2) { + TreeNode sss[] = ss[lvi].heirs(); + if (ss[lvi].isKind(N_IdentDecl)) { + // parameter is simple identifier + name = sss[0].getUS(); + arity = (sss.length - 1) / 2; + } else if (ss[lvi].isKind(N_InfixDecl)) { + // parameter is infix operator + // Call of Operators.resolveSynonym added by LL on 27 Mar 2013 + name = sss[1].getUS(); + + // Following added by LL on 27 Mar 2013 + // to handle parameters like _(+)_ + name = Operators.resolveSynonym(name); + + arity = 2; + } else if (ss[lvi].isKind(N_PrefixDecl)) { + // parameter is prefix operator + name = sss[0].getUS(); + arity = 1; + } else { + // parameter must be postfix operator + // SZ Jul 13, 2009: added the message to the assert + if (!ss[lvi].isKind(N_PostfixDecl)) { + throw new WrongInvocationException(MP.getMessage(EC.TLC_PARAMETER_MUST_BE_POSTFIX)); + } + name = sss[1].getUS(); + arity = 1; + } + params[(lvi - 2) / 2] = new FormalParamNode(name, arity, ss[lvi], symbolTable, cm); + } + } else { + // The operator has no arguments + params = new FormalParamNode[0]; + } + name = ss[0].getUS(); + } else if (children[0].isKind(N_PrefixLHS)) { // operator is a prefix operator + // Process the parameter + params = new FormalParamNode[1]; + params[0] = new FormalParamNode(ss[1].getUS(), 0, ss[1], symbolTable, cm); + + // Process the operator + name = Operators.resolveSynonym(ss[0].getUS()); + } else if (children[0].isKind(N_InfixLHS)) { // operator is an infix operator + params = new FormalParamNode[2]; + // Process the first param + params[0] = new FormalParamNode(ss[0].getUS(), 0, ss[0], symbolTable, cm); + + // Process the second param + params[1] = new FormalParamNode(ss[2].getUS(), 0, ss[2], symbolTable, cm); + + // Process the operator + name = Operators.resolveSynonym(ss[1].getUS()); + } else if (children[0].isKind(N_PostfixLHS)) { // operator is a postfix operator + // Process the parameter + params = new FormalParamNode[1]; + params[0] = new FormalParamNode(ss[0].getUS(), 0, ss[0], symbolTable, cm); + + // Process the operator + name = Operators.resolveSynonym(ss[1].getUS()); + } else { + errors.addError(children[0].getLocation(), "Unknown parameter declaration `" + children[0].getUS() + "'."); + } + + /*********************************************************************** + * The following code added by LL on 1 April 2007 to handle * recursively + * defined operators. * + ***********************************************************************/ + OpDefNode odn = null; + /*********************************************************************** + * Check if this operator has already been declared or defined. If * so, if it + * was declared in a RECURSIVE statement at this let/in * level and not yet + * defined, then set the OpDefNode's fields * appropriately, otherwise report an + * error. * + ***********************************************************************/ + SymbolNode symbolNode = symbolTable.resolveSymbol(name); + + if (symbolNode != null) { + /********************************************************************* + * The symbol has already been defined or declared. Check if it was * declared + * in a RECURSIVE statement. * + *********************************************************************/ + if (symbolNode instanceof OpDefNode) { + odn = (OpDefNode) symbolNode; + } + ; + if ((odn != null) && odn.inRecursive && (!odn.isDefined)) { + if (odn.letInLevel == curLevel) { + isRecursive = true; + + /***************************************************************** + * Check that the parameters of the definition match the ones in * the RECURSIVE + * declaration. * + *****************************************************************/ + boolean paramsMatch = (odn.getParams().length == params.length); + if (paramsMatch) { + for (int i = 0; i < params.length; i++) { + paramsMatch = (params[i].getArity() == 0); + } + ; + } + ; // if + if (!paramsMatch) { + errors.addError(treeNode.getLocation(), "Definition of " + odn.getName() + + " has different arity than " + "its RECURSIVE declaration."); + } + ; + + odn.setParams(params); + /*************************************************************** + * Here's where the params field of the OpDefNode is set for an * operator + * declared in a RECURSIVE statement. * + ***************************************************************/ + } // if (odn.letInLevel == curLevel) + else { + errors.addError(treeNode.getLocation(), + "Recursive operator " + name.toString() + " defined at wrong LET/IN level."); + odn = null; + } // else + } // if (odn != null) ... + else { + errors.addError(treeNode.getLocation(), + "Operator " + name.toString() + " already defined or declared."); + } + } // if (symbolNode != null) + + pushLS(); + /********************************************************************* + * Start fresh processing of labels. * + *********************************************************************/ + // Generate expression that is the body of the operator + ExprNode exp = generateExpression(children[2], cm); + + // Restore old context, popping off the context containing the parameters + symbolTable.popContext(); + + if (isRecursive) { + endOpDefNode(odn, exp, syntaxTreeNode); + } else { + // Create OpDefNode using symbolTable whose top context contains the + // parameter symbols + /******************************************************************** + * This comment appears to be incorrect, because it looks like the * parameter + * symbols were just popped off symbolTable. * + ********************************************************************/ + odn = new OpDefNode(name, UserDefinedOpKind, params, local, exp, cm, symbolTable, syntaxTreeNode, true, + null); + symbolNode = odn; + /******************************************************************* + * Keeping symbolNode for historical reasons--I'm too lazy to * rearrange the + * code to get rid of the redundant identifier. * + *******************************************************************/ + + setOpDefNodeRecursionFields(odn, cm); + + } // else + + Hashtable ht = popLabelNodeSet(); + /********************************************************************* + * Succeed or fail, we must execute popLabelNodeSet to match the * previous + * pushLS. * + *********************************************************************/ + if (odn != null) { + odn.setLabels(ht); + } + ; + /********************************************************************* + * If there was no error, then odn is an OpDefNode and we must set * it labels + * field. * + *********************************************************************/ + cm.appendDef(symbolNode); + /******************************************************************* + * Add the new OpDefNode to the current module's set of * definitions. * + *******************************************************************/ + // defs is non-null iff this definition is in the Let part of a + // Let-In expression + if (defs != null) + defs.addElement(symbolNode); + } // processOperator + + private final void processQuantBoundArgs(TreeNode[] treeNodeA, // node whose children include + // the bounded quants + int offset, // nodes to skip to get to first + // "quantifier" + FormalParamNode[][] odna, boolean[] bt, // set to true if arg is a tuple; + // otherwise false + ExprNode[] ena, ModuleNode cm) + /*********************************************************************** + * Despite the incoherent and/or incorrect comments, here's what I * think is + * going on: * * - odna, ena, and bt have the same length N. * * - treeNodeA is + * an array of nodes containing a subsequence of * N_QuantBound nodes of length + * N that starts at * treeNodeA[offset]. * * - odna, ena, and bt are set to the + * arguments for the OpApplNode * constructor that produces an OpApplNode for + * the operator * having this sequence of N_QuantBound nodes. * + ***********************************************************************/ + + throws AbortException { + // For each quantifier, evaluate the bound in the context of the + // current symbol table, i.e. before the quantified variables are + // added to the new context, since the quantified vars may not + // appear in the bounds. + for (int lvi = 0; lvi < bt.length; lvi++) { + // Make ss point to each N_QuantBound node in turn. + TreeNode[] ss = treeNodeA[offset + 2 * lvi].heirs(); + // the last element in ss is expression for the quantifier bound + ena[lvi] = generateExpression(ss[ss.length - 1], cm); + } + + // Now for each quantifier, process the variable names + for (int lvi = 0; lvi < bt.length; lvi++) { + TreeNode treeNode = treeNodeA[offset + 2 * lvi]; + + // The variable bound to the "quantifier" + TreeNode[] ss = treeNode.heirs(); + + if (ss[0].isKind(N_IdentifierTuple)) { // three elements only, go into node + bt[lvi] = true; + TreeNode[] sss = ss[0].heirs(); + odna[lvi] = new FormalParamNode[sss.length / 2]; + + for (int lvj = 0; lvj < sss.length / 2; lvj++) { + odna[lvi][lvj] = new FormalParamNode(sss[2 * lvj + 1].getUS(), 0, sss[2 * lvj + 1], symbolTable, + cm); + } + } else { // gotta be N_Identifier + bt[lvi] = false; + odna[lvi] = new FormalParamNode[(ss.length - 1) / 2]; + + for (int lvj = 0; lvj < (ss.length - 1) / 2; lvj++) { + odna[lvi][lvj] = new FormalParamNode(ss[2 * lvj].getUS(), 0, ss[2 * lvj], symbolTable, cm); + } + } + } + } + + // Process a function definition + private final void processFunction(TreeNode treeNode, Vector defs, ModuleNode cm) throws AbortException { + TreeNode syntaxTreeNode = treeNode; + boolean local = syntaxTreeNode.zero() != null; + TreeNode[] ss = syntaxTreeNode.one(); + // Heirs to N_FunctionDefinition node + int ql = (ss.length - 4) / 2; + // number of QuantBound's + OpApplNode oan; + OpDefNode odn = null; + FormalParamNode[][] quants = new FormalParamNode[ql][0]; + FormalParamNode[] fcnDeclForRecursion = new FormalParamNode[1]; + /********************************************************************* + * This is an array of length 1 instead of just an OpDeclNode * because it is + * needed in such an array to pass as an argument to * new OpApplNode. * + *********************************************************************/ + boolean[] tuples = new boolean[ql]; + ExprNode[] domains = new ExprNode[ql]; + ExprNode[] lhs = new ExprNode[1]; + Context newContext = new Context(moduleTable, errors); + boolean isRecursive = false; + /********************************************************************* + * Will be set to true if this operator was declared in a RECURSIVE * statement. + * * + *********************************************************************/ + + // Fill arrays with quantifier-related information; must be called + // in scope of *new* context, since it adds parameter symbols to + // the context. + symbolTable.pushContext(newContext); + processQuantBoundArgs(ss, 2, quants, tuples, domains, cm); + + UniqueString name = ss[0].getUS(); + SymbolNode symbolNode = symbolTable.resolveSymbol(name); + + // This is in anticipation of the possibility that the function is + // recursive. We are creating a new bound symbol of the same name + // as the function to stand in the body for the function. The + // arity of the bound symbol is 0 because a function formally has + // arity 0 as an operator, even if it has several arguments as a + // function. + /*********************************************************************** + * If the function name is already defined (which should happen only * if it was + * declared in a RECURSIVE statement, then there is no need * to add this + * OpDeclNode to the symbol table. As near as I can tell * (which might not be + * near enough), this OpDeclNode's entry in the * symbol table is needed only so + * the name will be declared in case * of a recursive call. The check for + * whether a function call in the * body actually is recursive is made by + * calling the recursionCheck * method of the Function subclass to see if the + * OpApplNode is in the * Function object's funcStack. * + ***********************************************************************/ + SymbolTable st = null; + if (symbolNode == null) { + st = symbolTable; + } + ; + fcnDeclForRecursion[0] = new FormalParamNode(name, 0, treeNode, st, cm); + symbolTable.popContext(); + + // Create OpApplNode to hold the function body; type is assumed to + // be non-recursive function (OP_nrfs); if the body is recursive, + // this will be discovered during generateExpression() for the + // body + oan = new OpApplNode(OP_nrfs, fcnDeclForRecursion, new ExprNode[0], quants, tuples, domains, syntaxTreeNode, + cm); + // constructor 5 + + /*********************************************************************** + * The following code added by LL on 19 April 2007 to handle * recursively + * defined operators. * + ***********************************************************************/ + if (symbolNode == null) { + odn = new OpDefNode(ss[0].getUS(), UserDefinedOpKind, nullParam, local, oan, cm, symbolTable, + syntaxTreeNode, true, null); + setOpDefNodeRecursionFields(odn, cm); + } else { + /********************************************************************* + * The symbol has already been defined or declared. Check if it was * declared + * in a RECURSIVE statement. * + *********************************************************************/ + if (symbolNode instanceof OpDefNode) { + odn = (OpDefNode) symbolNode; + } + ; + if ((odn != null) && odn.inRecursive && (!odn.isDefined)) { + if (odn.letInLevel == curLevel) { + isRecursive = true; + /***************************************************************** + * Check that the RECURSIVE declaration had no paramters. * + *****************************************************************/ + if (odn.getArity() == 0) { + endOpDefNode(odn, oan, syntaxTreeNode); + } else { + /************************************************************* + * RECURSIVE declaration had parameters. * + *************************************************************/ + errors.addError(treeNode.getLocation(), "Function " + odn.getName() + + " has operator arguments in " + "its RECURSIVE declaration."); + } + ; + } // if (odn.letInLevel == curLevel) + else { + errors.addError(treeNode.getLocation(), + "Recursive function " + name.toString() + " defined at wrong LET/IN level."); + odn = null; + } // else + } // if (odn != null) ... + else { + errors.addError(treeNode.getLocation(), + "Function name `" + name.toString() + "' already defined or declared."); + } + } // else (symbolNode != null) + + // Create OpDefNode to hold the function definition, including + // reference to the function body ("oan") + if (odn != null) { + /********************************************************************* + * There was no error, so the OpDefNode was created. * + *********************************************************************/ + cm.appendDef(odn); + + // defs is non-null iff this function definition is in the Let + // part of a Let-In expression. If so, then we have to accumulate + // these defs in a vector. + if (defs != null) + defs.addElement(odn); + + // Function body must be processed in the scope of the new + // context, including the parms + symbolTable.pushContext(newContext); + + } + ; // if (odn != null) + + // Keep stack of nested function defs to enable detection of recursion + functions.push(ss[0].getUS(), oan); + + // Create semantic graph function body in the inner context including parameters + pushLS(); + pushFormalParams(flattenParams(quants)); + /********************************************************************* + * Push a new empty label set onto LS, and push the function * definition's + * formal parameters onto Last(LS).paramSeq for * processing the function body. + * * + *********************************************************************/ + lhs[0] = generateExpression(ss[ss.length - 1], cm); + popFormalParams(); + /********************************************************************* + * Pop the formal params from Last(LS).paramSeq, which should now be * empty. + * This isn't really necessary, since we're going to pop the * LS stack below, + * but I hate to have a push without a pop. * + *********************************************************************/ + Hashtable ht = popLabelNodeSet(); + /********************************************************************* + * The matching pop for the pushLS above. * + *********************************************************************/ + if (odn != null) { + odn.setLabels(ht); + } + ; + /********************************************************************* + * If there was no error and we created an OpDefNode, then set its * label set. + * * + *********************************************************************/ + functions.pop(); + + oan.setArgs(lhs); + /*********************************************************************** + * Test for odn != null added 2 Jul 2009 to avoid bug that caused * popping of + * empty symbol table when the function name was * already declared to be a + * variable. * + ***********************************************************************/ + if (odn != null) { + // Restore old context + symbolTable.popContext(); + } + + // if the function body turned out to be non-recursive, then we + // should null-out the fcnDefForRecursion ref put in place above, + // since it is unnecessary for a nonrecursive func + if (oan.getOperator().getName() == OP_nrfs) { + oan.makeNonRecursive(); + } + } // end processFunction() + + private final ExprNode processLetIn(TreeNode treeNode, TreeNode[] children, ModuleNode cm) throws AbortException { + TreeNode[] syntaxTreeNode = children[1].heirs(); // extract LetDefinitions + Vector defVec = new Vector(4); + Vector instVec = new Vector(1); + + Context letCtxt = new Context(moduleTable, errors); + symbolTable.pushContext(letCtxt); + /********************************************************************* + * Create a new sub-Context for the IN expression, containing the * LET + * definitions * + *********************************************************************/ + + /*********************************************************************** + * Increment curLevel. * + ***********************************************************************/ + if (curLevel < MaxLetInLevel) { + curLevel++; + } else { + errors.addAbort(treeNode.getLocation(), "LETs nested more than " + MaxLetInLevel + " deep."); + } + ; + unresolvedCnt[curLevel] = 0; + /********************************************************************* + * Will not have been initialized if we haven't yet reached this * LET/IN + * nesting depth. * + *********************************************************************/ + + for (int lvi = 0; lvi < syntaxTreeNode.length; lvi++) { + /********************************************************************* + * Note: LL changed from an "if" and a sequence of "elseif"s to a * switch + * statement on 7 Apr 2007 when adding the N_Recursive case. * + *********************************************************************/ + switch (syntaxTreeNode[lvi].getKind()) { + case N_OperatorDefinition: + processOperator(syntaxTreeNode[lvi], defVec, cm); + break; + + case N_FunctionDefinition: + processFunction(syntaxTreeNode[lvi], defVec, cm); + break; + + case N_ModuleDefinition: + processModuleDefinition(syntaxTreeNode[lvi], defVec, instVec, cm); + break; + + case N_Recursive: + processRecursive(syntaxTreeNode[lvi], cm); + break; + + default: + errors.addAbort(syntaxTreeNode[lvi].getLocation(), + "Internal error: found unexpected syntax " + "tree node in LET."); + } // switch + } // for + + checkForUndefinedRecursiveOps(cm); + + /*********************************************************************** + * Decrement curLevel. * + ***********************************************************************/ + curLevel--; + if (curLevel < 0) { + curLevel = 0; + } + ; + + ExprNode body = generateExpression(children[3], cm); + + /*********************************************************************** + * Convert from Vector to array of SymbolNode, whose elements may be * OpDefNode + * or ThmOrAssumpDefNode objects. * + ***********************************************************************/ + SymbolNode[] opDefs = new SymbolNode[defVec.size()]; + for (int i = 0; i < opDefs.length; i++) { + opDefs[i] = (SymbolNode) defVec.elementAt(i); + } + + InstanceNode[] insts = new InstanceNode[instVec.size()]; + for (int i = 0; i < insts.length; i++) { + insts[i] = (InstanceNode) instVec.elementAt(i); + } + LetInNode letIn = new LetInNode(treeNode, opDefs, insts, body, letCtxt); + symbolTable.popContext(); + return letIn; + } // end processLetIn + + private final ExprNode generateExpression(TreeNode treeNode, ModuleNode cm) throws AbortException { + /*********************************************************************** + * Must return an ExprNode that represents an expression, and not a * labeled + * ASSUME/PROVE * + ***********************************************************************/ + return generateExpressionOrLAP(treeNode, cm, false); + } + + private final ExprNode generateExpressionOrLAP(TreeNode treeNode, ModuleNode cm, boolean allowLabeledAP) + /*********************************************************************** + * Can return a LabelNode labeling an ASSUME/PROVE iff allowLabeledAP * = true. + * Otherwise, it can return only an ExprNode that represents * an expression. * + ***********************************************************************/ + throws AbortException { + TreeNode[] children = treeNode.heirs(); + TreeNode[] ss = null; // grandchildren + SymbolNode opn = null; + TreeNode op = null; + GenID genID; + ExprOrOpArgNode[] sns; // a ExprNode list used for arguments + + switch (treeNode.getKind()) { + + case N_Real: + return new DecimalNode(children[0].getImage(), children[2].getImage(), treeNode); + + case N_Number: + return new NumeralNode(children[0].getImage(), treeNode); + + case N_String: + return new StringNode(treeNode, true); + + case N_ParenExpr: + return generateExpression(children[1], cm); + + case N_InfixExpr: + genID = generateGenID(children[1], cm); + + sns = new ExprOrOpArgNode[2]; + opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); + if (opn == null) { + errors.addError(treeNode.getLocation(), + "Couldn't resolve infix operator symbol `" + genID.getCompoundIDUS() + "'."); + return null; + } + + sns[0] = generateExpression(children[0], cm); + sns[1] = generateExpression(children[2], cm); + return new OpApplNode(opn, sns, treeNode, cm); + + case N_PrefixExpr: + // 1 get gen operator node + ss = children[0].heirs(); + + // 2 get rightmost part of the possibly compound Op itself; + op = ss[1]; + genID = generateGenID(children[0], cm, true); + sns = new ExprOrOpArgNode[1]; + opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); + + if (opn == null) { + errors.addError(treeNode.getLocation(), + "Couldn't resolve prefix operator symbol `" + genID.getCompoundIDUS() + "'."); + return null; + } + + sns[0] = generateExpression(children[1], cm); + return new OpApplNode(opn, sns, treeNode, cm); // constructor 2 + + case N_PostfixExpr: + genID = generateGenID(children[1], cm); + + sns = new ExprNode[1]; + opn = symbolTable.resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); + if (opn == null) { + errors.addError(treeNode.getLocation(), + "Couldn't resolve postfix " + "operator symbol `" + genID.getCompoundIDUS() + "'."); + return null; + } + + sns[0] = generateExpression(children[0], cm); + return new OpApplNode(opn, sns, treeNode, cm); // constructor 2 + + case N_Times: // or cartesian product + sns = new ExprNode[(children.length + 1) / 2]; + + for (int lvi = 0; lvi < sns.length; lvi++) { + sns[lvi] = generateExpression(children[2 * lvi], cm); + } + return new OpApplNode(OP_cp, sns, treeNode, cm); // constructor 3 + + case N_SetEnumerate: + int size = (children.length - 1) / 2; + sns = new ExprNode[size]; + for (int lvi = 0; lvi < size; lvi++) { + sns[lvi] = generateExpression(children[2 * lvi + 1], cm); + } + return new OpApplNode(OP_se, sns, treeNode, cm); // constructor 3 + + case N_GeneralId: + // This is a zero-ary operator; it should show in the syntax + // tree as an OpApp, but it does not. Hence, an OpApplication + // node with zero arguments must be constructed for it + // if we get here, the GeneralID really is an OpApplication with 0 + // primary arguments, but with any number of prefix arguments + + // process the generalized identifier, complete with its + // embedded argument lists (if any) + + /********************************************************************* + * If the N_GeneralId represents the identifier "@", then check for * errors and + * return an AtNode if none. * + *********************************************************************/ + SyntaxTreeNode sTreeNode = (SyntaxTreeNode) treeNode; + if ((sTreeNode.heirs()[1].getKind() == IDENTIFIER) && (sTreeNode.heirs()[1].getUS() == AtUS) + && (((SyntaxTreeNode) sTreeNode.heirs()[0]).heirs().length == 0)) { + if (excStack.empty() || excSpecStack.empty()) { + // if either stack is empty, then @ used in improper EXCEPT context + errors.addError(sTreeNode.getLocation(), "@ used where its meaning is not defined."); + return nullOAN; + } else { + // So, the context for @ is proper, then construct the + // AtNode and return it + return new AtNode((OpApplNode) excStack.peek(), (OpApplNode) excSpecStack.peek()); + } + } + ; + + ExprNode retVal = (ExprNode) selectorToNode(genIdToSelector(sTreeNode), 0, false, false, cm); + + /********************************************************************* + * A function definition generates an OpDefNode whose body is an * OpApplNode + * whose operator is either $RecursiveFcnSpec or * $NonRecursiveFcnSpec, the + * latter when the definition is * recursive. However, in SANY1 the definition * + * * f[x \in S] == ... * * was found to be recursive only if a subexpression + * f[...] occurs * in the body. It was not marked as recursive if another + * instance * of f occurs, such as Foo(f). To fix this, we need to check if * + * this genID is actually the Identifier of a function currently * being + * defined. The following call to functions.recursionCheck * does that. * + *********************************************************************/ + if (retVal.getKind() == OpApplKind) { + functions.recursionCheck(((OpApplNode) retVal).getOperator().getName()); + } + ; + + return retVal; + /************************** + * old version genID = generateGenID(treeNode, cm); + * + * // if the symbol is "@" then check for errors and // return an AtNode if + * none. if (genID.getCompoundIDUS() == S_at) { if (excStack.empty() || + * excSpecStack.empty()) { // if either stack is empty, then @ used in improper + * EXCEPT context errors.addError(treeNode.getLocation(), "@ used where its + * meaning is not defined."); } else { // So, the context for @ is proper, then + * construct the // AtNode and return it return new + * AtNode((OpApplNode)excStack.peek(), (OpApplNode)excSpecStack.peek()); } } + * else if (genID.getFullyQualifiedOp() == null || genID.getArgs() == null) { // + * If it is not an "@" symbol, it may still be an unresolved symbol return + * nullOAN; } else if (genID.getFullyQualifiedOp().getKind() == ModuleKind) { + * errors.addError( treeNode.getLocation(), "Module name '" + + * genID.getFullyQualifiedOp().getName() + "' used as operator."); return + * nullOAN; } else { // but if there are no problems then we are in a situation + * in // which return the appropriate OpApplNode an N_GenID node in // the + * syntax tree really stands for an OpApplication + * + * // ********************************************************************* // * + * Modified on 20 Apr 2007 by LL to correct the following bug. * // * * // * A + * function definition generates an OpDefNode whose body is an * // * OpApplNode + * whose operator is either $RecursiveFcnSpec or * // * $NonRecursiveFcnSpec, + * the latter when the definition is * // * recursive. However, the definition * + * // * * // * f[x \in S] == ... * // * * // * was found to be recursive only if + * a subexpression f[...] occurs * // * in the body. It was not marked as + * recursive if another instance * // * of f occurs, such as Foo(f). To fix + * this, we need to check if * // * this genID is actually the Identifier of a + * function currently * // * being defined. The call to functions.recursionCheck + * was added * // * here to do that. * // + * ********************************************************************* + * SymbolNode symNode = genID.getFullyQualifiedOp() ; + * + * if (symNode.getKind() == ThmOrAssumpDefKind) { + * errors.addError(treeNode.getLocation(), "Theorem or Assumption name used as + * expression.") ; }; OpApplNode retVal = // return new OpApplNode(symNode, + * genID.getArgs(), treeNode, cm); functions.recursionCheck(symNode.getName()); + * return retVal ; } + ******************************* + * old version + ******************/ + case N_OpApplication: + // for an operator with arguments + // Note: in neither case can this be an operator passed as an argument; + // the opAppl argument forces the return of an Operator application + // operators passed as arguments generate OpArg nodes, and that + // can happen only in certain contexts, not in every context where an + // expression can occur, which is the context we are in here + + SyntaxTreeNode genIdNode = (SyntaxTreeNode) treeNode.heirs()[0]; + SyntaxTreeNode opApplNode = (SyntaxTreeNode) treeNode.heirs()[1]; + + /********************************************************************* + * First a check. It appears that the children of an OpApplication * node must + * be a GeneralId node and an OpArgs node, but let's be * sure. * + *********************************************************************/ + if ((genIdNode.getKind() != N_GeneralId) || (opApplNode.getKind() != N_OpArgs)) { + errors.addAbort(treeNode.getLocation(), "Internal error: OpAppl node with unexpected children.", true); + } + ; + + Selector sel = genIdToSelector(genIdNode); + sel.args[sel.args.length - 1] = opApplNode; + sel.selSTN = (SyntaxTreeNode) treeNode; + /******************************************************************* + * For error reporting, make the syntax tree node of the selector * include both + * the general ID node and its argument. * + *******************************************************************/ + return (ExprNode) selectorToNode(sel, 0, false, false, cm); + + /***************** + * old version ********************* return generateOpAppl(treeNode, cm); + ************************/ + + case N_Tuple: + size = (children.length - 1) / 2; + sns = new ExprNode[size]; + for (int lvi = 0; lvi < size; lvi++) { + sns[lvi] = generateExpression(children[2 * lvi + 1], cm); + } + return new OpApplNode(OP_tup, sns, treeNode, cm); // Constructor 3 + + case N_FcnAppl: // Apparent function application + // Number of arguments to the apparent func app + int numArgs = (children.length - 2) / 2; + + // Function appl involves two semantic nodes: 1 for function, + // and 1 for arg or args tuple. + sns = new ExprNode[2]; + + // Generate expression tree for the function itself + sns[0] = generateExpression(children[0], cm); + + if (sns[0] == null) { + return null; + } + ; + /******************************************************************* + * sns[0] can be null if the parsing the function generates an * error (which is + * the case if the function is missing). * Added by LL on 29 Feb 2008 * + *******************************************************************/ + + // If the function is an OpApplNode (and could it be otherwise?) + if (sns[0].getKind() == OpApplKind) { + // Note if this is a recursive function, and change the top level + functions.recursionCheck(((OpApplNode) sns[0]).getOperator().getName()); + } + + // We next check that the number of arguments to a user-defined + // function is correct, if possible. + + // Retrieve the expression that represents the function being + // applied, i.e. the 1st arg to $FcnApply + ExprOrOpArgNode fcn = sns[0]; + + // The entire next conditional is for one purpose: to make sure + // that a function symbol is applied to the right number of + // arguments, when it is possible to do that during semantic + // analysis. This means that if a function is declared with, + // say, 3 parameters, e.g. "f[a,b,c] == {a,b,c}", then it is + // never used with 2 or 4 arguments. However, it can appear + // with zero arguments as the expression "f" (not as "f[]"), and + // it can appear with one argument, as in "f[e]", because e + // might be a 3-tuple value. (Whether it always is or not + // cannot be determined at the time of semantic analysis.) + // Furthermore a function declared with exactly one parameter + // can appear with any number of argument expressions because, + // e.g. f[1,2,3,4] is considered just an alternate way of + // writing f[<<1,2,3,4>>], so there is really just one argument + // value. + + // If it is an OpApplNode (as opposed to, say, an OpDeclNode) + if (fcn instanceof OpApplNode) { + // Retrieve the function being applied + SymbolNode funcOperator = ((OpApplNode) fcn).getOperator(); + + // If the function being applied is a user-defined function + // (as opposed to OpDeclNode, FormalParamNode, builtin + // operator, or expression) + if (funcOperator instanceof OpDefNode && funcOperator.getKind() == UserDefinedOpKind) { + // Retrieve the function body expression + ExprOrOpArgNode funcBody = ((OpDefNode) funcOperator).getBody(); + + // if the function body is an OpApplNode (as opposed to, + // say, NumeralNode, DecimalNode, etc.) + if (funcBody instanceof OpApplNode && (((OpApplNode) funcBody).getOperator().getName() == OP_nrfs + || ((OpApplNode) funcBody).getOperator().getName() == OP_rfs)) { + + // find out how many arguments it is SUPPOSED to have + int numParms = ((OpApplNode) funcBody).getNumberOfBoundedBoundSymbols(); + + // If the function appears with numArgs >= 2 argument + // expressions, it must be declared with exactly numArgs + // parameters; and a function with numParms parameters in + // its definition should be applied to exactly numParms + // expressions, or 1 expression (representing arguments in + // tuple form), or 0 expressions (representing the + // function itself). Note: one cannot define a function + // with 0 arguments in TLA+. + if (numArgs >= 2 && numParms != numArgs) { + errors.addError(treeNode.getLocation(), + "Function '" + ((OpApplNode) sns[0]).getOperator().getName() + "' is defined with " + + numParms + " parameters, but is applied to " + numArgs + " arguments."); + return nullOAN; + } // end if + } // end if + } // end if + } // end if + + // Assert.check(numArgs > 0); + if (numArgs == 1) { + sns[1] = generateExpression(children[2], cm); + } else { + // If there is more than one arg we have to create a tuple for the arguments. + ExprOrOpArgNode[] exprs = new ExprNode[numArgs]; // One for each of the arguments + + // For each argument... + for (int lvi = 0; lvi < numArgs; lvi++) { + // Create the expression for that argument + exprs[lvi] = generateExpression(children[2 + 2 * lvi], cm); + } + // Create an application of $Tuple + sns[1] = new OpApplNode(OP_tup, exprs, treeNode, cm); + } + // Create the function application node. + return new OpApplNode(OP_fa, sns, treeNode, cm); + + case N_UnboundOrBoundChoose: + return processChoose(treeNode, children, cm); + + case N_BoundQuant: + return processBoundQuant(treeNode, children, cm); + + case N_UnboundQuant: + return processUnboundQuant(treeNode, children, cm); + + case N_IfThenElse: + sns = new ExprNode[3]; + sns[0] = generateExpression(children[1], cm); + sns[1] = generateExpression(children[3], cm); + sns[2] = generateExpression(children[5], cm); + return new OpApplNode(OP_ite, sns, treeNode, cm); + + case N_Case: + return processCase(treeNode, children, cm); + + case N_DisjList: + case N_ConjList: + sns = new ExprNode[children.length]; + for (int lvi = 0; lvi < sns.length; lvi++) { + sns[lvi] = generateExpression(children[lvi].heirs()[1], cm); + } + if (treeNode.isKind(N_DisjList)) + return new OpApplNode(OP_dl, sns, treeNode, cm); + else + return new OpApplNode(OP_cl, sns, treeNode, cm); + + case N_RecordComponent: // really RcdSelect in the API + sns = new ExprNode[2]; + sns[0] = generateExpression(children[0], cm); + sns[1] = new StringNode(children[2], false); + return new OpApplNode(OP_rs, sns, treeNode, cm); + + case N_SetOfFcns: /* [S -> T] */ + sns = new ExprNode[2]; + sns[0] = generateExpression(children[1], cm); + sns[1] = generateExpression(children[3], cm); + + return new OpApplNode(OP_sof, sns, treeNode, cm); + + case N_SubsetOf: + return processSubsetOf(treeNode, children, cm); + + case N_SetOfAll: + return processSetOfAll(treeNode, children, cm); + + case N_RcdConstructor: + return processRcdForms(OP_rc, treeNode, children, cm); + + case N_SetOfRcds: + return processRcdForms(OP_sor, treeNode, children, cm); + + case N_FcnConst: + return processFcnConst(treeNode, children, cm); + + case N_ActionExpr: + case N_FairnessExpr: + return processAction(treeNode, children, cm); + + case N_Except: + return processExcept(treeNode, children, cm); + + case N_LetIn: + return processLetIn(treeNode, children, cm); + + case N_Lambda: + errors.addError(treeNode.getLocation(), "LAMBDA expression used where an expression is required."); + return null; + + case N_Label: + LabelNode ln = generateLabel(treeNode, cm); + if (ln.isAssumeProve && !allowLabeledAP) { + errors.addError(treeNode.getLocation(), "Labeled ASSUME/PROVE used where an expression is required."); + } + return ln; + + default: + errors.addError(treeNode.getLocation(), "Unsupported expression type `" + treeNode.getImage() + "'."); + return null; + + } // end switch + + } // end generateExpression() + + /*************************************************************************** + * The following variables are used in the processing of ASSUME/PROVE * nodes, + * and the labels that lie within them. * + ***************************************************************************/ + private int assumeProveDepth = 0; + /*********************************************************************** + * The nesting depth of ASSUME/PROVEs within which the node corrently * being + * processed lies. In * * THEOREM ASSUME P PROVE Q * * the nodes for P and Q are + * at depth 1 (not 0). * + ***********************************************************************/ + + private ThmOrAssumpDefNode currentGoal = null; + private int currentGoalClause; + /*********************************************************************** + * currentGoal is the named theorem or proof-step node within * which lies the + * current node that is being processed, or null if * we're not inside such a + * step. If currentGoal != null, and we're * within an ASSUME/PROVE step (which + * is true iff assumeProveDepth > * 0), then then currentGoalClause equals the + * clause of within which * the node being processed lies. (If we're processing + * Q in ASSUME P * PROVE Q, then Q = 1.) * + ***********************************************************************/ + + private static final int maxAPDepth = 100; + /*********************************************************************** + * Maximum allowed nesting depth of ASSUME/PROVES. 100 ought to * suffice. * + ***********************************************************************/ + + private boolean[] inScopeOfAPDecl = new boolean[maxAPDepth]; + + /*********************************************************************** + * For all i \leq assumeProveDepth, inScopeOfAPDecl[i] = true iff the * node + * currently being processed lies within a declaration made at * + * assumeProveDepth = i. Thus in * * THEOREM ASSUME NEW x \in S, * P, * ASSUME R + * , ACTION A PROVE T * PROVE Q * * inScopeOfAPDecl[1] equals false when S is + * being processed and * equals true when P, Q, R, and T are being processed. * + * * inScopeOfAPDecl[2] equals false when R is being processed and true * when T + * is being processed. * + ***********************************************************************/ + + private boolean noLabelsAllowed() { + /*********************************************************************** + * This returns true if we are inside an ASSUME/PROVE node where a * label is + * not allowed because we are in the scope of a declaration * from an inner + * ASSUME/PROVE. * + ***********************************************************************/ + for (int i = 2; i <= assumeProveDepth; i++) { + if (inScopeOfAPDecl[i]) { + return true; + } + ; + } + ; + return false; + } + + private final boolean illegalLabelRef(LabelNode ln, SyntaxTreeNode stn) throws AbortException { + /*********************************************************************** + * True iff we are currently in a point where a reference to this * label is + * illegal because it lies inside an ASSUME/PROVE clause from * outside the + * scope of a symbol it may contain. See the comments in * AssumeProveNode.java + * for an explanation of this method. * + ***********************************************************************/ + ThmOrAssumpDefNode goal = ln.goal; + if (goal == null) { + return false; + } + ; + if ((goal.getBody() == null) || (goal.getBody().getKind() != AssumeProveKind)) { + errors.addAbort(stn.getLocation(), + "Internal error: Expecting label to be in AssumeProveNode, " + "but it's not."); + } + ; + AssumeProveNode ap = (AssumeProveNode) goal.getBody(); + return ap.inScopeOfDecl[ln.goalClause] && (goal.isSuffices() == ap.inProof); + } // illegalLabelRef + + private final boolean illegalAPPosRef(AssumeProveNode ap, int pos) { + /*********************************************************************** + * True iff it is illegal for the node currently being processed to * access the + * clause number pos of AssumeProve node ap because it is * not in the scope of + * symbols declared in previous ASSUME clauses of * ap. See the comments in + * AssumeProveNode.java for an explanation of * this method. * + ***********************************************************************/ + return ap.inScopeOfDecl[pos - 1] && ((ap.getGoal() == null) || (ap.getGoal().isSuffices() == ap.inProof)); + } // XXXX Currently, this handles both label and positional subexpression // specifiers. To handle positional ones, we need to know what // the position is. // private final boolean withinScopeOf(SemanticNode goal) { - /************************************************************************* - * Returns true iff the node currently being processed lies within the * - * scope of (the declarations made in the ASSUME clauses) of goal, which * - * will be a TheoremNode or a proof-step node. * - * * - * XXXXX Dummy implementation for now. * - *************************************************************************/ + /************************************************************************* + * Returns true iff the node currently being processed lies within the * scope + * of (the declarations made in the ASSUME clauses) of goal, which * will be a + * TheoremNode or a proof-step node. * * XXXXX Dummy implementation for now. * + *************************************************************************/ // return true; // if (goal == null) {return true;} ; // return false ; // } - // The following objects added 10 Feb 2011 by LL are used to check that - // a []ASSUME does not lie within the scope of (the assumptions of) - // an ordinary ASSUME. It does this by declaring the dummy OpDeclNode - // InAssumeDummyNode as if it were declared within the ASSUME and then - // checking if it's defined where the []ASSUME is used. - private final static UniqueString S_InAssume = UniqueString.uniqueStringOf("$$InAssume"); - private final static OpDeclNode InAssumeDummyNode = - new OpDeclNode(S_InAssume, 0, 0, 0, null, null, null) ; - - private final AssumeProveNode - generateAssumeProve(TreeNode treeNode, ModuleNode cm) - /*********************************************************************** - * Added by LL on 17 Mar 2007. * - ***********************************************************************/ - throws AbortException { - // The following flag is used to record if this is a - // Following code added on 9 Nov 2009 so that the goal - // field of the AssumeProveNode is null unless this is - // a top-level Assume/Prove. - ThmOrAssumpDefNode cg = null ; - if (assumeProveDepth == 0) { - cg = currentGoal; - } ; - assumeProveDepth++ ; - AssumeProveNode apn = new AssumeProveNode(treeNode, cg) ; - TreeNode[] children = treeNode.heirs(); - int numOfChildren = children.length; - if (numOfChildren % 2 != 0) { - throw new WrongInvocationException("AssumeProve has odd number of children"); } ; - int numOfAssumptions = (numOfChildren - 2) / 2 ; - // Check if this is a []ASSUME and that the PROVE matches - // the ASSUME. - boolean isBoxAssumeProve = false; - String proveString = children[children.length -2].getImage(); - if (children[0].getImage().equals("[]ASSUME")) { - isBoxAssumeProve = true; - if (!proveString.equals("[]PROVE")) { - errors.addError(children[0].getLocation(), - "[]ASSUME matched by PROVE instead of []PROVE"); - } - } else { - if (!proveString.equals("PROVE")) { - errors.addError(children[0].getLocation(), - "ASSUME matched by []PROVE instead of PROVE"); - } - } - apn.setIsBoxAssumeProve(isBoxAssumeProve); - - apn.assumes = new LevelNode[numOfAssumptions] ; - boolean inDeclScope = false ; - /****************************************************************** - * Set true when after we've processed a declaration. * - ******************************************************************/ - apn.inScopeOfDecl = new boolean[numOfAssumptions + 1] ; - apn.inScopeOfDecl[0] = false ; - inScopeOfAPDecl[assumeProveDepth] = false ; - if (assumeProveDepth != 1) { - /****************************************************************** - * The context is pushed by the top-level caller of * - * generateAssumeProve, which is processTheorem. * - ******************************************************************/ - symbolTable.pushContext(new Context(moduleTable, errors)) ; - /****************************************************************** - * I don't understand exactly what's going on here, but this * - * seems to be the magic incantation for starting a new context * - * into which declarations among the assumptions should be put * - * for interpreting expressions later in the assumption list and * - * in the "prove" expression. * - ******************************************************************/ - } // if - - if (isBoxAssumeProve) { - if (symbolTable.resolveSymbol(S_InAssume) != null) { - errors.addError(children[0].getLocation(), - "[]ASSUME used within the scope of an ordinary ASSUME's assumptions"); - } - } else { - if (symbolTable.resolveSymbol(S_InAssume) == null) { - symbolTable.addSymbol(S_InAssume, InAssumeDummyNode); - } - } - - if (assumeProveDepth == 1) {currentGoalClause = 0 ; } ; - for (int i = 0 ; i < numOfAssumptions ; i++) { - /****************************************************************** - * The current assumption is assumption number i+1 (in human * - * numbering). * - ******************************************************************/ - apn.inScopeOfDecl[i+1] = apn.inScopeOfDecl[i] ; - TreeNode tn = children[2*i + 1] ; - switch (tn.getKind()) { - case N_AssumeProve : - apn.assumes[i] = generateAssumeProve(tn, cm) ; - break ; - case N_NewSymb : - apn.assumes[i] = generateNewSymb(tn, cm) ; - apn.inScopeOfDecl[i+1] = true ; - inScopeOfAPDecl[assumeProveDepth] = true ; - OpDeclNode[] odn = new OpDeclNode[1] ; - odn[0] = ((NewSymbNode) apn.assumes[i]).getOpDeclNode() ; - break ; - default : - /************************************************************** - * Should be an expression node or a labeled ASSUME/PROVE. * - **************************************************************/ + // The following objects added 10 Feb 2011 by LL are used to check that + // a []ASSUME does not lie within the scope of (the assumptions of) + // an ordinary ASSUME. It does this by declaring the dummy OpDeclNode + // InAssumeDummyNode as if it were declared within the ASSUME and then + // checking if it's defined where the []ASSUME is used. + private final static UniqueString S_InAssume = UniqueString.uniqueStringOf("$$InAssume"); + private final static OpDeclNode InAssumeDummyNode = new OpDeclNode(S_InAssume, 0, 0, 0, null, null, null); + + private final AssumeProveNode generateAssumeProve(TreeNode treeNode, ModuleNode cm) + /*********************************************************************** + * Added by LL on 17 Mar 2007. * + ***********************************************************************/ + throws AbortException { + // The following flag is used to record if this is a + // Following code added on 9 Nov 2009 so that the goal + // field of the AssumeProveNode is null unless this is + // a top-level Assume/Prove. + ThmOrAssumpDefNode cg = null; + if (assumeProveDepth == 0) { + cg = currentGoal; + } + ; + assumeProveDepth++; + AssumeProveNode apn = new AssumeProveNode(treeNode, cg); + TreeNode[] children = treeNode.heirs(); + int numOfChildren = children.length; + if (numOfChildren % 2 != 0) { + throw new WrongInvocationException("AssumeProve has odd number of children"); + } + ; + int numOfAssumptions = (numOfChildren - 2) / 2; + // Check if this is a []ASSUME and that the PROVE matches + // the ASSUME. + boolean isBoxAssumeProve = false; + String proveString = children[children.length - 2].getImage(); + if (children[0].getImage().equals("[]ASSUME")) { + isBoxAssumeProve = true; + if (!proveString.equals("[]PROVE")) { + errors.addError(children[0].getLocation(), "[]ASSUME matched by PROVE instead of []PROVE"); + } + } else { + if (!proveString.equals("PROVE")) { + errors.addError(children[0].getLocation(), "ASSUME matched by []PROVE instead of PROVE"); + } + } + apn.setIsBoxAssumeProve(isBoxAssumeProve); + + apn.assumes = new LevelNode[numOfAssumptions]; + boolean inDeclScope = false; + /****************************************************************** + * Set true when after we've processed a declaration. * + ******************************************************************/ + apn.inScopeOfDecl = new boolean[numOfAssumptions + 1]; + apn.inScopeOfDecl[0] = false; + inScopeOfAPDecl[assumeProveDepth] = false; + if (assumeProveDepth != 1) { + /****************************************************************** + * The context is pushed by the top-level caller of * generateAssumeProve, which + * is processTheorem. * + ******************************************************************/ + symbolTable.pushContext(new Context(moduleTable, errors)); + /****************************************************************** + * I don't understand exactly what's going on here, but this * seems to be the + * magic incantation for starting a new context * into which declarations among + * the assumptions should be put * for interpreting expressions later in the + * assumption list and * in the "prove" expression. * + ******************************************************************/ + } // if + + if (isBoxAssumeProve) { + if (symbolTable.resolveSymbol(S_InAssume) != null) { + errors.addError(children[0].getLocation(), + "[]ASSUME used within the scope of an ordinary ASSUME's assumptions"); + } + } else { + if (symbolTable.resolveSymbol(S_InAssume) == null) { + symbolTable.addSymbol(S_InAssume, InAssumeDummyNode); + } + } + + if (assumeProveDepth == 1) { + currentGoalClause = 0; + } + ; + for (int i = 0; i < numOfAssumptions; i++) { + /****************************************************************** + * The current assumption is assumption number i+1 (in human * numbering). * + ******************************************************************/ + apn.inScopeOfDecl[i + 1] = apn.inScopeOfDecl[i]; + TreeNode tn = children[2 * i + 1]; + switch (tn.getKind()) { + case N_AssumeProve: + apn.assumes[i] = generateAssumeProve(tn, cm); + break; + case N_NewSymb: + apn.assumes[i] = generateNewSymb(tn, cm); + apn.inScopeOfDecl[i + 1] = true; + inScopeOfAPDecl[assumeProveDepth] = true; + OpDeclNode[] odn = new OpDeclNode[1]; + odn[0] = ((NewSymbNode) apn.assumes[i]).getOpDeclNode(); + break; + default: + /************************************************************** + * Should be an expression node or a labeled ASSUME/PROVE. * + **************************************************************/ // apn.assumes[i] = generateExpression(tn, cm) ; - apn.assumes[i] = generateExpressionOrLAP(tn, cm, true) ; - break ; - } ; // end switch - if (assumeProveDepth == 1) { - currentGoalClause = currentGoalClause + 1; - } ; - } ; // end for - - apn.prove = generateExpression(children[numOfChildren - 1], cm) ; - - if (assumeProveDepth != 1) { - symbolTable.popContext(); - /**************************************************************** - * Restore the current context, removing the declarations by * - * the assumptions. assumption list. * - ****************************************************************/ - } ; - assumeProveDepth-- ; - return apn ; } - - private final NewSymbNode generateNewSymb(TreeNode treeNode, ModuleNode cm) - /*********************************************************************** - * Added by LL on 21 Mar 2007. * - ***********************************************************************/ - throws AbortException { - TreeNode[] children = treeNode.heirs(); - int numOfChildren = children.length; - - /********************************************************************* - * Determine if this node should have a non-null "set" field, which * - * is the case iff the declaration ends with "\in S", in which case * - * set the set field to the ExprNode for S. * - *********************************************************************/ - ExprNode set = null ; - if (children[numOfChildren-2].getKind() == IN) { - set = generateExpression(children[numOfChildren-1], cm) ;} ; - - int declKind ; - int declLevel ; - /********************************************************************* - * Set declKind to the kind of the NewSymbNode object's OpDeclNode. * - * Set declLevel to its level. * - * * - * Start by setting i to 1 or 0 depending on whether the declaration * - * begins with a NEW token. * - *********************************************************************/ - int i = 0 ; - if (children[0].getKind() == NEW) {i = 1;}; - - /********************************************************************* - * Set declKind, and leave i so that children[i+1] is the syntax * - * tree node describing the declared symbol and its arity. * - * * - * We do this by seeing if the next token is "CONSTANT", "VARIABLE", * - * etc. If it isn't, then the declaration begins "NEW id", so it's * - * a CONSTANT declaration and i must be set to 0. * - *********************************************************************/ - switch (children[i].getKind()) { - case CONSTANT : - declKind = NewConstantKind ; - declLevel = ConstantLevel; - break ; - case VARIABLE : - declKind = NewVariableKind ; - declLevel = VariableLevel; - break ; - case STATE : - declKind = NewStateKind ; - declLevel = VariableLevel; - break ; - case ACTION : - declKind = NewActionKind ; - declLevel = ActionLevel; - break ; - case TEMPORAL : - declKind = NewTemporalKind ; - declLevel = TemporalLevel; - break ; - default : - declKind = NewConstantKind ; - declLevel = ConstantLevel; - i = 0 ; - }; // switch - return new NewSymbNode( - buildParameter(children[i+1], declKind, declLevel, cm, true), - set, - treeNode) ; - } - - private final ExprNode - processChoose(TreeNode treeNode, TreeNode[] children, ModuleNode cm) - throws AbortException { - ExprNode[] semanticNode = new ExprNode[1]; - TreeNode[] syntaxTreeNode = children[2].heirs(); - OpApplNode result; - - symbolTable.pushContext( new Context(moduleTable, errors) ); - - if (syntaxTreeNode == null || syntaxTreeNode.length == 0) { - // unbounded case - FormalParamNode[] odn; - boolean tuple; - - // either Tuple or single identifier - if (children[1].isKind( N_IdentifierTuple)) { - syntaxTreeNode = children[1].heirs(); - odn = new FormalParamNode[ syntaxTreeNode.length / 2 ]; - for (int lvj = 0; lvj < syntaxTreeNode.length / 2; lvj++ ) { - odn[lvj] = new FormalParamNode( - syntaxTreeNode[ 2*lvj+1 ].getUS(), 0, - syntaxTreeNode[ 2*lvj+1 ], symbolTable, cm); - } - tuple = true; - } - else { - odn = new FormalParamNode[1]; - odn[0] = new FormalParamNode(children[1].getUS(), 0, children[0], - symbolTable, cm); - tuple = false; - } - pushFormalParams(odn) ; - /******************************************************************* - * Push formal parameters on Last(LS).paramSeq for processing the * - * body. * - *******************************************************************/ - semanticNode[0] = generateExpression( children[4], cm ); - popFormalParams() ; - - result = new OpApplNode(OP_uc, semanticNode, odn, treeNode, cm); - } - else { - // bounded case - FormalParamNode[][] odna = new FormalParamNode[1][0]; - boolean[] tuples = new boolean[1]; - ExprNode[] exprs = new ExprNode[1]; - - // syntaxTreeNode can be reused further down. - exprs[0] = generateExpression(syntaxTreeNode[1], cm); - - if ( children[1].isKind( N_IdentifierTuple ) ) { - syntaxTreeNode = children[1].heirs(); - odna[0] = new FormalParamNode[ syntaxTreeNode.length / 2 ]; - for (int lvj = 0; lvj < syntaxTreeNode.length / 2; lvj++ ) { - odna[0][lvj] = - new FormalParamNode( - syntaxTreeNode[ 2*lvj+1 ].getUS(), 0, - syntaxTreeNode[2*lvj+1], symbolTable, cm); - } - tuples[0] = true; - } - else { - odna[0] = new FormalParamNode[1]; - odna[0][0] = new FormalParamNode(children[1].getUS(), 0, - children[1], symbolTable, cm); - tuples[0] = false; - } - pushFormalParams(flattenParams(odna)) ; - /******************************************************************* - * Push the bound variables on Last(LS).paramSeq and process the * - * body of the CHOOSE. * - *******************************************************************/ - semanticNode[0] = generateExpression( children[4], cm ); - popFormalParams() ; - - result = new OpApplNode(OP_bc, null, semanticNode, odna, - tuples, exprs, treeNode, cm); - } - symbolTable.popContext(); - return result; - } - - private final ExprNode processBoundQuant(TreeNode treeNode, - TreeNode[] children, - ModuleNode cm) - throws AbortException { - // Create data structures for all parameters - int length = (children.length - 2) / 2; - FormalParamNode[][] odna = new FormalParamNode[length][0]; - boolean[] bt = new boolean[length]; - ExprNode[] ea = new ExprNode[ length ]; - - // then process parameters - symbolTable.pushContext( new Context(moduleTable, errors) ); - processQuantBoundArgs( children, 1, odna, bt, ea, cm ); - - // process expression - ExprNode semanticNode[] = new ExprNode[1]; - pushFormalParams(flattenParams(odna)) ; - /******************************************************************* - * Push the bound variables on Last(LS).paramSeq and process the * - * body of the quantified expression. * - *******************************************************************/ - semanticNode[0] = generateExpression( children[ children.length - 1 ], cm ); - popFormalParams() ; - - symbolTable.popContext(); - - // then return new node. - // which variety? look under first child. - boolean isExists = children[0].getUS().equals( S_e ) - || children[0].getUS().equals( S_ex ); - if (isExists) { - return new OpApplNode(OP_be, null, semanticNode, odna, - bt, ea, treeNode, cm); - } - else { - return new OpApplNode(OP_bf, null, semanticNode, odna, - bt, ea, treeNode, cm); - } - } - - private final ExprNode processUnboundQuant(TreeNode treeNode, - TreeNode[] children, - ModuleNode cm) - throws AbortException { - // which variety? look under first child. - UniqueString us = children[0].getUS(); - UniqueString r_us; - int level; - - if ( us.equals (S_e ) ) { r_us = OP_ue; level = 0; } // \E - else if ( us.equals (S_ex) ) { r_us = OP_ue; level = 0; } // \exists - else if ( us.equals (S_f ) ) { r_us = OP_uf; level = 0; } // \A - else if ( us.equals (S_fx) ) { r_us = OP_uf; level = 0; } // \always - else if ( us.equals (S_te) ) { r_us = OP_te; level = 1; } // \EE - else { r_us = OP_tf; level = 1; } // \AA - - // Process all identifiers bound by thus quantifier - int length = ( children.length - 2 ) / 2; - FormalParamNode odn[] = new FormalParamNode[ length ]; - symbolTable.pushContext( new Context(moduleTable, errors) ); - - for ( int lvi = 0; lvi < length; lvi ++ ) { - odn[lvi] = new FormalParamNode( - children[2*lvi +1].getUS(), 0, - children[2*lvi +1], symbolTable, cm); - } - - // now the expression - ExprNode semanticNode[] = new ExprNode[1]; - pushFormalParams(odn) ; - /********************************************************************** - * Push formal parameters on Last(LS).paramSeq for processing the * - * body. * - **********************************************************************/ - semanticNode[0] = generateExpression(children[children.length-1], cm); - popFormalParams() ; - - // wrap up. - symbolTable.popContext(); - return new OpApplNode(r_us, semanticNode, odn, treeNode, cm); - } - - private final ExprNode processCase(TreeNode treeNode, TreeNode[] children, ModuleNode cm) - throws AbortException { - // number of arms to CASE-expr, not counting the CASE nodse itself - // or the []-separators - int armCount = children.length/2; - ExprNode[] casePairs = new ExprNode[armCount]; - - for (int lvi = 0; lvi < armCount; lvi++) { - TreeNode caseArm = children[2*lvi+1]; - TreeNode[] ss = caseArm.heirs(); - ExprNode[] sops = new ExprNode[2]; - if (!caseArm.isKind(N_OtherArm)) { - sops[0] = this.generateExpression(ss[0], cm); - } - sops[1] = this.generateExpression(ss[2], cm); - casePairs[lvi] = new OpApplNode(OP_pair, sops, caseArm, cm); - } - return new OpApplNode(OP_case, casePairs, treeNode, cm); - } - - private final ExprNode processSubsetOf(TreeNode treeNode, - TreeNode children[], - ModuleNode cm ) - throws AbortException { - // cfr. unbounded choose - ExprNode[] ops = new ExprNode[1]; - FormalParamNode[][] odna = new FormalParamNode[1][0]; - boolean[] tuples = new boolean[1]; - ExprNode[] exprs = new ExprNode[1]; - - exprs[0] = generateExpression( children[3], cm ); - - symbolTable.pushContext( new Context(moduleTable, errors) ); - - if ( children[1].isKind( N_IdentifierTuple ) ) { - TreeNode[] ss = children[1].heirs(); - odna[0] = new FormalParamNode[ ss.length / 2 ]; - for (int lvj = 0; lvj < ss.length / 2; lvj++ ) { - odna[0][lvj] = new FormalParamNode( - ss[ 2*lvj+1 ].getUS(), 0, ss[ 2*lvj+1 ], - symbolTable, cm); - } - tuples[0] = true; - } - else { - odna[0] = new FormalParamNode[1]; - odna[0][0] = new FormalParamNode( - children[1].getUS(), 0, children[1], - symbolTable, cm); - tuples[0] = false; - } - - pushFormalParams(flattenParams(odna)) ; - /********************************************************************* - * Push the bound variables on Last(LS).paramSeq and process the * - * body of the CHOOSE. * - *********************************************************************/ - ops[0] = generateExpression( children[5], cm ); - popFormalParams() ; - - symbolTable.popContext(); - return new OpApplNode(OP_sso, null, ops, odna, tuples, exprs, - treeNode, cm); - } - - private final ExprNode processSetOfAll(TreeNode treeNode, - TreeNode children[], - ModuleNode cm) - throws AbortException { - ExprNode[] ops = new ExprNode[1]; - int length = (children.length - 3) / 2; - FormalParamNode[][] odna = new FormalParamNode[length][0]; - boolean[] tuples = new boolean[length]; - ExprNode[] exprs = new ExprNode[length]; - - symbolTable.pushContext(new Context(moduleTable, errors)); - processQuantBoundArgs(children, 3, odna, tuples, exprs, cm); - - pushFormalParams(flattenParams(odna)) ; - /********************************************************************* - * Push the bound variables on Last(LS).paramSeq and process the * - * body of the CHOOSE. * - *********************************************************************/ - ops[0] = generateExpression( children[1], cm ); - popFormalParams() ; - - symbolTable.popContext(); - - return new OpApplNode(OP_soa, null, ops, odna, tuples, exprs, - treeNode, cm); - } - - private final ExprNode processFcnConst(TreeNode treeNode, - TreeNode children[], ModuleNode cm) - throws AbortException { - ExprNode[] ops = new ExprNode[1]; - int length = (children.length - 3) / 2; // number of args to function constant - FormalParamNode[][] odna = new FormalParamNode[length][0]; - boolean[] tuples = new boolean[length]; - ExprNode[] exprs = new ExprNode[length]; - - symbolTable.pushContext( new Context(moduleTable, errors) ); - processQuantBoundArgs( children, 1, odna, tuples, exprs, cm ); - - pushFormalParams(flattenParams(odna)) ; - /********************************************************************* - * Push the bound variables on Last(LS).paramSeq and process the * - * body of the CHOOSE. * - *********************************************************************/ - ops[0] = generateExpression( children[children.length-2], cm ); - popFormalParams() ; - - symbolTable.popContext(); - - return new OpApplNode(OP_fc, null, ops, odna, tuples, exprs, - treeNode, cm); - } - - /** - * This method processes both the RecordConstructor construct and the - * SetOfRecords operator. The two are essentially identical except for - * which builtin operator is used. - */ - private final ExprNode processRcdForms(UniqueString operator, - TreeNode treeNode, - TreeNode children[], - ModuleNode cm) - throws AbortException { - // handles RcdConstructor or SetOfRcds - int length = (children.length - 1) / 2; - - // Create an array of pairs to handle all of the fields mentioned in the form - ExprNode[] fieldPairs = new ExprNode[length]; - // Create an array of Unique Strings to check uniqueness of fields. Not very efficient - // but a HashTable may be overkill most of the time. - // Remember a label is a string. - UniqueString [] labels = new UniqueString[length]; - - // For each field in the RcdConstructor or SetOfRecords - for ( int lvi = 0; lvi < length; lvi++ ) { - TreeNode syntaxTreeNode[] = children[ 2*lvi + 1].heirs(); - - // Create a pair of SemanticNodes to represent one record component - ExprNode sops[] = new ExprNode[2]; - - // The first one gets a new StringNode indicating the field name - sops[0] = new StringNode(syntaxTreeNode[0], false); - labels[ lvi ] = ((StringNode) sops[0]).getRep(); - for ( int cmpIndex=0; cmpIndex < lvi; cmpIndex++) { - if ( labels[lvi].compareTo(labels[cmpIndex]) == 0) { - errors.addError(syntaxTreeNode[0].getLocation(), - "Non-unique fields in constructor."); - } - } - - // The second one gets the expression indicating the field value (or set of values) - sops[1] = generateExpression( syntaxTreeNode[2], cm ); - - // Put the $Pair OpApplNode into the fieldPairs array - fieldPairs[lvi] = new OpApplNode(OP_pair, sops, children[2*lvi+1], cm); - } - // Create the top-level OpApplNode, for either the SetOfRecords op - // or the RcdConstructor op. - return new OpApplNode(operator, fieldPairs, treeNode, cm); - } - - private final ExprNode processAction(TreeNode treeNode, TreeNode children[], ModuleNode cm) - throws AbortException { - UniqueString match = children[0].getUS(); - if ( match.equals( S_a ) ) - match = OP_aa; - else if ( match.equals( S_brack ) ) - match = OP_sa; - else if ( match.equals( S_sf) ) - match = OP_sf; - else if ( match.equals( S_wf) ) - match = OP_wf; - - ExprNode ops[] = new ExprNode[2]; - ops[0] = generateExpression( children[1], cm ); - ops[1] = generateExpression( children[3], cm ); - return new OpApplNode( match, ops, treeNode, cm); - } - - private final ExprNode processExcept(TreeNode treeNode, TreeNode[] children, ModuleNode cm) - throws AbortException { - int numExcepts = (children.length-3)/2 ; // number of ExceptSpec's; - ExprNode[] operands = new ExprNode[numExcepts+1]; // 1 for each ExceptionSpec + first expr - OpApplNode excNode; // Holds OpApplNode for $Except operator - OpApplNode excSpecNode; // Holds $Pair node for ExceptSpec - - // The first operand of the $Except operator is the expression to - // which the exceptions apply Note this first operand is generated - // BEFORE the $Except node is stacked in the next couple of lines, - // because an @ in the first expression does NOT refer to the - // $Except node currently being generated, but to the next outer - // $Except node. - operands[0] = generateExpression( children[ 1 ], cm ); - - // Create the $Except OpApplNode that will be returned by this - // method. We create it now, and fill out its contents later, - // because we need a reference to it in order to process @ properly. - excNode = new OpApplNode( OP_exc, operands, treeNode, cm); - - // for each of the ExceptSpecs produce another element of the operands array - for ( int excSpecIx = 0; excSpecIx < numExcepts; excSpecIx++ ) { - TreeNode[] syntaxTreeNode = children[3 + 2*excSpecIx].heirs(); // extract ExceptSpec - ExprNode[] sops = new ExprNode[2]; // Each ExceptionSpec is a $Pair - int slength = syntaxTreeNode.length - 3; // # of ExceptComponents in ExceptSpec - ExprNode[] ssops = new ExprNode[ slength ]; // to store ExceptComponents - - // Process the LHS of the ExceptSpec - - // for each ExceptComponent of the form .h or [i] or [i,j,k] add - // an arg to $SEQ node and add build up the syntax tree for - // exceptionTarget - for ( int excCompIx = 0; excCompIx < slength ; excCompIx++ ) { - // the heirs of an ExceptComponent - TreeNode subSyntaxTreeNode[] = syntaxTreeNode[ 1 + excCompIx ].heirs(); - - if (subSyntaxTreeNode[0].getUS().equals( S_brack ) ) { - // The first heir is "[" , indicates one or more fcn args; - // add expressions as function args - if ( subSyntaxTreeNode.length > 3 ) { - // if so, must generate a tuple for comma list of fcn args - int sslength = (subSyntaxTreeNode.length-1)/2; // number of func args in comma list - ExprNode[] sssops = new ExprNode[ sslength ]; // holds the comma list of fcn args - - // for each of multiple function args in the ExceptComponent - for (int fArgIx=0; fArgIx < sslength; fArgIx++ ) { - sssops[ fArgIx ] = generateExpression( subSyntaxTreeNode[1+ 2*fArgIx], cm); - } - - // add one ExceptComponent to vector of ExceptComponents - ssops[ excCompIx ] = - new OpApplNode(OP_tup, sssops, syntaxTreeNode[2*excCompIx+1], cm); - } - else { - // add one ExceptComponent to vector of ExceptComponents - ssops[ excCompIx ] = generateExpression( subSyntaxTreeNode[1], cm ); - } - } - else { - // otherwise a "." indicates record selection; add a - // StringNode operand as record selector add one - // ExceptComponent to vector of ExceptComponents - ssops[ excCompIx ] = new StringNode(subSyntaxTreeNode[1], false); - } - } // end for (each ExceptionComponent) - - // Create OpAppl for $SEQ applied to array of ExceptComponents - // following record or func expr or ! - // This is the LHS of an ExceptionSpec - sops[0] = new OpApplNode(OP_seq, ssops, children[3 + 2*excSpecIx], cm); - - // Process the RHS of the ExceptionSpec - - // Create exceptSpec node now, so that it can be available in - // case the RHS expression of this ExceptSpec contains an @ - excSpecNode = new OpApplNode(OP_pair, sops, children[3+2*excSpecIx], cm); - - // Push the except node and the except spec node on stacks so - // that the RHS of the ExceptSpec, which might contain an @, can - // be evaluated in their "context". - excSpecStack.push(excSpecNode); - excStack.push(excNode); - - // Generate the expression constituting the RHS of the - // ExceptionSpec allow @ in the context of this expression. - sops[1] = generateExpression(syntaxTreeNode[syntaxTreeNode.length-1], cm ); - - // Pop them back off - excSpecStack.pop(); - excStack.pop(); - - // Store excSpecNode as another operand of $Except - operands[ excSpecIx+1 ] = excSpecNode; - } // end for (each ExceptionSpec) - - return excNode; - } // end processExcept() - - /** - * This method generates an expression tree or an OpArgNode as an - * argument to an OpApplNode - * - * mainOp is the operator under that node - * mainSTN is the "parent" OpApplNode, used in case an error message - * must be generated - * argPosition is the argument position (counting from 0) that treeNode - * represents - * argRoot is the argument syntax tree that either becomes an - * ExprNode or an OpArgNode - * mn is the module these expressions are part of - */ - private ExprOrOpArgNode generateExprOrOpArg(SymbolNode mainOp, - TreeNode mainSTN, - int argPosition, - TreeNode argRoot, - ModuleNode mn) - throws AbortException { - SymbolNode argOp = null; - // the SymbolNode that heads the argRoot expression - int argArity; - // number of actual arguments under argRoot - int arityExpected; - // arity that mainOp expects of argument number <argPosition> - - if ( mainOp == null) { - errors.addError( - mainSTN.getLocation(), - "Unable to generate expression or operator argument; " + - "this is probably because of previously reported errors." ); - return nullOAN; - } - - // Are we sure the "operator" is not a ModuleNode? - if (mainOp instanceof ModuleNode) { - errors.addError(mainSTN.getLocation(), - "Module name '" + mainOp.getName() + - "' used as operator."); - return nullOAN; - } - - // Are there too many arguments to mainOp? - if (argPosition+1 > mainOp.getArity()) { - errors.addError(mainSTN.getLocation(), - "Too many arguments for operator '" + - mainOp.getName() + "'. There should be only " + - mainOp.getArity() + "." ); - - return nullOAN; - } - - // For user-defined mainOp check the FormalParamNodes array - // associated with the mainOp to find out whether it expects an - // operator argument or an ordinary expression argument in - // position number argPosition. (Only UserDefined ops can have - // other multi-arg ops passed to them as params, so we can just - // assign arityExpected = 0 in other cases.) - /*********************************************************************** - * In SANY2, mainOp can also be a ModuleInstanceKind, so the if test * - * was modified appropriately. * - ***********************************************************************/ - if ( (mainOp.getKind() == UserDefinedOpKind) - || (mainOp.getKind() == ModuleInstanceKind)) { - arityExpected = - ((OpDefNode)mainOp).getParams()[argPosition].getArity(); - } else { - arityExpected = 0; - }; - - // if mainOp expects zero arguments, then it expects an ordinary - // expression arg in this position, so generate an expression. - // Any errors will be found in the generateExpression method. - if ( arityExpected == 0 ) { - return generateExpression( argRoot, mn ); - } - else { - // otherwise, we are expecting an OpArg or Lambda - /********************************************************************* - * The following test was originally * - * * - * if (argRoot.getImage().equals("N_OpApplication")) * - * * - * However, that was not sufficient, because there are lots of other * - * nodes that represent expressions. At best, these caused weird * - * error messages. At worst, as in the case of a number or string, * - * they caused an array out of bounds exception when generateGenID * - * was called a few lines later. I hope that the following test * - * covers all the cases in which this should be called with argRoot * - * not an expression. * - * * - * Change made by LL on 9 May 2007. * - *********************************************************************/ - if ( !( argRoot.getImage().equals("N_GeneralId") - || argRoot.getImage().equals("N_GenInfixOp") - || argRoot.getImage().equals("N_GenNonExpPrefixOp") - || argRoot.getImage().equals("N_GenPostfixOp") - || argRoot.getImage().equals("N_GenPrefixOp") - || argRoot.getImage().equals("N_Lambda") )) { - errors.addError( - argRoot.getLocation(), - "An expression appears as argument number " + (argPosition+1) + - " (counting from 1) to operator '" + mainOp.getName() + - "', in a position an operator is required."); - return nullOAN; - } // end if - - if (argRoot.getKind() == N_Lambda) { - /******************************************************************* - * The argument is a lambda expression. * - *******************************************************************/ - argOp = generateLambda(argRoot, mn) ; - if (arityExpected == argOp.getArity()) - {return new OpArgNode(argOp, argRoot, mn);} // if - else { errors.addError( - mainSTN.getLocation(), - "Lambda expression with arity " + argOp.getArity() + - " used as argument " + (argPosition+1) + - " of operator `" + mainOp.getName() + - "', \nbut an operator of arity " + arityExpected - + " is required."); - return nullOpArg; - } // else - } // if (argRoot.kind == N_Lambda) - else { - /******************************************************************* - * The argument is not a lambda expression. * - *******************************************************************/ - - /******************************************************************* - * If the argument is a GeneralId node, then we use * - * genIdToSelector and selectorToNode to generate the OpArg node. * - *******************************************************************/ - if (argRoot.getKind() == N_GeneralId) { - return (ExprOrOpArgNode) - selectorToNode(genIdToSelector((SyntaxTreeNode) argRoot), - arityExpected, false, false, mn); - } ; - - /******************************************************************* - * If the argument is not a GeneralId node, we use the code from * - * SANY1 to generate the OpArg node. * - *******************************************************************/ - GenID genID = generateGenID(argRoot, mn); - argOp = genID.getFullyQualifiedOp(); ; - - // If the symbol has not been defined, then indicate an error and - // return a nullOAN, allowing semantic analysis to continue - if (argOp == null) - return nullOAN; - - argArity = argOp.getArity(); - if ( arityExpected == argArity && genID.getArgs().length == 0) { - return new OpArgNode(genID.getFullyQualifiedOp(), argRoot, mn); - } - else if (genID.getArgs().length > 0) { - // expression (with or without correct number of args) being - // used where operator should be - errors.addError( - mainSTN.getLocation(), - "Expression used in argument position " + (argPosition+1) + - " (counting from 1) of operator `" + mainOp.getName() + - "', whereas an operator of arity " + arityExpected + - " is required."); - return nullOpArg; - } - else { - // operator of the wrong arity is being passed as argument - errors.addError( - mainSTN.getLocation(), - "Operator with incorrect arity passed as argument. " + - "\nOperator '" + argOp.getName() + "' of arity " + argArity + - " is argument number " + (argPosition+1) + - " (counting from 1) to operator `" + mainOp + - "', \nbut an operator of arity " + arityExpected + - " was expected."); - return nullOpArg; - } - } // else of non-Lambda expression case - } // end else of if (arityExpected == 0) - } // end generateExprOrOpArgOrLambda - - /** - * Process the General ID syntax tree, i.e. the part that contains - * an expression of the form A(x,y)!B!C(u,v,w)!D (with no params to - * D) and represents an operator. A General ID occurs in the - * syntax in only a few places: as an operator in an operator - * application; as an operator used as an operand to another - * operator, and as an operator being substituted for a suitable - * constant in module instantiation. - * - * Returns a GenID object, which must be further processed. - */ - private GenID generateGenID(TreeNode syntaxTreeNode, ModuleNode mn) throws AbortException { - return generateGenID(syntaxTreeNode, mn, false); - } - - /************************************************************************* - * It appears that this is called with unaryNegKludge = true only when * - * processing a prefix operator. * - *************************************************************************/ - private GenID generateGenID(TreeNode syntaxTreeNode, ModuleNode mn, boolean unaryNegKludge) - throws AbortException { - GenID genID; // Holds components of the generalized ID for this operator - TreeNode[] children = syntaxTreeNode.heirs(); // To contain N_IdPrefix node and the main operator - TreeNode[] prefix = null; // Contains array of prefix elements - // This is the array of N_IdPrefixElements for the operator, - // i.e. A!B(3)!C has 2 N_IdPrefixElements, A and B(3). - TreeNode[] prefixElt; // a prefixElement; 2- or 3-elem array: [op, (args), "!"] - TreeNode[] allArgs = null; // to collect arg arrays from prefix - TreeNode[] argsList = null; // Will hold an arg list tree - - if (children == null || children.length <= 0) { - // almost certainly an @ used outside of EXCEPT, which is detected elsewhere - return null; - } - - prefix = children[0].heirs(); - - // Allocate object to hold the Generized ID that is part of this OpAppl - genID = new GenID(syntaxTreeNode); - - // Number of elements in the prefix - int len = prefix.length; - - // Allocate array of SyntaxTreeNodes, one for each prefix element - allArgs = new SyntaxTreeNode[ len ]; - - // Process all of the prefix elements; construct the compound - // identifier (with embedded !-characters), and also accumulate an - // array of argument arrays (allArgs) for each prefix element - for (int i = 0; i < len; i++ ) { - // prefixElt becomes a 2- or 3-element array containing - // [operator, args (optional), and "!"] - prefixElt = prefix[i].heirs(); - - // Append the next part of compound identifier name and a "!" - genID.append(prefixElt[0].getImage()); - genID.append("!"); - - // allArgs[i] = array of arg syntax trees for next prefix - // element (if any) or "!" (if not) - allArgs[i] = prefixElt[1]; // Note: whether this is args or a "!" is checked below - } - - // Append the primary (rightmost) operator name to compoundID; - // calling "finalAppend" signals that the appending is finished, - // i.e. that the string can be converted to a UniqueString and to - // a SymbolNode inside the genID object - genID.finalAppend(children[1].getImage(), unaryNegKludge); - - // for each argument in each potential argument list in the prefix, - // generate the expression or opArg corresponding to it - - // for each argument list in prefix - int iarg = 0; - for (int i = 0; i < allArgs.length ; i++ ) { - // if there is an actual arg list here (instead of a "!" or null) - if ( allArgs[i] != null && allArgs[i].isKind( N_OpArgs ) ) { - // pick up array of arg list syntax elements - argsList = allArgs[ i ].heirs(); - - // The odd numbered syntax elements are the args expressions; - // the even numbered ones are parens and commas. - for (int ia = 1; ia < argsList.length; ia += 2) { - // Each arg may be an ordinary expression, or it may be an OpArg; - // produce appropriate semantic tree or node for it. - // Note that operators can be used in place of expressions in only two contexts: - // as argument to suitable user-defined ops, and in the RHS of a substitution - // in module instantiation - genID.addArg(generateExprOrOpArg(genID.getFullyQualifiedOp(), syntaxTreeNode, - iarg, argsList[ia], mn)); - iarg++; - } - } - } - - // "finalize the GenID object (i.e. convert argument vector to array) - genID.finalizeID(); - return genID; - } - - /************************************************************************* - * Added by LL on 27 March 2007. * - * * - * A lambda expression is represented as an OpDefNode. Since it is * - * always used only as an operator argument, this OpDefNode will appear * - * in an OpArgNode. * - *************************************************************************/ - private final OpDefNode generateLambda(TreeNode syntaxTreeNode, - ModuleNode cm) - throws AbortException { - TreeNode [] children = syntaxTreeNode.heirs(); - int arity = (children.length - 2) / 2 ; - /********************************************************************* - * children = <<"LAMBDA", arg_1, ",", ... , "," , arg_arity, ":", * - * body>> * - * so children.length = 3 + arity + arity-1 * - * so arity = (children.length - 2) / 2. * - *********************************************************************/ - Context ctxt = new Context(moduleTable, errors); - symbolTable.pushContext( ctxt ); - /********************************************************************* - * The context ctxt will hold the parameters of the lambda * - * expression, which may appear in its body. * - *********************************************************************/ - FormalParamNode [] params = new FormalParamNode[arity] ; - int argPos = 1 ; - /********************************************************************* - * children[argPos] is the next parameter's identifier node. * - *********************************************************************/ - for (int i = 0 ; i < arity ; i++) { - /********************************************************************* - * Set params[i] to the FormalParamNode for the i-th formal * - * parameter. * - *********************************************************************/ - params[i] = new FormalParamNode(children[argPos].getUS(), - 0, // parameters of a lambda expression - // have arity 0. - children[argPos], - symbolTable, - cm) ; - argPos = argPos + 2 ; - } // for - + apn.assumes[i] = generateExpressionOrLAP(tn, cm, true); + break; + } + ; // end switch + if (assumeProveDepth == 1) { + currentGoalClause = currentGoalClause + 1; + } + ; + } + ; // end for + + apn.prove = generateExpression(children[numOfChildren - 1], cm); + + if (assumeProveDepth != 1) { + symbolTable.popContext(); + /**************************************************************** + * Restore the current context, removing the declarations by * the assumptions. + * assumption list. * + ****************************************************************/ + } + ; + assumeProveDepth--; + return apn; + } + + private final NewSymbNode generateNewSymb(TreeNode treeNode, ModuleNode cm) + /*********************************************************************** + * Added by LL on 21 Mar 2007. * + ***********************************************************************/ + throws AbortException { + TreeNode[] children = treeNode.heirs(); + int numOfChildren = children.length; + + /********************************************************************* + * Determine if this node should have a non-null "set" field, which * is the + * case iff the declaration ends with "\in S", in which case * set the set field + * to the ExprNode for S. * + *********************************************************************/ + ExprNode set = null; + if (children[numOfChildren - 2].getKind() == IN) { + set = generateExpression(children[numOfChildren - 1], cm); + } + ; + + int declKind; + int declLevel; + /********************************************************************* + * Set declKind to the kind of the NewSymbNode object's OpDeclNode. * Set + * declLevel to its level. * * Start by setting i to 1 or 0 depending on whether + * the declaration * begins with a NEW token. * + *********************************************************************/ + int i = 0; + if (children[0].getKind() == NEW) { + i = 1; + } + ; + + /********************************************************************* + * Set declKind, and leave i so that children[i+1] is the syntax * tree node + * describing the declared symbol and its arity. * * We do this by seeing if the + * next token is "CONSTANT", "VARIABLE", * etc. If it isn't, then the + * declaration begins "NEW id", so it's * a CONSTANT declaration and i must be + * set to 0. * + *********************************************************************/ + switch (children[i].getKind()) { + case CONSTANT: + declKind = NewConstantKind; + declLevel = ConstantLevel; + break; + case VARIABLE: + declKind = NewVariableKind; + declLevel = VariableLevel; + break; + case STATE: + declKind = NewStateKind; + declLevel = VariableLevel; + break; + case ACTION: + declKind = NewActionKind; + declLevel = ActionLevel; + break; + case TEMPORAL: + declKind = NewTemporalKind; + declLevel = TemporalLevel; + break; + default: + declKind = NewConstantKind; + declLevel = ConstantLevel; + i = 0; + } + ; // switch + return new NewSymbNode(buildParameter(children[i + 1], declKind, declLevel, cm, true), set, treeNode); + } + + private final ExprNode processChoose(TreeNode treeNode, TreeNode[] children, ModuleNode cm) throws AbortException { + ExprNode[] semanticNode = new ExprNode[1]; + TreeNode[] syntaxTreeNode = children[2].heirs(); + OpApplNode result; + + symbolTable.pushContext(new Context(moduleTable, errors)); + + if (syntaxTreeNode == null || syntaxTreeNode.length == 0) { + // unbounded case + FormalParamNode[] odn; + boolean tuple; + + // either Tuple or single identifier + if (children[1].isKind(N_IdentifierTuple)) { + syntaxTreeNode = children[1].heirs(); + odn = new FormalParamNode[syntaxTreeNode.length / 2]; + for (int lvj = 0; lvj < syntaxTreeNode.length / 2; lvj++) { + odn[lvj] = new FormalParamNode(syntaxTreeNode[2 * lvj + 1].getUS(), 0, syntaxTreeNode[2 * lvj + 1], + symbolTable, cm); + } + tuple = true; + } else { + odn = new FormalParamNode[1]; + odn[0] = new FormalParamNode(children[1].getUS(), 0, children[0], symbolTable, cm); + tuple = false; + } + pushFormalParams(odn); + /******************************************************************* + * Push formal parameters on Last(LS).paramSeq for processing the * body. * + *******************************************************************/ + semanticNode[0] = generateExpression(children[4], cm); + popFormalParams(); + + result = new OpApplNode(OP_uc, semanticNode, odn, treeNode, cm); + } else { + // bounded case + FormalParamNode[][] odna = new FormalParamNode[1][0]; + boolean[] tuples = new boolean[1]; + ExprNode[] exprs = new ExprNode[1]; + + // syntaxTreeNode can be reused further down. + exprs[0] = generateExpression(syntaxTreeNode[1], cm); + + if (children[1].isKind(N_IdentifierTuple)) { + syntaxTreeNode = children[1].heirs(); + odna[0] = new FormalParamNode[syntaxTreeNode.length / 2]; + for (int lvj = 0; lvj < syntaxTreeNode.length / 2; lvj++) { + odna[0][lvj] = new FormalParamNode(syntaxTreeNode[2 * lvj + 1].getUS(), 0, + syntaxTreeNode[2 * lvj + 1], symbolTable, cm); + } + tuples[0] = true; + } else { + odna[0] = new FormalParamNode[1]; + odna[0][0] = new FormalParamNode(children[1].getUS(), 0, children[1], symbolTable, cm); + tuples[0] = false; + } + pushFormalParams(flattenParams(odna)); + /******************************************************************* + * Push the bound variables on Last(LS).paramSeq and process the * body of the + * CHOOSE. * + *******************************************************************/ + semanticNode[0] = generateExpression(children[4], cm); + popFormalParams(); + + result = new OpApplNode(OP_bc, null, semanticNode, odna, tuples, exprs, treeNode, cm); + } + symbolTable.popContext(); + return result; + } + + private final ExprNode processBoundQuant(TreeNode treeNode, TreeNode[] children, ModuleNode cm) + throws AbortException { + // Create data structures for all parameters + int length = (children.length - 2) / 2; + FormalParamNode[][] odna = new FormalParamNode[length][0]; + boolean[] bt = new boolean[length]; + ExprNode[] ea = new ExprNode[length]; + + // then process parameters + symbolTable.pushContext(new Context(moduleTable, errors)); + processQuantBoundArgs(children, 1, odna, bt, ea, cm); + + // process expression + ExprNode semanticNode[] = new ExprNode[1]; + pushFormalParams(flattenParams(odna)); + /******************************************************************* + * Push the bound variables on Last(LS).paramSeq and process the * body of the + * quantified expression. * + *******************************************************************/ + semanticNode[0] = generateExpression(children[children.length - 1], cm); + popFormalParams(); + + symbolTable.popContext(); + + // then return new node. + // which variety? look under first child. + boolean isExists = children[0].getUS().equals(S_e) || children[0].getUS().equals(S_ex); + if (isExists) { + return new OpApplNode(OP_be, null, semanticNode, odna, bt, ea, treeNode, cm); + } else { + return new OpApplNode(OP_bf, null, semanticNode, odna, bt, ea, treeNode, cm); + } + } + + private final ExprNode processUnboundQuant(TreeNode treeNode, TreeNode[] children, ModuleNode cm) + throws AbortException { + // which variety? look under first child. + UniqueString us = children[0].getUS(); + UniqueString r_us; + int level; + + if (us.equals(S_e)) { + r_us = OP_ue; + level = 0; + } // \E + else if (us.equals(S_ex)) { + r_us = OP_ue; + level = 0; + } // \exists + else if (us.equals(S_f)) { + r_us = OP_uf; + level = 0; + } // \A + else if (us.equals(S_fx)) { + r_us = OP_uf; + level = 0; + } // \always + else if (us.equals(S_te)) { + r_us = OP_te; + level = 1; + } // \EE + else { + r_us = OP_tf; + level = 1; + } // \AA + + // Process all identifiers bound by thus quantifier + int length = (children.length - 2) / 2; + FormalParamNode odn[] = new FormalParamNode[length]; + symbolTable.pushContext(new Context(moduleTable, errors)); + + for (int lvi = 0; lvi < length; lvi++) { + odn[lvi] = new FormalParamNode(children[2 * lvi + 1].getUS(), 0, children[2 * lvi + 1], symbolTable, cm); + } + + // now the expression + ExprNode semanticNode[] = new ExprNode[1]; + pushFormalParams(odn); + /********************************************************************** + * Push formal parameters on Last(LS).paramSeq for processing the * body. * + **********************************************************************/ + semanticNode[0] = generateExpression(children[children.length - 1], cm); + popFormalParams(); + + // wrap up. + symbolTable.popContext(); + return new OpApplNode(r_us, semanticNode, odn, treeNode, cm); + } + + private final ExprNode processCase(TreeNode treeNode, TreeNode[] children, ModuleNode cm) throws AbortException { + // number of arms to CASE-expr, not counting the CASE nodse itself + // or the []-separators + int armCount = children.length / 2; + ExprNode[] casePairs = new ExprNode[armCount]; + + for (int lvi = 0; lvi < armCount; lvi++) { + TreeNode caseArm = children[2 * lvi + 1]; + TreeNode[] ss = caseArm.heirs(); + ExprNode[] sops = new ExprNode[2]; + if (!caseArm.isKind(N_OtherArm)) { + sops[0] = this.generateExpression(ss[0], cm); + } + sops[1] = this.generateExpression(ss[2], cm); + casePairs[lvi] = new OpApplNode(OP_pair, sops, caseArm, cm); + } + return new OpApplNode(OP_case, casePairs, treeNode, cm); + } + + private final ExprNode processSubsetOf(TreeNode treeNode, TreeNode children[], ModuleNode cm) + throws AbortException { + // cfr. unbounded choose + ExprNode[] ops = new ExprNode[1]; + FormalParamNode[][] odna = new FormalParamNode[1][0]; + boolean[] tuples = new boolean[1]; + ExprNode[] exprs = new ExprNode[1]; + + exprs[0] = generateExpression(children[3], cm); + + symbolTable.pushContext(new Context(moduleTable, errors)); + + if (children[1].isKind(N_IdentifierTuple)) { + TreeNode[] ss = children[1].heirs(); + odna[0] = new FormalParamNode[ss.length / 2]; + for (int lvj = 0; lvj < ss.length / 2; lvj++) { + odna[0][lvj] = new FormalParamNode(ss[2 * lvj + 1].getUS(), 0, ss[2 * lvj + 1], symbolTable, cm); + } + tuples[0] = true; + } else { + odna[0] = new FormalParamNode[1]; + odna[0][0] = new FormalParamNode(children[1].getUS(), 0, children[1], symbolTable, cm); + tuples[0] = false; + } + + pushFormalParams(flattenParams(odna)); + /********************************************************************* + * Push the bound variables on Last(LS).paramSeq and process the * body of the + * CHOOSE. * + *********************************************************************/ + ops[0] = generateExpression(children[5], cm); + popFormalParams(); + + symbolTable.popContext(); + return new OpApplNode(OP_sso, null, ops, odna, tuples, exprs, treeNode, cm); + } + + private final ExprNode processSetOfAll(TreeNode treeNode, TreeNode children[], ModuleNode cm) + throws AbortException { + ExprNode[] ops = new ExprNode[1]; + int length = (children.length - 3) / 2; + FormalParamNode[][] odna = new FormalParamNode[length][0]; + boolean[] tuples = new boolean[length]; + ExprNode[] exprs = new ExprNode[length]; + + symbolTable.pushContext(new Context(moduleTable, errors)); + processQuantBoundArgs(children, 3, odna, tuples, exprs, cm); + + pushFormalParams(flattenParams(odna)); + /********************************************************************* + * Push the bound variables on Last(LS).paramSeq and process the * body of the + * CHOOSE. * + *********************************************************************/ + ops[0] = generateExpression(children[1], cm); + popFormalParams(); + + symbolTable.popContext(); + + return new OpApplNode(OP_soa, null, ops, odna, tuples, exprs, treeNode, cm); + } + + private final ExprNode processFcnConst(TreeNode treeNode, TreeNode children[], ModuleNode cm) + throws AbortException { + ExprNode[] ops = new ExprNode[1]; + int length = (children.length - 3) / 2; // number of args to function constant + FormalParamNode[][] odna = new FormalParamNode[length][0]; + boolean[] tuples = new boolean[length]; + ExprNode[] exprs = new ExprNode[length]; + + symbolTable.pushContext(new Context(moduleTable, errors)); + processQuantBoundArgs(children, 1, odna, tuples, exprs, cm); + + pushFormalParams(flattenParams(odna)); + /********************************************************************* + * Push the bound variables on Last(LS).paramSeq and process the * body of the + * CHOOSE. * + *********************************************************************/ + ops[0] = generateExpression(children[children.length - 2], cm); + popFormalParams(); + + symbolTable.popContext(); + + return new OpApplNode(OP_fc, null, ops, odna, tuples, exprs, treeNode, cm); + } + + /** + * This method processes both the RecordConstructor construct and the + * SetOfRecords operator. The two are essentially identical except for which + * builtin operator is used. + */ + private final ExprNode processRcdForms(UniqueString operator, TreeNode treeNode, TreeNode children[], ModuleNode cm) + throws AbortException { + // handles RcdConstructor or SetOfRcds + int length = (children.length - 1) / 2; + + // Create an array of pairs to handle all of the fields mentioned in the form + ExprNode[] fieldPairs = new ExprNode[length]; + // Create an array of Unique Strings to check uniqueness of fields. Not very + // efficient + // but a HashTable may be overkill most of the time. + // Remember a label is a string. + UniqueString[] labels = new UniqueString[length]; + + // For each field in the RcdConstructor or SetOfRecords + for (int lvi = 0; lvi < length; lvi++) { + TreeNode syntaxTreeNode[] = children[2 * lvi + 1].heirs(); + + // Create a pair of SemanticNodes to represent one record component + ExprNode sops[] = new ExprNode[2]; + + // The first one gets a new StringNode indicating the field name + sops[0] = new StringNode(syntaxTreeNode[0], false); + labels[lvi] = ((StringNode) sops[0]).getRep(); + for (int cmpIndex = 0; cmpIndex < lvi; cmpIndex++) { + if (labels[lvi].compareTo(labels[cmpIndex]) == 0) { + errors.addError(syntaxTreeNode[0].getLocation(), "Non-unique fields in constructor."); + } + } + + // The second one gets the expression indicating the field value (or set of + // values) + sops[1] = generateExpression(syntaxTreeNode[2], cm); + + // Put the $Pair OpApplNode into the fieldPairs array + fieldPairs[lvi] = new OpApplNode(OP_pair, sops, children[2 * lvi + 1], cm); + } + // Create the top-level OpApplNode, for either the SetOfRecords op + // or the RcdConstructor op. + return new OpApplNode(operator, fieldPairs, treeNode, cm); + } + + private final ExprNode processAction(TreeNode treeNode, TreeNode children[], ModuleNode cm) throws AbortException { + UniqueString match = children[0].getUS(); + if (match.equals(S_a)) + match = OP_aa; + else if (match.equals(S_brack)) + match = OP_sa; + else if (match.equals(S_sf)) + match = OP_sf; + else if (match.equals(S_wf)) + match = OP_wf; + + ExprNode ops[] = new ExprNode[2]; + ops[0] = generateExpression(children[1], cm); + ops[1] = generateExpression(children[3], cm); + return new OpApplNode(match, ops, treeNode, cm); + } + + private final ExprNode processExcept(TreeNode treeNode, TreeNode[] children, ModuleNode cm) throws AbortException { + int numExcepts = (children.length - 3) / 2; // number of ExceptSpec's; + ExprNode[] operands = new ExprNode[numExcepts + 1]; // 1 for each ExceptionSpec + first expr + OpApplNode excNode; // Holds OpApplNode for $Except operator + OpApplNode excSpecNode; // Holds $Pair node for ExceptSpec + + // The first operand of the $Except operator is the expression to + // which the exceptions apply Note this first operand is generated + // BEFORE the $Except node is stacked in the next couple of lines, + // because an @ in the first expression does NOT refer to the + // $Except node currently being generated, but to the next outer + // $Except node. + operands[0] = generateExpression(children[1], cm); + + // Create the $Except OpApplNode that will be returned by this + // method. We create it now, and fill out its contents later, + // because we need a reference to it in order to process @ properly. + excNode = new OpApplNode(OP_exc, operands, treeNode, cm); + + // for each of the ExceptSpecs produce another element of the operands array + for (int excSpecIx = 0; excSpecIx < numExcepts; excSpecIx++) { + TreeNode[] syntaxTreeNode = children[3 + 2 * excSpecIx].heirs(); // extract ExceptSpec + ExprNode[] sops = new ExprNode[2]; // Each ExceptionSpec is a $Pair + int slength = syntaxTreeNode.length - 3; // # of ExceptComponents in ExceptSpec + ExprNode[] ssops = new ExprNode[slength]; // to store ExceptComponents + + // Process the LHS of the ExceptSpec + + // for each ExceptComponent of the form .h or [i] or [i,j,k] add + // an arg to $SEQ node and add build up the syntax tree for + // exceptionTarget + for (int excCompIx = 0; excCompIx < slength; excCompIx++) { + // the heirs of an ExceptComponent + TreeNode subSyntaxTreeNode[] = syntaxTreeNode[1 + excCompIx].heirs(); + + if (subSyntaxTreeNode[0].getUS().equals(S_brack)) { + // The first heir is "[" , indicates one or more fcn args; + // add expressions as function args + if (subSyntaxTreeNode.length > 3) { + // if so, must generate a tuple for comma list of fcn args + int sslength = (subSyntaxTreeNode.length - 1) / 2; // number of func args in comma list + ExprNode[] sssops = new ExprNode[sslength]; // holds the comma list of fcn args + + // for each of multiple function args in the ExceptComponent + for (int fArgIx = 0; fArgIx < sslength; fArgIx++) { + sssops[fArgIx] = generateExpression(subSyntaxTreeNode[1 + 2 * fArgIx], cm); + } + + // add one ExceptComponent to vector of ExceptComponents + ssops[excCompIx] = new OpApplNode(OP_tup, sssops, syntaxTreeNode[2 * excCompIx + 1], cm); + } else { + // add one ExceptComponent to vector of ExceptComponents + ssops[excCompIx] = generateExpression(subSyntaxTreeNode[1], cm); + } + } else { + // otherwise a "." indicates record selection; add a + // StringNode operand as record selector add one + // ExceptComponent to vector of ExceptComponents + ssops[excCompIx] = new StringNode(subSyntaxTreeNode[1], false); + } + } // end for (each ExceptionComponent) + + // Create OpAppl for $SEQ applied to array of ExceptComponents + // following record or func expr or ! + // This is the LHS of an ExceptionSpec + sops[0] = new OpApplNode(OP_seq, ssops, children[3 + 2 * excSpecIx], cm); + + // Process the RHS of the ExceptionSpec + + // Create exceptSpec node now, so that it can be available in + // case the RHS expression of this ExceptSpec contains an @ + excSpecNode = new OpApplNode(OP_pair, sops, children[3 + 2 * excSpecIx], cm); + + // Push the except node and the except spec node on stacks so + // that the RHS of the ExceptSpec, which might contain an @, can + // be evaluated in their "context". + excSpecStack.push(excSpecNode); + excStack.push(excNode); + + // Generate the expression constituting the RHS of the + // ExceptionSpec allow @ in the context of this expression. + sops[1] = generateExpression(syntaxTreeNode[syntaxTreeNode.length - 1], cm); + + // Pop them back off + excSpecStack.pop(); + excStack.pop(); + + // Store excSpecNode as another operand of $Except + operands[excSpecIx + 1] = excSpecNode; + } // end for (each ExceptionSpec) + + return excNode; + } // end processExcept() + + /** + * This method generates an expression tree or an OpArgNode as an argument to an + * OpApplNode + * + * mainOp is the operator under that node mainSTN is the "parent" OpApplNode, + * used in case an error message must be generated argPosition is the argument + * position (counting from 0) that treeNode represents argRoot is the argument + * syntax tree that either becomes an ExprNode or an OpArgNode mn is the module + * these expressions are part of + */ + private ExprOrOpArgNode generateExprOrOpArg(SymbolNode mainOp, TreeNode mainSTN, int argPosition, TreeNode argRoot, + ModuleNode mn) throws AbortException { + SymbolNode argOp = null; + // the SymbolNode that heads the argRoot expression + int argArity; + // number of actual arguments under argRoot + int arityExpected; + // arity that mainOp expects of argument number <argPosition> + + if (mainOp == null) { + errors.addError(mainSTN.getLocation(), "Unable to generate expression or operator argument; " + + "this is probably because of previously reported errors."); + return nullOAN; + } + + // Are we sure the "operator" is not a ModuleNode? + if (mainOp instanceof ModuleNode) { + errors.addError(mainSTN.getLocation(), "Module name '" + mainOp.getName() + "' used as operator."); + return nullOAN; + } + + // Are there too many arguments to mainOp? + if (argPosition + 1 > mainOp.getArity()) { + errors.addError(mainSTN.getLocation(), "Too many arguments for operator '" + mainOp.getName() + + "'. There should be only " + mainOp.getArity() + "."); + + return nullOAN; + } + + // For user-defined mainOp check the FormalParamNodes array + // associated with the mainOp to find out whether it expects an + // operator argument or an ordinary expression argument in + // position number argPosition. (Only UserDefined ops can have + // other multi-arg ops passed to them as params, so we can just + // assign arityExpected = 0 in other cases.) + /*********************************************************************** + * In SANY2, mainOp can also be a ModuleInstanceKind, so the if test * was + * modified appropriately. * + ***********************************************************************/ + if ((mainOp.getKind() == UserDefinedOpKind) || (mainOp.getKind() == ModuleInstanceKind)) { + arityExpected = ((OpDefNode) mainOp).getParams()[argPosition].getArity(); + } else { + arityExpected = 0; + } + ; + + // if mainOp expects zero arguments, then it expects an ordinary + // expression arg in this position, so generate an expression. + // Any errors will be found in the generateExpression method. + if (arityExpected == 0) { + return generateExpression(argRoot, mn); + } else { + // otherwise, we are expecting an OpArg or Lambda + /********************************************************************* + * The following test was originally * * if + * (argRoot.getImage().equals("N_OpApplication")) * * However, that was not + * sufficient, because there are lots of other * nodes that represent + * expressions. At best, these caused weird * error messages. At worst, as in + * the case of a number or string, * they caused an array out of bounds + * exception when generateGenID * was called a few lines later. I hope that the + * following test * covers all the cases in which this should be called with + * argRoot * not an expression. * * Change made by LL on 9 May 2007. * + *********************************************************************/ + if (!(argRoot.getImage().equals("N_GeneralId") || argRoot.getImage().equals("N_GenInfixOp") + || argRoot.getImage().equals("N_GenNonExpPrefixOp") || argRoot.getImage().equals("N_GenPostfixOp") + || argRoot.getImage().equals("N_GenPrefixOp") || argRoot.getImage().equals("N_Lambda"))) { + errors.addError(argRoot.getLocation(), + "An expression appears as argument number " + (argPosition + 1) + + " (counting from 1) to operator '" + mainOp.getName() + + "', in a position an operator is required."); + return nullOAN; + } // end if + + if (argRoot.getKind() == N_Lambda) { + /******************************************************************* + * The argument is a lambda expression. * + *******************************************************************/ + argOp = generateLambda(argRoot, mn); + if (arityExpected == argOp.getArity()) { + return new OpArgNode(argOp, argRoot, mn); + } // if + else { + errors.addError(mainSTN.getLocation(), + "Lambda expression with arity " + argOp.getArity() + " used as argument " + + (argPosition + 1) + " of operator `" + mainOp.getName() + + "', \nbut an operator of arity " + arityExpected + " is required."); + return nullOpArg; + } // else + } // if (argRoot.kind == N_Lambda) + else { + /******************************************************************* + * The argument is not a lambda expression. * + *******************************************************************/ + + /******************************************************************* + * If the argument is a GeneralId node, then we use * genIdToSelector and + * selectorToNode to generate the OpArg node. * + *******************************************************************/ + if (argRoot.getKind() == N_GeneralId) { + return (ExprOrOpArgNode) selectorToNode(genIdToSelector((SyntaxTreeNode) argRoot), arityExpected, + false, false, mn); + } + ; + + /******************************************************************* + * If the argument is not a GeneralId node, we use the code from * SANY1 to + * generate the OpArg node. * + *******************************************************************/ + GenID genID = generateGenID(argRoot, mn); + argOp = genID.getFullyQualifiedOp(); + ; + + // If the symbol has not been defined, then indicate an error and + // return a nullOAN, allowing semantic analysis to continue + if (argOp == null) + return nullOAN; + + argArity = argOp.getArity(); + if (arityExpected == argArity && genID.getArgs().length == 0) { + return new OpArgNode(genID.getFullyQualifiedOp(), argRoot, mn); + } else if (genID.getArgs().length > 0) { + // expression (with or without correct number of args) being + // used where operator should be + errors.addError(mainSTN.getLocation(), + "Expression used in argument position " + (argPosition + 1) + + " (counting from 1) of operator `" + mainOp.getName() + + "', whereas an operator of arity " + arityExpected + " is required."); + return nullOpArg; + } else { + // operator of the wrong arity is being passed as argument + errors.addError(mainSTN.getLocation(), + "Operator with incorrect arity passed as argument. " + "\nOperator '" + argOp.getName() + + "' of arity " + argArity + " is argument number " + (argPosition + 1) + + " (counting from 1) to operator `" + mainOp + "', \nbut an operator of arity " + + arityExpected + " was expected."); + return nullOpArg; + } + } // else of non-Lambda expression case + } // end else of if (arityExpected == 0) + } // end generateExprOrOpArgOrLambda + + /** + * Process the General ID syntax tree, i.e. the part that contains an expression + * of the form A(x,y)!B!C(u,v,w)!D (with no params to D) and represents an + * operator. A General ID occurs in the syntax in only a few places: as an + * operator in an operator application; as an operator used as an operand to + * another operator, and as an operator being substituted for a suitable + * constant in module instantiation. + * + * Returns a GenID object, which must be further processed. + */ + private GenID generateGenID(TreeNode syntaxTreeNode, ModuleNode mn) throws AbortException { + return generateGenID(syntaxTreeNode, mn, false); + } + + /************************************************************************* + * It appears that this is called with unaryNegKludge = true only when * + * processing a prefix operator. * + *************************************************************************/ + private GenID generateGenID(TreeNode syntaxTreeNode, ModuleNode mn, boolean unaryNegKludge) throws AbortException { + GenID genID; // Holds components of the generalized ID for this operator + TreeNode[] children = syntaxTreeNode.heirs(); // To contain N_IdPrefix node and the main operator + TreeNode[] prefix = null; // Contains array of prefix elements + // This is the array of N_IdPrefixElements for the operator, + // i.e. A!B(3)!C has 2 N_IdPrefixElements, A and B(3). + TreeNode[] prefixElt; // a prefixElement; 2- or 3-elem array: [op, (args), "!"] + TreeNode[] allArgs = null; // to collect arg arrays from prefix + TreeNode[] argsList = null; // Will hold an arg list tree + + if (children == null || children.length <= 0) { + // almost certainly an @ used outside of EXCEPT, which is detected elsewhere + return null; + } + + prefix = children[0].heirs(); + + // Allocate object to hold the Generized ID that is part of this OpAppl + genID = new GenID(syntaxTreeNode); + + // Number of elements in the prefix + int len = prefix.length; + + // Allocate array of SyntaxTreeNodes, one for each prefix element + allArgs = new SyntaxTreeNode[len]; + + // Process all of the prefix elements; construct the compound + // identifier (with embedded !-characters), and also accumulate an + // array of argument arrays (allArgs) for each prefix element + for (int i = 0; i < len; i++) { + // prefixElt becomes a 2- or 3-element array containing + // [operator, args (optional), and "!"] + prefixElt = prefix[i].heirs(); + + // Append the next part of compound identifier name and a "!" + genID.append(prefixElt[0].getImage()); + genID.append("!"); + + // allArgs[i] = array of arg syntax trees for next prefix + // element (if any) or "!" (if not) + allArgs[i] = prefixElt[1]; // Note: whether this is args or a "!" is checked below + } + + // Append the primary (rightmost) operator name to compoundID; + // calling "finalAppend" signals that the appending is finished, + // i.e. that the string can be converted to a UniqueString and to + // a SymbolNode inside the genID object + genID.finalAppend(children[1].getImage(), unaryNegKludge); + + // for each argument in each potential argument list in the prefix, + // generate the expression or opArg corresponding to it + + // for each argument list in prefix + int iarg = 0; + for (int i = 0; i < allArgs.length; i++) { + // if there is an actual arg list here (instead of a "!" or null) + if (allArgs[i] != null && allArgs[i].isKind(N_OpArgs)) { + // pick up array of arg list syntax elements + argsList = allArgs[i].heirs(); + + // The odd numbered syntax elements are the args expressions; + // the even numbered ones are parens and commas. + for (int ia = 1; ia < argsList.length; ia += 2) { + // Each arg may be an ordinary expression, or it may be an OpArg; + // produce appropriate semantic tree or node for it. + // Note that operators can be used in place of expressions in only two contexts: + // as argument to suitable user-defined ops, and in the RHS of a substitution + // in module instantiation + genID.addArg( + generateExprOrOpArg(genID.getFullyQualifiedOp(), syntaxTreeNode, iarg, argsList[ia], mn)); + iarg++; + } + } + } + + // "finalize the GenID object (i.e. convert argument vector to array) + genID.finalizeID(); + return genID; + } + + /************************************************************************* + * Added by LL on 27 March 2007. * * A lambda expression is represented as an + * OpDefNode. Since it is * always used only as an operator argument, this + * OpDefNode will appear * in an OpArgNode. * + *************************************************************************/ + private final OpDefNode generateLambda(TreeNode syntaxTreeNode, ModuleNode cm) throws AbortException { + TreeNode[] children = syntaxTreeNode.heirs(); + int arity = (children.length - 2) / 2; + /********************************************************************* + * children = <<"LAMBDA", arg_1, ",", ... , "," , arg_arity, ":", * body>> * so + * children.length = 3 + arity + arity-1 * so arity = (children.length - 2) / 2. + * * + *********************************************************************/ + Context ctxt = new Context(moduleTable, errors); + symbolTable.pushContext(ctxt); + /********************************************************************* + * The context ctxt will hold the parameters of the lambda * expression, which + * may appear in its body. * + *********************************************************************/ + FormalParamNode[] params = new FormalParamNode[arity]; + int argPos = 1; + /********************************************************************* + * children[argPos] is the next parameter's identifier node. * + *********************************************************************/ + for (int i = 0; i < arity; i++) { + /********************************************************************* + * Set params[i] to the FormalParamNode for the i-th formal * parameter. * + *********************************************************************/ + params[i] = new FormalParamNode(children[argPos].getUS(), 0, // parameters of a lambda expression + // have arity 0. + children[argPos], symbolTable, cm); + argPos = argPos + 2; + } // for + // /*********************************************************************** // * Convert the FormalParamNode array params to the OpDeclNode array * // * odn. * @@ -4531,2903 +4245,2754 @@ OpDefNode node = (OpDefNode) vec.elementAt(i); // null, // SymbolTable // params[i].stn); // TreeNode // }; // for - pushFormalParams(params) ; - /******************************************************************* - * Push formal parameters on Last(LS).paramSeq for processing the * - * body - *******************************************************************/ - ExprNode body = generateExpression( children[children.length - 1], cm ); - /********************************************************************* - * Generate the lambda expression's body. * - *********************************************************************/ - popFormalParams() ; - - symbolTable.popContext(); - /********************************************************************* - * Restore original context. * - *********************************************************************/ - return new OpDefNode( - S_lambda, // The operator name is "LAMBDA" - UserDefinedOpKind, // The node kind for a lambda expression - params, // the array of formal parameters - false , // localness, which is meaningless - body, // the body (an expression node) - cm, // the module - null, // the symbol table, which is null for an - // OpDefNode representing a lambda expression. - syntaxTreeNode, - true, // Is defined. Its value should not matter. - null ) ; // Source - } // generateLambda - - /** - * Generates an OpApplNode or an OpArgNode for a SyntaxTreeNode, - * according to whether the value of "typeExpected" is either opAppl - * or opArg. - */ - private final ExprNode generateOpAppl(TreeNode syntaxTreeNode, ModuleNode cm) - throws AbortException { - TreeNode primaryArgs = null; - // points to syntax tree of primary arg list (if any); otherwise null - boolean isOpApp = syntaxTreeNode.isKind( N_OpApplication ) ; - // true ==> to indicate this is an OpAppl; must have primary args - // false ==> operator used as an argument (OpArg); has no primary args - int primaryArgCount = 0; - // total # of arguments, including those of prefix, if any - int len; - // number of prefix elements - TreeNode[] children = syntaxTreeNode.heirs(); - // temp used for finding the prefix - TreeNode [] prefix; - // array of prefix elements - TreeNode[] allArgs = null; - // to collect arg arrays from both prefix and the main op (if any) - TreeNode [] prefixElt; - // a prefixElement; 2 or 3 elem array: [op, (args), "!"] - UniqueString symbol; - // UniqueString name of the fully-qualified operator - SymbolNode fullOperator; - // The SymbolNode for the fully-qualified operator - int iarg = 0; - // loop counter for actual args (as opposed to - // arg syntax elements like commas and parens) - TreeNode[] argsList = null; - // Will hold an array of arg syntax trees for primary operator - ExprOrOpArgNode[] args = null; - // Will hold an array of arg semantic trees for primary operator - - // Process the Generized ID that is the operator for this OpAppl - GenID genID = generateGenID(children[0], cm); - - // Set up pointers to OpAppl's primary args - primaryArgs = children[1]; - // Array of argument list syntax elements for the main - // (rightmost) operator, including parens and commas; - // should be an N_OpArgs node - - // calc number of primary args; - // args are interspersed w/ parens & commas--hence the /2 - primaryArgCount = primaryArgs.heirs().length / 2; - - if (genID == null || genID.getFullyQualifiedOp() == null) { - // if operator is @ or an unresolved symbol; error has already - // been generated inside genID - return nullOAN; - } - - args = new ExprOrOpArgNode[primaryArgCount]; - // Array to hold semantic trees for primary args - - // pick up array of arg list syntax elements - argsList = primaryArgs.heirs(); - - // The odd numbered syntax elements are the args expressions; the - // even numbered ones are parens and commas. - // for each arg in this arg list ... - for ( int ia = 1; ia < argsList.length; ia += 2 ) { - // Each arg may be an ordinary expression, or it may be an OpArg; - // produce appropriate semantic tree or node for it. - // Note that operators can be used in place of expressions - // in only two contexts: - // as argument to suitable user-defined ops, and in the RHS - // of a substitution in module instantiation - args[iarg] = generateExprOrOpArg(genID.getFullyQualifiedOp(), - syntaxTreeNode, - iarg, argsList[ia], cm); - iarg++; // count the actual args - } // end for - - // Concatenate the list of args in the GenID object to the - // primary arg list just created - Vector genIDArgList = genID.getArgsVector(); - ExprOrOpArgNode[] finalArgList = - new ExprOrOpArgNode[genIDArgList.size() + iarg]; - - // Copy the args from the prefix - for (int i = 0; i < genIDArgList.size(); i++) { - finalArgList[i] = (ExprOrOpArgNode)(genIDArgList.elementAt(i)); - } - // Copy the primary args - for (int i = 0, j = genIDArgList.size(); i < iarg; i++, j++ ) { - finalArgList[j] = args[i]; - } - - // return an OpApplNode constructed from the fully-qualified - // operator and the final arg list - return new OpApplNode(genID.getFullyQualifiedOp(), finalArgList, - syntaxTreeNode, cm); - } // end generateOpAppl() - - /** - * Process a named, parameterixed instantiation, e.g. of the form - * D(p1,...pn) = INSTANCE M WITH a1 <- e1 ,..., ar <- er - */ - /************************************************************************* - * Note: the returned value does not seem to be used. * - *************************************************************************/ - private final OpDefNode processModuleDefinition( - TreeNode treeNode, - Vector defs, - /******************************************************* - * This is non-null when called from inside a LET, in * - * which case the OpDef node is appended to defs. If * - * null, the OpDef node is appended to the * - * module-level lists of such nodes. * - *******************************************************/ - Vector insts, - /******************************************************* - * If non-null, then a vector of InstanceNode objects * - * to which the current instance node is to be * - * appended. If null, cm.appendInstance is called to * - * put the InstanceNode onto the module-level lists of * - * such nodes. * - *******************************************************/ - ModuleNode cm) - throws AbortException { - // Start with a LHS for an instance: we must extract from it name - // and possibly parameters. Then we need the external Context of - // the module and to extract all non-local, non-builtin - // symbols. Then build the proper symbol list and add it. - - // We must remember to identify explicitly whether or not the new - // nodes would be local. - - // assert treeNode.isKind(N_ModuleDefinition) - // - // Note that this code does nothing about THEOREMS and ASSUMES in - // modules being instantiated - boolean localness = treeNode.zero() != null; - TreeNode[] children = treeNode.one()[0].heirs(); // heirs of IdentLHS - UniqueString name = children[0].getUS(); - - // processing of LHS of the definition, i.e. the name and parameters - FormalParamNode[] args = nullParam; - Context parmCtxt = null; - - // If the operator being defined as a module instance has any parameters - if (children.length > 1) { - // Create new array of FormalParamNodes for the new operator - args = new FormalParamNode[ children.length /2 -1 ]; - - // Push a new context in current module's SymbolTable - parmCtxt = new Context(moduleTable, errors); - symbolTable.pushContext(parmCtxt); - - // For each formal parameter declared for the op being defined - for (int i = 0; i < args.length; i++) { - TreeNode child = children[2 + 2 * i]; - UniqueString id = null; - int count = 0; - - if ( child.isKind(N_IdentDecl)) { - id = child.heirs()[0].getUS(); - count = (child.heirs().length -1)/ 2; - } - else if ( child.isKind(N_InfixDecl)) { - id = child.heirs()[1].getUS(); - count = 2; - } - else if ( child.isKind(N_PrefixDecl)) { - id = child.heirs()[0].getUS(); - count = 1; - } - else if ( child.isKind(N_PostfixDecl)) { - id = child.heirs()[1].getUS(); - count = 1; - } - else { - errors.addAbort( - treeNode.getLocation(), - "Internal error: Error in formal params part of parse tree.", - true); - } - - // If there was no error - if ( id != null ) { - // Create a new FormalParamNode for the defined Op and put - // it in the SymbolTable - args[i] = new FormalParamNode(id, count, child, symbolTable, cm); - } // end if - } // end for - } // end if - - // processing RHS of the definition, starting with identification - // of module being instantiated, followed by processing of the - // WITH clause (if any) - children = treeNode.one()[2].heirs(); // heirs of NonLocalInstance - - // Find the Context and ModuleNode for the module being instantiated - Context instanceeCtxt = this.getContext(children[1].getUS()); - ModuleNode instanceeModule = symbolTable.resolveModule(children[1].getUS()); - - if (instanceeCtxt == null) { - errors.addError( - children[1].getLocation(), - "Module " + children[1].getImage() + " does not have a context."); - return nullODN; - } - - if (instanceeModule == null) { - errors.addError(children[1].getLocation(), - "Module name " + children[1].getImage() + - " is not known" + " in current context."); - return nullODN; - } - - /* - * Set isInstantiated field of instancee. Added by LL 23 July 2013 - */ - instanceeModule.setInstantiated(true) ; - - - // Create a SubstInNode that will be used to wrap each definition - // body in the module being defined. "children" is the array of - // explicit substitution clauses used in the module definition. - // Both instanceeCtxt and symbolTable are involved here since for - // each substitution c <- e, c must be resolved in the - // instanceeCtxt, and e must be interpreted in symbolTable - SubstInNode substIn = processSubst(treeNode, children, symbolTable, - instanceeCtxt, instanceeModule, cm); - - // We are done with the local context (if one was created because - // of parameters) - if (parmCtxt != null) symbolTable.popContext(); - - // Create a vector of all of the OpDefNodes in the instancee module - /*********************************************************************** - * I have no idea why the module's getOpDefs method isn't used here. * - ***********************************************************************/ - Vector elts = instanceeCtxt.getByClass( OpDefNode.class ); - - // For each definition in the instancee module, create a - // corresponding definition in the instancer module - for (int i = 0; i < elts.size(); i++) { - // Find the OpDefNode to be instantiated - OpDefNode odn = (OpDefNode)elts.elementAt(i); - - /********************************************************************** - * Ignore it if it is local or a builtin def. * - **********************************************************************/ - if ( !odn.isLocal() - && ( (odn.getKind() == UserDefinedOpKind) - || (odn.getKind() == ModuleInstanceKind) )) { - // Create the new name prepended with "name!" - String compoundID = name + "!" + odn.getName(); - UniqueString qualifiedName = UniqueString.uniqueStringOf(compoundID); - - // Copy parameters for the op being defined - FormalParamNode [] fpn = odn.getParams(); - FormalParamNode [] params = new FormalParamNode[fpn.length + args.length]; - System.arraycopy(args, 0, params, 0, args.length); - System.arraycopy(fpn, 0, params, args.length, fpn.length); - - OpDefNode newOdn ; - if (odn.getKind() == UserDefinedOpKind) { - if (substIn.getSubsts().length > 0) { - // If there are substitutions, then the body of the new - // definition instance must be wrapped in a SUBST-IN node. - // Create the "wrapping" SubstInNode as a clone of "subst" - // above, but with a body from the OpDefNode in the module - // being instantiated - SubstInNode substInNode = - new SubstInNode(treeNode, substIn.getSubsts(), odn.getBody(), - cm, instanceeModule); - - // Create the OpDefNode for the new instance of this - // definition; because of the new operator name, cm is the - // module of origin for purposes of deciding of two defs are - // "the same" or "different" - newOdn = new OpDefNode(qualifiedName, UserDefinedOpKind, params, - localness, substInNode, cm, symbolTable, - treeNode, true, odn.getSource()); - setOpDefNodeRecursionFields(newOdn, cm) ; - newOdn.setLabels(odn.getLabelsHT()) ; - } // if (substIn.getSubsts().length > 0) - else { - // no SUBST-IN node required; but because of the new - // operator name, cm is the module of origin for purposes of - // deciding of two defs are "the same" or "different" - newOdn = new OpDefNode(qualifiedName, UserDefinedOpKind, params, - localness, odn.getBody(), cm, symbolTable, - treeNode, true, odn.getSource()); - setOpDefNodeRecursionFields(newOdn, cm) ; - newOdn.setLabels(odn.getLabelsHT()) ; - } // else - } // if (odn.kind == UserDefinedOpKind) - else { - /***************************************************************** - * This is a ModuleInstanceKind node. * - *****************************************************************/ - newOdn = new OpDefNode( - qualifiedName, params, localness, - odn.getOriginallyDefinedInModuleNode(), symbolTable, - treeNode, odn.getSource()); - } ; // else - // defs is non-null iff this module definition is in the Let - // part of a Let-In expression. Add this newly created OpDef - // to either the LET list or the module cm's definition list. - if (defs == null) { - cm.appendDef(newOdn); - } - else { - defs.addElement(newOdn); - } - } // if (!odn.isLocal()&& ... ) - } // for - - /********************************************************************** - * Import the ThmOrAssumpDefNode objects to the current module. The * - * following code for doing this was copied and modified without * - * much thinking from the code above for OpDefNode objects * - **********************************************************************/ - // Create a vector of all of the ThmOrAssumpDefNodes in the - // instancee module - Vector taelts = instanceeCtxt.getByClass( ThmOrAssumpDefNode.class ); - - // For each definition in the instancee module, create a - // corresponding definition in the instancer module - for (int i = 0; i < taelts.size(); i++) { - // Find the ThmOrAssumpDefNode to be instantiated - ThmOrAssumpDefNode taOdn = (ThmOrAssumpDefNode)taelts.elementAt(i); - - /********************************************************************* - * There are no builtin ThmOrAssumpDefNode objects. * - *********************************************************************/ - // Ignore it if it is local - if (!taOdn.isLocal()) { - // Create the new name prepended with "name!" - String compoundID = name + "!" + taOdn.getName(); - UniqueString qualifiedName = UniqueString.uniqueStringOf(compoundID); - - // Copy parameters for the op being defined - /******************************************************************* - * Theorem or assumption definitions have no parameters. * - *******************************************************************/ - FormalParamNode [] fpn = taOdn.getParams(); - FormalParamNode [] params = - new FormalParamNode[fpn.length + args.length]; - System.arraycopy(args, 0, params, 0, args.length); - System.arraycopy(fpn, 0, params, args.length, fpn.length); - - ThmOrAssumpDefNode newtaOdn; - if (substIn.getSubsts().length > 0) { - // If there are substitutions, then the body of the new - // definition instance must be wrapped in a SUBST-IN node. - // Create the "wrapping" SubstInNode as a clone of "subst" - // above, but with a body from the ThmOrAssumpDefNode in the module - // being instantiated - APSubstInNode substInNode = - new APSubstInNode(treeNode, substIn.getSubsts(), taOdn.getBody(), - cm, instanceeModule); - - // Create the ThmOrAssumpDefNode for the new instance of this - // definition; because of the new operator name, cm is the - // module of origin for purposes of deciding of two defs are - // "the same" or "different" - newtaOdn = new ThmOrAssumpDefNode(qualifiedName, taOdn.isTheorem(), - substInNode, cm, symbolTable, - treeNode, params, instanceeModule, - taOdn.getSource()); - // Following statement added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. Added setLabels call - // on 31 Oct 2012. - newtaOdn.setLocal(localness); - newtaOdn.setLabels(taOdn.getLabelsHT()) ; - - /***************************************************************** - * No recursion fields needed for a theorem or assumption * - * because it can't appear in a recursive section. * - *****************************************************************/ - // setThmOrAssumpDefNodeRecursionFields(newtaOdn, cm) ; - } - else { - // no SUBST-IN node required; but because of the new - // operator name, cm is the module of origin for purposes of - // deciding if two defs are "the same" or "different" - newtaOdn = new ThmOrAssumpDefNode(qualifiedName, taOdn.isTheorem(), - taOdn.getBody(), cm, symbolTable, - treeNode, params, instanceeModule, - taOdn.getSource()); - // Following statement added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. Added setLabels call - // on 31 Oct 2012. - newtaOdn.setLocal(localness); - newtaOdn.setLabels(taOdn.getLabelsHT()) ; - /***************************************************************** - * No recursion fields needed for theorems or assumptions * - * because they can't appear in a recursive section. * - *****************************************************************/ - // setThmOrAssumpDefNodeRecursionFields(newtaOdn, cm) ; - } - - // defs is non-null iff this module definition is in the Let - // part of a Let-In expression. Add this newly created ThmOrAssumpDef - // to either the LET list or the module cm's definition list. - if (defs == null) { - cm.appendDef(newtaOdn); - } - else { - defs.addElement(newtaOdn); - } - } // if (!taOdn.isLocal()&& ... ) - } // for - - // Create a new InstanceNode to represent this INSTANCE stmt - // in the current module - InstanceNode inst = new InstanceNode(name, localness, args, - instanceeModule, - substIn.getSubsts(), treeNode); - - // Append this new InstanceNode to the vector of InstanceNodes - // being accumulated for this module - if (insts == null) { - cm.appendInstance(inst); - } - else { - insts.addElement(inst); - } - - // Create new OpDefNode with ModuleInstanceKind. The reason for - // doing this is to get the name in the symbol table so the name - // cannot be re-used later in this module for a user-defined - // operator. - return new OpDefNode(name, args, localness, cm, symbolTable, treeNode, - null); - /********************************************************************* - * Note: the module's OpDefNode does not have recursive parameters * - * set. If the module definition statement occurs in a recursive * - * section, then it is the instantiated definitions that are * - * recursive, not the module definition itself. (The name under * - * which the module is instantiated cannot appear in a RECURSIVE * - * statement.) * - *********************************************************************/ - - } // end processModuleDefinition() - - /** - * From a particular explicit substitution (substTarget <- substValue) - * check the legality of the substTarget, and if OK, generate the - * appropriate type of node for substValue - */ - private ExprOrOpArgNode generateSubst( - Context instanceeCtxt, - TreeNode substTarget, - TreeNode substValue, - ModuleNode mn) - throws AbortException { - SymbolNode targetSymbol = instanceeCtxt.getSymbol(substTarget.getUS()); - - // if the targetSymbol cannot be found in the instancee context, - // or if it does not correspond to a declaration, then it is an - // illegal substitution target - - if (targetSymbol == null || ! (targetSymbol instanceof OpDeclNode) ) { - errors.addError( - substTarget.getLocation(), - "Identifier '" + substTarget.getUS() + "' is not a legal" + - " target of a substitution. \nA legal target must be a declared" + - " CONSTANT or VARIABLE in the module being instantiated." + - " \n(Also, check for warnings about multiple declarations of" + - " this same identifier.)"); - return nullOAN; - } - - // but if the symbol is found, then if it has arity 0, the RHS - // should be an expression, if arity > 0, the the RHS should be an OpArg - ExprOrOpArgNode returnObject; - - if ( targetSymbol.getArity() == 0 ) { - // if the target of the substitution has arity 0, - // then we expect an expression to be substituted for it - returnObject = generateExpression(substValue, mn); - } - else { - // if the target of the substitution has arity > 0, - // then and operator must be substituted for it - returnObject = generateOpArg(targetSymbol, substValue, mn); - - // and it better have the same arity as the target - if ( ((OpArgNode)returnObject).getArity() != targetSymbol.getArity() ) { - errors.addError(substValue.getLocation(), - "An operator must be substituted for symbol '" + - targetSymbol.getName() + "', and it must have arity " + - targetSymbol.getArity() + "."); - } - } - return returnObject; - } // end generateSubst() - - /** - * Return an OpArgNode constructed from a GeneralId tree to be used - * in the RHS of a substitution - */ - private OpArgNode generateOpArg(SymbolNode targetSymbol, - TreeNode opArgSyntaxNode, - ModuleNode mn) - throws AbortException { - /*********************************************************************** - * If this is a lambda expressiion, then just get it and go. * - ***********************************************************************/ - if (opArgSyntaxNode.isKind(N_Lambda)) { - return new OpArgNode(generateLambda(opArgSyntaxNode, mn), - opArgSyntaxNode, mn) ; - } ; - // First, make sure that an operator ID is present, and not an expression - if ( ! ( opArgSyntaxNode.isKind(N_GeneralId) || - opArgSyntaxNode.isKind(N_GenInfixOp) || - opArgSyntaxNode.isKind(N_GenPrefixOp) || - opArgSyntaxNode.isKind(N_GenNonExpPrefixOp) || - /************************************************************ - * This last disjunct was added by LL on 9 May 2007. * - * * - * The original parser phase produced an N_GenPrefixOp * - * here, but an N_GenNonExpPrefixOp for the syntactically * - * identical situation in an operator argument. The new * - * TLA+2 parser produces N_GenNonExpPrefixOp nodes here, * - * but I left the N_GenPrefixOp case in here just in case * - * this is called somewhere else that I haven't found. * - ************************************************************/ - - opArgSyntaxNode.isKind(N_GenPostfixOp) - ) - ) { - errors.addError(opArgSyntaxNode.getLocation(), - "Arity " + targetSymbol.getArity() + - " operator (not an expression) is expected" + - " \nto substitute for CONSTANT '" + - targetSymbol.getName() + "'." ); - return nullOpArg; - } - - /*********************************************************************** - * If the argument is a GeneralId node, then we use * - * genIdToSelector and selectorToNode to generate the OpArg node. * - ***********************************************************************/ - if (opArgSyntaxNode.getKind() == N_GeneralId) { - /********************************************************************* - * First, a sanity check to make sure we're never looking for an * - * expression argument. * - *********************************************************************/ - if (targetSymbol.getArity() <= 0) { - errors.addAbort(opArgSyntaxNode.getLocation(), - "Internal error: expected to find arity > 0.", true); - } ; - - LevelNode ln = selectorToNode(genIdToSelector( - (SyntaxTreeNode) opArgSyntaxNode), - targetSymbol.getArity(), false, false, mn); - - /******************************************************************* - * Added 23 February 2009: It appears that, in case of an error, * - * selectorToNode can return something other than an OpArgNode * - * here. (In particular, an OpApplNode.) Rather than tix * - * selectorToNode, I am adding a kludge to simply ignore the * - * problem and hope that it can be caused only by some other * - * error. If no error has been found, then we abort and debug if * - * this is encountered. * - *******************************************************************/ - if (!(ln instanceof OpArgNode)) { - if (errors.getNumErrors() > 0) { return nullOpArg; } - errors.addAbort(opArgSyntaxNode.getLocation(), - "Internal error: " + - "Expected an operator argument but " + - "found something else."); - }; - return (OpArgNode) ln ; - } ; - - /******************************************************************* - * If the argument is not a GeneralId node, we use the code from * - * SANY1 to generate the OpArg node. * - *******************************************************************/ - - // Assemble the (possibly compound) generalized identifier, and resolve it. - GenID genID = generateGenID(opArgSyntaxNode, mn); - - // If the fully-qualified op is undefined, then a message has already been - // put in errors, but we must insert a nullOpArgNode in the tree. - if (genID.getFullyQualifiedOp() != null && genID.getArgs().length == 0 ) { - // Create an OpArgNode from it. - return new OpArgNode(genID.getFullyQualifiedOp(), opArgSyntaxNode, mn); - } - else if ( genID.getArgs().length > 0 ) { - // Expression being used where Operator is required - errors.addError(opArgSyntaxNode.getLocation(), - "Arity " + targetSymbol.getArity() + - " operator (not an expression) is expected" + - " to substitute for CONSTANT '" + - targetSymbol.getName() + "'." ); - return nullOpArg; - } - else { - return nullOpArg; - } - } // end generateOpArg() - - /** - * Process the substitutions clause of a module definition or instantiation; - * returns a SubstInNode that can be used as a template for the wrapper that - * must be present around each OpDefNode body created from the module - * instantiation or module definition. - */ - private SubstInNode processSubst( - TreeNode treeNode, - TreeNode[] substNodes, - // array of subst nodes [c1 <- e1, ... ,cn <- en] - SymbolTable instancerST, - // SymbolTable in which the ei must be resolved - Context instanceeCtxt, - // Context in which the ci must be resolved - ModuleNode instanceeModule, - // the ModuleNode of the module in which ci must be resolved - ModuleNode mn) throws AbortException { - TreeNode[] children; // find the substitution part of the syntax tree - - // Create a vector of all declarations of CONSTANTS and VARIABLES - // in the context of the module being instantiated (instancee). - // These are all the symbols that must have substitutions defined - // for them in the instantiation, either explictly or implicitly. - Vector decls = instanceeCtxt.getByClass( OpDeclNode.class ); - - // Create a SubstInNode to be used as a template for the SubstInNodes - // in the body of every newly instantiated OpDef in the module. - // The substitutions in the returned SubstInNode object will be the - // implicit substitutions of the form c<-c for all CONSTANTS and - // VARIABLES c that are BOTH declared in instancee and for which the - // same name is declared or defined in instancer. Note the instancerST - // must be passed to this constructor because with a default substitution - // LHS<-RHS the LHS is resolved in the instanceeCtxt, (done - // in the previous line) and the RHS is resolved in the instancerST. - SubstInNode substIn = - new SubstInNode(treeNode, instancerST, decls, mn, instanceeModule); - - // For each explicit substitution in the syntax tree, overwrite or add - // the corresponding default entry in SubstInNode just created - for (int i = 3; i < substNodes.length; i += 2) { - // pick up array of syntax elements for one substitution, - // e.g. ["c","<-",expr] - TreeNode sc[] = substNodes[i].heirs(); - - // substRHS is the expression "exp" in "c <- exp"; this stmt first - // checks that c is properly declared in the instancee context, - // and then generates an ExprOrOpArgNode. If c is a constant - // with parameters, then an OpArgNode is returned; otherwise it is - // an ExprNode. - ExprOrOpArgNode substRHS = - generateSubst(instanceeCtxt, sc[0], sc[2], mn); - - // Overwrite an implicit substitution if there is one, or add a new one, - // checking for duplicate substitutions for the same symbol - substIn.addExplicitSubstitute(instanceeCtxt, sc[0].getUS(), - sc[2], substRHS ); - } - - // Check if substitution is complete, i.e. that all constants and vars - // have been substituted for. - substIn.matchAll( decls ); - return substIn; - } // end processSubst - - /** - * This method treats *unnamed* INSTANCE stmts - * NOTE: this code does nothing with ASSUMES or THEOREMS - */ - /************************************************************************* - * However, SANY2 imports ThmOrAssumpDef nodes. * - *************************************************************************/ - /** - * @param treeNode - * @param cm - * @param topLevel - * @return - * @throws AbortException - */ -/** - * @param treeNode - * @param cm - * @param topLevel - * @return - * @throws AbortException - */ -/** - * @param treeNode - * @param cm - * @param topLevel - * @return - * @throws AbortException - */ -/** - * @param treeNode - * @param cm - * @param topLevel - * @return - * @throws AbortException - */ -private final InstanceNode - generateInstance(TreeNode treeNode, ModuleNode cm, boolean topLevel) - throws AbortException { - /********************************************************************** - * topLevel argument is true for a top-level INSTANCE statement, and * - * false elsewise--that is, for an INSTANCE inside a proof. * - **********************************************************************/ - TreeNode[] children ; - if (topLevel) { - children = treeNode.one()[0].heirs(); } - // skip one generation below NonLocalInstance - // because we know zero defines local in a - // top-level INSTANCE - else {children = treeNode.heirs();} ; - // id of module being instanced - UniqueString moduleId = children[1].getUS(); - - // If this module instance is declared "LOCAL" then all of the - // definitions in it must be instanced as if they were "LOCAL" - boolean localness = treeNode.local(); - - // Create a list of all declarations for module moduleId. - // Match them against either something in the substitutions or - // something in the current context (symbol table) for the - // substitution. Check that the symbol does occur in the module - // and as a declaration. - Context instanceeCtxt = this.getContext(moduleId); - if (instanceeCtxt == null) { - errors.addAbort(children[1].getLocation(), - "Internal error: No context available for module `" + - moduleId.toString() + "'.", true); - } ; - // Try to find the ModuleNode for the module being instanced in - // the symbolTable - ModuleNode instanceeModuleNode = symbolTable.resolveModule(moduleId); - - // It must be an external module if it isn't in the symbolTable; - // try to find it in moduleTable (it cannot be in both places, or - // a name conflict would have resulted) - if (instanceeModuleNode == null) { - instanceeModuleNode = moduleTable.getModuleNode(moduleId); - } - - if (instanceeModuleNode == null) { - errors.addAbort(children[1].getLocation(), - "Could not find module " + moduleId.toString(), - false); - } - - /* - * Set isInstantiated field of instancee. Added by LL 23 July 2013 - */ - instanceeModuleNode.setInstantiated(true) ; - - // Create the SubstInNode that will act as a template "wrapper" - // for each definition in the module being instantiated; this - // SubstInNode itself gets discarded after being used as template - // however many times is necessary - SubstInNode subst = processSubst(treeNode, children, symbolTable, - instanceeCtxt, instanceeModuleNode, cm); - - // Create a vector of all of the OpDefNodes in the module being - // instantiated - Vector defs = instanceeCtxt.getByClass(OpDefNode.class); - - OpDefNode odn; // OpDefNode in module being instantiated (instancee) - OpDefNode newOdn; // Its counterpart current module (instancer) - SubstInNode substInTemplate; // Template to be used for any - // SubstInNode wrappers required - - // Duplicate the OpDef records from the module being INSTANCE'd - for (int i = 0; i < defs.size(); i++) { - odn = (OpDefNode)defs.elementAt(i); - // OpDefNode in module being instantiated (instancee) - - // Do not instantiate built-in or local operators, or those - // OpDefNodes created solely to prevent a ModuleName from being - // used as an operator node. - if (odn.getKind() == BuiltInKind || - odn.getKind() == ModuleInstanceKind || - odn.isLocal()) { - continue; - } - - // If there are parameters to the module being instantiated, then - // a SubstInNode is required, and possibly a different module of - // origin should be indicated - if (!instanceeModuleNode.isParameterFree()) { - // Create the OpDefNode for the new instance of this definition - // Note that the new OpDefNode shares the array of FormalParamNodes - // with the old OpDefNode, as well as large parts of its body - // (all but the SubstInNode). Hence, changes by a tool to an Original - // OpDefNode will likely be reflected in all instances of it. - if ( odn.getOriginallyDefinedInModuleNode().isParameterFree() ) { - - /**************************************************************** - * Originally, newOdn was set the way it now is if localness = * - * true. Here's the problem with it. Suppose the instantiated * - * module EXTENDS the Naturals module. Then this will add new * - * OpDefNodes for all the symbols defined in Naturals. If the * - * current module EXTENDS Naturals, this will lead to multiple * - * definitions. So, for nonlocal definitions, we just * - * set newOdn to odn. * - * * - * However, now the problem is: suppose the current module * - * does not EXTEND the Naturals module. Then the operators * - * defined in Naturals, which should be defined in the current * - * module, are not. So, we add them to symbolTable. This does * - * not lead to a multiple definition error because apparently * - * it's the addSymbol method that is smart enough to detect if * - * we are adding a definition that comes from the same source as * - * the original one. * - * * - * This fix was made by LL on 16 Feb 2009. * - * * - * On 6 June 2010, LL add "&& topLevel" to the following `if' * - * test. This was needed because an INSTANCE inside a proof * - * was producing a "Multiple declarations or definition" * - * warning if the INSTANCEd module and the current module both * - * EXTENDed Naturals. This fix seems to do the right thing, * - * but I have not extensively tested it and I have no idea what * - * problems may remain. * - ****************************************************************/ - if (localness && topLevel ) { - newOdn = new OpDefNode( odn.getName(), UserDefinedOpKind, odn.getParams(), - localness, odn.getBody(), - odn.getOriginallyDefinedInModuleNode(), - symbolTable, treeNode, true, odn.getSource() ); - /*************************************************************** - * The following statement was added by LL on 16 Feb 2009, by * - * analogy with the corresponding code about 45 lines below. I * - * have no idea if it was originally omitted for a good reason. * - ***************************************************************/ - newOdn.setLabels(odn.getLabelsHT()) ; - } - else { - newOdn = odn; - symbolTable.addSymbol(odn.getName(), odn); - } - } - else { - // Create the "wrapping" SubstInNode as a clone of "subst" above, - // but with a body from the OpDefNode in the module being - // instantiated - substInTemplate = new SubstInNode(treeNode, subst.getSubsts(), - odn.getBody(), cm, - instanceeModuleNode); - newOdn = new OpDefNode(odn.getName(), UserDefinedOpKind, - odn.getParams(), localness, - substInTemplate, cm, symbolTable, treeNode, - true, odn.getSource()); - newOdn.setLabels(odn.getLabelsHT()) ; - - - } - } - else { - // There are no parameters to the instancee module; this - // means that a SubstInNode is not necessary, and also that - // the new operator should be considered to be "originally - // defined in" the same module as the old one for purposes of - // telling whether they are "the same" or different definitions - - // Create an OpDefNode whose body is the same as the instancer's. - - if (localness) { - /**************************************************************** - * See the comments about the similar change made to the * - * setting of newOdn in the `then' clause, just above. * - * This entire change was made by LL on 16 Feb 2009. * - ****************************************************************/ - newOdn = new OpDefNode(odn.getName(), UserDefinedOpKind, odn.getParams(), - localness, odn.getBody(), - odn.getOriginallyDefinedInModuleNode(), - symbolTable, treeNode, true, odn.getSource()); - newOdn.setLabels(odn.getLabelsHT()) ; - } - else { - newOdn = odn; - symbolTable.addSymbol(odn.getName(), odn); - } - } - cm.appendDef(newOdn); - setOpDefNodeRecursionFields(newOdn, cm) ; - } // end for - - /********************************************************************** - * Import the ThmOrAssumpDefNode objects to the current module. The * - * following code for doing this was copied and modified without * - * thinking from the code above for OpDefNode objects * - **********************************************************************/ - Vector tadefs = instanceeCtxt.getByClass(ThmOrAssumpDefNode.class); - - ThmOrAssumpDefNode tadn; - // ThmOrAssumpDefNode in module being instantiated (instancee) - ThmOrAssumpDefNode newTadn; - // Its counterpart current module (instancer) - APSubstInNode tasubstInTemplate; // Template to be used for any - // SubstInNode wrappers required - - // Duplicate the OpDef records from the module being INSTANCE'd - for (int i = 0; i < tadefs.size(); i++) { - tadn = (ThmOrAssumpDefNode)tadefs.elementAt(i); - // ThmOrAssumpDefNode in module being instantiated (instancee) - - // Following statement added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. - if (tadn.isLocal()) { - continue ; - } - - // If there are parameters to the module being instantiated, then - // a SubstInNode is required, and possibly a different module of - // origin should be indicated - if (!instanceeModuleNode.isParameterFree()) { - // Create the ThmOrAssumpDefNode for the new instance of this - // definition. Note that the new ThmOrAssumpDefNode shares the - // array of FormalParamNodes with the old ThmOrAssumpDefNode, - // as well as large parts of its body (all but the SubstInNode). - // Hence, changes by a tool to an Original ThmOrAssumpDefNode will - // likely be reflected in all instances of it. - if ( tadn.getOriginallyDefinedInModuleNode().isParameterFree() ) { - // Following if/else added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. - if (localness && topLevel ) { - newTadn = new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), - tadn.getBody(), cm, symbolTable, treeNode, - tadn.getParams(), instanceeModuleNode, - tadn.getSource()) ; - newTadn.setLocal(true); - } - else { - newTadn = tadn; - // On 30 Oct 2012, LL noticed that code was added on 16 Feb 2009 - // to the corresponding place in the code for an OpDefNode, but that - // nothing was added here. I suspect that something should have been - // that the 2009 code should also have been added here, but wasn't-- - // perhaps because there's no getLabelsHT method for a ThmOrAssumpDefNode. - // This may mean that there's a bug in handling labels in the - // instantiated theorem or assumption. - } - /* - new ThmOrAssumpDefNode( tadn.getName(), UserDefinedOpKind, - tadn.getParams(), - localness, tasubstInTemplate, - tadn.getOriginallyDefinedInModuleNode(), - symbolTable, treeNode, true ); - */ - } - else { - // Create the "wrapping" SubstInNode as a clone of "subst" above, - // but with a body from the ThmOrAssumpDefNode in the module being - // instantiated - tasubstInTemplate = new APSubstInNode(treeNode, subst.getSubsts(), - tadn.getBody() , cm, - instanceeModuleNode); - newTadn = new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), - tasubstInTemplate, cm, symbolTable, - treeNode, tadn.getParams(), - instanceeModuleNode, tadn.getSource()); - // Following if/else added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. - newTadn.setLocal(localness) ; - // cm.appendDef(newTadn); - newTadn.setLabels(tadn.getLabelsHT()) ; - - } - } - else { - // There are no parameters to the instancee module; this - // means that a SubstInNode is not necessary, and also that - // the new operator should be considered to be "originally - // defined in" the same module as the old one for purposes of - // telling whether they are "the same" or different definitions - - // Create a ThmOrAssumpDefNode whose body is the same as - // the instancer's. - if (localness && topLevel) { - newTadn = - new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), - tadn.getBody(), - tadn.getOriginallyDefinedInModuleNode(), - symbolTable, treeNode, tadn.getParams(), - instanceeModuleNode, tadn.getSource()); - // Following if/else added by LL on 30 Oct 2012 to handle locally - // instantiated theorems and assumptions. - newTadn.setLocal(localness) ; - newTadn.setLabels(tadn.getLabelsHT()) ; - } - else { - newTadn = tadn; - symbolTable.addSymbol(tadn.getName(), tadn); - } - } - if (topLevel) {cm.appendDef(newTadn);} ; - /******************************************************************** - * No recursion fields needed for theorems or assumptions because * - * they can't appear in a recursive section. * - ********************************************************************/ - // setOpDefNodeRecursionFields(newTadn, cm) ; - } // end for - - // Create a new InstanceNode to represent this INSTANCE stmt in - // the current module - InstanceNode inst = - new InstanceNode(null /*no name*/, localness, null /*no parms*/, - instanceeModuleNode, subst.getSubsts(), treeNode); - - // Append this new InstanceNode to the vector of InstanceNodes - // being accumulated for this module - if (topLevel){ cm.appendInstance(inst); } ; - return inst; - - } // void generateInstance - - - private final void processTheorem(TreeNode stn, ModuleNode cm) - throws AbortException { - ThmOrAssumpDefNode tadn = null ; - LevelNode body ; - ProofNode proof = null ; - int bodyIndex = stn.heirs().length - 1 ; - boolean isAssumeProve = false ; - /********************************************************************* - * Set true if the body is an ASSUME/PROVE. * - *********************************************************************/ - boolean hasProof = - (stn.heirs()[bodyIndex].getKind() == N_Proof) - || (stn.heirs()[bodyIndex].getKind() == N_TerminalProof) ; - if (hasProof) {bodyIndex--;} ; - - if (bodyIndex > 1) { - /********************************************************************* - * If this is a named theorem, start fresh processing of labels, * - * create the object. * - *********************************************************************/ - pushLS(); - UniqueString name = stn.heirs()[1].getUS() ; - tadn = new ThmOrAssumpDefNode(name, stn) ; - } ; - if (stn.zero()[bodyIndex].isKind(N_AssumeProve)) - { /******************************************************************* - * Theorem statement is an ASSUME/PROVE. Must set currentGoal. * - *******************************************************************/ - currentGoal = tadn ; - isAssumeProve = true ; - - /******************************************************************* - * We want the symbols declared in top-level NEW statements of the * - * ASSUME clause to be visible in the proof. Therefore, we do the * - * context push for the top-level AssumeProveNode here instead of * - * in generateAssumeProve. * - *******************************************************************/ - symbolTable.pushContext(new Context(moduleTable, errors)) ; - body = generateAssumeProve(stn.heirs()[bodyIndex], cm); - currentGoal = null ; - } - else { /**************************************************************** - * Theorem statement must be an ExprNode. * - ****************************************************************/ - body = generateExpression(stn.heirs()[bodyIndex], cm); - } ; - if (bodyIndex > 1) { - /********************************************************************** - * The theorem node has the form * - * THEOREM Ident == statement * - **********************************************************************/ - Context assumeContext = null; - if (isAssumeProve) { - /******************************************************************** - * If the body is an ASSUME/PROVE, we must save in assumeContext * - * the context containing the symbols declared in the ASSUME * - * clause and pop it, so Ident is made visible outside the proof. * - ********************************************************************/ - assumeContext = symbolTable.getContext() ; - symbolTable.popContext() ; - } ; - UniqueString name = stn.heirs()[1].getUS() ; - tadn.construct(true, body, cm, symbolTable, null) ; - tadn.setLabels(popLabelNodeSet()) ; - cm.appendDef(tadn) ; - if (isAssumeProve) { - /******************************************************************** - * After putting Ident into the symbol table, we push the ASSUME * - * context back onto symboltable. * - ********************************************************************/ - symbolTable.pushContext(assumeContext) ; - }; - } ; // if (bodyIndex > 1) - - /************************************************************************ - * Note: If this is a named theorem, then the name has been added to * - * symbolTable so it can be referred to within the theorem's proof (if * - * it has one). * - ************************************************************************/ - if (hasProof) {proof = generateProof(stn.heirs()[bodyIndex+1], cm);} ; - - if (isAssumeProve) { - symbolTable.popContext(); - /******************************************************************** - * Pop the context containing ASSUME declarations. * - ********************************************************************/ - ((AssumeProveNode) body).inProof = false ; - /******************************************************************** - * Reset the AssumeProve node's inProof field. * - ********************************************************************/ - } ; - cm.addTheorem(stn, body, proof, tadn) ; - } // ProcessTheorem - - private final void processAssumption(TreeNode stn, ModuleNode cm) - throws AbortException { - ThmOrAssumpDefNode tadn = null ; - int lastIndex = stn.heirs().length - 1 ; - if (lastIndex > 1) {pushLS();} ; - /********************************************************************* - * If this is a named assumption, start fresh processing of labels. * - *********************************************************************/ - ExprNode expr = generateExpression(stn.heirs()[lastIndex], cm); - - if (lastIndex > 1) { - /********************************************************************** - * The assumption node has the form * - * ASSUME Ident == expression * - **********************************************************************/ - UniqueString name = stn.heirs()[1].getUS() ; - tadn = new ThmOrAssumpDefNode(name, false, expr, cm, symbolTable, stn, - null, null, null) ; - tadn.setLabels(popLabelNodeSet()) ; - cm.appendDef(tadn) ; - } ; - cm.addAssumption(stn, expr, symbolTable, tadn); - return; - } // processAssumption - - - private final ProofNode generateProof(TreeNode stn, ModuleNode cm) - /*********************************************************************** - * Node stn is of kind N_TerminalProof or an N_Proof. The heirs of an * - * N_Proof node consist of an optional PROOF token followed by a * - * seequence of N_ProofStep nodes. The heirs of an N_ProofStep node * - * are a StartStep() token, a statement body, and an optional proof. * - * A statement body is one of the following node kinds: * - * * - * Have no proof: * - * N_DefStep N_UseOrHide N_NonLocalInstance N_HaveStep, * - * N_TakeStep N_WitnessStep * - * * - * Have a proof * - * N_QEDStep N_PickStep N_CaseStep N_AssertStep * - * * - * Each step produces the following kind of semantic node: * - * * - * N_DefStep : DefStepNode * - * * - * N_UseOrHide : UseOrNideNode * - * * - * N_NonLocalInstance : InstanceNode * - * * - * Others: TheoremNode * - * The type of statement is indicated by the body of the * - * node. For any step other than an N_AssertStep, the body * - * is an OpApplNode with the following dummy operator: * - * * - * N_HaveStep : $Have * - * N_CaseStep : $Pfcase * - * N_TakeStep : $Take * - * N_PickStep : $Pick * - * N_WitnessStep : $Witness * - * N_QEDStep : $Qed * - ***********************************************************************/ - throws AbortException { - int numberOfPops = 0; - /********************************************************************* - * For each SUFFICES ASSUME/PROVE step, we push a new context onto * - * the symbol table containing declarations of any NEW symbols. * - * These need to be popped off when through processing the proof. * - *********************************************************************/ - if (stn.getKind() == N_TerminalProof) { - return generateLeafProof(stn, cm) ;} ; - - Context pfCtxt = new Context(moduleTable, errors) ; - symbolTable.pushContext(pfCtxt); - /********************************************************************* - * Create a new sub-Context for the proof. * - *********************************************************************/ - - TreeNode heirs[] = stn.heirs() ; - int offset = 0 ; - if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { offset = 1 ; } ; - LevelNode[] steps = new LevelNode[heirs.length - offset] ; - Vector iVec = new Vector() ; - /********************************************************************* - * A vector to hold the InstanceNodes generated by steps of the form * - * Id == INSTANCE ... so they can be level checked. * - *********************************************************************/ - - /*********************************************************************** - * At the beginning of each loop iteration, the variable prevIsInFix * - * equals true iff the previous step consists of a formula whose main * - * operator is an infix operator, including an "@-step" of the form "@ * - * infix-op expression". If it is true, then rhSide is the ExprNode * - * of the infix-op's right-hand-side expression. * - ***********************************************************************/ - boolean prevIsInfix = false ; - ExprNode prevRHS = null ; - - for (int i = offset ; i < heirs.length; i++) { - /********************************************************************* - * Process proof step i. * - *********************************************************************/ - boolean isAssumeProve = false ; - /******************************************************************* - * Will be set true for an ASSUME/PROVE, so we can reset the * - * node's inProof field. * - *******************************************************************/ - boolean isSuffices = false ; - /******************************************************************* - * Will be set to true for a SUFFICES statement. This is used to * - * do the right thing with ASSUME declarations in an ASSUME/PROVE * - * step, and to set the suffices field of the ThmOrAssumpDefNode * - * if this is a named step. * - *******************************************************************/ - - /********************************************************************* - * For an ASSUME/PROVE, we set assumeContext to a context containing * - * the declarations from the outer-most NEWs of the ASSUME. For an * - * ordinary ASSUME/PROVE, this context is pushed onto the symbol * - * table for statement's processing the proof. For a SUFFICE * - * ASSUME/PROVE, it is pushed onto the symbol table after processing * - * the statement's proof so the outermost NEW declarations are * - * visible for the rest of the current proof. * - * The handling of the assumeContext was changed on 1 Jul 2009 * - * because SUFFICE ASSUME/PROVE was not being handled properly. * - *********************************************************************/ - Context assumeContext = null; - - /********************************************************************* - * For "PICK x : exp", the symbol x is declared in exp, undeclared * - * in the proof of the step, and declared afterwards. (There'd be a * - * similar problem with TAKE if it took a proof.) The following * - * variables are used to manipulate this, with pickContext holding * - * the declarations of the symbols introduced by the PICK step. * - *********************************************************************/ - boolean isPick = false; - Context pickContext = null; - - /********************************************************************* - * Set stepNumSTN, stepBodySTN, and stepPfSTN to the syntax tree * - * nodes of the step number, the body, and the proof (the latter * - * equal to null if there's no proof. * - *********************************************************************/ - TreeNode pfStepSTN = heirs[i] ; - TreeNode stepNumSTN = pfStepSTN.heirs()[0] ; - TreeNode stepBodySTN = pfStepSTN.heirs()[1] ; - TreeNode stepPfSTN = null ; - if (pfStepSTN.heirs().length > 2) {stepPfSTN = pfStepSTN.heirs()[2];}; - - LevelNode pfNumNode = null ; - boolean makePfNumNode = true ; - /******************************************************************* - * For a numbered step that doesn't produce a TheoremNode, * - * pfNumNode is set to a node that will be the stepNode of a * - * NumberedProofStepKind OpDefNode. * - *******************************************************************/ - /* - * On 23 Feb 2014 LL added the following code to make step numbers - * like <*>13 illegal, so <+> and <*> can be used only for unnamed - * steps. It would be most natural to make the change age the - * parsing level by changing the JavaCC code. However, that code - * is a Kludge that it is best not to touch unless absolutely necessary. - * Also, detecting the error here allows multiple instances of the - * error to be reported in a single execution of the parser. - * - * The modification is based on the following empirical observation: - * - * - For a step number like "<3>13." - * stepNumSTN.image = stepNumSTN.originalImage = "<3>13." - * - For a step number like "<*>13.", - * stepNumSTN.image = "<3>13." and stepNumSTN.originalImage = "<*>13." - * - For unnumbered steps, - * stepNumSTN.originalImage = null and stepNumSTN.image = the actual token. - */ - SyntaxTreeNode STN = (SyntaxTreeNode) stepNumSTN ; - if ( (STN.originalImage != null) - && (STN.originalImage != STN.image) - ) { - String oimage = STN.originalImage.toString() ; - if ( (! oimage.equals(STN.image.toString())) - && ( (oimage.charAt(1) == '*') || (oimage.charAt(1) == '+') ) - ) { - errors.addError(stepNumSTN.getLocation(), - "<*> and <+> cannot be used for a named step."); - } - } - - /********************************************************************* - * Set stepNum to the step number, or null if its an unnumbered step. * - *********************************************************************/ - UniqueString stepNum = null ; - switch (stepNumSTN.getKind()) { - // LL: On 25 Feb 2010 I discovered the following comment here: - // XXXXXX xyz: need to add the following case - // The ProofImplicitStepLexeme case (something like <*>3) seems to be - // handled properly in tests. I presume that this is an obsolete - // comment that I didn't remove when I added the case to the code. - case TLAplusParserConstants.ProofImplicitStepLexeme : - case TLAplusParserConstants.ProofStepLexeme : - stepNum = stepNumSTN.getUS() ; - break ; - case TLAplusParserConstants.ProofStepDotLexeme : - String stNum = stepNumSTN.getUS().toString() ; - stepNum = UniqueString.uniqueStringOf( - stNum.substring(0, stNum.indexOf("."))) ; - break ; - default : - makePfNumNode = false ; - break ; - } ; // switch - - /********************************************************************* - * If this is a numbered step, process labels. * - *********************************************************************/ - if (stepNum != null) { - pushLS(); - } ; - - /******************************************************************** - * Construct the ThmOrOpDefNode if needed. (We need to do it now * - * because we have to set currentGoal before we generate the body.) * - ********************************************************************/ - ThmOrAssumpDefNode tadn = null ; - if (stepNum != null) { - tadn = new ThmOrAssumpDefNode(stepNum, stepNumSTN) ; - } ; - - /********************************************************************* - * Set prevIsInfix false unless this is an AssertStep node. * - *********************************************************************/ - int stepKind = stepBodySTN.getKind(); - if (stepKind != N_AssertStep) {prevIsInfix = false ;} ; - - switch (stepKind) { - case N_DefStep : - /***************************************************************** - * Set defSTNs to the array of heirs, and defOffSet so that * - * defSTNs[defOffSet] ... defSTNs[defSTNs.length-1] is the * - * sequence of definitions. * - *****************************************************************/ - TreeNode[] defSTNs = stepBodySTN.heirs(); - int defOffSet = 0 ; - if (defSTNs[0].getKind() == DEFINE) {defOffSet = 1;}; - - OpDefNode[] defs = new OpDefNode[defSTNs.length - defOffSet] ; - /*************************************************************** - * Will be set to the sequence of OpDefNodes for the * - * definitions. * - ***************************************************************/ - for (int j = defOffSet; j < defSTNs.length ; j++) { - TreeNode defSTN = defSTNs[j]; ; - Vector vec = new Vector() ; - switch (defSTN.getKind()) { - /*************************************************************** - * Need to check if it's an operator, function, or module * - * definition. * - ***************************************************************/ - case N_FunctionDefinition : - processFunction(defSTN, vec, cm) ; - break ; - case N_ModuleDefinition : - /************************************************************* - * The call to processModuleDefinition sets defsVec to a * - * vector of all the definitions it makes, and adds the new * - * InstanceNode to iVec. For now, we're just throwing * - * away defsVec. (If defsVec were null, then * - * processModuleDefinition would add these definitions to to * - * the module's list of top-level definitions.) * - *************************************************************/ - Vector defsVec = new Vector() ; - vec.addElement( - processModuleDefinition(defSTN, defsVec, iVec, cm)) ; - break ; - case N_OperatorDefinition : - processOperator(defSTN, vec, cm) ; - /************************************************************* - * processOperator creates an OpDefNode, puts an entry for * - * it in symbolTable, and adds the OpDefNode to vec. * - *************************************************************/ - break ; - }; // switch (def.getKind()) - defs[j - defOffSet] = (OpDefNode) vec.elementAt(0); - }; // for j - pfNumNode = new DefStepNode(stepBodySTN, stepNum, defs) ; - steps[i - offset] = pfNumNode ; - break ; - - case N_UseOrHide : - UseOrHideNode uohn = generateUseOrHide(stepBodySTN, cm) ; - - // Added by LL on 16 Jun 2010 so location returnedby getLocation() will - // include the step number. - uohn.stn = pfStepSTN; - - uohn.setStepName(stepNum); // Added 6 June 2010 by LL. - - if (uohn.facts.length + uohn.defs.length == 0) { - errors.addError(stepBodySTN.getLocation(), - "Empty USE or HIDE statement."); - }; - uohn.factCheck(); - // Added 4 Mar 2009. - pfNumNode = uohn ; - steps[i - offset] = pfNumNode ; - break ; - - case N_NonLocalInstance : - // Code to set step name added by LL on 6 June 2010 - InstanceNode inst = generateInstance(stepBodySTN, cm, false); - inst.setStepName(stepNum); - pfNumNode = inst; - steps[i - offset] = pfNumNode ; - break ; - - default : - makePfNumNode = false ; - TreeNode[] bodyHeirs = stepBodySTN.heirs() ; - LevelNode body = null ; - /*************************************************************** - * This will be set to the body of the TheoremNode or * - * ThmOrAssumpDefNode. * - ***************************************************************/ - UniqueString op = null ; - ExprNode[] args ; - /*************************************************************** - * For anything but an N_Assert node, body is set to an * - * OpApplNode having these as its operator and arguments. * - ***************************************************************/ - - switch (stepBodySTN.getKind()) { - case N_AssertStep : - int bodyNext = 0 ; - if (bodyHeirs[0].getKind() == - TLAplusParserConstants.SUFFICES) { - bodyNext = 1 ; - isSuffices = true ; - /************************************************************ - * We can't have an "@" in a SUFFICES step. * - ************************************************************/ - } ; - if (bodyHeirs[bodyNext].getKind() == N_AssumeProve) { - /************************************************************ - * This is an AssumeProve node. * - ************************************************************/ - isAssumeProve = true ; - - /************************************************************ - * For an ASSUME/PROVE, we need save the symbol * - * declarations from top-level NEW statements in the ASSUME * - * to make them visible only in the statement's proof for * - * an ordinary ASSUME/PROVE, and only after the statement's * - * proof for a SUFFICES ASSUME/PROVE. * - ************************************************************/ - symbolTable.pushContext(new Context(moduleTable, errors)) ; - - currentGoal = tadn ; - /********************************************************** - * Need to set currentGoal before generating the * - * AssumeProve node. * - **********************************************************/ - body = generateAssumeProve(bodyHeirs[bodyNext], cm); - - if (isSuffices) { ((AssumeProveNode) body).setSuffices(); }; - /********************************************************** - * Added 16 Feb 2009 by LL. * - **********************************************************/ - currentGoal = null ; - assumeContext = symbolTable.getContext() ; - symbolTable.popContext() ; - prevIsInfix = false ; - } - else { - /************************************************************ - * This is an ordinary expression. * - ************************************************************/ - TreeNode curExpr = bodyHeirs[bodyNext] ; - - /************************************************************ - * Special handling of SUFFICES added by LL 16 Feb 2009. * - ************************************************************/ - if (isSuffices) { - args = new ExprNode[1] ; - args[0] = generateExpression(curExpr, cm) ; - body = new OpApplNode(OP_suffices, args, stepBodySTN, cm) ; - } // if (isSuffices) - else { - /************************************************************ - * If the current expression is an infix expression, set * - * curLHS to its current LHS, otherwise set it to null. * - ************************************************************/ - SyntaxTreeNode curLHS = null ; - if (curExpr.getKind() == N_InfixExpr) { - curLHS = (SyntaxTreeNode) curExpr.heirs()[0] ; - } ; - /************************************************************ - * If prevIsInfix is true and curLHS is an "@", then * - * process it, using as the right-hand side a new $Nop node * - * with prevRHS as its argument. * - ************************************************************/ - if ( prevIsInfix - && (curLHS != null) - && (curLHS.heirs().length > 0) - /*************************************************** - * This test added 25 Feb 2010 because if curLHS * - * is a string, then curLHS.heirs() is a * - * zero-length array, so the following test threw * - * an out-of-bounds array index exception. Note * - * that curLHS.heirs() should never be null, * - * because the heirs() method can never return * - * null. * - ***************************************************/ - && (((SyntaxTreeNode) - curLHS.heirs()[0]).heirs().length == 0) - && (curLHS.heirs()).length > 1 - /*************************************************** - * This test added 2 Mar 2009 to fix following * - * bug. When we are here and the left-hand side * - * is something like a number, then curLHS.heirs() * - * seems to have length 1 and the following test * - * causes an ArrayIndexOverflowException. * - ***************************************************/ - && (curLHS.heirs()[1].getKind() == IDENTIFIER) - && (curLHS.heirs()[1].getUS() == AtUS)) { - - /********************************************************** - * The following code obtained by a simple modification * - * of the N_InfixExpr case of generateExpression. * - **********************************************************/ - TreeNode[] children = curExpr.heirs() ; - GenID genID = generateGenID(children[1], cm); - ExprNode[]sns = new ExprNode[2]; - SymbolNode opn = - symbolTable.resolveSymbol( - Operators.resolveSynonym(genID.getCompoundIDUS())); - if ( opn == null ) { - errors.addError(curExpr.getLocation(), - "Couldn't resolve infix operator symbol `" + - genID.getCompoundIDUS() + "'." ); - return null; - } ; - sns[1] = generateExpression( children[2], cm ); - /********************************************************** - * Set sns[1] to a new $Nop OpApplNode whose argument is * - * prevRHS. * - **********************************************************/ - ExprNode[] nopArgs = new ExprNode[1] ; - nopArgs[0] = prevRHS ; - sns[0] = new OpApplNode(OP_nop, nopArgs, curLHS, cm) ; - body = new OpApplNode(opn, sns, curExpr, cm); - } // if ( prevIsInfix ...) - else { // this is not an @-step - body = generateExpression(curExpr, cm) ; - } ; - - /************************************************************ - * If this is an infix ioperator, set prevIsInfix true and * - * prevRHS equal to its right-hand argument, else set * - * prevIsInfix false. * - ************************************************************/ - prevIsInfix = false ; - if ( (curLHS != null) - /******************************************************* - * The following conjuncts should be true unless there * - * was an error in the expression. * - *******************************************************/ - && (body != null) - && (body.getKind() == OpApplKind) - && ( ((OpApplNode) body).getArgs().length > 1)) { - prevIsInfix = true ; - prevRHS = (ExprNode) ((OpApplNode) body).getArgs()[1] ; - } - } - }; // else This is an ordinary expression. - break ; - - case N_HaveStep : - case N_CaseStep : - if (stepBodySTN.getKind() == N_HaveStep) {op = OP_have ;} - else {op = OP_pfcase ;} ; - args = new ExprNode[1] ; - args[0] = generateExpression(bodyHeirs[1], cm) ; - body = new OpApplNode(op, args, stepBodySTN, cm) ; - break ; - - case N_TakeStep : - case N_PickStep : - if (stepBodySTN.getKind() == N_TakeStep) {op = OP_take ;} - else { - op = OP_pick ; - isPick = true; - /************************************************************ - * Push a new context onto the symbolTable stack to get the * - * declarations of the PICK symbols. * - ************************************************************/ - symbolTable.pushContext(new Context(moduleTable, errors)) ; - } ; - - if (bodyHeirs[1].getKind() == N_QuantBound) { - /************************************************************ - * The introduced identifiers are bounded--e.g., "TAKE id * - * \in Set". * - ************************************************************/ - - /************************************************************ - * Set quants to the number of N_QuantBound nodes. * - ************************************************************/ - int quants = 1 ; - int nextTok = 2; - while ( (nextTok < bodyHeirs.length) - && (bodyHeirs[nextTok].getKind() - == TLAplusParserConstants.COMMA)) { - quants++ ; - nextTok = nextTok + 2 ; - }; - FormalParamNode[][] params = new FormalParamNode[quants][0]; - boolean[] bt = new boolean[quants] ; - ExprNode[] paramBounds = new ExprNode[quants]; - processQuantBoundArgs( - bodyHeirs, 1, params, bt, paramBounds, cm) ; - - if (isPick) { - /********************************************************** - * Save the declarations in pickContext. * - **********************************************************/ - pickContext = symbolTable.getContext() ; - /********************************************************** - * This is a PICK step; get the ": expr". * - **********************************************************/ - nextTok++ ; // Skip over the ":" - args = new ExprNode[1] ; - pushFormalParams(flattenParams(params)) ; - /******************************************************** - * Push the bound variables on Last(LS).paramSeq and * - * process the body of the PICK. * - ********************************************************/ - args[0] = generateExpression(bodyHeirs[nextTok], cm) ; - popFormalParams() ; - symbolTable.popContext() ; - /******************************************************** - * Remove the bound symbols from the symbol table so * - * they're undefined for the proof of the PICK. * - ********************************************************/ - } - else { - /********************************************************** - * This is a TAKE step. * - **********************************************************/ - args = new ExprNode[0] ; - }; - body = new OpApplNode(op, null, args, params, - bt, paramBounds, stepBodySTN, cm) ; - } - else { - /************************************************************ - * The introduced identifiers are unbounded--e.g., "TAKE * - * id1, id2". * - ************************************************************/ - - /************************************************************ - * Set ids to the number of introduced identifiers. * - ************************************************************/ - int ids = 1 ; - while ( (2*ids < bodyHeirs.length) - && (bodyHeirs[2*ids].getKind() == - TLAplusParserConstants.COMMA)) {ids++;} ; - - /************************************************************ - * Set params to the array of new FormalParamNodes for the * - * identifiers. The identifiers are added to the current * - * symbol table. * - ************************************************************/ - FormalParamNode[] params = new FormalParamNode[ids]; - for (int j = 0 ; j < ids ; j++) { - params[j] = new FormalParamNode( - bodyHeirs[2*j + 1].getUS(), 0, - bodyHeirs[2*j + 1], symbolTable, cm); - } ; - - if (isPick) { - /********************************************************** - * Save the declarations in pickContext. * - **********************************************************/ - pickContext = symbolTable.getContext() ; - - /********************************************************** - * This is a PICK step; get the ": expr". * - **********************************************************/ - pushFormalParams(params) ; - /******************************************************** - * Push formal parameters on Last(LS).paramSeq for * - * processing the body. * - ********************************************************/ - args = new ExprNode[1] ; - args[0] = generateExpression(bodyHeirs[2*ids + 1], cm) ; - popFormalParams() ; - symbolTable.popContext() ; - /******************************************************** - * Remove the bound symbols from the symbol table so * - * they're undefined for the proof of the PICK. * - ********************************************************/ - } - else { - /********************************************************** - * This is a TAKE step. * - **********************************************************/ - args = new ExprNode[0] ; - }; - body = new OpApplNode(op, args, params, stepBodySTN, cm) ; - } ; - - break ; - - case N_WitnessStep : - /************************************************************** - * Set ids to the number of expressions. * - **************************************************************/ - int ids = 1 ; - while ( (2 * ids < bodyHeirs.length) - && (bodyHeirs[2 * ids].getKind() == - TLAplusParserConstants.COMMA)) {ids++;} ; - - args = new ExprNode[ids] ; - for (int j = 0 ; j < ids ; j++) { - args[j] = generateExpression(bodyHeirs[2*j + 1], cm); - } ; - body = new OpApplNode(OP_witness, args, stepBodySTN, cm) ; - break ; - - case N_QEDStep : - args = new ExprNode[0] ; - body = new OpApplNode(OP_qed, args, stepBodySTN, cm) ; - break ; - - default : - errors.addAbort( - stn.getLocation(), - "Internal error: Unexpected SyntaxTreeNode kind: " - + heirs[i].getKind()) ; - break ; - }; // switch - - - /******************************************************************** - * Set the fields of the ThmOrOpDefNode if there is one, including * - * the suffices field. * - ********************************************************************/ - if (stepNum != null) { - tadn.construct(true, body, cm, symbolTable, null) ; - tadn.setLabels(popLabelNodeSet()) ; - if (isSuffices) { tadn.setSuffices() ;} ; - } ; - /*********************************************************************** - * Set proof to the proof, or to null if there is none. There is no * - * check made to see if this is a kind of step that should have a * - * proof. Thus, adding a proof to something like a WITNESS statement * - * requires changing only the parsing phase (specified by tla+.jj). * - ***********************************************************************/ - ProofNode proof = null ; - if (stepPfSTN != null) { - /****************************************************************** - * For an ordinary ASSUME/PROVE, must make the ASSUME's * - * declarations visible in the statement's proof. * - ******************************************************************/ - if (isAssumeProve && !isSuffices) { - symbolTable.pushContext(assumeContext) ; - } ; - proof = generateProof(stepPfSTN, cm); - if (isAssumeProve && !isSuffices) {symbolTable.popContext(); } ; - } ; - - /******************************************************************** - * For a SUFFICES ASSUME/PROVE, must make the ASSUME's declarations * - * visible after the proof. This is done by pushing assumeContext * - * onto the symbol table and incrementing numberOfPops so it will * - * be popped at the end of the proof. * - ********************************************************************/ - if (isAssumeProve && isSuffices) { - numberOfPops++ ; - symbolTable.pushContext(assumeContext) ; } ; - if (isAssumeProve) { ((AssumeProveNode) body).inProof = false ; } ; - /****************************************************************** - * For an ASSUME/PROVE, set the inProof field to false. * - ******************************************************************/ - TheoremNode thm = new TheoremNode(stepBodySTN, body, cm, proof, tadn); - - // Added by LL on 16 Jun 2010 so location returnedby getLocation() will - // include the step number. - thm.stn = pfStepSTN; - - thm.suffices = isSuffices ; - steps[i - offset] = thm; - }; // switch - if (makePfNumNode) { - /******************************************************************* - * Make an OpDefNode for the numbered step and add any label * - * declarations to it. * - *******************************************************************/ - OpDefNode nodeMadeOnlyToBePutInSymbolTable = - new OpDefNode(stepNum, pfNumNode, cm, symbolTable, pfStepSTN) ; - nodeMadeOnlyToBePutInSymbolTable.setLabels(popLabelNodeSet()) ; - } - if (isPick) { - /******************************************************************* - * We have to take the symbol declarations from pickContext and * - * put them into the current symbol table. * - *******************************************************************/ - Enumeration e = pickContext.content() ; - while (e.hasMoreElements()) { - SymbolNode sym = ((Context.Pair)(e.nextElement())).getSymbol(); - symbolTable.addSymbol(sym.getName(), sym) ; - } - } - } ; // for i - InstanceNode[] insts = new InstanceNode[iVec.size()] ; - for (int i = 0 ; i < insts.length; i++) { - insts[i] = (InstanceNode) iVec.elementAt(i) ; - }; - - /*********************************************************************** - * Pop the contexts that were pushed onto the symbol table for SUFFICE * - * ASSUME/PROVE steps. * - ***********************************************************************/ - for (int i = 0; i < numberOfPops; i++) { - // Added by LL on 24 June 2010 - // Need to add the symbols in the context being popped to pfCtxt - // so they will be put into the context of the NonLeafProofNode. - Context topContext = symbolTable.getContext(); - Enumeration e = topContext.content() ; - while (e.hasMoreElements()) { - SymbolNode sym = ((Context.Pair)(e.nextElement())).getSymbol(); - pfCtxt.addSymbolToContext(sym.getName(), sym) ; - } - symbolTable.popContext(); - }; - symbolTable.popContext(); - return new NonLeafProofNode(stn, steps, insts, pfCtxt); - /********************************************************************* - * Pop the sub-Context. * - *********************************************************************/ - } // generateProof - -/*************************************************************************** -* The following method is not used and I have no idea why it's still * -* here. * -***************************************************************************/ - private final LevelNode generateNumerableStep( - TreeNode stn, + pushFormalParams(params); + /******************************************************************* + * Push formal parameters on Last(LS).paramSeq for processing the * body + *******************************************************************/ + ExprNode body = generateExpression(children[children.length - 1], cm); + /********************************************************************* + * Generate the lambda expression's body. * + *********************************************************************/ + popFormalParams(); + + symbolTable.popContext(); + /********************************************************************* + * Restore original context. * + *********************************************************************/ + return new OpDefNode(S_lambda, // The operator name is "LAMBDA" + UserDefinedOpKind, // The node kind for a lambda expression + params, // the array of formal parameters + false, // localness, which is meaningless + body, // the body (an expression node) + cm, // the module + null, // the symbol table, which is null for an + // OpDefNode representing a lambda expression. + syntaxTreeNode, true, // Is defined. Its value should not matter. + null); // Source + } // generateLambda + + /** + * Generates an OpApplNode or an OpArgNode for a SyntaxTreeNode, according to + * whether the value of "typeExpected" is either opAppl or opArg. + */ + private final ExprNode generateOpAppl(TreeNode syntaxTreeNode, ModuleNode cm) throws AbortException { + TreeNode primaryArgs = null; + // points to syntax tree of primary arg list (if any); otherwise null + boolean isOpApp = syntaxTreeNode.isKind(N_OpApplication); + // true ==> to indicate this is an OpAppl; must have primary args + // false ==> operator used as an argument (OpArg); has no primary args + int primaryArgCount = 0; + // total # of arguments, including those of prefix, if any + int len; + // number of prefix elements + TreeNode[] children = syntaxTreeNode.heirs(); + // temp used for finding the prefix + TreeNode[] prefix; + // array of prefix elements + TreeNode[] allArgs = null; + // to collect arg arrays from both prefix and the main op (if any) + TreeNode[] prefixElt; + // a prefixElement; 2 or 3 elem array: [op, (args), "!"] + UniqueString symbol; + // UniqueString name of the fully-qualified operator + SymbolNode fullOperator; + // The SymbolNode for the fully-qualified operator + int iarg = 0; + // loop counter for actual args (as opposed to + // arg syntax elements like commas and parens) + TreeNode[] argsList = null; + // Will hold an array of arg syntax trees for primary operator + ExprOrOpArgNode[] args = null; + // Will hold an array of arg semantic trees for primary operator + + // Process the Generized ID that is the operator for this OpAppl + GenID genID = generateGenID(children[0], cm); + + // Set up pointers to OpAppl's primary args + primaryArgs = children[1]; + // Array of argument list syntax elements for the main + // (rightmost) operator, including parens and commas; + // should be an N_OpArgs node + + // calc number of primary args; + // args are interspersed w/ parens & commas--hence the /2 + primaryArgCount = primaryArgs.heirs().length / 2; + + if (genID == null || genID.getFullyQualifiedOp() == null) { + // if operator is @ or an unresolved symbol; error has already + // been generated inside genID + return nullOAN; + } + + args = new ExprOrOpArgNode[primaryArgCount]; + // Array to hold semantic trees for primary args + + // pick up array of arg list syntax elements + argsList = primaryArgs.heirs(); + + // The odd numbered syntax elements are the args expressions; the + // even numbered ones are parens and commas. + // for each arg in this arg list ... + for (int ia = 1; ia < argsList.length; ia += 2) { + // Each arg may be an ordinary expression, or it may be an OpArg; + // produce appropriate semantic tree or node for it. + // Note that operators can be used in place of expressions + // in only two contexts: + // as argument to suitable user-defined ops, and in the RHS + // of a substitution in module instantiation + args[iarg] = generateExprOrOpArg(genID.getFullyQualifiedOp(), syntaxTreeNode, iarg, argsList[ia], cm); + iarg++; // count the actual args + } // end for + + // Concatenate the list of args in the GenID object to the + // primary arg list just created + Vector genIDArgList = genID.getArgsVector(); + ExprOrOpArgNode[] finalArgList = new ExprOrOpArgNode[genIDArgList.size() + iarg]; + + // Copy the args from the prefix + for (int i = 0; i < genIDArgList.size(); i++) { + finalArgList[i] = (ExprOrOpArgNode) (genIDArgList.elementAt(i)); + } + // Copy the primary args + for (int i = 0, j = genIDArgList.size(); i < iarg; i++, j++) { + finalArgList[j] = args[i]; + } + + // return an OpApplNode constructed from the fully-qualified + // operator and the final arg list + return new OpApplNode(genID.getFullyQualifiedOp(), finalArgList, syntaxTreeNode, cm); + } // end generateOpAppl() + + /** + * Process a named, parameterixed instantiation, e.g. of the form D(p1,...pn) = + * INSTANCE M WITH a1 <- e1 ,..., ar <- er + */ + /************************************************************************* + * Note: the returned value does not seem to be used. * + *************************************************************************/ + private final OpDefNode processModuleDefinition(TreeNode treeNode, Vector defs, + /******************************************************* + * This is non-null when called from inside a LET, in * which case the OpDef + * node is appended to defs. If * null, the OpDef node is appended to the * + * module-level lists of such nodes. * + *******************************************************/ + Vector insts, + /******************************************************* + * If non-null, then a vector of InstanceNode objects * to which the current + * instance node is to be * appended. If null, cm.appendInstance is called to * + * put the InstanceNode onto the module-level lists of * such nodes. * + *******************************************************/ + ModuleNode cm) throws AbortException { + // Start with a LHS for an instance: we must extract from it name + // and possibly parameters. Then we need the external Context of + // the module and to extract all non-local, non-builtin + // symbols. Then build the proper symbol list and add it. + + // We must remember to identify explicitly whether or not the new + // nodes would be local. + + // assert treeNode.isKind(N_ModuleDefinition) + // + // Note that this code does nothing about THEOREMS and ASSUMES in + // modules being instantiated + boolean localness = treeNode.zero() != null; + TreeNode[] children = treeNode.one()[0].heirs(); // heirs of IdentLHS + UniqueString name = children[0].getUS(); + + // processing of LHS of the definition, i.e. the name and parameters + FormalParamNode[] args = nullParam; + Context parmCtxt = null; + + // If the operator being defined as a module instance has any parameters + if (children.length > 1) { + // Create new array of FormalParamNodes for the new operator + args = new FormalParamNode[children.length / 2 - 1]; + + // Push a new context in current module's SymbolTable + parmCtxt = new Context(moduleTable, errors); + symbolTable.pushContext(parmCtxt); + + // For each formal parameter declared for the op being defined + for (int i = 0; i < args.length; i++) { + TreeNode child = children[2 + 2 * i]; + UniqueString id = null; + int count = 0; + + if (child.isKind(N_IdentDecl)) { + id = child.heirs()[0].getUS(); + count = (child.heirs().length - 1) / 2; + } else if (child.isKind(N_InfixDecl)) { + id = child.heirs()[1].getUS(); + count = 2; + } else if (child.isKind(N_PrefixDecl)) { + id = child.heirs()[0].getUS(); + count = 1; + } else if (child.isKind(N_PostfixDecl)) { + id = child.heirs()[1].getUS(); + count = 1; + } else { + errors.addAbort(treeNode.getLocation(), + "Internal error: Error in formal params part of parse tree.", true); + } + + // If there was no error + if (id != null) { + // Create a new FormalParamNode for the defined Op and put + // it in the SymbolTable + args[i] = new FormalParamNode(id, count, child, symbolTable, cm); + } // end if + } // end for + } // end if + + // processing RHS of the definition, starting with identification + // of module being instantiated, followed by processing of the + // WITH clause (if any) + children = treeNode.one()[2].heirs(); // heirs of NonLocalInstance + + // Find the Context and ModuleNode for the module being instantiated + Context instanceeCtxt = this.getContext(children[1].getUS()); + ModuleNode instanceeModule = symbolTable.resolveModule(children[1].getUS()); + + if (instanceeCtxt == null) { + errors.addError(children[1].getLocation(), + "Module " + children[1].getImage() + " does not have a context."); + return nullODN; + } + + if (instanceeModule == null) { + errors.addError(children[1].getLocation(), + "Module name " + children[1].getImage() + " is not known" + " in current context."); + return nullODN; + } + + /* + * Set isInstantiated field of instancee. Added by LL 23 July 2013 + */ + instanceeModule.setInstantiated(true); + + // Create a SubstInNode that will be used to wrap each definition + // body in the module being defined. "children" is the array of + // explicit substitution clauses used in the module definition. + // Both instanceeCtxt and symbolTable are involved here since for + // each substitution c <- e, c must be resolved in the + // instanceeCtxt, and e must be interpreted in symbolTable + SubstInNode substIn = processSubst(treeNode, children, symbolTable, instanceeCtxt, instanceeModule, cm); + + // We are done with the local context (if one was created because + // of parameters) + if (parmCtxt != null) + symbolTable.popContext(); + + // Create a vector of all of the OpDefNodes in the instancee module + /*********************************************************************** + * I have no idea why the module's getOpDefs method isn't used here. * + ***********************************************************************/ + Vector elts = instanceeCtxt.getByClass(OpDefNode.class); + + // For each definition in the instancee module, create a + // corresponding definition in the instancer module + for (int i = 0; i < elts.size(); i++) { + // Find the OpDefNode to be instantiated + OpDefNode odn = (OpDefNode) elts.elementAt(i); + + /********************************************************************** + * Ignore it if it is local or a builtin def. * + **********************************************************************/ + if (!odn.isLocal() && ((odn.getKind() == UserDefinedOpKind) || (odn.getKind() == ModuleInstanceKind))) { + // Create the new name prepended with "name!" + String compoundID = name + "!" + odn.getName(); + UniqueString qualifiedName = UniqueString.uniqueStringOf(compoundID); + + // Copy parameters for the op being defined + FormalParamNode[] fpn = odn.getParams(); + FormalParamNode[] params = new FormalParamNode[fpn.length + args.length]; + System.arraycopy(args, 0, params, 0, args.length); + System.arraycopy(fpn, 0, params, args.length, fpn.length); + + OpDefNode newOdn; + if (odn.getKind() == UserDefinedOpKind) { + if (substIn.getSubsts().length > 0) { + // If there are substitutions, then the body of the new + // definition instance must be wrapped in a SUBST-IN node. + // Create the "wrapping" SubstInNode as a clone of "subst" + // above, but with a body from the OpDefNode in the module + // being instantiated + SubstInNode substInNode = new SubstInNode(treeNode, substIn.getSubsts(), odn.getBody(), cm, + instanceeModule); + + // Create the OpDefNode for the new instance of this + // definition; because of the new operator name, cm is the + // module of origin for purposes of deciding of two defs are + // "the same" or "different" + newOdn = new OpDefNode(qualifiedName, UserDefinedOpKind, params, localness, substInNode, cm, + symbolTable, treeNode, true, odn.getSource()); + setOpDefNodeRecursionFields(newOdn, cm); + newOdn.setLabels(odn.getLabelsHT()); + } // if (substIn.getSubsts().length > 0) + else { + // no SUBST-IN node required; but because of the new + // operator name, cm is the module of origin for purposes of + // deciding of two defs are "the same" or "different" + newOdn = new OpDefNode(qualifiedName, UserDefinedOpKind, params, localness, odn.getBody(), cm, + symbolTable, treeNode, true, odn.getSource()); + setOpDefNodeRecursionFields(newOdn, cm); + newOdn.setLabels(odn.getLabelsHT()); + } // else + } // if (odn.kind == UserDefinedOpKind) + else { + /***************************************************************** + * This is a ModuleInstanceKind node. * + *****************************************************************/ + newOdn = new OpDefNode(qualifiedName, params, localness, odn.getOriginallyDefinedInModuleNode(), + symbolTable, treeNode, odn.getSource()); + } + ; // else + // defs is non-null iff this module definition is in the Let + // part of a Let-In expression. Add this newly created OpDef + // to either the LET list or the module cm's definition list. + if (defs == null) { + cm.appendDef(newOdn); + } else { + defs.addElement(newOdn); + } + } // if (!odn.isLocal()&& ... ) + } // for + + /********************************************************************** + * Import the ThmOrAssumpDefNode objects to the current module. The * following + * code for doing this was copied and modified without * much thinking from the + * code above for OpDefNode objects * + **********************************************************************/ + // Create a vector of all of the ThmOrAssumpDefNodes in the + // instancee module + Vector taelts = instanceeCtxt.getByClass(ThmOrAssumpDefNode.class); + + // For each definition in the instancee module, create a + // corresponding definition in the instancer module + for (int i = 0; i < taelts.size(); i++) { + // Find the ThmOrAssumpDefNode to be instantiated + ThmOrAssumpDefNode taOdn = (ThmOrAssumpDefNode) taelts.elementAt(i); + + /********************************************************************* + * There are no builtin ThmOrAssumpDefNode objects. * + *********************************************************************/ + // Ignore it if it is local + if (!taOdn.isLocal()) { + // Create the new name prepended with "name!" + String compoundID = name + "!" + taOdn.getName(); + UniqueString qualifiedName = UniqueString.uniqueStringOf(compoundID); + + // Copy parameters for the op being defined + /******************************************************************* + * Theorem or assumption definitions have no parameters. * + *******************************************************************/ + FormalParamNode[] fpn = taOdn.getParams(); + FormalParamNode[] params = new FormalParamNode[fpn.length + args.length]; + System.arraycopy(args, 0, params, 0, args.length); + System.arraycopy(fpn, 0, params, args.length, fpn.length); + + ThmOrAssumpDefNode newtaOdn; + if (substIn.getSubsts().length > 0) { + // If there are substitutions, then the body of the new + // definition instance must be wrapped in a SUBST-IN node. + // Create the "wrapping" SubstInNode as a clone of "subst" + // above, but with a body from the ThmOrAssumpDefNode in the module + // being instantiated + APSubstInNode substInNode = new APSubstInNode(treeNode, substIn.getSubsts(), taOdn.getBody(), cm, + instanceeModule); + + // Create the ThmOrAssumpDefNode for the new instance of this + // definition; because of the new operator name, cm is the + // module of origin for purposes of deciding of two defs are + // "the same" or "different" + newtaOdn = new ThmOrAssumpDefNode(qualifiedName, taOdn.isTheorem(), substInNode, cm, symbolTable, + treeNode, params, instanceeModule, taOdn.getSource()); + // Following statement added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. Added setLabels call + // on 31 Oct 2012. + newtaOdn.setLocal(localness); + newtaOdn.setLabels(taOdn.getLabelsHT()); + + /***************************************************************** + * No recursion fields needed for a theorem or assumption * because it can't + * appear in a recursive section. * + *****************************************************************/ + // setThmOrAssumpDefNodeRecursionFields(newtaOdn, cm) ; + } else { + // no SUBST-IN node required; but because of the new + // operator name, cm is the module of origin for purposes of + // deciding if two defs are "the same" or "different" + newtaOdn = new ThmOrAssumpDefNode(qualifiedName, taOdn.isTheorem(), taOdn.getBody(), cm, + symbolTable, treeNode, params, instanceeModule, taOdn.getSource()); + // Following statement added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. Added setLabels call + // on 31 Oct 2012. + newtaOdn.setLocal(localness); + newtaOdn.setLabels(taOdn.getLabelsHT()); + /***************************************************************** + * No recursion fields needed for theorems or assumptions * because they can't + * appear in a recursive section. * + *****************************************************************/ + // setThmOrAssumpDefNodeRecursionFields(newtaOdn, cm) ; + } + + // defs is non-null iff this module definition is in the Let + // part of a Let-In expression. Add this newly created ThmOrAssumpDef + // to either the LET list or the module cm's definition list. + if (defs == null) { + cm.appendDef(newtaOdn); + } else { + defs.addElement(newtaOdn); + } + } // if (!taOdn.isLocal()&& ... ) + } // for + + // Create a new InstanceNode to represent this INSTANCE stmt + // in the current module + InstanceNode inst = new InstanceNode(name, localness, args, instanceeModule, substIn.getSubsts(), treeNode); + + // Append this new InstanceNode to the vector of InstanceNodes + // being accumulated for this module + if (insts == null) { + cm.appendInstance(inst); + } else { + insts.addElement(inst); + } + + // Create new OpDefNode with ModuleInstanceKind. The reason for + // doing this is to get the name in the symbol table so the name + // cannot be re-used later in this module for a user-defined + // operator. + return new OpDefNode(name, args, localness, cm, symbolTable, treeNode, null); + /********************************************************************* + * Note: the module's OpDefNode does not have recursive parameters * set. If the + * module definition statement occurs in a recursive * section, then it is the + * instantiated definitions that are * recursive, not the module definition + * itself. (The name under * which the module is instantiated cannot appear in a + * RECURSIVE * statement.) * + *********************************************************************/ + + } // end processModuleDefinition() + + /** + * From a particular explicit substitution (substTarget <- substValue) check the + * legality of the substTarget, and if OK, generate the appropriate type of node + * for substValue + */ + private ExprOrOpArgNode generateSubst(Context instanceeCtxt, TreeNode substTarget, TreeNode substValue, + ModuleNode mn) throws AbortException { + SymbolNode targetSymbol = instanceeCtxt.getSymbol(substTarget.getUS()); + + // if the targetSymbol cannot be found in the instancee context, + // or if it does not correspond to a declaration, then it is an + // illegal substitution target + + if (targetSymbol == null || !(targetSymbol instanceof OpDeclNode)) { + errors.addError(substTarget.getLocation(), "Identifier '" + substTarget.getUS() + "' is not a legal" + + " target of a substitution. \nA legal target must be a declared" + + " CONSTANT or VARIABLE in the module being instantiated." + + " \n(Also, check for warnings about multiple declarations of" + " this same identifier.)"); + return nullOAN; + } + + // but if the symbol is found, then if it has arity 0, the RHS + // should be an expression, if arity > 0, the the RHS should be an OpArg + ExprOrOpArgNode returnObject; + + if (targetSymbol.getArity() == 0) { + // if the target of the substitution has arity 0, + // then we expect an expression to be substituted for it + returnObject = generateExpression(substValue, mn); + } else { + // if the target of the substitution has arity > 0, + // then and operator must be substituted for it + returnObject = generateOpArg(targetSymbol, substValue, mn); + + // and it better have the same arity as the target + if (((OpArgNode) returnObject).getArity() != targetSymbol.getArity()) { + errors.addError(substValue.getLocation(), "An operator must be substituted for symbol '" + + targetSymbol.getName() + "', and it must have arity " + targetSymbol.getArity() + "."); + } + } + return returnObject; + } // end generateSubst() + + /** + * Return an OpArgNode constructed from a GeneralId tree to be used in the RHS + * of a substitution + */ + private OpArgNode generateOpArg(SymbolNode targetSymbol, TreeNode opArgSyntaxNode, ModuleNode mn) + throws AbortException { + /*********************************************************************** + * If this is a lambda expressiion, then just get it and go. * + ***********************************************************************/ + if (opArgSyntaxNode.isKind(N_Lambda)) { + return new OpArgNode(generateLambda(opArgSyntaxNode, mn), opArgSyntaxNode, mn); + } + ; + // First, make sure that an operator ID is present, and not an expression + if (!(opArgSyntaxNode.isKind(N_GeneralId) || opArgSyntaxNode.isKind(N_GenInfixOp) + || opArgSyntaxNode.isKind(N_GenPrefixOp) || opArgSyntaxNode.isKind(N_GenNonExpPrefixOp) || + /************************************************************ + * This last disjunct was added by LL on 9 May 2007. * * The original parser + * phase produced an N_GenPrefixOp * here, but an N_GenNonExpPrefixOp for the + * syntactically * identical situation in an operator argument. The new * TLA+2 + * parser produces N_GenNonExpPrefixOp nodes here, * but I left the + * N_GenPrefixOp case in here just in case * this is called somewhere else that + * I haven't found. * + ************************************************************/ + + opArgSyntaxNode.isKind(N_GenPostfixOp))) { + errors.addError(opArgSyntaxNode.getLocation(), + "Arity " + targetSymbol.getArity() + " operator (not an expression) is expected" + + " \nto substitute for CONSTANT '" + targetSymbol.getName() + "'."); + return nullOpArg; + } + + /*********************************************************************** + * If the argument is a GeneralId node, then we use * genIdToSelector and + * selectorToNode to generate the OpArg node. * + ***********************************************************************/ + if (opArgSyntaxNode.getKind() == N_GeneralId) { + /********************************************************************* + * First, a sanity check to make sure we're never looking for an * expression + * argument. * + *********************************************************************/ + if (targetSymbol.getArity() <= 0) { + errors.addAbort(opArgSyntaxNode.getLocation(), "Internal error: expected to find arity > 0.", true); + } + ; + + LevelNode ln = selectorToNode(genIdToSelector((SyntaxTreeNode) opArgSyntaxNode), targetSymbol.getArity(), + false, false, mn); + + /******************************************************************* + * Added 23 February 2009: It appears that, in case of an error, * + * selectorToNode can return something other than an OpArgNode * here. (In + * particular, an OpApplNode.) Rather than tix * selectorToNode, I am adding a + * kludge to simply ignore the * problem and hope that it can be caused only by + * some other * error. If no error has been found, then we abort and debug if * + * this is encountered. * + *******************************************************************/ + if (!(ln instanceof OpArgNode)) { + if (errors.getNumErrors() > 0) { + return nullOpArg; + } + errors.addAbort(opArgSyntaxNode.getLocation(), + "Internal error: " + "Expected an operator argument but " + "found something else."); + } + ; + return (OpArgNode) ln; + } + ; + + /******************************************************************* + * If the argument is not a GeneralId node, we use the code from * SANY1 to + * generate the OpArg node. * + *******************************************************************/ + + // Assemble the (possibly compound) generalized identifier, and resolve it. + GenID genID = generateGenID(opArgSyntaxNode, mn); + + // If the fully-qualified op is undefined, then a message has already been + // put in errors, but we must insert a nullOpArgNode in the tree. + if (genID.getFullyQualifiedOp() != null && genID.getArgs().length == 0) { + // Create an OpArgNode from it. + return new OpArgNode(genID.getFullyQualifiedOp(), opArgSyntaxNode, mn); + } else if (genID.getArgs().length > 0) { + // Expression being used where Operator is required + errors.addError(opArgSyntaxNode.getLocation(), + "Arity " + targetSymbol.getArity() + " operator (not an expression) is expected" + + " to substitute for CONSTANT '" + targetSymbol.getName() + "'."); + return nullOpArg; + } else { + return nullOpArg; + } + } // end generateOpArg() + + /** + * Process the substitutions clause of a module definition or instantiation; + * returns a SubstInNode that can be used as a template for the wrapper that + * must be present around each OpDefNode body created from the module + * instantiation or module definition. + */ + private SubstInNode processSubst(TreeNode treeNode, TreeNode[] substNodes, + // array of subst nodes [c1 <- e1, ... ,cn <- en] + SymbolTable instancerST, + // SymbolTable in which the ei must be resolved + Context instanceeCtxt, + // Context in which the ci must be resolved + ModuleNode instanceeModule, + // the ModuleNode of the module in which ci must be resolved + ModuleNode mn) throws AbortException { + TreeNode[] children; // find the substitution part of the syntax tree + + // Create a vector of all declarations of CONSTANTS and VARIABLES + // in the context of the module being instantiated (instancee). + // These are all the symbols that must have substitutions defined + // for them in the instantiation, either explictly or implicitly. + Vector decls = instanceeCtxt.getByClass(OpDeclNode.class); + + // Create a SubstInNode to be used as a template for the SubstInNodes + // in the body of every newly instantiated OpDef in the module. + // The substitutions in the returned SubstInNode object will be the + // implicit substitutions of the form c<-c for all CONSTANTS and + // VARIABLES c that are BOTH declared in instancee and for which the + // same name is declared or defined in instancer. Note the instancerST + // must be passed to this constructor because with a default substitution + // LHS<-RHS the LHS is resolved in the instanceeCtxt, (done + // in the previous line) and the RHS is resolved in the instancerST. + SubstInNode substIn = new SubstInNode(treeNode, instancerST, decls, mn, instanceeModule); + + // For each explicit substitution in the syntax tree, overwrite or add + // the corresponding default entry in SubstInNode just created + for (int i = 3; i < substNodes.length; i += 2) { + // pick up array of syntax elements for one substitution, + // e.g. ["c","<-",expr] + TreeNode sc[] = substNodes[i].heirs(); + + // substRHS is the expression "exp" in "c <- exp"; this stmt first + // checks that c is properly declared in the instancee context, + // and then generates an ExprOrOpArgNode. If c is a constant + // with parameters, then an OpArgNode is returned; otherwise it is + // an ExprNode. + ExprOrOpArgNode substRHS = generateSubst(instanceeCtxt, sc[0], sc[2], mn); + + // Overwrite an implicit substitution if there is one, or add a new one, + // checking for duplicate substitutions for the same symbol + substIn.addExplicitSubstitute(instanceeCtxt, sc[0].getUS(), sc[2], substRHS); + } + + // Check if substitution is complete, i.e. that all constants and vars + // have been substituted for. + substIn.matchAll(decls); + return substIn; + } // end processSubst + + /** + * This method treats *unnamed* INSTANCE stmts NOTE: this code does nothing with + * ASSUMES or THEOREMS + */ + /************************************************************************* + * However, SANY2 imports ThmOrAssumpDef nodes. * + *************************************************************************/ + /** + * @param treeNode + * @param cm + * @param topLevel + * @return + * @throws AbortException + */ + /** + * @param treeNode + * @param cm + * @param topLevel + * @return + * @throws AbortException + */ + /** + * @param treeNode + * @param cm + * @param topLevel + * @return + * @throws AbortException + */ + /** + * @param treeNode + * @param cm + * @param topLevel + * @return + * @throws AbortException + */ + private final InstanceNode generateInstance(TreeNode treeNode, ModuleNode cm, boolean topLevel) + throws AbortException { + /********************************************************************** + * topLevel argument is true for a top-level INSTANCE statement, and * false + * elsewise--that is, for an INSTANCE inside a proof. * + **********************************************************************/ + TreeNode[] children; + if (topLevel) { + children = treeNode.one()[0].heirs(); + } + // skip one generation below NonLocalInstance + // because we know zero defines local in a + // top-level INSTANCE + else { + children = treeNode.heirs(); + } + ; + // id of module being instanced + UniqueString moduleId = children[1].getUS(); + + // If this module instance is declared "LOCAL" then all of the + // definitions in it must be instanced as if they were "LOCAL" + boolean localness = treeNode.local(); + + // Create a list of all declarations for module moduleId. + // Match them against either something in the substitutions or + // something in the current context (symbol table) for the + // substitution. Check that the symbol does occur in the module + // and as a declaration. + Context instanceeCtxt = this.getContext(moduleId); + if (instanceeCtxt == null) { + errors.addAbort(children[1].getLocation(), + "Internal error: No context available for module `" + moduleId.toString() + "'.", true); + } + ; + // Try to find the ModuleNode for the module being instanced in + // the symbolTable + ModuleNode instanceeModuleNode = symbolTable.resolveModule(moduleId); + + // It must be an external module if it isn't in the symbolTable; + // try to find it in moduleTable (it cannot be in both places, or + // a name conflict would have resulted) + if (instanceeModuleNode == null) { + instanceeModuleNode = moduleTable.getModuleNode(moduleId); + } + + if (instanceeModuleNode == null) { + errors.addAbort(children[1].getLocation(), "Could not find module " + moduleId.toString(), false); + } + + /* + * Set isInstantiated field of instancee. Added by LL 23 July 2013 + */ + instanceeModuleNode.setInstantiated(true); + + // Create the SubstInNode that will act as a template "wrapper" + // for each definition in the module being instantiated; this + // SubstInNode itself gets discarded after being used as template + // however many times is necessary + SubstInNode subst = processSubst(treeNode, children, symbolTable, instanceeCtxt, instanceeModuleNode, cm); + + // Create a vector of all of the OpDefNodes in the module being + // instantiated + Vector defs = instanceeCtxt.getByClass(OpDefNode.class); + + OpDefNode odn; // OpDefNode in module being instantiated (instancee) + OpDefNode newOdn; // Its counterpart current module (instancer) + SubstInNode substInTemplate; // Template to be used for any + // SubstInNode wrappers required + + // Duplicate the OpDef records from the module being INSTANCE'd + for (int i = 0; i < defs.size(); i++) { + odn = (OpDefNode) defs.elementAt(i); + // OpDefNode in module being instantiated (instancee) + + // Do not instantiate built-in or local operators, or those + // OpDefNodes created solely to prevent a ModuleName from being + // used as an operator node. + if (odn.getKind() == BuiltInKind || odn.getKind() == ModuleInstanceKind || odn.isLocal()) { + continue; + } + + // If there are parameters to the module being instantiated, then + // a SubstInNode is required, and possibly a different module of + // origin should be indicated + if (!instanceeModuleNode.isParameterFree()) { + // Create the OpDefNode for the new instance of this definition + // Note that the new OpDefNode shares the array of FormalParamNodes + // with the old OpDefNode, as well as large parts of its body + // (all but the SubstInNode). Hence, changes by a tool to an Original + // OpDefNode will likely be reflected in all instances of it. + if (odn.getOriginallyDefinedInModuleNode().isParameterFree()) { + + /**************************************************************** + * Originally, newOdn was set the way it now is if localness = * true. Here's + * the problem with it. Suppose the instantiated * module EXTENDS the Naturals + * module. Then this will add new * OpDefNodes for all the symbols defined in + * Naturals. If the * current module EXTENDS Naturals, this will lead to + * multiple * definitions. So, for nonlocal definitions, we just * set newOdn to + * odn. * * However, now the problem is: suppose the current module * does not + * EXTEND the Naturals module. Then the operators * defined in Naturals, which + * should be defined in the current * module, are not. So, we add them to + * symbolTable. This does * not lead to a multiple definition error because + * apparently * it's the addSymbol method that is smart enough to detect if * we + * are adding a definition that comes from the same source as * the original + * one. * * This fix was made by LL on 16 Feb 2009. * * On 6 June 2010, LL add + * "&& topLevel" to the following `if' * test. This was needed because an + * INSTANCE inside a proof * was producing a "Multiple declarations or + * definition" * warning if the INSTANCEd module and the current module both * + * EXTENDed Naturals. This fix seems to do the right thing, * but I have not + * extensively tested it and I have no idea what * problems may remain. * + ****************************************************************/ + if (localness && topLevel) { + newOdn = new OpDefNode(odn.getName(), UserDefinedOpKind, odn.getParams(), localness, + odn.getBody(), odn.getOriginallyDefinedInModuleNode(), symbolTable, treeNode, true, + odn.getSource()); + /*************************************************************** + * The following statement was added by LL on 16 Feb 2009, by * analogy with the + * corresponding code about 45 lines below. I * have no idea if it was + * originally omitted for a good reason. * + ***************************************************************/ + newOdn.setLabels(odn.getLabelsHT()); + } else { + newOdn = odn; + symbolTable.addSymbol(odn.getName(), odn); + } + } else { + // Create the "wrapping" SubstInNode as a clone of "subst" above, + // but with a body from the OpDefNode in the module being + // instantiated + substInTemplate = new SubstInNode(treeNode, subst.getSubsts(), odn.getBody(), cm, + instanceeModuleNode); + newOdn = new OpDefNode(odn.getName(), UserDefinedOpKind, odn.getParams(), localness, + substInTemplate, cm, symbolTable, treeNode, true, odn.getSource()); + newOdn.setLabels(odn.getLabelsHT()); + + } + } else { + // There are no parameters to the instancee module; this + // means that a SubstInNode is not necessary, and also that + // the new operator should be considered to be "originally + // defined in" the same module as the old one for purposes of + // telling whether they are "the same" or different definitions + + // Create an OpDefNode whose body is the same as the instancer's. + + if (localness) { + /**************************************************************** + * See the comments about the similar change made to the * setting of newOdn in + * the `then' clause, just above. * This entire change was made by LL on 16 Feb + * 2009. * + ****************************************************************/ + newOdn = new OpDefNode(odn.getName(), UserDefinedOpKind, odn.getParams(), localness, odn.getBody(), + odn.getOriginallyDefinedInModuleNode(), symbolTable, treeNode, true, odn.getSource()); + newOdn.setLabels(odn.getLabelsHT()); + } else { + newOdn = odn; + symbolTable.addSymbol(odn.getName(), odn); + } + } + cm.appendDef(newOdn); + setOpDefNodeRecursionFields(newOdn, cm); + } // end for + + /********************************************************************** + * Import the ThmOrAssumpDefNode objects to the current module. The * following + * code for doing this was copied and modified without * thinking from the code + * above for OpDefNode objects * + **********************************************************************/ + Vector tadefs = instanceeCtxt.getByClass(ThmOrAssumpDefNode.class); + + ThmOrAssumpDefNode tadn; + // ThmOrAssumpDefNode in module being instantiated (instancee) + ThmOrAssumpDefNode newTadn; + // Its counterpart current module (instancer) + APSubstInNode tasubstInTemplate; // Template to be used for any + // SubstInNode wrappers required + + // Duplicate the OpDef records from the module being INSTANCE'd + for (int i = 0; i < tadefs.size(); i++) { + tadn = (ThmOrAssumpDefNode) tadefs.elementAt(i); + // ThmOrAssumpDefNode in module being instantiated (instancee) + + // Following statement added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. + if (tadn.isLocal()) { + continue; + } + + // If there are parameters to the module being instantiated, then + // a SubstInNode is required, and possibly a different module of + // origin should be indicated + if (!instanceeModuleNode.isParameterFree()) { + // Create the ThmOrAssumpDefNode for the new instance of this + // definition. Note that the new ThmOrAssumpDefNode shares the + // array of FormalParamNodes with the old ThmOrAssumpDefNode, + // as well as large parts of its body (all but the SubstInNode). + // Hence, changes by a tool to an Original ThmOrAssumpDefNode will + // likely be reflected in all instances of it. + if (tadn.getOriginallyDefinedInModuleNode().isParameterFree()) { + // Following if/else added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. + if (localness && topLevel) { + newTadn = new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), tadn.getBody(), cm, + symbolTable, treeNode, tadn.getParams(), instanceeModuleNode, tadn.getSource()); + newTadn.setLocal(true); + } else { + newTadn = tadn; + // On 30 Oct 2012, LL noticed that code was added on 16 Feb 2009 + // to the corresponding place in the code for an OpDefNode, but that + // nothing was added here. I suspect that something should have been + // that the 2009 code should also have been added here, but wasn't-- + // perhaps because there's no getLabelsHT method for a ThmOrAssumpDefNode. + // This may mean that there's a bug in handling labels in the + // instantiated theorem or assumption. + } + /* + * new ThmOrAssumpDefNode( tadn.getName(), UserDefinedOpKind, tadn.getParams(), + * localness, tasubstInTemplate, tadn.getOriginallyDefinedInModuleNode(), + * symbolTable, treeNode, true ); + */ + } else { + // Create the "wrapping" SubstInNode as a clone of "subst" above, + // but with a body from the ThmOrAssumpDefNode in the module being + // instantiated + tasubstInTemplate = new APSubstInNode(treeNode, subst.getSubsts(), tadn.getBody(), cm, + instanceeModuleNode); + newTadn = new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), tasubstInTemplate, cm, + symbolTable, treeNode, tadn.getParams(), instanceeModuleNode, tadn.getSource()); + // Following if/else added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. + newTadn.setLocal(localness); + // cm.appendDef(newTadn); + newTadn.setLabels(tadn.getLabelsHT()); + + } + } else { + // There are no parameters to the instancee module; this + // means that a SubstInNode is not necessary, and also that + // the new operator should be considered to be "originally + // defined in" the same module as the old one for purposes of + // telling whether they are "the same" or different definitions + + // Create a ThmOrAssumpDefNode whose body is the same as + // the instancer's. + if (localness && topLevel) { + newTadn = new ThmOrAssumpDefNode(tadn.getName(), tadn.isTheorem(), tadn.getBody(), + tadn.getOriginallyDefinedInModuleNode(), symbolTable, treeNode, tadn.getParams(), + instanceeModuleNode, tadn.getSource()); + // Following if/else added by LL on 30 Oct 2012 to handle locally + // instantiated theorems and assumptions. + newTadn.setLocal(localness); + newTadn.setLabels(tadn.getLabelsHT()); + } else { + newTadn = tadn; + symbolTable.addSymbol(tadn.getName(), tadn); + } + } + if (topLevel) { + cm.appendDef(newTadn); + } + ; + /******************************************************************** + * No recursion fields needed for theorems or assumptions because * they can't + * appear in a recursive section. * + ********************************************************************/ + // setOpDefNodeRecursionFields(newTadn, cm) ; + } // end for + + // Create a new InstanceNode to represent this INSTANCE stmt in + // the current module + InstanceNode inst = new InstanceNode(null /* no name */, localness, null /* no parms */, instanceeModuleNode, + subst.getSubsts(), treeNode); + + // Append this new InstanceNode to the vector of InstanceNodes + // being accumulated for this module + if (topLevel) { + cm.appendInstance(inst); + } + ; + return inst; + + } // void generateInstance + + private final void processTheorem(TreeNode stn, ModuleNode cm) throws AbortException { + ThmOrAssumpDefNode tadn = null; + LevelNode body; + ProofNode proof = null; + int bodyIndex = stn.heirs().length - 1; + boolean isAssumeProve = false; + /********************************************************************* + * Set true if the body is an ASSUME/PROVE. * + *********************************************************************/ + boolean hasProof = (stn.heirs()[bodyIndex].getKind() == N_Proof) + || (stn.heirs()[bodyIndex].getKind() == N_TerminalProof); + if (hasProof) { + bodyIndex--; + } + ; + + if (bodyIndex > 1) { + /********************************************************************* + * If this is a named theorem, start fresh processing of labels, * create the + * object. * + *********************************************************************/ + pushLS(); + UniqueString name = stn.heirs()[1].getUS(); + tadn = new ThmOrAssumpDefNode(name, stn); + } + ; + if (stn.zero()[bodyIndex] + .isKind(N_AssumeProve)) { /******************************************************************* + * Theorem statement is an ASSUME/PROVE. Must set currentGoal. * + *******************************************************************/ + currentGoal = tadn; + isAssumeProve = true; + + /******************************************************************* + * We want the symbols declared in top-level NEW statements of the * ASSUME + * clause to be visible in the proof. Therefore, we do the * context push for + * the top-level AssumeProveNode here instead of * in generateAssumeProve. * + *******************************************************************/ + symbolTable.pushContext(new Context(moduleTable, errors)); + body = generateAssumeProve(stn.heirs()[bodyIndex], cm); + currentGoal = null; + } else { /**************************************************************** + * Theorem statement must be an ExprNode. * + ****************************************************************/ + body = generateExpression(stn.heirs()[bodyIndex], cm); + } + ; + if (bodyIndex > 1) { + /********************************************************************** + * The theorem node has the form * THEOREM Ident == statement * + **********************************************************************/ + Context assumeContext = null; + if (isAssumeProve) { + /******************************************************************** + * If the body is an ASSUME/PROVE, we must save in assumeContext * the context + * containing the symbols declared in the ASSUME * clause and pop it, so Ident + * is made visible outside the proof. * + ********************************************************************/ + assumeContext = symbolTable.getContext(); + symbolTable.popContext(); + } + ; + UniqueString name = stn.heirs()[1].getUS(); + tadn.construct(true, body, cm, symbolTable, null); + tadn.setLabels(popLabelNodeSet()); + cm.appendDef(tadn); + if (isAssumeProve) { + /******************************************************************** + * After putting Ident into the symbol table, we push the ASSUME * context back + * onto symboltable. * + ********************************************************************/ + symbolTable.pushContext(assumeContext); + } + ; + } + ; // if (bodyIndex > 1) + + /************************************************************************ + * Note: If this is a named theorem, then the name has been added to * + * symbolTable so it can be referred to within the theorem's proof (if * it has + * one). * + ************************************************************************/ + if (hasProof) { + proof = generateProof(stn.heirs()[bodyIndex + 1], cm); + } + ; + + if (isAssumeProve) { + symbolTable.popContext(); + /******************************************************************** + * Pop the context containing ASSUME declarations. * + ********************************************************************/ + ((AssumeProveNode) body).inProof = false; + /******************************************************************** + * Reset the AssumeProve node's inProof field. * + ********************************************************************/ + } + ; + cm.addTheorem(stn, body, proof, tadn); + } // ProcessTheorem + + private final void processAssumption(TreeNode stn, ModuleNode cm) throws AbortException { + ThmOrAssumpDefNode tadn = null; + int lastIndex = stn.heirs().length - 1; + if (lastIndex > 1) { + pushLS(); + } + ; + /********************************************************************* + * If this is a named assumption, start fresh processing of labels. * + *********************************************************************/ + ExprNode expr = generateExpression(stn.heirs()[lastIndex], cm); + + if (lastIndex > 1) { + /********************************************************************** + * The assumption node has the form * ASSUME Ident == expression * + **********************************************************************/ + UniqueString name = stn.heirs()[1].getUS(); + tadn = new ThmOrAssumpDefNode(name, false, expr, cm, symbolTable, stn, null, null, null); + tadn.setLabels(popLabelNodeSet()); + cm.appendDef(tadn); + } + ; + cm.addAssumption(stn, expr, symbolTable, tadn); + return; + } // processAssumption + + private final ProofNode generateProof(TreeNode stn, ModuleNode cm) + /*********************************************************************** + * Node stn is of kind N_TerminalProof or an N_Proof. The heirs of an * N_Proof + * node consist of an optional PROOF token followed by a * seequence of + * N_ProofStep nodes. The heirs of an N_ProofStep node * are a StartStep() + * token, a statement body, and an optional proof. * A statement body is one of + * the following node kinds: * * Have no proof: * N_DefStep N_UseOrHide + * N_NonLocalInstance N_HaveStep, * N_TakeStep N_WitnessStep * * Have a proof * + * N_QEDStep N_PickStep N_CaseStep N_AssertStep * * Each step produces the + * following kind of semantic node: * * N_DefStep : DefStepNode * * N_UseOrHide + * : UseOrNideNode * * N_NonLocalInstance : InstanceNode * * Others: TheoremNode + * * The type of statement is indicated by the body of the * node. For any step + * other than an N_AssertStep, the body * is an OpApplNode with the following + * dummy operator: * * N_HaveStep : $Have * N_CaseStep : $Pfcase * N_TakeStep : + * $Take * N_PickStep : $Pick * N_WitnessStep : $Witness * N_QEDStep : $Qed * + ***********************************************************************/ + throws AbortException { + int numberOfPops = 0; + /********************************************************************* + * For each SUFFICES ASSUME/PROVE step, we push a new context onto * the symbol + * table containing declarations of any NEW symbols. * These need to be popped + * off when through processing the proof. * + *********************************************************************/ + if (stn.getKind() == N_TerminalProof) { + return generateLeafProof(stn, cm); + } + ; + + Context pfCtxt = new Context(moduleTable, errors); + symbolTable.pushContext(pfCtxt); + /********************************************************************* + * Create a new sub-Context for the proof. * + *********************************************************************/ + + TreeNode heirs[] = stn.heirs(); + int offset = 0; + if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { + offset = 1; + } + ; + LevelNode[] steps = new LevelNode[heirs.length - offset]; + Vector iVec = new Vector(); + /********************************************************************* + * A vector to hold the InstanceNodes generated by steps of the form * Id == + * INSTANCE ... so they can be level checked. * + *********************************************************************/ + + /*********************************************************************** + * At the beginning of each loop iteration, the variable prevIsInFix * equals + * true iff the previous step consists of a formula whose main * operator is an + * infix operator, including an "@-step" of the form "@ * infix-op expression". + * If it is true, then rhSide is the ExprNode * of the infix-op's + * right-hand-side expression. * + ***********************************************************************/ + boolean prevIsInfix = false; + ExprNode prevRHS = null; + + for (int i = offset; i < heirs.length; i++) { + /********************************************************************* + * Process proof step i. * + *********************************************************************/ + boolean isAssumeProve = false; + /******************************************************************* + * Will be set true for an ASSUME/PROVE, so we can reset the * node's inProof + * field. * + *******************************************************************/ + boolean isSuffices = false; + /******************************************************************* + * Will be set to true for a SUFFICES statement. This is used to * do the right + * thing with ASSUME declarations in an ASSUME/PROVE * step, and to set the + * suffices field of the ThmOrAssumpDefNode * if this is a named step. * + *******************************************************************/ + + /********************************************************************* + * For an ASSUME/PROVE, we set assumeContext to a context containing * the + * declarations from the outer-most NEWs of the ASSUME. For an * ordinary + * ASSUME/PROVE, this context is pushed onto the symbol * table for statement's + * processing the proof. For a SUFFICE * ASSUME/PROVE, it is pushed onto the + * symbol table after processing * the statement's proof so the outermost NEW + * declarations are * visible for the rest of the current proof. * The handling + * of the assumeContext was changed on 1 Jul 2009 * because SUFFICE ASSUME/PROVE + * was not being handled properly. * + *********************************************************************/ + Context assumeContext = null; + + /********************************************************************* + * For "PICK x : exp", the symbol x is declared in exp, undeclared * in the + * proof of the step, and declared afterwards. (There'd be a * similar problem + * with TAKE if it took a proof.) The following * variables are used to + * manipulate this, with pickContext holding * the declarations of the symbols + * introduced by the PICK step. * + *********************************************************************/ + boolean isPick = false; + Context pickContext = null; + + /********************************************************************* + * Set stepNumSTN, stepBodySTN, and stepPfSTN to the syntax tree * nodes of the + * step number, the body, and the proof (the latter * equal to null if there's + * no proof. * + *********************************************************************/ + TreeNode pfStepSTN = heirs[i]; + TreeNode stepNumSTN = pfStepSTN.heirs()[0]; + TreeNode stepBodySTN = pfStepSTN.heirs()[1]; + TreeNode stepPfSTN = null; + if (pfStepSTN.heirs().length > 2) { + stepPfSTN = pfStepSTN.heirs()[2]; + } + ; + + LevelNode pfNumNode = null; + boolean makePfNumNode = true; + /******************************************************************* + * For a numbered step that doesn't produce a TheoremNode, * pfNumNode is set to + * a node that will be the stepNode of a * NumberedProofStepKind OpDefNode. * + *******************************************************************/ + /* + * On 23 Feb 2014 LL added the following code to make step numbers like <*>13 + * illegal, so <+> and <*> can be used only for unnamed steps. It would be most + * natural to make the change age the parsing level by changing the JavaCC code. + * However, that code is a Kludge that it is best not to touch unless absolutely + * necessary. Also, detecting the error here allows multiple instances of the + * error to be reported in a single execution of the parser. + * + * The modification is based on the following empirical observation: + * + * - For a step number like "<3>13." stepNumSTN.image = stepNumSTN.originalImage + * = "<3>13." - For a step number like "<*>13.", stepNumSTN.image = "<3>13." and + * stepNumSTN.originalImage = "<*>13." - For unnumbered steps, + * stepNumSTN.originalImage = null and stepNumSTN.image = the actual token. + */ + SyntaxTreeNode STN = (SyntaxTreeNode) stepNumSTN; + if ((STN.originalImage != null) && (STN.originalImage != STN.image)) { + String oimage = STN.originalImage.toString(); + if ((!oimage.equals(STN.image.toString())) + && ((oimage.charAt(1) == '*') || (oimage.charAt(1) == '+'))) { + errors.addError(stepNumSTN.getLocation(), "<*> and <+> cannot be used for a named step."); + } + } + + /********************************************************************* + * Set stepNum to the step number, or null if its an unnumbered step. * + *********************************************************************/ + UniqueString stepNum = null; + switch (stepNumSTN.getKind()) { + // LL: On 25 Feb 2010 I discovered the following comment here: + // XXXXXX xyz: need to add the following case + // The ProofImplicitStepLexeme case (something like <*>3) seems to be + // handled properly in tests. I presume that this is an obsolete + // comment that I didn't remove when I added the case to the code. + case TLAplusParserConstants.ProofImplicitStepLexeme: + case TLAplusParserConstants.ProofStepLexeme: + stepNum = stepNumSTN.getUS(); + break; + case TLAplusParserConstants.ProofStepDotLexeme: + String stNum = stepNumSTN.getUS().toString(); + stepNum = UniqueString.uniqueStringOf(stNum.substring(0, stNum.indexOf("."))); + break; + default: + makePfNumNode = false; + break; + } + ; // switch + + /********************************************************************* + * If this is a numbered step, process labels. * + *********************************************************************/ + if (stepNum != null) { + pushLS(); + } + ; + + /******************************************************************** + * Construct the ThmOrOpDefNode if needed. (We need to do it now * because we + * have to set currentGoal before we generate the body.) * + ********************************************************************/ + ThmOrAssumpDefNode tadn = null; + if (stepNum != null) { + tadn = new ThmOrAssumpDefNode(stepNum, stepNumSTN); + } + ; + + /********************************************************************* + * Set prevIsInfix false unless this is an AssertStep node. * + *********************************************************************/ + int stepKind = stepBodySTN.getKind(); + if (stepKind != N_AssertStep) { + prevIsInfix = false; + } + ; + + switch (stepKind) { + case N_DefStep: + /***************************************************************** + * Set defSTNs to the array of heirs, and defOffSet so that * defSTNs[defOffSet] + * ... defSTNs[defSTNs.length-1] is the * sequence of definitions. * + *****************************************************************/ + TreeNode[] defSTNs = stepBodySTN.heirs(); + int defOffSet = 0; + if (defSTNs[0].getKind() == DEFINE) { + defOffSet = 1; + } + ; + + OpDefNode[] defs = new OpDefNode[defSTNs.length - defOffSet]; + /*************************************************************** + * Will be set to the sequence of OpDefNodes for the * definitions. * + ***************************************************************/ + for (int j = defOffSet; j < defSTNs.length; j++) { + TreeNode defSTN = defSTNs[j]; + ; + Vector vec = new Vector(); + switch (defSTN.getKind()) { + /*************************************************************** + * Need to check if it's an operator, function, or module * definition. * + ***************************************************************/ + case N_FunctionDefinition: + processFunction(defSTN, vec, cm); + break; + case N_ModuleDefinition: + /************************************************************* + * The call to processModuleDefinition sets defsVec to a * vector of all the + * definitions it makes, and adds the new * InstanceNode to iVec. For now, we're + * just throwing * away defsVec. (If defsVec were null, then * + * processModuleDefinition would add these definitions to to * the module's list + * of top-level definitions.) * + *************************************************************/ + Vector defsVec = new Vector(); + vec.addElement(processModuleDefinition(defSTN, defsVec, iVec, cm)); + break; + case N_OperatorDefinition: + processOperator(defSTN, vec, cm); + /************************************************************* + * processOperator creates an OpDefNode, puts an entry for * it in symbolTable, + * and adds the OpDefNode to vec. * + *************************************************************/ + break; + } + ; // switch (def.getKind()) + defs[j - defOffSet] = (OpDefNode) vec.elementAt(0); + } + ; // for j + pfNumNode = new DefStepNode(stepBodySTN, stepNum, defs); + steps[i - offset] = pfNumNode; + break; + + case N_UseOrHide: + UseOrHideNode uohn = generateUseOrHide(stepBodySTN, cm); + + // Added by LL on 16 Jun 2010 so location returnedby getLocation() will + // include the step number. + uohn.stn = pfStepSTN; + + uohn.setStepName(stepNum); // Added 6 June 2010 by LL. + + if (uohn.facts.length + uohn.defs.length == 0) { + errors.addError(stepBodySTN.getLocation(), "Empty USE or HIDE statement."); + } + ; + uohn.factCheck(); + // Added 4 Mar 2009. + pfNumNode = uohn; + steps[i - offset] = pfNumNode; + break; + + case N_NonLocalInstance: + // Code to set step name added by LL on 6 June 2010 + InstanceNode inst = generateInstance(stepBodySTN, cm, false); + inst.setStepName(stepNum); + pfNumNode = inst; + steps[i - offset] = pfNumNode; + break; + + default: + makePfNumNode = false; + TreeNode[] bodyHeirs = stepBodySTN.heirs(); + LevelNode body = null; + /*************************************************************** + * This will be set to the body of the TheoremNode or * ThmOrAssumpDefNode. * + ***************************************************************/ + UniqueString op = null; + ExprNode[] args; + /*************************************************************** + * For anything but an N_Assert node, body is set to an * OpApplNode having + * these as its operator and arguments. * + ***************************************************************/ + + switch (stepBodySTN.getKind()) { + case N_AssertStep: + int bodyNext = 0; + if (bodyHeirs[0].getKind() == TLAplusParserConstants.SUFFICES) { + bodyNext = 1; + isSuffices = true; + /************************************************************ + * We can't have an "@" in a SUFFICES step. * + ************************************************************/ + } + ; + if (bodyHeirs[bodyNext].getKind() == N_AssumeProve) { + /************************************************************ + * This is an AssumeProve node. * + ************************************************************/ + isAssumeProve = true; + + /************************************************************ + * For an ASSUME/PROVE, we need save the symbol * declarations from top-level + * NEW statements in the ASSUME * to make them visible only in the statement's + * proof for * an ordinary ASSUME/PROVE, and only after the statement's * proof + * for a SUFFICES ASSUME/PROVE. * + ************************************************************/ + symbolTable.pushContext(new Context(moduleTable, errors)); + + currentGoal = tadn; + /********************************************************** + * Need to set currentGoal before generating the * AssumeProve node. * + **********************************************************/ + body = generateAssumeProve(bodyHeirs[bodyNext], cm); + + if (isSuffices) { + ((AssumeProveNode) body).setSuffices(); + } + ; + /********************************************************** + * Added 16 Feb 2009 by LL. * + **********************************************************/ + currentGoal = null; + assumeContext = symbolTable.getContext(); + symbolTable.popContext(); + prevIsInfix = false; + } else { + /************************************************************ + * This is an ordinary expression. * + ************************************************************/ + TreeNode curExpr = bodyHeirs[bodyNext]; + + /************************************************************ + * Special handling of SUFFICES added by LL 16 Feb 2009. * + ************************************************************/ + if (isSuffices) { + args = new ExprNode[1]; + args[0] = generateExpression(curExpr, cm); + body = new OpApplNode(OP_suffices, args, stepBodySTN, cm); + } // if (isSuffices) + else { + /************************************************************ + * If the current expression is an infix expression, set * curLHS to its current + * LHS, otherwise set it to null. * + ************************************************************/ + SyntaxTreeNode curLHS = null; + if (curExpr.getKind() == N_InfixExpr) { + curLHS = (SyntaxTreeNode) curExpr.heirs()[0]; + } + ; + /************************************************************ + * If prevIsInfix is true and curLHS is an "@", then * process it, using as the + * right-hand side a new $Nop node * with prevRHS as its argument. * + ************************************************************/ + if (prevIsInfix && (curLHS != null) && (curLHS.heirs().length > 0) + /*************************************************** + * This test added 25 Feb 2010 because if curLHS * is a string, then + * curLHS.heirs() is a * zero-length array, so the following test threw * an + * out-of-bounds array index exception. Note * that curLHS.heirs() should never + * be null, * because the heirs() method can never return * null. * + ***************************************************/ + && (((SyntaxTreeNode) curLHS.heirs()[0]).heirs().length == 0) + && (curLHS.heirs()).length > 1 + /*************************************************** + * This test added 2 Mar 2009 to fix following * bug. When we are here and the + * left-hand side * is something like a number, then curLHS.heirs() * seems to + * have length 1 and the following test * causes an ArrayIndexOverflowException. + * * + ***************************************************/ + && (curLHS.heirs()[1].getKind() == IDENTIFIER) + && (curLHS.heirs()[1].getUS() == AtUS)) { + + /********************************************************** + * The following code obtained by a simple modification * of the N_InfixExpr + * case of generateExpression. * + **********************************************************/ + TreeNode[] children = curExpr.heirs(); + GenID genID = generateGenID(children[1], cm); + ExprNode[] sns = new ExprNode[2]; + SymbolNode opn = symbolTable + .resolveSymbol(Operators.resolveSynonym(genID.getCompoundIDUS())); + if (opn == null) { + errors.addError(curExpr.getLocation(), "Couldn't resolve infix operator symbol `" + + genID.getCompoundIDUS() + "'."); + return null; + } + ; + sns[1] = generateExpression(children[2], cm); + /********************************************************** + * Set sns[1] to a new $Nop OpApplNode whose argument is * prevRHS. * + **********************************************************/ + ExprNode[] nopArgs = new ExprNode[1]; + nopArgs[0] = prevRHS; + sns[0] = new OpApplNode(OP_nop, nopArgs, curLHS, cm); + body = new OpApplNode(opn, sns, curExpr, cm); + } // if ( prevIsInfix ...) + else { // this is not an @-step + body = generateExpression(curExpr, cm); + } + ; + + /************************************************************ + * If this is an infix ioperator, set prevIsInfix true and * prevRHS equal to + * its right-hand argument, else set * prevIsInfix false. * + ************************************************************/ + prevIsInfix = false; + if ((curLHS != null) + /******************************************************* + * The following conjuncts should be true unless there * was an error in the + * expression. * + *******************************************************/ + && (body != null) && (body.getKind() == OpApplKind) + && (((OpApplNode) body).getArgs().length > 1)) { + prevIsInfix = true; + prevRHS = (ExprNode) ((OpApplNode) body).getArgs()[1]; + } + } + } + ; // else This is an ordinary expression. + break; + + case N_HaveStep: + case N_CaseStep: + if (stepBodySTN.getKind() == N_HaveStep) { + op = OP_have; + } else { + op = OP_pfcase; + } + ; + args = new ExprNode[1]; + args[0] = generateExpression(bodyHeirs[1], cm); + body = new OpApplNode(op, args, stepBodySTN, cm); + break; + + case N_TakeStep: + case N_PickStep: + if (stepBodySTN.getKind() == N_TakeStep) { + op = OP_take; + } else { + op = OP_pick; + isPick = true; + /************************************************************ + * Push a new context onto the symbolTable stack to get the * declarations of + * the PICK symbols. * + ************************************************************/ + symbolTable.pushContext(new Context(moduleTable, errors)); + } + ; + + if (bodyHeirs[1].getKind() == N_QuantBound) { + /************************************************************ + * The introduced identifiers are bounded--e.g., "TAKE id * \in Set". * + ************************************************************/ + + /************************************************************ + * Set quants to the number of N_QuantBound nodes. * + ************************************************************/ + int quants = 1; + int nextTok = 2; + while ((nextTok < bodyHeirs.length) + && (bodyHeirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { + quants++; + nextTok = nextTok + 2; + } + ; + FormalParamNode[][] params = new FormalParamNode[quants][0]; + boolean[] bt = new boolean[quants]; + ExprNode[] paramBounds = new ExprNode[quants]; + processQuantBoundArgs(bodyHeirs, 1, params, bt, paramBounds, cm); + + if (isPick) { + /********************************************************** + * Save the declarations in pickContext. * + **********************************************************/ + pickContext = symbolTable.getContext(); + /********************************************************** + * This is a PICK step; get the ": expr". * + **********************************************************/ + nextTok++; // Skip over the ":" + args = new ExprNode[1]; + pushFormalParams(flattenParams(params)); + /******************************************************** + * Push the bound variables on Last(LS).paramSeq and * process the body of the + * PICK. * + ********************************************************/ + args[0] = generateExpression(bodyHeirs[nextTok], cm); + popFormalParams(); + symbolTable.popContext(); + /******************************************************** + * Remove the bound symbols from the symbol table so * they're undefined for the + * proof of the PICK. * + ********************************************************/ + } else { + /********************************************************** + * This is a TAKE step. * + **********************************************************/ + args = new ExprNode[0]; + } + ; + body = new OpApplNode(op, null, args, params, bt, paramBounds, stepBodySTN, cm); + } else { + /************************************************************ + * The introduced identifiers are unbounded--e.g., "TAKE * id1, id2". * + ************************************************************/ + + /************************************************************ + * Set ids to the number of introduced identifiers. * + ************************************************************/ + int ids = 1; + while ((2 * ids < bodyHeirs.length) + && (bodyHeirs[2 * ids].getKind() == TLAplusParserConstants.COMMA)) { + ids++; + } + ; + + /************************************************************ + * Set params to the array of new FormalParamNodes for the * identifiers. The + * identifiers are added to the current * symbol table. * + ************************************************************/ + FormalParamNode[] params = new FormalParamNode[ids]; + for (int j = 0; j < ids; j++) { + params[j] = new FormalParamNode(bodyHeirs[2 * j + 1].getUS(), 0, bodyHeirs[2 * j + 1], + symbolTable, cm); + } + ; + + if (isPick) { + /********************************************************** + * Save the declarations in pickContext. * + **********************************************************/ + pickContext = symbolTable.getContext(); + + /********************************************************** + * This is a PICK step; get the ": expr". * + **********************************************************/ + pushFormalParams(params); + /******************************************************** + * Push formal parameters on Last(LS).paramSeq for * processing the body. * + ********************************************************/ + args = new ExprNode[1]; + args[0] = generateExpression(bodyHeirs[2 * ids + 1], cm); + popFormalParams(); + symbolTable.popContext(); + /******************************************************** + * Remove the bound symbols from the symbol table so * they're undefined for the + * proof of the PICK. * + ********************************************************/ + } else { + /********************************************************** + * This is a TAKE step. * + **********************************************************/ + args = new ExprNode[0]; + } + ; + body = new OpApplNode(op, args, params, stepBodySTN, cm); + } + ; + + break; + + case N_WitnessStep: + /************************************************************** + * Set ids to the number of expressions. * + **************************************************************/ + int ids = 1; + while ((2 * ids < bodyHeirs.length) + && (bodyHeirs[2 * ids].getKind() == TLAplusParserConstants.COMMA)) { + ids++; + } + ; + + args = new ExprNode[ids]; + for (int j = 0; j < ids; j++) { + args[j] = generateExpression(bodyHeirs[2 * j + 1], cm); + } + ; + body = new OpApplNode(OP_witness, args, stepBodySTN, cm); + break; + + case N_QEDStep: + args = new ExprNode[0]; + body = new OpApplNode(OP_qed, args, stepBodySTN, cm); + break; + + default: + errors.addAbort(stn.getLocation(), + "Internal error: Unexpected SyntaxTreeNode kind: " + heirs[i].getKind()); + break; + } + ; // switch + + /******************************************************************** + * Set the fields of the ThmOrOpDefNode if there is one, including * the + * suffices field. * + ********************************************************************/ + if (stepNum != null) { + tadn.construct(true, body, cm, symbolTable, null); + tadn.setLabels(popLabelNodeSet()); + if (isSuffices) { + tadn.setSuffices(); + } + ; + } + ; + /*********************************************************************** + * Set proof to the proof, or to null if there is none. There is no * check made + * to see if this is a kind of step that should have a * proof. Thus, adding a + * proof to something like a WITNESS statement * requires changing only the + * parsing phase (specified by tla+.jj). * + ***********************************************************************/ + ProofNode proof = null; + if (stepPfSTN != null) { + /****************************************************************** + * For an ordinary ASSUME/PROVE, must make the ASSUME's * declarations visible + * in the statement's proof. * + ******************************************************************/ + if (isAssumeProve && !isSuffices) { + symbolTable.pushContext(assumeContext); + } + ; + proof = generateProof(stepPfSTN, cm); + if (isAssumeProve && !isSuffices) { + symbolTable.popContext(); + } + ; + } + ; + + /******************************************************************** + * For a SUFFICES ASSUME/PROVE, must make the ASSUME's declarations * visible + * after the proof. This is done by pushing assumeContext * onto the symbol + * table and incrementing numberOfPops so it will * be popped at the end of the + * proof. * + ********************************************************************/ + if (isAssumeProve && isSuffices) { + numberOfPops++; + symbolTable.pushContext(assumeContext); + } + ; + if (isAssumeProve) { + ((AssumeProveNode) body).inProof = false; + } + ; + /****************************************************************** + * For an ASSUME/PROVE, set the inProof field to false. * + ******************************************************************/ + TheoremNode thm = new TheoremNode(stepBodySTN, body, cm, proof, tadn); + + // Added by LL on 16 Jun 2010 so location returnedby getLocation() will + // include the step number. + thm.stn = pfStepSTN; + + thm.suffices = isSuffices; + steps[i - offset] = thm; + } + ; // switch + if (makePfNumNode) { + /******************************************************************* + * Make an OpDefNode for the numbered step and add any label * declarations to + * it. * + *******************************************************************/ + OpDefNode nodeMadeOnlyToBePutInSymbolTable = new OpDefNode(stepNum, pfNumNode, cm, symbolTable, + pfStepSTN); + nodeMadeOnlyToBePutInSymbolTable.setLabels(popLabelNodeSet()); + } + if (isPick) { + /******************************************************************* + * We have to take the symbol declarations from pickContext and * put them into + * the current symbol table. * + *******************************************************************/ + Enumeration e = pickContext.content(); + while (e.hasMoreElements()) { + SymbolNode sym = ((Context.Pair) (e.nextElement())).getSymbol(); + symbolTable.addSymbol(sym.getName(), sym); + } + } + } + ; // for i + InstanceNode[] insts = new InstanceNode[iVec.size()]; + for (int i = 0; i < insts.length; i++) { + insts[i] = (InstanceNode) iVec.elementAt(i); + } + ; + + /*********************************************************************** + * Pop the contexts that were pushed onto the symbol table for SUFFICE * + * ASSUME/PROVE steps. * + ***********************************************************************/ + for (int i = 0; i < numberOfPops; i++) { + // Added by LL on 24 June 2010 + // Need to add the symbols in the context being popped to pfCtxt + // so they will be put into the context of the NonLeafProofNode. + Context topContext = symbolTable.getContext(); + Enumeration e = topContext.content(); + while (e.hasMoreElements()) { + SymbolNode sym = ((Context.Pair) (e.nextElement())).getSymbol(); + pfCtxt.addSymbolToContext(sym.getName(), sym); + } + symbolTable.popContext(); + } + ; + symbolTable.popContext(); + return new NonLeafProofNode(stn, steps, insts, pfCtxt); + /********************************************************************* + * Pop the sub-Context. * + *********************************************************************/ + } // generateProof + + /*************************************************************************** + * The following method is not used and I have no idea why it's still * here. * + ***************************************************************************/ + private final LevelNode generateNumerableStep(TreeNode stn, // TreeNode stmt, // UniqueString stepNum, // TreeNode proof, - ModuleNode cm) - throws AbortException { - /*********************************************************************** - * Used to generate the step for a NumerableStep or QEDStep token. * - * Returns a TheoremNode or ThmOrAssumpDefNode. * - * * - * The parsing into the syntactic tree makes it hard to rationalize * - * processing of an N_NumerableStep node because there are two * - * different ways such a step can be parsed * - * * - * 1. [step number] (sequence of tokens of the statement) [proof] * - * 2. [step number] (NonExprBody) [proof] * - * * - * where, in case 2, the NonExprBody node contains all the tokens of * - * the statement except the optional step number. Here are the * - * classes into which the different kinds of NumerableStep nodes fall. * - * * - * 1. CASE, (step number) expression. * - * * - * 2. WITNESS, TAKE, PICK, HAVE, ASSUME/PROVE, SUFFICES, * - * and PROVE expression * - ***********************************************************************/ -errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; - UniqueString stepNum = null ; - TreeNode[] heirs = stn.heirs() ; - int nextTok = 0 ; - ThmOrAssumpDefNode tadn = null ; - boolean isSuffices = false ; - boolean isAssumeProve = false ; - /********************************************************************* - * Set true if this is an ASSUME/PROVE step, in which case some * - * messing with the symbol table is necessary so that symbols * - * declared in the ASSUME are visible in the proof of this step. * - * They should be visible in the rest of the proof iff this is a * - * SUFFICES ASSUME... step. * - *********************************************************************/ - Context assumeContext = null; - /********************************************************************* - * For use with an ASSUME/PROVE. * - *********************************************************************/ - LevelNode body = null ; - /********************************************************************* - * This will be set to the body of the TheoremNode or * - * ThmOrAssumpDefNode. * - *********************************************************************/ - - /*********************************************************************** - * We now save the values of heirs and nextTok. If the tokens of the * - * statement are inside a NonExprBody node, we set heirs to the * - * children of that node, nextTok to 0, and hasNonExprBody true. * - * After processing the statement, we will reset heirs and set nextTok * - * to the its saved value plus 1. * - ***********************************************************************/ - TreeNode[] savedHeirs = heirs ; - int savedNextTok = nextTok ; - boolean hasNonExprBody = false ; - if (heirs[nextTok].getKind() == N_NonExprBody) { - heirs = heirs[nextTok].heirs() ; - nextTok = 0 ; - hasNonExprBody = true ; - } ; - - /*********************************************************************** - * If next token is "SUFFICES", then skip over it and set isSuffices * - * true. With the current grammar, this is the case only for an * - * ordinary assertion (a statement or ASSUME/PROVE). * - ***********************************************************************/ - if (heirs[nextTok].getKind() == TLAplusParserConstants.SUFFICES) { - nextTok++ ; - isSuffices = true ; - } ; - - /*********************************************************************** - * Skip over the next token if it's "PROVE". With current grammar, * - * this only happens when nextTok = 0. * - ***********************************************************************/ - if (heirs[nextTok].getKind() == TLAplusParserConstants.PROVE) { - nextTok++ ; - } ; - - /*********************************************************************** - * If body will be an OpApplNode with a dummy operator (like $Pick), * - * then set op to the operator's name and move past the determining * - * token (like "PICK"). Otherwise, the body will be an ordinary * - * assertion and op is left null. * - ***********************************************************************/ - UniqueString op = null ; - switch (heirs[nextTok].getKind()) { - case TLAplusParserConstants.QED : - body = new OpApplNode(OP_qed, new ExprNode[0], heirs[nextTok], cm) ; - nextTok++ ; - break ; - - case TLAplusParserConstants.CASE : - case TLAplusParserConstants.HAVE : - op = OP_have ; - if (heirs[nextTok].getKind() == TLAplusParserConstants.CASE) { - op = OP_pfcase ; - }; - nextTok++ ; - ExprNode[] args = new ExprNode[1] ; - args[0] = generateExpression(heirs[nextTok], cm) ; - body = new OpApplNode(op, args, heirs[nextTok], cm) ; - nextTok++ ; - break ; - - case TLAplusParserConstants.TAKE : - case TLAplusParserConstants.PICK : - op = OP_take ; - if (heirs[nextTok].getKind() == TLAplusParserConstants.PICK) { - op = OP_pick ; - }; - nextTok++ ; - - if (heirs[nextTok].getKind() == N_QuantBound) { - int offset = nextTok; - /***************************************************************** - * The introduced identifiers are bounded--e.g., * - * "TAKE id \in Set". * - *****************************************************************/ - /***************************************************************** - * Set quants to the number of N_QuantBound nodes. * - *****************************************************************/ - int quants = 1 ; - nextTok++ ; - while ( (nextTok < heirs.length) - && (heirs[nextTok].getKind() - == TLAplusParserConstants.COMMA)) { - quants++ ; - nextTok = nextTok + 2 ; - }; - FormalParamNode[][] params = new FormalParamNode[quants][0]; - boolean[] bt = new boolean[quants] ; - ExprNode[] paramBounds = new ExprNode[quants]; - processQuantBoundArgs(heirs, offset, params, bt, paramBounds, cm) ; + ModuleNode cm) throws AbortException { + /*********************************************************************** + * Used to generate the step for a NumerableStep or QEDStep token. * Returns a + * TheoremNode or ThmOrAssumpDefNode. * * The parsing into the syntactic tree + * makes it hard to rationalize * processing of an N_NumerableStep node because + * there are two * different ways such a step can be parsed * * 1. [step number] + * (sequence of tokens of the statement) [proof] * 2. [step number] + * (NonExprBody) [proof] * * where, in case 2, the NonExprBody node contains all + * the tokens of * the statement except the optional step number. Here are the * + * classes into which the different kinds of NumerableStep nodes fall. * * 1. + * CASE, (step number) expression. * * 2. WITNESS, TAKE, PICK, HAVE, + * ASSUME/PROVE, SUFFICES, * and PROVE expression * + ***********************************************************************/ + errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step"); + UniqueString stepNum = null; + TreeNode[] heirs = stn.heirs(); + int nextTok = 0; + ThmOrAssumpDefNode tadn = null; + boolean isSuffices = false; + boolean isAssumeProve = false; + /********************************************************************* + * Set true if this is an ASSUME/PROVE step, in which case some * messing with + * the symbol table is necessary so that symbols * declared in the ASSUME are + * visible in the proof of this step. * They should be visible in the rest of + * the proof iff this is a * SUFFICES ASSUME... step. * + *********************************************************************/ + Context assumeContext = null; + /********************************************************************* + * For use with an ASSUME/PROVE. * + *********************************************************************/ + LevelNode body = null; + /********************************************************************* + * This will be set to the body of the TheoremNode or * ThmOrAssumpDefNode. * + *********************************************************************/ + + /*********************************************************************** + * We now save the values of heirs and nextTok. If the tokens of the * statement + * are inside a NonExprBody node, we set heirs to the * children of that node, + * nextTok to 0, and hasNonExprBody true. * After processing the statement, we + * will reset heirs and set nextTok * to the its saved value plus 1. * + ***********************************************************************/ + TreeNode[] savedHeirs = heirs; + int savedNextTok = nextTok; + boolean hasNonExprBody = false; + if (heirs[nextTok].getKind() == N_NonExprBody) { + heirs = heirs[nextTok].heirs(); + nextTok = 0; + hasNonExprBody = true; + } + ; + + /*********************************************************************** + * If next token is "SUFFICES", then skip over it and set isSuffices * true. + * With the current grammar, this is the case only for an * ordinary assertion + * (a statement or ASSUME/PROVE). * + ***********************************************************************/ + if (heirs[nextTok].getKind() == TLAplusParserConstants.SUFFICES) { + nextTok++; + isSuffices = true; + } + ; + + /*********************************************************************** + * Skip over the next token if it's "PROVE". With current grammar, * this only + * happens when nextTok = 0. * + ***********************************************************************/ + if (heirs[nextTok].getKind() == TLAplusParserConstants.PROVE) { + nextTok++; + } + ; + + /*********************************************************************** + * If body will be an OpApplNode with a dummy operator (like $Pick), * then set + * op to the operator's name and move past the determining * token (like + * "PICK"). Otherwise, the body will be an ordinary * assertion and op is left + * null. * + ***********************************************************************/ + UniqueString op = null; + switch (heirs[nextTok].getKind()) { + case TLAplusParserConstants.QED: + body = new OpApplNode(OP_qed, new ExprNode[0], heirs[nextTok], cm); + nextTok++; + break; + + case TLAplusParserConstants.CASE: + case TLAplusParserConstants.HAVE: + op = OP_have; + if (heirs[nextTok].getKind() == TLAplusParserConstants.CASE) { + op = OP_pfcase; + } + ; + nextTok++; + ExprNode[] args = new ExprNode[1]; + args[0] = generateExpression(heirs[nextTok], cm); + body = new OpApplNode(op, args, heirs[nextTok], cm); + nextTok++; + break; + + case TLAplusParserConstants.TAKE: + case TLAplusParserConstants.PICK: + op = OP_take; + if (heirs[nextTok].getKind() == TLAplusParserConstants.PICK) { + op = OP_pick; + } + ; + nextTok++; + + if (heirs[nextTok].getKind() == N_QuantBound) { + int offset = nextTok; + /***************************************************************** + * The introduced identifiers are bounded--e.g., * "TAKE id \in Set". * + *****************************************************************/ + /***************************************************************** + * Set quants to the number of N_QuantBound nodes. * + *****************************************************************/ + int quants = 1; + nextTok++; + while ((nextTok < heirs.length) && (heirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { + quants++; + nextTok = nextTok + 2; + } + ; + FormalParamNode[][] params = new FormalParamNode[quants][0]; + boolean[] bt = new boolean[quants]; + ExprNode[] paramBounds = new ExprNode[quants]; + processQuantBoundArgs(heirs, offset, params, bt, paramBounds, cm); // ExprNode[] args ; - if (op == OP_pick) { - /**************************************************************** - * This is a PICK step; get the ": expr". * - ****************************************************************/ - nextTok++ ; // Skip over the ":" - args = new ExprNode[1] ; - args[0] = generateExpression(heirs[nextTok], cm) ; - nextTok++ ; - } - else { - /**************************************************************** - * This is a TAKE step. * - ****************************************************************/ - args = new ExprNode[0] ; - }; - body = - new OpApplNode(op, null, args, params, bt, paramBounds, stn, cm) ; - } - else { - /***************************************************************** - * The introduced identifiers are unbounded--e.g., * - * "TAKE id1, id2". * - *****************************************************************/ - /***************************************************************** - * Set ids to the number of introduced identifiers. * - *****************************************************************/ - int ids = 1 ; - while ( (nextTok + 2*ids - 1 < heirs.length) - && (heirs[nextTok + 2*ids - 1].getKind() == - TLAplusParserConstants.COMMA)) {ids++;} ; - - /***************************************************************** - * Set params to the array of new FormalParamNodes for the * - * identifiers. The identifiers are added to the current symbol * - * table. * - *****************************************************************/ - FormalParamNode[] params = new FormalParamNode[ids]; - for (int i = 0 ; i < ids ; i++) { - params[i] = new FormalParamNode( - heirs[2*i + nextTok].getUS(), 0, - heirs[2*i + nextTok], symbolTable, cm); - } ; - /***************************************************************** - * Skip over the identifier-list tokens. * - *****************************************************************/ - nextTok = nextTok + 2*ids - 1; + if (op == OP_pick) { + /**************************************************************** + * This is a PICK step; get the ": expr". * + ****************************************************************/ + nextTok++; // Skip over the ":" + args = new ExprNode[1]; + args[0] = generateExpression(heirs[nextTok], cm); + nextTok++; + } else { + /**************************************************************** + * This is a TAKE step. * + ****************************************************************/ + args = new ExprNode[0]; + } + ; + body = new OpApplNode(op, null, args, params, bt, paramBounds, stn, cm); + } else { + /***************************************************************** + * The introduced identifiers are unbounded--e.g., * "TAKE id1, id2". * + *****************************************************************/ + /***************************************************************** + * Set ids to the number of introduced identifiers. * + *****************************************************************/ + int ids = 1; + while ((nextTok + 2 * ids - 1 < heirs.length) + && (heirs[nextTok + 2 * ids - 1].getKind() == TLAplusParserConstants.COMMA)) { + ids++; + } + ; + + /***************************************************************** + * Set params to the array of new FormalParamNodes for the * identifiers. The + * identifiers are added to the current symbol * table. * + *****************************************************************/ + FormalParamNode[] params = new FormalParamNode[ids]; + for (int i = 0; i < ids; i++) { + params[i] = new FormalParamNode(heirs[2 * i + nextTok].getUS(), 0, heirs[2 * i + nextTok], + symbolTable, cm); + } + ; + /***************************************************************** + * Skip over the identifier-list tokens. * + *****************************************************************/ + nextTok = nextTok + 2 * ids - 1; // ExprNode[] args ; - if (op == OP_pick) { - /**************************************************************** - * This is a PICK step; get the ": expr". * - ****************************************************************/ - nextTok++ ; // Skip over the ":" - args = new ExprNode[1] ; - args[0] = generateExpression(heirs[nextTok], cm) ; - nextTok++ ; - } - else { - /**************************************************************** - * This is a TAKE step. * - ****************************************************************/ - args = new ExprNode[0] ; - }; - body = - new OpApplNode(op, args, params, stn, cm) ; - } ; - break ; - - case TLAplusParserConstants.WITNESS : - nextTok++ ; - - /******************************************************************* - * Set ids to the number of expressions. * - *******************************************************************/ - int ids = 1 ; - while ( (nextTok + 2*ids - 1 < heirs.length) - && (heirs[nextTok + 2*ids - 1].getKind() == - TLAplusParserConstants.COMMA)) {ids++;} ; - ExprNode[] exprs = new ExprNode[ids] ; - for (int i = 0 ; i < ids ; i++) { - exprs[i] = generateExpression(heirs[2*i + nextTok], cm); - } ; - - body = new OpApplNode(OP_tup, exprs, stn, cm) ; - nextTok = nextTok + 2*ids - 1; - break ; - - default: - /******************************************************************* - * This is an ordinary assertion--either an ExprNode or an * - * AssumeProve node. * - *******************************************************************/ - if (heirs[nextTok].getKind() == N_AssumeProve) { - /***************************************************************** - * This is an AssumeProve node. * - * * - * For an ordinary ASSUME/PROVE, we need to save symbol * - * declarations from top-level NEW statements in the ASSUME to * - * make them visible only in the proof. If this is a SUFFICES * - * ASSUME/PROVE, we don't need to do that because we want those * - * symbol declarations to be visible outside the PROVE clause as * - * well. * - *****************************************************************/ - isAssumeProve = true ; - if (!isSuffices) { - symbolTable.pushContext(new Context(moduleTable, errors)) ; + if (op == OP_pick) { + /**************************************************************** + * This is a PICK step; get the ": expr". * + ****************************************************************/ + nextTok++; // Skip over the ":" + args = new ExprNode[1]; + args[0] = generateExpression(heirs[nextTok], cm); + nextTok++; + } else { + /**************************************************************** + * This is a TAKE step. * + ****************************************************************/ + args = new ExprNode[0]; + } + ; + body = new OpApplNode(op, args, params, stn, cm); + } + ; + break; + + case TLAplusParserConstants.WITNESS: + nextTok++; + + /******************************************************************* + * Set ids to the number of expressions. * + *******************************************************************/ + int ids = 1; + while ((nextTok + 2 * ids - 1 < heirs.length) + && (heirs[nextTok + 2 * ids - 1].getKind() == TLAplusParserConstants.COMMA)) { + ids++; + } + ; + ExprNode[] exprs = new ExprNode[ids]; + for (int i = 0; i < ids; i++) { + exprs[i] = generateExpression(heirs[2 * i + nextTok], cm); + } + ; + + body = new OpApplNode(OP_tup, exprs, stn, cm); + nextTok = nextTok + 2 * ids - 1; + break; + + default: + /******************************************************************* + * This is an ordinary assertion--either an ExprNode or an * AssumeProve node. * + *******************************************************************/ + if (heirs[nextTok].getKind() == N_AssumeProve) { + /***************************************************************** + * This is an AssumeProve node. * * For an ordinary ASSUME/PROVE, we need to + * save symbol * declarations from top-level NEW statements in the ASSUME to * + * make them visible only in the proof. If this is a SUFFICES * ASSUME/PROVE, we + * don't need to do that because we want those * symbol declarations to be + * visible outside the PROVE clause as * well. * + *****************************************************************/ + isAssumeProve = true; + if (!isSuffices) { + symbolTable.pushContext(new Context(moduleTable, errors)); // System.out.println("here") ; - } ; + } + ; // System.out.println("here and there") ; - body = generateAssumeProve(heirs[nextTok], cm); - if (!isSuffices) { - assumeContext = symbolTable.getContext() ; - symbolTable.popContext() ; - } ; - } - else { - /***************************************************************** - * This is an ordinary expression. * - *****************************************************************/ - body = generateExpression(heirs[nextTok], cm) ; - }; - nextTok++ ; - break ; - } ; // switch - - /*********************************************************************** - * Complete the ThmOrOpDefNode, if there is one. * - ***********************************************************************/ - if (stepNum != null) { - // SZA: the next line commented, to prevent a NullPointerException - // The method is not executed anyways. - // tadn.construct(true, body, cm, symbolTable, null) ; - } ; - - - /*********************************************************************** - * Restore heirs and nextTok if the statement's tokens were inside a * - * NonExprBody node. * - ***********************************************************************/ - if (hasNonExprBody) { - heirs = savedHeirs ; - nextTok = savedNextTok + 1; - } ; - - /*********************************************************************** - * Set proof to the proof, or to null if there is none. There is no * - * check made to see if this is a kind of step that should have a * - * proof. Thus, adding a proof to something like a WITNESS statement * - * requires changing only the parsing phase (specified by tla+.jj). * - ***********************************************************************/ - ProofNode proof = null ; - if (heirs.length > nextTok) { - if (isAssumeProve && !isSuffices) { - symbolTable.pushContext(assumeContext) ; - } ; - proof = generateProof(heirs[nextTok], cm); - if (isAssumeProve && !isSuffices) { - symbolTable.popContext(); - } ; - } ; - - TheoremNode thm = new TheoremNode(stn, body, cm, proof, tadn); - thm.suffices = isSuffices ; - return thm; - - } // generateNumerableStep - - private final LeafProofNode generateLeafProof(TreeNode stn, ModuleNode cm) - throws AbortException { - TreeNode heirs[] = stn.heirs() ; - LevelNode[] facts ; - SymbolNode[] defs ; - int nextTok = 0 ; - boolean omitted = false ; - - /*********************************************************************** - * Skip over an optional "PROOF" (which can occur in a BY statement). * - ***********************************************************************/ - if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { - nextTok++ ; - } ; - - boolean isOnly = false ; - - if (heirs[nextTok].getKind() == TLAplusParserConstants.BY) { - /********************************************************************* - * For a BY proof, call generate a UseOrHideNode and use its facts * - * and defs field. * - *********************************************************************/ - UseOrHideNode uh = generateUseOrHide(stn, cm) ; - isOnly = uh.isOnly ; - facts = uh.facts; - defs = uh.defs; - /********************************************************************* - * The following check added by LL on 16 Feb 2009. * - *********************************************************************/ - if (facts.length + defs.length == 0) { - errors.addError(stn.getLocation(), "Empty BY"); - }; - } - else{ - facts = new LevelNode[0]; - defs = new SymbolNode[0]; - if (heirs[nextTok].getKind() == TLAplusParserConstants.OMITTED) { - omitted = true ; }; - } ; - return new LeafProofNode(stn, facts, defs, omitted, isOnly) ; - } - - UseOrHideNode - generateUseOrHide(TreeNode stn, ModuleNode cm) throws AbortException { - /*********************************************************************** - * Since a BY statement currently has essentially the same syntax as * - * USE and HIDE, this is also used to parse a BY statement. If given * - * a BY statement, it returns a UseOrHideNode that will be used to * - * form the LeafProofNode (and then thrown away). * - ***********************************************************************/ - int kind = UseKind ; - TreeNode heirs[] = stn.heirs() ; - - boolean isOnly = false; - /********************************************************************* - * True iff this is an "ONLY" step--either a BY ONLY or a USE ONLY. * - * However, we may decide not to include USE ONLY in the language, * - * which wil require a simple modification of the javacc code. * - *********************************************************************/ - - if (heirs[0].getKind() == TLAplusParserConstants.HIDE) - {kind = HideKind; } ; - - int nextTok = 1 ; - - /*********************************************************************** - * Skip over an optional "PROOF" (which can occur in a BY statement). * - ***********************************************************************/ - if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { - nextTok++ ; - } ; - - if (nextTok >= heirs.length) { - errors.addError(stn.getLocation(), "Empty BY, USE, or HIDE"); - return new UseOrHideNode(kind, stn, new LevelNode[0], new SymbolNode[0], isOnly); - } - Vector vec = new Vector() ; - /********************************************************************* - * To hold the facts and then the defs. * - *********************************************************************/ - - if (heirs[nextTok].getKind() == TLAplusParserConstants.ONLY) { - isOnly = true; - nextTok++ ; - } ; - - /*********************************************************************** - * Get the facts. * - ***********************************************************************/ - while ( (nextTok < heirs.length) - && (heirs[nextTok].getKind() != TLAplusParserConstants.DF)) { - if (heirs[nextTok].getKind() == TLAplusParserConstants.MODULE) { - nextTok++ ; - UniqueString moduleId = heirs[nextTok].getUS(); - ModuleNode moduleNode = symbolTable.resolveModule(moduleId); - - /******************************************************************* - * The following added 16 Oct 2007 to allow a fact to be the * - * current module. This will probably mean to use or hide facts * - * introduced so far in the current module. * - *******************************************************************/ - if ((moduleNode == null) && (moduleId == cm.getName())) { - moduleNode = cm ;} ; - if (moduleNode != null) { vec.addElement(moduleNode) ; } - else { - errors.addError( - heirs[nextTok].getLocation(), - "Module `" + moduleId + - "' used without being extended or instantiated."); - } - } // if - else { - /******************************************************************* - * If the this token is an N_GeneralId, then we generate it here * - * using selectorToNode so we can call that method with the isFact * - * argument true. Otherwise, we just call generateExpression. * - *******************************************************************/ - if (heirs[nextTok].getKind() == N_GeneralId) { - /***************************************************************** - * Here, we are using the fact that a theorem name must be a * - * GeneralId and not something like an N_GenInfixOp. * - *****************************************************************/ - vec.addElement( - selectorToNode(genIdToSelector((SyntaxTreeNode) heirs[nextTok]), - 0, true, false, cm)) ; - } - else if (heirs[nextTok].getKind() == N_AssumeProve) { - vec.addElement(generateAssumeProve(heirs[nextTok], cm)) ; - } - else { - vec.addElement(generateExpression(heirs[nextTok], cm)) ; - } // else - } // else - nextTok++ ; - if ( (nextTok < heirs.length) - && (heirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { - nextTok++ ; - }; - } ; // while - LevelNode[] facts = new LevelNode[vec.size()] ; - for (int i = 0 ; i < vec.size() ; i++) { - facts[i] = (LevelNode) vec.elementAt(i) ; - } ; - - /*********************************************************************** - * Get the defs. * - ***********************************************************************/ - SymbolNode[] defs ; - if (nextTok >= heirs.length) { - defs = new SymbolNode[0] ; - } - else { - vec = new Vector() ; - nextTok++ ; - while (nextTok < heirs.length) { - if (heirs[nextTok].getKind() == TLAplusParserConstants.MODULE) { - nextTok++ ; - UniqueString moduleId = heirs[nextTok].getUS(); - ModuleNode moduleNode = symbolTable.resolveModule(moduleId); - - /***************************************************************** - * The following added 16 Oct 2007 to allow a fact to be the * - * current module. This will probably mean to use or hide * - * definitions introduced so far in the current module. * - *****************************************************************/ - if ((moduleNode == null) && (moduleId == cm.getName())) { - moduleNode = cm ;} ; - if (moduleNode != null) { vec.addElement(moduleNode) ; } - else { - errors.addError( - heirs[nextTok].getLocation(), - "Module `" + moduleId + - "' used without being extended or instantiated."); - } - } // if - else { - Selector sel = genIdToSelector((SyntaxTreeNode) heirs[nextTok]) ; - SemanticNode selToNd = selectorToNode(sel, -1, false, true, cm); - if ( (selToNd instanceof OpDefNode) - || ( (selToNd instanceof ThmOrAssumpDefNode) - && // This conjunct added 4 Feb 2015 by LL to forbid step - // names in a DEF clause. - (((ThmOrAssumpDefNode) selToNd).getName().toString().charAt(0) != '<' ) - )) { - SymbolNode def = (SymbolNode) selToNd; - vec.addElement(def) ; - } - else { - /*************************************************************** - * This error is redundant, because it should have been caught * - * in selectorToNode. But a little redundancy can't hurt. * - * But a little redundancy can't hurt. * - ***************************************************************/ - errors.addError( - heirs[nextTok].getLocation(), - "DEF clause entry should describe a defined operator.") ; - } // else - } // else - nextTok++ ; - if ( (nextTok < heirs.length) - && (heirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { - nextTok++ ; - }; - } ; // while - defs = new SymbolNode[vec.size()] ; - for (int i = 0 ; i < vec.size() ; i++) { - defs[i] = (SymbolNode) vec.elementAt(i) ; - } ; - } // else of if (nextTok >= heirs.length) - return new UseOrHideNode(kind, stn, facts, defs, isOnly) ; - } // generateUseOrHide - - void processRecursive(TreeNode tn, ModuleNode cm) { - /*********************************************************************** - * Process a RECURSIVE statement. Creates an OpDefNode for each of * - * the declared operators. * - ***********************************************************************/ - TreeNode[] children = tn.heirs() ; - - /*********************************************************************** - * Increment unresolvedCnt unresolvedSum, and, if necessary, * - * recursiveSectionCount. This needs to be done before the calls to * - * startOpDefNode so that we are in a recursive section when it is * - * called. Note that for * - * * - * RECURSIVE op_1, ... , op_n * - * * - * children is the sequence of tokens * - * * - * "RECURSIVE", op_1, ",", ... , "," , op_n * - * * - * so children.length = 2*n and n = children.length / 2. * - ***********************************************************************/ - if (unresolvedSum == 0) {recursiveSectionCount ++; }; - int numOfDecls = children.length / 2 ; - unresolvedCnt[curLevel] = unresolvedCnt[curLevel] + numOfDecls ; - unresolvedSum = unresolvedSum + numOfDecls; - - for (int i = 1 ; i < children.length; i = i+2) { - /********************************************************************* - * Process the i-th declaration in the RECURSIVE statement. * - *********************************************************************/ - TreeNode declNode = children[i] ; - - /********************************************************************* - * Set odn to an OpDeclNode made from the i-th declaration. * - *********************************************************************/ - OpDeclNode odn = - buildParameter(declNode, - ConstantDeclKind, // Value of argument doesn't matter. - ConstantLevel, // Value of argument doesn't matter. - cm, - false) ; // Not adding OpDeclNode to symbolTable - - /********************************************************************* - * Set params to the array of parameters for the declared operator's * - * OpDefNode. * - *********************************************************************/ - FormalParamNode[] params = new FormalParamNode[odn.getArity()] ; - for (int ip = 0 ; ip < params.length ; ip++) { - params[ip] = new FormalParamNode(null, 0, null, null, cm) ; - } ; - OpDefNode node = startOpDefNode(odn.getName(), - declNode, - UserDefinedOpKind, - params, - false, //localness - cm, - symbolTable); - /****************************************************************** - * This node isn't saved anywhere. It will be found either by * - * looking up the operator when the N_OperatorDefinition node is * - * encountered, or else by looking through the module's * - * recursiveDecls vector when it is discovered that some operator * - * has been declared but not defined (by finding unresolvedCnt > * - * 0 when coming to the end of a LET or of the module). * - ******************************************************************/ - cm.recursiveOpDefNodes.addElement(node) ; - - } // for (int i = 1 ...) - } - - - -/*************************************************************************** -* LABEL HANDLING * -* * -* The following methods are used to create the labels fields of OpDefNode * -* and LabelNode objects. They are specified in terms of an abstract data * -* object LS which is an element of * -* * -* Seq( [labels : SUBSET LabelNode, * -* paramSeq : Seq (SUBSET OpDeclNode)] ) * -* * -* Thus, for all i \in 1..Len(LS) : * -* LS[i].labels is a set of LabelNode objects * -* LS[i].paramSeq is a sequence of sets of OpDeclNode objects. * -* * -* Initially, LS equals the empty sequence << >>. * -* * -* We define * -* Front(LS) == [i \in 1..Len(LS-1) |-> LS[i]] * -* Last(LS) == LS[Len(LS)] * -* * -* LS is a stack containing one element for each OpDefNode and LabelNode * -* within which we are currently processing nodes, where Last(LS) is the * -* inner-most such node. Last(LS).paramSeq is a stack containing one * -* element for each node that comes between the the preceding OpDefNode or * -* LabelNode and the current node that introduces bound variables. * -* Last(LS).paramSeq[j] is the set of bound variables introduced by the * -* j-th such node, where Last(Last(LS).paramSeq) is the most recent such * -* set of bound variables. * -***************************************************************************/ - -/*************************************************************************** -* Code for handling labels was added in the following methods: * -* generateAssumeProve * -* generateLambda * -* processTheorem * -* processAssumption * -* processOperator * -* processFunction * -* processChoose * -* processBoundQuant * -* processUnboundQuant * -* processSubsetOf * -* processSetOfAll * -* processFcnConst * -* generateExpression * -* generateProof * -***************************************************************************/ - - LabelNode generateLabel(TreeNode stn, ModuleNode cm) - throws AbortException { - - boolean isAssumeProve = false ; - /********************************************************************* - * Set true iff this is a labeled ASSUME/PROVE. * - *********************************************************************/ - - if (!inOpDefNode()) { - errors.addError(stn.getLocation(), - "Label not in definition or proof step."); - return nullLabelNode ; - }; - - if (noLabelsAllowed()) { - errors.addError( - stn.getLocation(), - "Label not allowed within scope of declaration in " + - "nested ASSUME/PROVE."); - return nullLabelNode ; - } ; - - /*********************************************************************** - * For now at least, and probably forever, we are not allowing an * - * expression to be labeled if it lies inside an EXCEPT clause--which * - * means if it is used where an "@" could appear. The test for this * - * is taken from generateExpression. * - ***********************************************************************/ - if (!((excStack.empty() || excSpecStack.empty()))) { - errors.addError(stn.getLocation(), - "Labels inside EXCEPT clauses are not yet implemented."); - return nullLabelNode ; - } ; - - TreeNode[] labelExpChildren = stn.heirs() ; - - /*********************************************************************** - * We first process the body, since we need it to create the LabelNode. * - ***********************************************************************/ - pushLS() ; - LevelNode body ; - if (labelExpChildren[2].getKind() == N_AssumeProve) { - body = generateAssumeProve(labelExpChildren[2], cm) ; - isAssumeProve = true ; - } - else { body = generateExpression(labelExpChildren[2], cm) ; } ; - Hashtable ht = popLabelNodeSet() ; - - /*********************************************************************** - * We now create the LabelNode. * - ***********************************************************************/ - UniqueString name ; - FormalParamNode[] params; - /********************************************************************* - * The label's name and parameter list. * - *********************************************************************/ - if (labelExpChildren[0].getKind() == N_GeneralId) { - /********************************************************************* - * There are no arguments to the label. * - *********************************************************************/ - name = labelExpChildren[0].heirs()[1].getUS() ; - params = new FormalParamNode[0] ; - } - else { - /********************************************************************** - * The label should be represented as an N_OpApplication node. * - **********************************************************************/ - if (labelExpChildren[0].getKind() != N_OpApplication) - { throw new WrongInvocationException("Label has unexpected syntax tree kind.") ; }; - - TreeNode[] opApplChildren = labelExpChildren[0].heirs() ; - name = opApplChildren[0].heirs()[1].getUS() ; - TreeNode[] opArgsChildren = opApplChildren[1].heirs() ; - int numOfParams = (opArgsChildren.length - 1) / 2 ; - params = new FormalParamNode[numOfParams] ; - for (int i = 0; i < numOfParams; i++) { - /******************************************************************* - * We have to get the FormalParamNode objects for the parameter * - * array params by looking them up in the current context, since * - * they could be either ConstantLevel (normal case) or StateLevel * - * (if they're introduced in a \AA or \EE expression). * - *******************************************************************/ - TreeNode argSyntaxNode = opArgsChildren[2*i + 1]; - UniqueString argName = argSyntaxNode.heirs()[1].getUS() ; - SymbolNode argNode = symbolTable.resolveSymbol(argName) ; - FormalParamNode arg = null ; - if (argNode instanceof FormalParamNode) - {arg = (FormalParamNode) argNode ;} - else {errors.addError(argSyntaxNode.getLocation(), - "Illegal parameter " + argName.toString() + - " of label `" + name.toString() + "'."); - arg = new FormalParamNode(argName, 0, argSyntaxNode, null, cm); - /********************************************************** - * Create a dummy FormalParamNode to prevent a null * - * pointer exception in later processing. * - **********************************************************/ - }; - params[i] = arg ; - } // for - } ; // else - SemanticNode cg = null ; - if (assumeProveDepth > 0) {cg = currentGoal;} ; - LabelNode retVal = new LabelNode(stn, name, params, currentGoal, - currentGoalClause, body, isAssumeProve) ; - retVal.setLabels(ht) ; - boolean ignore = formalParamsEqual(retVal) ; - /********************************************************************* - * We throw away the return value because if there's an error, it is * - * reported by the method. * - *********************************************************************/ - if (!addLabelNodeToSet(retVal)) { - errors.addError(stn.getLocation(), - "Duplicate label `" + name.toString() + "'."); - } ; - return retVal ; - } // generateLabel - - Vector LSlabels = new Vector() ; - /*********************************************************************** - * LSlabels.elementAt(i) is a HashTable that represents * - * LS.labels[i+1]. The values in the Hashtable are LabelNode objects, * - * where ln.getName() is the key of object ln. The empty set is * - * represented by null. * - ***********************************************************************/ - - Vector LSparamSeq = new Vector() ; - /*********************************************************************** - * LsparamSeq.elementAt(i) is a Vector whose elements are of type * - * FormalParamNode[] that represents LS.paramSeq[i+1]. In particular * - * LS.paramSeq[i+1][j+1] equals * - * LET foo == (FormalParamNode[]) * - * ((Vector) LsparamSeq.elementAt(i))).elementAt(j) * - * IN { (FormalParamNode) foo[j] : j \in 0 .. foo.length} * - ***********************************************************************/ - - void pushLS() { - /*********************************************************************** - * Implements LS' = Append(LS, [labels |-> {}, paramSeq |-> << >>]) * - * That is, it pushes an "empty" record onto the end of LS. * - ***********************************************************************/ - LSlabels.addElement(null) ; - LSparamSeq.addElement(new Vector()) ; - } - - Hashtable popLabelNodeSet() { - /*********************************************************************** - * Implements LS' = Front(LS) * - * return Last(LS).labels * - ***********************************************************************/ - int size = LSlabels.size() ; - if (size == 0) - {throw new WrongInvocationException("popLabelNodeSet called on empty stack.");} ; - Hashtable retVal = (Hashtable) LSlabels.elementAt(size-1) ; - LSlabels.removeElementAt(size-1) ; - LSparamSeq.removeElementAt(size-1) ; - return retVal ; - } - - boolean addLabelNodeToSet(LabelNode ln) { - /*********************************************************************** - * Implements * - * LET succ == \A eln \in Last(LS).labels : eln.name # ln.name * - * IN LS' = IF succ THEN [LS EXCEPT * - * ![Len(LS)].labels = @ \cup {ln}] * - * ELSE Labeling Stack * - * return succ * - * That is, it adds LabelNode ln to Last(LS).labels iff there is not * - * already a LabelNode with the same name in it, otherwise do nothing. * - * It returns true iff ln was added. * - ***********************************************************************/ - int size = LSlabels.size() ; - if (size == 0) - {throw new WrongInvocationException("addLabelNodeToSet called on empty stack.");} ; - Hashtable ht = (Hashtable) LSlabels.elementAt(size-1) ; - if (ht == null) { - ht = new Hashtable() ; - LSlabels.setElementAt(ht, size-1) ; - } - boolean retVal = ! ht.containsKey(ln.getName()) ; - if (retVal) { ht.put(ln.getName(), ln); } ; - return retVal ; - } - - void pushFormalParams(FormalParamNode[] odns) { - /*********************************************************************** - * Implements * - * * - * LS' = IF LS # << >> * - * THEN [LS EXCEPT ![Len(LS)].paramSeq = * - * Append(@, {odns[i] : i \in DOMAIN odns)] * - * ELSE LS * - * * - * That is, if LS is not empty, then it pushes the set of * - * FormalParamNode objects in the array odns onto the end of * - * Last(LS).paramSeq. * - ***********************************************************************/ - if (!inOpDefNode()){return;} ; - Vector lastFormalParams = - (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1) ; - lastFormalParams.addElement(odns) ; - } - - void popFormalParams() { - /*********************************************************************** - * Implements * - * * - * LS' = IF LS # << >> * - * THEN [LS EXCEPT ![Len(LS)].paramSeq = Front(@)] * - * ELSE LS * - * That is, if LS is not empty, then it removes the last item from * - * Last(LS).paramSeq. * - ***********************************************************************/ - if (!inOpDefNode()){return;} ; - Vector lastFormalParams = - (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1) ; - int size = lastFormalParams.size() ; - if (size == 0) - {throw new WrongInvocationException("popFormalParams called on empty stack.");} ; - lastFormalParams.removeElementAt(size - 1); - } - - boolean formalParamsEqual(LabelNode ln) { - /*********************************************************************** - * Returns LET odns == ln.params * - * IN /\ \A i, j \in DOMAIN odns : * - * (i # j) => odns[i] # odns[j] * - * /\ {odns[i] : i \in DOMAINE odns} = * - * UNION {Last(LS).parmSeq[i] : * - * i \in DOMAIN Last(LS).parmSeq} * - * That is, it returns true iff all the FormalParamNode objects in * - * odns are distinct and the set of all thos objects equals the union * - * of all the sets in the sequence Last(LS).paramSeq. * - * * - * If this returns false, then an error message explains why. * - ***********************************************************************/ - boolean retVal = true ; - HashSet opParams = new HashSet() ; - FormalParamNode[] odns = ln.params ; - for (int i = 0; i < odns.length; i++) { - if (!opParams.add(odns[i])) { - retVal = false; - errors.addError(ln.stn.getLocation(), - "Repeated formal parameter " + - odns[i].getName().toString() + " \nin label `" + - ln.getName().toString() + "'.") ; - }; - } // for ; - Vector lastFormalParams = - (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1) ; - int size = lastFormalParams.size() ; - for (int i = 0 ; i < size; i++) { - FormalParamNode[] ops = (FormalParamNode[]) lastFormalParams.elementAt(i); - for (int j = 0 ; j < ops.length ; j++) { - if (! opParams.remove(ops[j])) { - retVal = false; - errors.addError(ln.stn.getLocation(), - "Label " + ln.getName().toString() + - " must contain formal parameter `" + - ops[j].getName().toString() + "'.") ; - }; - } // for j; - } // for i; - if (!opParams.isEmpty()) { - retVal = false ; - Iterator iter = opParams.iterator(); - String res = "Label " + ln.getName().toString() + - " declares extra parameter(s) "; - while (iter.hasNext()){ - FormalParamNode nd = (FormalParamNode) iter.next() ; - res = res + nd.getName().toString() + " "; - } // while - errors.addError(ln.stn.getLocation(), res) ; - } // if - return retVal ; - } - - boolean inOpDefNode() { return LSlabels.size() > 0; } - /*********************************************************************** - * Returns true iff LS is not equal to the empty sequence << >>. * - ***********************************************************************/ - - FormalParamNode[] flattenParams(FormalParamNode[][] array) { - /*********************************************************************** - * Flatten a 2-dimensional array of FormalParamNodes into a * - * 1-dimensional array. Used because the oan.boundedBoundSymbols * - * field for an OpApplNode is such a 2-dimensional array, since * - * "bounded bound symbols" may be tuples. * - ***********************************************************************/ - int size = 0 ; - for (int i = 0 ; i < array.length; i++) { size = size + array[i].length; } ; - FormalParamNode[] res = new FormalParamNode[size] ; - int k = 0 ; - for (int i = 0 ; i < array.length; i++) { - for (int j = 0 ; j < array[i].length; j++) { - res[k] = array[i][j] ; - k++ ; - } ; // for j - } ; // for i - return res ; - } - -/*************************************************************************** -* Recursion Processing * -* * -* This is the code for setting the fields of OpDefNode objects that are * -* related to recursion--namely, letInLevel, inRecursive, * -* inRecursiveSection. See the description of these fields in * -* semantic/OpDefNode.java to see what they mean. * -* * -* A tool might also want to compute the strongly connected components of * -* the dependency graph--the graph of OpDefNode objects containing an edge * -* from n to m iff m's operator appears in the body of n. * -* * -* I originally thought that the dependency graph could be created while * -* the semantic graph was being constructed, and that the strongly * -* connected components could be computed incrementally by running a * -* connected-component algorithm at the end of each recursive section. I * -* thought that could be done easily by creating an OpDefNode for a * -* definition before processing the definition's body, and adding to a * -* field in that OpDefNode a list of the OpDefNodes that appeared in * -* OpApplNodes in the body. However, that didn't work because of * -* definitions like * -* * -* f == LET f == ... * -* IN ... * -* * -* So, I abandoned that idea. It's probably easiest to compute the * -* connected components after the module is processed. * -* * -* If we ever do want to construct those connected components, we can run * -* a version of Tarjan's algorithm for computing strongly connected * -* components of a directed graph. A +cal coding of this algorithm is in * -* the file Tarjan.tla, a copy of which appears as a comment at the end of * -* this file. * -***************************************************************************/ - -/*************************************************************************** -* The fields. * -***************************************************************************/ - final int MaxLetInLevel = 100 ; - /*********************************************************************** - * It seems safe to assume that LETs won't be nested more than 100 * - * deep, so we can use arrays instead of having to deal with vectors * - * to allow arbitrary depths. * - ***********************************************************************/ - - int curLevel = 0 ; - /*********************************************************************** - * The current LET/IN nesting level--that is, the number of LET/IN * - * statements within which the nodes we are currently processing lie. * - ***********************************************************************/ - - int[] unresolvedCnt = new int[MaxLetInLevel] ; - /*********************************************************************** - * For i \in 0..curLevel, the value of unresolvedCnt[i] is the number * - * of operators declared in RECURSIVE statements at let/in level i that * - * have not yet been defined. * - ***********************************************************************/ - - int unresolvedSum = 0; - /*********************************************************************** - * Equals the sum from i = 0 to curLevel of unresolvedCnt[i]. * - ***********************************************************************/ - - int recursiveSectionCount = 0 ; - /*********************************************************************** - * This field is incremented whenever a new recursive section is * - * begun--that is, when unresolvedSum changes from 0 to a positive * - * value (which must be 1). * - ***********************************************************************/ + body = generateAssumeProve(heirs[nextTok], cm); + if (!isSuffices) { + assumeContext = symbolTable.getContext(); + symbolTable.popContext(); + } + ; + } else { + /***************************************************************** + * This is an ordinary expression. * + *****************************************************************/ + body = generateExpression(heirs[nextTok], cm); + } + ; + nextTok++; + break; + } + ; // switch + + /*********************************************************************** + * Complete the ThmOrOpDefNode, if there is one. * + ***********************************************************************/ + if (stepNum != null) { + // SZA: the next line commented, to prevent a NullPointerException + // The method is not executed anyways. + // tadn.construct(true, body, cm, symbolTable, null) ; + } + ; + + /*********************************************************************** + * Restore heirs and nextTok if the statement's tokens were inside a * + * NonExprBody node. * + ***********************************************************************/ + if (hasNonExprBody) { + heirs = savedHeirs; + nextTok = savedNextTok + 1; + } + ; + + /*********************************************************************** + * Set proof to the proof, or to null if there is none. There is no * check made + * to see if this is a kind of step that should have a * proof. Thus, adding a + * proof to something like a WITNESS statement * requires changing only the + * parsing phase (specified by tla+.jj). * + ***********************************************************************/ + ProofNode proof = null; + if (heirs.length > nextTok) { + if (isAssumeProve && !isSuffices) { + symbolTable.pushContext(assumeContext); + } + ; + proof = generateProof(heirs[nextTok], cm); + if (isAssumeProve && !isSuffices) { + symbolTable.popContext(); + } + ; + } + ; + + TheoremNode thm = new TheoremNode(stn, body, cm, proof, tadn); + thm.suffices = isSuffices; + return thm; + + } // generateNumerableStep + + private final LeafProofNode generateLeafProof(TreeNode stn, ModuleNode cm) throws AbortException { + TreeNode heirs[] = stn.heirs(); + LevelNode[] facts; + SymbolNode[] defs; + int nextTok = 0; + boolean omitted = false; + + /*********************************************************************** + * Skip over an optional "PROOF" (which can occur in a BY statement). * + ***********************************************************************/ + if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { + nextTok++; + } + ; + + boolean isOnly = false; + + if (heirs[nextTok].getKind() == TLAplusParserConstants.BY) { + /********************************************************************* + * For a BY proof, call generate a UseOrHideNode and use its facts * and defs + * field. * + *********************************************************************/ + UseOrHideNode uh = generateUseOrHide(stn, cm); + isOnly = uh.isOnly; + facts = uh.facts; + defs = uh.defs; + /********************************************************************* + * The following check added by LL on 16 Feb 2009. * + *********************************************************************/ + if (facts.length + defs.length == 0) { + errors.addError(stn.getLocation(), "Empty BY"); + } + ; + } else { + facts = new LevelNode[0]; + defs = new SymbolNode[0]; + if (heirs[nextTok].getKind() == TLAplusParserConstants.OMITTED) { + omitted = true; + } + ; + } + ; + return new LeafProofNode(stn, facts, defs, omitted, isOnly); + } + + UseOrHideNode generateUseOrHide(TreeNode stn, ModuleNode cm) throws AbortException { + /*********************************************************************** + * Since a BY statement currently has essentially the same syntax as * USE and + * HIDE, this is also used to parse a BY statement. If given * a BY statement, + * it returns a UseOrHideNode that will be used to * form the LeafProofNode (and + * then thrown away). * + ***********************************************************************/ + int kind = UseKind; + TreeNode heirs[] = stn.heirs(); + + boolean isOnly = false; + /********************************************************************* + * True iff this is an "ONLY" step--either a BY ONLY or a USE ONLY. * However, + * we may decide not to include USE ONLY in the language, * which wil require a + * simple modification of the javacc code. * + *********************************************************************/ + + if (heirs[0].getKind() == TLAplusParserConstants.HIDE) { + kind = HideKind; + } + ; + + int nextTok = 1; + + /*********************************************************************** + * Skip over an optional "PROOF" (which can occur in a BY statement). * + ***********************************************************************/ + if (heirs[0].getKind() == TLAplusParserConstants.PROOF) { + nextTok++; + } + ; + + if (nextTok >= heirs.length) { + errors.addError(stn.getLocation(), "Empty BY, USE, or HIDE"); + return new UseOrHideNode(kind, stn, new LevelNode[0], new SymbolNode[0], isOnly); + } + Vector vec = new Vector(); + /********************************************************************* + * To hold the facts and then the defs. * + *********************************************************************/ + + if (heirs[nextTok].getKind() == TLAplusParserConstants.ONLY) { + isOnly = true; + nextTok++; + } + ; + + /*********************************************************************** + * Get the facts. * + ***********************************************************************/ + while ((nextTok < heirs.length) && (heirs[nextTok].getKind() != TLAplusParserConstants.DF)) { + if (heirs[nextTok].getKind() == TLAplusParserConstants.MODULE) { + nextTok++; + UniqueString moduleId = heirs[nextTok].getUS(); + ModuleNode moduleNode = symbolTable.resolveModule(moduleId); + + /******************************************************************* + * The following added 16 Oct 2007 to allow a fact to be the * current module. + * This will probably mean to use or hide facts * introduced so far in the + * current module. * + *******************************************************************/ + if ((moduleNode == null) && (moduleId == cm.getName())) { + moduleNode = cm; + } + ; + if (moduleNode != null) { + vec.addElement(moduleNode); + } else { + errors.addError(heirs[nextTok].getLocation(), + "Module `" + moduleId + "' used without being extended or instantiated."); + } + } // if + else { + /******************************************************************* + * If the this token is an N_GeneralId, then we generate it here * using + * selectorToNode so we can call that method with the isFact * argument true. + * Otherwise, we just call generateExpression. * + *******************************************************************/ + if (heirs[nextTok].getKind() == N_GeneralId) { + /***************************************************************** + * Here, we are using the fact that a theorem name must be a * GeneralId and not + * something like an N_GenInfixOp. * + *****************************************************************/ + vec.addElement( + selectorToNode(genIdToSelector((SyntaxTreeNode) heirs[nextTok]), 0, true, false, cm)); + } else if (heirs[nextTok].getKind() == N_AssumeProve) { + vec.addElement(generateAssumeProve(heirs[nextTok], cm)); + } else { + vec.addElement(generateExpression(heirs[nextTok], cm)); + } // else + } // else + nextTok++; + if ((nextTok < heirs.length) && (heirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { + nextTok++; + } + ; + } + ; // while + LevelNode[] facts = new LevelNode[vec.size()]; + for (int i = 0; i < vec.size(); i++) { + facts[i] = (LevelNode) vec.elementAt(i); + } + ; + + /*********************************************************************** + * Get the defs. * + ***********************************************************************/ + SymbolNode[] defs; + if (nextTok >= heirs.length) { + defs = new SymbolNode[0]; + } else { + vec = new Vector(); + nextTok++; + while (nextTok < heirs.length) { + if (heirs[nextTok].getKind() == TLAplusParserConstants.MODULE) { + nextTok++; + UniqueString moduleId = heirs[nextTok].getUS(); + ModuleNode moduleNode = symbolTable.resolveModule(moduleId); + + /***************************************************************** + * The following added 16 Oct 2007 to allow a fact to be the * current module. + * This will probably mean to use or hide * definitions introduced so far in the + * current module. * + *****************************************************************/ + if ((moduleNode == null) && (moduleId == cm.getName())) { + moduleNode = cm; + } + ; + if (moduleNode != null) { + vec.addElement(moduleNode); + } else { + errors.addError(heirs[nextTok].getLocation(), + "Module `" + moduleId + "' used without being extended or instantiated."); + } + } // if + else { + Selector sel = genIdToSelector((SyntaxTreeNode) heirs[nextTok]); + SemanticNode selToNd = selectorToNode(sel, -1, false, true, cm); + if ((selToNd instanceof OpDefNode) || ((selToNd instanceof ThmOrAssumpDefNode) && // This conjunct + // added 4 Feb + // 2015 by LL to + // forbid step + // names in a + // DEF clause. + (((ThmOrAssumpDefNode) selToNd).getName().toString().charAt(0) != '<'))) { + SymbolNode def = (SymbolNode) selToNd; + vec.addElement(def); + } else { + /*************************************************************** + * This error is redundant, because it should have been caught * in + * selectorToNode. But a little redundancy can't hurt. * But a little redundancy + * can't hurt. * + ***************************************************************/ + errors.addError(heirs[nextTok].getLocation(), + "DEF clause entry should describe a defined operator."); + } // else + } // else + nextTok++; + if ((nextTok < heirs.length) && (heirs[nextTok].getKind() == TLAplusParserConstants.COMMA)) { + nextTok++; + } + ; + } + ; // while + defs = new SymbolNode[vec.size()]; + for (int i = 0; i < vec.size(); i++) { + defs[i] = (SymbolNode) vec.elementAt(i); + } + ; + } // else of if (nextTok >= heirs.length) + return new UseOrHideNode(kind, stn, facts, defs, isOnly); + } // generateUseOrHide + + void processRecursive(TreeNode tn, ModuleNode cm) { + /*********************************************************************** + * Process a RECURSIVE statement. Creates an OpDefNode for each of * the + * declared operators. * + ***********************************************************************/ + TreeNode[] children = tn.heirs(); + + /*********************************************************************** + * Increment unresolvedCnt unresolvedSum, and, if necessary, * + * recursiveSectionCount. This needs to be done before the calls to * + * startOpDefNode so that we are in a recursive section when it is * called. + * Note that for * * RECURSIVE op_1, ... , op_n * * children is the sequence of + * tokens * * "RECURSIVE", op_1, ",", ... , "," , op_n * * so children.length = + * 2*n and n = children.length / 2. * + ***********************************************************************/ + if (unresolvedSum == 0) { + recursiveSectionCount++; + } + ; + int numOfDecls = children.length / 2; + unresolvedCnt[curLevel] = unresolvedCnt[curLevel] + numOfDecls; + unresolvedSum = unresolvedSum + numOfDecls; + + for (int i = 1; i < children.length; i = i + 2) { + /********************************************************************* + * Process the i-th declaration in the RECURSIVE statement. * + *********************************************************************/ + TreeNode declNode = children[i]; + + /********************************************************************* + * Set odn to an OpDeclNode made from the i-th declaration. * + *********************************************************************/ + OpDeclNode odn = buildParameter(declNode, ConstantDeclKind, // Value of argument doesn't matter. + ConstantLevel, // Value of argument doesn't matter. + cm, false); // Not adding OpDeclNode to symbolTable + + /********************************************************************* + * Set params to the array of parameters for the declared operator's * + * OpDefNode. * + *********************************************************************/ + FormalParamNode[] params = new FormalParamNode[odn.getArity()]; + for (int ip = 0; ip < params.length; ip++) { + params[ip] = new FormalParamNode(null, 0, null, null, cm); + } + ; + OpDefNode node = startOpDefNode(odn.getName(), declNode, UserDefinedOpKind, params, false, // localness + cm, symbolTable); + /****************************************************************** + * This node isn't saved anywhere. It will be found either by * looking up the + * operator when the N_OperatorDefinition node is * encountered, or else by + * looking through the module's * recursiveDecls vector when it is discovered + * that some operator * has been declared but not defined (by finding + * unresolvedCnt > * 0 when coming to the end of a LET or of the module). * + ******************************************************************/ + cm.recursiveOpDefNodes.addElement(node); + + } // for (int i = 1 ...) + } + + /*************************************************************************** + * LABEL HANDLING * * The following methods are used to create the labels fields + * of OpDefNode * and LabelNode objects. They are specified in terms of an + * abstract data * object LS which is an element of * * Seq( [labels : SUBSET + * LabelNode, * paramSeq : Seq (SUBSET OpDeclNode)] ) * * Thus, for all i \in + * 1..Len(LS) : * LS[i].labels is a set of LabelNode objects * LS[i].paramSeq is + * a sequence of sets of OpDeclNode objects. * * Initially, LS equals the empty + * sequence << >>. * * We define * Front(LS) == [i \in 1..Len(LS-1) |-> LS[i]] * + * Last(LS) == LS[Len(LS)] * * LS is a stack containing one element for each + * OpDefNode and LabelNode * within which we are currently processing nodes, + * where Last(LS) is the * inner-most such node. Last(LS).paramSeq is a stack + * containing one * element for each node that comes between the the preceding + * OpDefNode or * LabelNode and the current node that introduces bound + * variables. * Last(LS).paramSeq[j] is the set of bound variables introduced by + * the * j-th such node, where Last(Last(LS).paramSeq) is the most recent such * + * set of bound variables. * + ***************************************************************************/ + + /*************************************************************************** + * Code for handling labels was added in the following methods: * + * generateAssumeProve * generateLambda * processTheorem * processAssumption * + * processOperator * processFunction * processChoose * processBoundQuant * + * processUnboundQuant * processSubsetOf * processSetOfAll * processFcnConst * + * generateExpression * generateProof * + ***************************************************************************/ + + LabelNode generateLabel(TreeNode stn, ModuleNode cm) throws AbortException { + + boolean isAssumeProve = false; + /********************************************************************* + * Set true iff this is a labeled ASSUME/PROVE. * + *********************************************************************/ + + if (!inOpDefNode()) { + errors.addError(stn.getLocation(), "Label not in definition or proof step."); + return nullLabelNode; + } + ; + + if (noLabelsAllowed()) { + errors.addError(stn.getLocation(), + "Label not allowed within scope of declaration in " + "nested ASSUME/PROVE."); + return nullLabelNode; + } + ; + + /*********************************************************************** + * For now at least, and probably forever, we are not allowing an * expression + * to be labeled if it lies inside an EXCEPT clause--which * means if it is used + * where an "@" could appear. The test for this * is taken from + * generateExpression. * + ***********************************************************************/ + if (!((excStack.empty() || excSpecStack.empty()))) { + errors.addError(stn.getLocation(), "Labels inside EXCEPT clauses are not yet implemented."); + return nullLabelNode; + } + ; + + TreeNode[] labelExpChildren = stn.heirs(); + + /*********************************************************************** + * We first process the body, since we need it to create the LabelNode. * + ***********************************************************************/ + pushLS(); + LevelNode body; + if (labelExpChildren[2].getKind() == N_AssumeProve) { + body = generateAssumeProve(labelExpChildren[2], cm); + isAssumeProve = true; + } else { + body = generateExpression(labelExpChildren[2], cm); + } + ; + Hashtable ht = popLabelNodeSet(); + + /*********************************************************************** + * We now create the LabelNode. * + ***********************************************************************/ + UniqueString name; + FormalParamNode[] params; + /********************************************************************* + * The label's name and parameter list. * + *********************************************************************/ + if (labelExpChildren[0].getKind() == N_GeneralId) { + /********************************************************************* + * There are no arguments to the label. * + *********************************************************************/ + name = labelExpChildren[0].heirs()[1].getUS(); + params = new FormalParamNode[0]; + } else { + /********************************************************************** + * The label should be represented as an N_OpApplication node. * + **********************************************************************/ + if (labelExpChildren[0].getKind() != N_OpApplication) { + throw new WrongInvocationException("Label has unexpected syntax tree kind."); + } + ; + + TreeNode[] opApplChildren = labelExpChildren[0].heirs(); + name = opApplChildren[0].heirs()[1].getUS(); + TreeNode[] opArgsChildren = opApplChildren[1].heirs(); + int numOfParams = (opArgsChildren.length - 1) / 2; + params = new FormalParamNode[numOfParams]; + for (int i = 0; i < numOfParams; i++) { + /******************************************************************* + * We have to get the FormalParamNode objects for the parameter * array params + * by looking them up in the current context, since * they could be either + * ConstantLevel (normal case) or StateLevel * (if they're introduced in a \AA + * or \EE expression). * + *******************************************************************/ + TreeNode argSyntaxNode = opArgsChildren[2 * i + 1]; + UniqueString argName = argSyntaxNode.heirs()[1].getUS(); + SymbolNode argNode = symbolTable.resolveSymbol(argName); + FormalParamNode arg = null; + if (argNode instanceof FormalParamNode) { + arg = (FormalParamNode) argNode; + } else { + errors.addError(argSyntaxNode.getLocation(), + "Illegal parameter " + argName.toString() + " of label `" + name.toString() + "'."); + arg = new FormalParamNode(argName, 0, argSyntaxNode, null, cm); + /********************************************************** + * Create a dummy FormalParamNode to prevent a null * pointer exception in later + * processing. * + **********************************************************/ + } + ; + params[i] = arg; + } // for + } + ; // else + SemanticNode cg = null; + if (assumeProveDepth > 0) { + cg = currentGoal; + } + ; + LabelNode retVal = new LabelNode(stn, name, params, currentGoal, currentGoalClause, body, isAssumeProve); + retVal.setLabels(ht); + boolean ignore = formalParamsEqual(retVal); + /********************************************************************* + * We throw away the return value because if there's an error, it is * reported + * by the method. * + *********************************************************************/ + if (!addLabelNodeToSet(retVal)) { + errors.addError(stn.getLocation(), "Duplicate label `" + name.toString() + "'."); + } + ; + return retVal; + } // generateLabel + + Vector LSlabels = new Vector(); + /*********************************************************************** + * LSlabels.elementAt(i) is a HashTable that represents * LS.labels[i+1]. The + * values in the Hashtable are LabelNode objects, * where ln.getName() is the + * key of object ln. The empty set is * represented by null. * + ***********************************************************************/ + + Vector LSparamSeq = new Vector(); + + /*********************************************************************** + * LsparamSeq.elementAt(i) is a Vector whose elements are of type * + * FormalParamNode[] that represents LS.paramSeq[i+1]. In particular * + * LS.paramSeq[i+1][j+1] equals * LET foo == (FormalParamNode[]) * ((Vector) + * LsparamSeq.elementAt(i))).elementAt(j) * IN { (FormalParamNode) foo[j] : j + * \in 0 .. foo.length} * + ***********************************************************************/ + + void pushLS() { + /*********************************************************************** + * Implements LS' = Append(LS, [labels |-> {}, paramSeq |-> << >>]) * That is, + * it pushes an "empty" record onto the end of LS. * + ***********************************************************************/ + LSlabels.addElement(null); + LSparamSeq.addElement(new Vector()); + } + + Hashtable popLabelNodeSet() { + /*********************************************************************** + * Implements LS' = Front(LS) * return Last(LS).labels * + ***********************************************************************/ + int size = LSlabels.size(); + if (size == 0) { + throw new WrongInvocationException("popLabelNodeSet called on empty stack."); + } + ; + Hashtable retVal = (Hashtable) LSlabels.elementAt(size - 1); + LSlabels.removeElementAt(size - 1); + LSparamSeq.removeElementAt(size - 1); + return retVal; + } + + boolean addLabelNodeToSet(LabelNode ln) { + /*********************************************************************** + * Implements * LET succ == \A eln \in Last(LS).labels : eln.name # ln.name * IN + * LS' = IF succ THEN [LS EXCEPT * ![Len(LS)].labels = @ \cup {ln}] * ELSE + * Labeling Stack * return succ * That is, it adds LabelNode ln to + * Last(LS).labels iff there is not * already a LabelNode with the same name in + * it, otherwise do nothing. * It returns true iff ln was added. * + ***********************************************************************/ + int size = LSlabels.size(); + if (size == 0) { + throw new WrongInvocationException("addLabelNodeToSet called on empty stack."); + } + ; + Hashtable ht = (Hashtable) LSlabels.elementAt(size - 1); + if (ht == null) { + ht = new Hashtable(); + LSlabels.setElementAt(ht, size - 1); + } + boolean retVal = !ht.containsKey(ln.getName()); + if (retVal) { + ht.put(ln.getName(), ln); + } + ; + return retVal; + } + + void pushFormalParams(FormalParamNode[] odns) { + /*********************************************************************** + * Implements * * LS' = IF LS # << >> * THEN [LS EXCEPT ![Len(LS)].paramSeq = * + * Append(@, {odns[i] : i \in DOMAIN odns)] * ELSE LS * * That is, if LS is not + * empty, then it pushes the set of * FormalParamNode objects in the array odns + * onto the end of * Last(LS).paramSeq. * + ***********************************************************************/ + if (!inOpDefNode()) { + return; + } + ; + Vector lastFormalParams = (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1); + lastFormalParams.addElement(odns); + } + + void popFormalParams() { + /*********************************************************************** + * Implements * * LS' = IF LS # << >> * THEN [LS EXCEPT ![Len(LS)].paramSeq = + * Front(@)] * ELSE LS * That is, if LS is not empty, then it removes the last + * item from * Last(LS).paramSeq. * + ***********************************************************************/ + if (!inOpDefNode()) { + return; + } + ; + Vector lastFormalParams = (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1); + int size = lastFormalParams.size(); + if (size == 0) { + throw new WrongInvocationException("popFormalParams called on empty stack."); + } + ; + lastFormalParams.removeElementAt(size - 1); + } + + boolean formalParamsEqual(LabelNode ln) { + /*********************************************************************** + * Returns LET odns == ln.params * IN /\ \A i, j \in DOMAIN odns : * (i # j) => + * odns[i] # odns[j] * /\ {odns[i] : i \in DOMAINE odns} = * UNION + * {Last(LS).parmSeq[i] : * i \in DOMAIN Last(LS).parmSeq} * That is, it returns + * true iff all the FormalParamNode objects in * odns are distinct and the set + * of all thos objects equals the union * of all the sets in the sequence + * Last(LS).paramSeq. * * If this returns false, then an error message explains + * why. * + ***********************************************************************/ + boolean retVal = true; + HashSet opParams = new HashSet(); + FormalParamNode[] odns = ln.params; + for (int i = 0; i < odns.length; i++) { + if (!opParams.add(odns[i])) { + retVal = false; + errors.addError(ln.stn.getLocation(), "Repeated formal parameter " + odns[i].getName().toString() + + " \nin label `" + ln.getName().toString() + "'."); + } + ; + } // for ; + Vector lastFormalParams = (Vector) LSparamSeq.elementAt(LSparamSeq.size() - 1); + int size = lastFormalParams.size(); + for (int i = 0; i < size; i++) { + FormalParamNode[] ops = (FormalParamNode[]) lastFormalParams.elementAt(i); + for (int j = 0; j < ops.length; j++) { + if (!opParams.remove(ops[j])) { + retVal = false; + errors.addError(ln.stn.getLocation(), "Label " + ln.getName().toString() + + " must contain formal parameter `" + ops[j].getName().toString() + "'."); + } + ; + } // for j; + } // for i; + if (!opParams.isEmpty()) { + retVal = false; + Iterator iter = opParams.iterator(); + String res = "Label " + ln.getName().toString() + " declares extra parameter(s) "; + while (iter.hasNext()) { + FormalParamNode nd = (FormalParamNode) iter.next(); + res = res + nd.getName().toString() + " "; + } // while + errors.addError(ln.stn.getLocation(), res); + } // if + return retVal; + } + + boolean inOpDefNode() { + return LSlabels.size() > 0; + } + + /*********************************************************************** + * Returns true iff LS is not equal to the empty sequence << >>. * + ***********************************************************************/ + + FormalParamNode[] flattenParams(FormalParamNode[][] array) { + /*********************************************************************** + * Flatten a 2-dimensional array of FormalParamNodes into a * 1-dimensional + * array. Used because the oan.boundedBoundSymbols * field for an OpApplNode is + * such a 2-dimensional array, since * "bounded bound symbols" may be tuples. * + ***********************************************************************/ + int size = 0; + for (int i = 0; i < array.length; i++) { + size = size + array[i].length; + } + ; + FormalParamNode[] res = new FormalParamNode[size]; + int k = 0; + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array[i].length; j++) { + res[k] = array[i][j]; + k++; + } + ; // for j + } + ; // for i + return res; + } + + /*************************************************************************** + * Recursion Processing * * This is the code for setting the fields of OpDefNode + * objects that are * related to recursion--namely, letInLevel, inRecursive, * + * inRecursiveSection. See the description of these fields in * + * semantic/OpDefNode.java to see what they mean. * * A tool might also want to + * compute the strongly connected components of * the dependency graph--the + * graph of OpDefNode objects containing an edge * from n to m iff m's operator + * appears in the body of n. * * I originally thought that the dependency graph + * could be created while * the semantic graph was being constructed, and that + * the strongly * connected components could be computed incrementally by + * running a * connected-component algorithm at the end of each recursive + * section. I * thought that could be done easily by creating an OpDefNode for a + * * definition before processing the definition's body, and adding to a * field + * in that OpDefNode a list of the OpDefNodes that appeared in * OpApplNodes in + * the body. However, that didn't work because of * definitions like * * f == + * LET f == ... * IN ... * * So, I abandoned that idea. It's probably easiest to + * compute the * connected components after the module is processed. * * If we + * ever do want to construct those connected components, we can run * a version + * of Tarjan's algorithm for computing strongly connected * components of a + * directed graph. A +cal coding of this algorithm is in * the file Tarjan.tla, + * a copy of which appears as a comment at the end of * this file. * + ***************************************************************************/ + + /*************************************************************************** + * The fields. * + ***************************************************************************/ + final int MaxLetInLevel = 100; + /*********************************************************************** + * It seems safe to assume that LETs won't be nested more than 100 * deep, so we + * can use arrays instead of having to deal with vectors * to allow arbitrary + * depths. * + ***********************************************************************/ + + int curLevel = 0; + /*********************************************************************** + * The current LET/IN nesting level--that is, the number of LET/IN * statements + * within which the nodes we are currently processing lie. * + ***********************************************************************/ + + int[] unresolvedCnt = new int[MaxLetInLevel]; + /*********************************************************************** + * For i \in 0..curLevel, the value of unresolvedCnt[i] is the number * of + * operators declared in RECURSIVE statements at let/in level i that * have not + * yet been defined. * + ***********************************************************************/ + + int unresolvedSum = 0; + /*********************************************************************** + * Equals the sum from i = 0 to curLevel of unresolvedCnt[i]. * + ***********************************************************************/ + + int recursiveSectionCount = 0; + /*********************************************************************** + * This field is incremented whenever a new recursive section is * begun--that + * is, when unresolvedSum changes from 0 to a positive * value (which must be + * 1). * + ***********************************************************************/ // Code to construct dependence graph removed by LL on 7 Apr 2007 // OpDefNode[] defStack = new OpDefNode[MaxLetInLevel] ; @@ -7458,59 +7023,51 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; // * Perhaps some other use will be found for it, in which case it * // * should be put into the module's ModuleNode object. * // ***********************************************************************/ - - int max_dfs = 0; - /*********************************************************************** - * A variable used in the Tarjan algorithm. * - ***********************************************************************/ - - Vector nstack = new Vector(10) ; - /*********************************************************************** - * A vector of OpDefNode objects, representing the stack of the Tarjan * - * algorithm. * - ***********************************************************************/ - - int moduleNestingLevel = -1 ; - /*********************************************************************** - * When processing a module, this is its nesting level--that is, its * - * depth in the tree of inner modules of the outermost module. * - ***********************************************************************/ -/*************************************************************************** -* Methods. * -***************************************************************************/ - OpDefNode startOpDefNode(UniqueString us, - TreeNode tn, - int kind, - FormalParamNode[] params, - boolean localness, - ModuleNode oModNode, - SymbolTable st - ) { - /*********************************************************************** - * Called to create an OpDefNode for a RECURSIVE declaration. The * - * params argument should be an array of dummy FormalParamNode * - * objects, with null names. The OpDefNode's setParams method should * - * be used to add the actual formal parameter's to the object. * - * * - * Note: for an operator declared in a RECURSIVE statement, this * - * method is called when processing that statement with the Treenode * - * tn equal to the syntax tree node for the declaration. * - ***********************************************************************/ - OpDefNode odn = new OpDefNode(us, UserDefinedOpKind, params, localness, - null, // the expression - oModNode, st, tn, false, null) ; + int max_dfs = 0; + /*********************************************************************** + * A variable used in the Tarjan algorithm. * + ***********************************************************************/ + + Vector nstack = new Vector(10); + /*********************************************************************** + * A vector of OpDefNode objects, representing the stack of the Tarjan * + * algorithm. * + ***********************************************************************/ + + int moduleNestingLevel = -1; + + /*********************************************************************** + * When processing a module, this is its nesting level--that is, its * depth in + * the tree of inner modules of the outermost module. * + ***********************************************************************/ + + /*************************************************************************** + * Methods. * + ***************************************************************************/ + OpDefNode startOpDefNode(UniqueString us, TreeNode tn, int kind, FormalParamNode[] params, boolean localness, + ModuleNode oModNode, SymbolTable st) { + /*********************************************************************** + * Called to create an OpDefNode for a RECURSIVE declaration. The * params + * argument should be an array of dummy FormalParamNode * objects, with null + * names. The OpDefNode's setParams method should * be used to add the actual + * formal parameter's to the object. * * Note: for an operator declared in a + * RECURSIVE statement, this * method is called when processing that statement + * with the Treenode * tn equal to the syntax tree node for the declaration. * + ***********************************************************************/ + OpDefNode odn = new OpDefNode(us, UserDefinedOpKind, params, localness, null, // the expression + oModNode, st, tn, false, null); // was incrementing it twice // unresolvedCnt[curLevel] ++ ; // unresolvedSum = unresolvedSum ++ ; - oModNode.recursiveDecls.addElement(odn) ; + oModNode.recursiveDecls.addElement(odn); - odn.letInLevel = curLevel ; - odn.inRecursive = true ; - odn.inRecursiveSection = true ; - odn.recursiveSection = recursiveSectionCount; - oModNode.opDefsInRecursiveSection.addElement(odn) ; + odn.letInLevel = curLevel; + odn.inRecursive = true; + odn.inRecursiveSection = true; + odn.recursiveSection = recursiveSectionCount; + oModNode.opDefsInRecursiveSection.addElement(odn); // the participating and nbrs field have been removed from OpDefNode objects // odn.participating = true ; @@ -7521,29 +7078,25 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; // defStack[defStackLen] = odn ; // defStackLen ++ ; // } ; - return odn; - } - - void endOpDefNode(OpDefNode nd, - ExprNode exp, - TreeNode stn) { - /*********************************************************************** - * Called to complete the creation of an OpDefNode nd that was created * - * by an invocation of startOpDefNode. If we are processing recursive * - * definitions, then it modifies unresolvedCnt and unresolvedSum if * - * necessary. * - * * - * When called for an operator not declared in a RECURSIVE statement, * - * the TreeNode stn is the same one that startOpDefNode was called * - * with to create the OpDefNode. * - ***********************************************************************/ - nd.isDefined = true ; - - /*********************************************************************** - * Set the node's body and syntax-tree node. * - ***********************************************************************/ - nd.setBody(exp) ; - nd.stn = stn ; + return odn; + } + + void endOpDefNode(OpDefNode nd, ExprNode exp, TreeNode stn) { + /*********************************************************************** + * Called to complete the creation of an OpDefNode nd that was created * by an + * invocation of startOpDefNode. If we are processing recursive * definitions, + * then it modifies unresolvedCnt and unresolvedSum if * necessary. * * When + * called for an operator not declared in a RECURSIVE statement, * the TreeNode + * stn is the same one that startOpDefNode was called * with to create the + * OpDefNode. * + ***********************************************************************/ + nd.isDefined = true; + + /*********************************************************************** + * Set the node's body and syntax-tree node. * + ***********************************************************************/ + nd.setBody(exp); + nd.stn = stn; // Code to construct dependence graph removed by LL on 7 Apr 2007 // if (unresolvedSum > 0) { @@ -7553,9 +7106,9 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; // defStackLen -- ; // } ; - if (nd.inRecursive) { - unresolvedCnt[curLevel] -- ; - unresolvedSum -- ; + if (nd.inRecursive) { + unresolvedCnt[curLevel]--; + unresolvedSum--; // Code to construct dependence graph removed by LL on 7 Apr 2007 // if (unresolvedSum == 0) { // tarjan() ; @@ -7564,12 +7117,13 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; // } ; // for // participants = new Vector(100) ; // } // if (unresolvedSum == 0) - if (unresolvedSum < 0) { - throw new WrongInvocationException("Defined more recursive operators than were declared " + - "in RECURSIVE statements.") ; - }; - } // if (nd.inRecursive) - } + if (unresolvedSum < 0) { + throw new WrongInvocationException( + "Defined more recursive operators than were declared " + "in RECURSIVE statements."); + } + ; + } // if (nd.inRecursive) + } // Code to construct dependence graph removed by LL on 7 Apr 2007 // void registerSymbolNode(SymbolNode nd) { @@ -7610,72 +7164,64 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; // return nd ; // } // findSymbol - - void setOpDefNodeRecursionFields(OpDefNode odn, ModuleNode cm) { - /*********************************************************************** - * Called to set the field odn.letInLevel and the fields * - * odn.recursiveSection and odn.inRecursiveSection if they need * - * non-default values, and to add odn to cm.opDefsInRecursiveSection * - * if necessary. * - ***********************************************************************/ - odn.letInLevel = curLevel ; - if (unresolvedSum > 0) { - odn.recursiveSection = recursiveSectionCount; - odn.inRecursiveSection = (unresolvedCnt[curLevel] > 0) ; - cm.opDefsInRecursiveSection.addElement(odn) ; - } - - } - - void checkIfInRecursiveSection(TreeNode tn, String type) { - /*********************************************************************** - * Report an error if we are in a recursive section--between an * - * operator's declaration in a RECURSIVE statement and its definition. * - ***********************************************************************/ - if (unresolvedSum > 0) { - errors.addError(tn.getLocation(), - type + " may not appear within " + - "a recursive definition section." - ) ; - } - } - - void checkForUndefinedRecursiveOps(ModuleNode cm) { - /*********************************************************************** - * Called at the end of a LET clause and at the end of processing a * - * module to check for operators that were declared in a RECURSIVE * - * statement but not defined. It calls errors.addError to report any * - * that it finds. * - ***********************************************************************/ - /*********************************************************************** - * The number of operators declared in RECURSIVE statements within the * - * LET but not defined equals unresolvedCnt[curLevel]. * - ***********************************************************************/ - if (unresolvedCnt[curLevel] > 0) { - /********************************************************************* - * Go through the module's recursiveDecls vector to find all symbols * - * declared at the current LET/IN level but not defined. * - *********************************************************************/ - for (int i = 0 ; i < cm.recursiveDecls.size() ; i++) { - OpDefNode odn = (OpDefNode) cm.recursiveDecls.elementAt(i) ; - if ( (odn.letInLevel == curLevel) - && odn.inRecursive - && (! odn.isDefined)) { - errors.addError(odn.getTreeNode().getLocation(), - "Symbol " + odn.getName().toString() + - " declared in RECURSIVE statement but not defined." - ) ; - } ; - }; // for - - unresolvedSum = unresolvedSum - unresolvedCnt[curLevel] ; - /******************************************************************* - * Need to update unresolvedSum correct because we are effectively * - * setting unresolvedCnt[curLevel] to 0. * - *******************************************************************/ - }; // if (unresolvedCnt[curLevel] > 0) - } - + void setOpDefNodeRecursionFields(OpDefNode odn, ModuleNode cm) { + /*********************************************************************** + * Called to set the field odn.letInLevel and the fields * odn.recursiveSection + * and odn.inRecursiveSection if they need * non-default values, and to add odn + * to cm.opDefsInRecursiveSection * if necessary. * + ***********************************************************************/ + odn.letInLevel = curLevel; + if (unresolvedSum > 0) { + odn.recursiveSection = recursiveSectionCount; + odn.inRecursiveSection = (unresolvedCnt[curLevel] > 0); + cm.opDefsInRecursiveSection.addElement(odn); + } + + } + + void checkIfInRecursiveSection(TreeNode tn, String type) { + /*********************************************************************** + * Report an error if we are in a recursive section--between an * operator's + * declaration in a RECURSIVE statement and its definition. * + ***********************************************************************/ + if (unresolvedSum > 0) { + errors.addError(tn.getLocation(), type + " may not appear within " + "a recursive definition section."); + } + } + + void checkForUndefinedRecursiveOps(ModuleNode cm) { + /*********************************************************************** + * Called at the end of a LET clause and at the end of processing a * module to + * check for operators that were declared in a RECURSIVE * statement but not + * defined. It calls errors.addError to report any * that it finds. * + ***********************************************************************/ + /*********************************************************************** + * The number of operators declared in RECURSIVE statements within the * LET but + * not defined equals unresolvedCnt[curLevel]. * + ***********************************************************************/ + if (unresolvedCnt[curLevel] > 0) { + /********************************************************************* + * Go through the module's recursiveDecls vector to find all symbols * declared + * at the current LET/IN level but not defined. * + *********************************************************************/ + for (int i = 0; i < cm.recursiveDecls.size(); i++) { + OpDefNode odn = (OpDefNode) cm.recursiveDecls.elementAt(i); + if ((odn.letInLevel == curLevel) && odn.inRecursive && (!odn.isDefined)) { + errors.addError(odn.getTreeNode().getLocation(), + "Symbol " + odn.getName().toString() + " declared in RECURSIVE statement but not defined."); + } + ; + } + ; // for + + unresolvedSum = unresolvedSum - unresolvedCnt[curLevel]; + /******************************************************************* + * Need to update unresolvedSum correct because we are effectively * setting + * unresolvedCnt[curLevel] to 0. * + *******************************************************************/ + } + ; // if (unresolvedCnt[curLevel] > 0) + } // void tarjan() { // /*********************************************************************** @@ -7687,4489 +7233,2300 @@ errors.addAbort(stn.getLocation(), "Uses generateNumerable_Step") ; //***************************************************************************/ // } -} - -/************************ file Tarjan.tla *********************************** ------------------------------- MODULE Tarjan -------------------------------- -(***************************************************************************) -(* This version of Tarjan's algorithm for computing the strongly *) -(* connected components of a directed graph was adapted from the version *) -(* of 27 Mar 2007 on the Wikipedia page *) -(* *) -(* http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm *) -(* *) -(* One modification is that the set of connected components it returns *) -(* does not contain a singleton {n} unless n has an edge pointing to *) -(* itself. *) -(* *) -(* This is an implementation of the algorithm in Tarjan.tla with data *) -(* structures that correspond to the ones used in the algorithm for *) -(* constructing dependency components in semantic/Generator. *) -(* *) -(* *) -(* I have not rigorously verified this algorithm, but I think I understand *) -(* why it works. I have tested it only on the 10 graphs at the end of *) -(* this file. *) -(***************************************************************************) - -EXTENDS Integers, Sequences, TLC - -CONSTANT N, \* The number of nodes - Neighbors \* A sequence of edges. - -Node == 1..N - -ASSUME Neighbors \in Seq(Node \X Node) - -Min(a, b) == IF a < b THEN a ELSE b - -Front(s) == [i \in 1 .. (Len(s)-1) |-> s[i]] - (*************************************************************************) - (* The sequence obtained from a sequence s by deleting the last item. *) - (*************************************************************************) - -Last(s) == s[Len(s)] - (*************************************************************************) - (* The last item in the sequence s. *) - (*************************************************************************) - -(***************************************************************************) -(* I believe the algorithm works because it maintains the following *) -(* invariants (at reasonable points in the code). We say that node *) -(* nstack[i] precedes nstack[j] iff i < j. *) -(* *) -(* - A node n is in nstack iff n.dfs \geq 0 *) -(* *) -(* - For all nodes n # m in nstack, if n precedes m then: *) -(* /\ n.dfs < m.dfs. *) -(* /\ there is a path from n to m in the graph. *) -(* *) -(* - For every node n in nstack, *) -(* /\ n.lowlink \leq n.dfs and *) -(* /\ there is a node m in nstack such that *) -(* 1. n.lowlink = m.dfs. *) -(* 2. if m # n then there is a path from n to m in the graph. *) -(* /\ For every node m in the same connected component as n: *) -(* m.examined = TRUE implies m is in nstack *) -(***************************************************************************) - -(************************* ---algorithm Tarjan2 -variables nstack = << >> ; - (***************************************************************) - (* The stack of nodes, where nstack[1] is the bottom of the *) - (* stack. *) - (***************************************************************) - max_dfs = 0 ; - (***************************************************************) - (* Incremented by 1 every time a new element is added to the *) - (* stack. *) - (***************************************************************) - - data = [nd \in Node |-> [lowlink |-> -1, - dfs |-> -1, - examined |-> FALSE, - nbrs |-> << >>, - (*****************************************) - (* A sequence of nodes to which there *) - (* are edges from this node. The *) - (* same node may appear multiple *) - (* times. *) - (*****************************************) - nxtDep |-> -1 ]] ; - (***************************************************************) - (* The information maintained for the nodes. Note that *) - (* *) - (* - Node nd is on nstack iff data[nd].dfs \geq 0, in *) - (* which case nstack[data[nd].dfs + 1] = nd. *) - (* *) - (* - nbrs is set from Neighbors by the initialization code. *) - (* *) - (* - nxtDep represents the nextDependency field of the *) - (* OpDefNode object, where a value of -1 represents *) - (* null. Following nxtDep pointers leads in a cycle of *) - (* the node's connected component. See the comments on *) - (* the nextDependency field in semantic/OpDefNode. *) - (***************************************************************) - - idx ; \* A counter variable. - -procedure tarjan(n) - variable nxt ; \* A counter variable - nxtnbr ; \* An abbreviation - - begin - data[n].lowlink := max_dfs || - data[n].dfs := max_dfs || - data[n].examined := TRUE ; - max_dfs := max_dfs + 1; - nstack := Append(nstack, n) ; - nxt := 1 ; - while nxt \leq Len(data[n].nbrs) do - nxtnbr := data[n].nbrs[nxt] ; - if ~ data[nxtnbr].examined - then (***************************************************************) - (* nxtnbr is unexamined *) - (***************************************************************) - call tarjan(nxtnbr) ; - data[n].lowlink := Min(data[n].lowlink, data[nxtnbr].lowlink) ; - - elsif data[nxtnbr].dfs \geq 0 - then (**********************************************************) - (* nxtnbr is in nstack *) - (**********************************************************) - data[n].lowlink := Min(data[n].lowlink, data[nxtnbr].dfs) ; - end if ; - nxt := nxt + 1; - end while ; - if data[n].lowlink = data[n].dfs - then (*****************************************************************) - (* The set of all nodes on nstack from n to the end form a *) - (* connected component. *) - (*****************************************************************) - nxtnbr := Last(nstack) ; \* save last node on stack. - while n # Last(nstack) do - data[Last(nstack)].nxtDep := nstack[Len(nstack)-1] || - data[Last(nstack)].dfs := -1 ; - (*************************************************************) - (* Make nxtDep field of last node on stack point to next to *) - (* last node. *) - (*************************************************************) - nstack := Front(nstack) ; - end while ; - if \/ n # nxtnbr - \/ \E i \in 1..Len(data[n].nbrs) : n = data[n].nbrs[i] - then (**********************************************************) - (* Form a connected component consisting of just n only *) - (* if n is a neighbor of itself. *) - (**********************************************************) - data[n].nxtDep := nxtnbr; - end if; - data[n].dfs := -1 ; - nstack := Front(nstack) ; - end if ; - data[n].nbrs := << >> ; - (**********************************************************************) - (* Can garbage collect the sequence of neighbors. *) - (**********************************************************************) - return ; -end procedure - -begin - (************************************************************************) - (* Initialize the nbrs field of data elements from Neighbors. *) - (************************************************************************) - idx := 1 ; - while idx \leq Len(Neighbors) do - with edge = Neighbors[idx] do - data[edge[1]].nbrs := Append(data[edge[1]].nbrs, edge[2]) ; - end with ; - idx := idx + 1; - end while ; - - (************************************************************************) - (* while there is an unexamined node, call tarjan(nd) *) - (* for any unexamined node nd. *) - (************************************************************************) - idx := 1 ; - while idx \leq N do - if data[idx].lowlink < 0 - then (***************************************************************) - (* idx is unexamined *) - (***************************************************************) - call tarjan(idx) ; - end if; - idx := idx + 1 ; - end while ; - - (************************************************************************) - (* print result. *) - (************************************************************************) - idx := 1 ; - while idx \leq N do - if data[idx].nxtDep \geq 0 - then print <<idx, "->", data[idx].nxtDep>> - end if ; - idx := idx+1; - end while -end algorithm -***********************) - -\* BEGIN TRANSLATION -\* END TRANSLATION - -\**** Test data - -Node1 == {1, 2, 3, 4} - -Nbrs1 == << <<1, 2>>, \* components 1 and 3,4 - <<1, 2>>, \* components 1 and 3,4 - <<1, 1>>, - <<1, 1>>, - <<3, 4>> , - <<3, 4>> , - <<4, 3>> , - <<4, 3>>, - <<4, 3>> - >> - -Nbrs2 == << <<1, 2>>, \* components 1 and 3,4 - <<1, 1>>, - <<1, 3>>, - <<3, 4>>, - <<4, 3>> - >> -Nbrs3 == << <<1, 2>>, \* components 1 and 3,4 - <<1, 1>>, - <<3, 1>>, - <<3, 4>>, - <<4, 3>> - >> -Nbrs4 == << <<1, 3>>, \* - <<1, 8>>, \* componetns: 2,3,4,5 and 7,8,9 - <<1, 9>>, - <<1, 9>>, - <<1, 9>>, - <<3, 2>>, - <<3, 2>>, - <<2, 4>>, - <<4, 5>>, - <<4, 10>>, - <<5, 3>>, - <<8, 7>>, - <<8, 7>>, - <<9, 8>>, - <<7, 9>>, - <<7, 9>>, - <<9, 10>>, - <<9, 10>>, - <<9, 10>> - >> - -Nbrs5 == << <<1, 8>>, \* components 7,8,9 - <<1, 9>>, - <<4, 10>>, - <<8, 7>>, - <<9, 8>>, - <<7, 9>>, - <<9, 10>> - >> - -Nbrs6 == << <<6, 4>>, \* components 2,3,4,5 - <<3, 4>>, - <<4, 5>>, - <<5, 2>>, - <<2, 3>>, - <<5, 1>>, - <<2, 1>> - >> - -Nbrs7 == << <<1, 7>>, \* 1 component with 1..9 \ {3} - <<1, 9>>, - <<2, 1>>, - <<3, 2>>, - <<3, 6>>, - <<4, 6>>, - <<5, 2>>, - <<6, 5>>, - <<6, 8>>, - <<7, 5>>, - <<7, 8>>, - <<8, 4>>, - <<8, 10>>, - <<9, 7>>, - <<9, 10>> - >> -Nbrs8 == << <<1, 7>>, \* 1 component with 1..8 \ {3} - <<2, 1>>, - <<3, 2>>, - <<3, 2>>, - <<3, 2>>, - <<3, 6>>, - <<4, 6>>, - <<5, 2>>, - <<6, 5>>, - <<6, 8>>, - <<6, 8>>, - <<6, 8>>, - <<7, 5>>, - <<7, 8>>, - <<8, 4>>, - <<8, 10>>, - <<9, 7>>, - <<9, 10>> - >> -Nbrs9 == << \* 4,6, 7,8,9,10 - <<2, 1>>, - <<3, 2>>, - <<3, 6>>, - <<4, 6>>, - <<4, 6>>, - <<4, 6>>, - <<5, 2>>, - <<6, 5>>, - <<6, 8>>, - <<7, 5>>, - <<7, 5>>, - <<7, 5>>, - <<7, 5>>, - <<7, 8>>, - <<8, 4>>, - <<8, 10>>, - <<9, 7>>, - <<10, 9>> - >> -Nbrs == << \* 1, 3, 4, 5 and 6 - <<1, 4>>, - <<2, 1>>, - <<2, 3>>, - <<2, 3>>, - <<2, 3>>, - <<2, 5>>, - <<3, 4>>, - <<4, 1>>, - <<4, 5>>, - <<4, 5>>, - <<4, 5>>, - <<5, 3>>, - <<6, 5>>, - <<6, 6>> - >> - -============================================================================= - -************************** end file Tarjan.tla ******************************/ - -/************************* file Subexpression.tla ********************** -last modified on Fri 13 November 2009 at 14:11:05 PST by lamport ------------------------- MODULE Subexpression --------------------------- - - -(***************************************************************************) -(* NAMING *) -(* *) -(* There are four kinds of Nameable Objects: *) -(* - Expressions *) -(* - Operators that take an argument *) -(* (and that can appear as operator arguments) *) -(* - Operator definitions (named in BY/USE/HIDE statements) *) -(* - ASSUME/PROVEs. *) -(* *) -(* There are three relevant kinds of primitive names that appear in a *) -(* TLA+ module. *) -(* *) -(* Defined Module Name (ModuleName): *) -(* It appears to the left of "== INSTANCE...". It may or may not *) -(* contain arguments. *) -(* Primitive Operator Name (PrimOpName): *) -(* It appear to the left of the "==" in a definition, theorem *) -(* or assumption. It may or may not contain arguments. *) -(* Label: *) -(* It appears before a "::" in an expression. *) -(* *) -(* Examples of possible primitive names are "Foo" and "Bar(x+1, 42)". *) -(* *) -(* The Built-In Operator names (like "SUBSET") will not be considered to *) -(* be primitive names in the following. *) -(* *) -(* To these explicit names we add the following Operand Selector (OpSel) *) -(* names: *) -(* - numbers, *) -(* - "<<", ">>", *) -(* - Things of the form (exp_1, ... , exp_n) where the exp_i are *) -(* expressions or operator arguments and n > 0. *) -(* - "@", *) -(* *) -(* A Compound Name is a sequence of primitive names, operand selectors, *) -(* and ":"s separated by "!"s. *) -(* *) -(* In TLA+1, the general way of naming a non-built-in operator is with *) -(* what I will call an Elementary Operator Name (ElemOpName) which has *) -(* the following syntax. For simplicity, I will ignore the "!"s in the *) -(* `formal' syntax. *) -(* *) -(* ElemOpName ::= (ModuleName)* PrimOpName *) -(* *) -(* We consider this to name both the operator and its definition (the *) -(* expression to the right of the "=="). How the two meanings are *) -(* disambiguated will be explained below. *) -(* *) -(* If EON is an ElemOpName and Lab_1, ... , Lab_n are a sequence of *) -(* label names, then EON ! Lab_1 ! ... ! Lab_N names the expression *) -(* labeled by Lab_N, where each Lab_(i+1) must be the name of a labeled *) -(* expression within the expression labeled by Lab_i with no labels *) -(* between Lab_i and Lab_(i+1). Thus a name described by *) -(* *) -(* ElemOpName (Label)* *) -(* *) -(* describes an operator definition or a labeled expression. To such a *) -(* name, we can append a sequence of OperandSelectors. By rules *) -(* described later, the resulting name selects a subexpression (or *) -(* ASSUME/PROVE node) or Operator (appearing as an operator argument) *) -(* from the body of the operator definition or labeled expression. If *) -(* the labeled expression is a LET/IN, then to this name can be appended *) -(* an ElemOpName defined in the LET part, and the naming process can then *) -(* be iterated. The full syntax of a General Name is: *) -(* *) -(* OperatorName ::= ElemOpName *) -(* | ElemOpName (Label)* ((OpSel)+ | ":") ElemOpName *) -(* *) -(* GeneralName ::= OperatorName (":" | (Label)* (OpSeq)* ) *) -(* *) -(* Note that ":" is used in two ways: *) -(* *) -(* - An OperatorName not followed by ":" names the operator; one *) -(* followed by ":" names the operator's definition. *) -(* - Suppose a general name GN ending in a label names a LET/IN *) -(* expression and EON is an ElemOpName. Then GN !: !EON names *) -(* an operator defined in the LET. The general name GN ! Foo would *) -(* name an expression labeled by Foo inside the IN clause. *) -(***************************************************************************) - - -(***************************************************************************) -(* This +cal program describes an algorithm used in generating the *) -(* semantic tree for a parse tree consisting of a GeneralId node or an *) -(* OpApplication node whose first child is a GeneralId node. Two examples *) -(* are *) -(* *) -(* Foo(x)!Bar!<<!(a,b)!G *) -(* Foo(x)!Bar!<<!(a,b)!G(c) *) -(* *) -(* We assume that these are processed to yield two sequences of nodes: *) -(* op and args. The sequences for the first are *) -(* *) -(* op = << "Foo", "Bar", "<<", "null", "G" >> *) -(* args = << <<x>>, << >>, << >>, <<a, b>>, <<>> >> *) -(* *) -(* and for the second are *) -(* *) -(* op = << "Foo", "Bar", "<<", "null", "G" >> *) -(* args = << <<x>>, << >>, << >>, <<a, b>>, <<c>> >> *) -(* *) -(* where each symbol in args represents the semantic node produced by that *) -(* symbol. *) -(* *) -(* The other input to the algortithm is an integer expectedArity. There *) -(* are three cases: *) -(* *) -(* expectedArity = 0 : *) -(* The parser is expecting an expression. This is the case *) -(* when the expression occurs in the first part of a USE *) -(* or HIDE statement. *) -(* *) -(* expectedArity > 0 : The parser is expecting an operator *) -(* argument of this arity. *) -(* *) -(* expectedArity = -1 : *) -(* The parser is expecting the name of a definition. This is *) -(* the case when the expression occurs in the DEF clause of a USE *) -(* or HIDE or BY statement. *) -(* *) -(* If expectedArity # 0, then args equals a sequence each of whose *) -(* element is the empty sequence. *) -(***************************************************************************) - -(***************************************************************************) -(* Note: This spec is assuming that proof-step numbers are treated like *) -(* operator names. That is, a step *) -(* *) -(* <3>2. foo > bar *) -(* *) -(* will be represented by a ThmOrAssumpDefKind node just as if it were *) -(* *) -(* THEOREM <3>2 == foo > bar *) -(* *) -(* If this is not the case, then additional code needs to be added to deal *) -(* with numbered steps. But however it is handled, the "<3>2" will be a *) -(* name in the current symbol table. *) -(***************************************************************************) - -EXTENDS Integers, Sequences, TLC - -(***************************************************************************) -(* SeqSeqToSeq(ss) is defined to be the concatenation of the sequences *) -(* that are the elements of the sequence ss. *) -(***************************************************************************) -RECURSIVE SeqSeqToSeq(_) -SeqSeqToSeq(ss) == IF ss = << >> - THEN << >> - ELSE Head(ss) \o SeqSeqToSeq(Tail(ss)) - -(***************************************************************************) -(* These are kinds of semantic nodes that can be encountered by the *) -(* algorithm. See tlasany/sematic/ASTConstants.java. *) -(***************************************************************************) -ConstantDeclKind == "ConstantDecl" -VariableDeclKind == "VariableDecl" -BoundSymbolKind == "BoundSymbol" -UserDefinedOpKind == "UserDefinedOp" -ModuleInstanceKind == "ModuleInstance" -BuiltInKind == "BuiltIn" -OpArgKind == "OpArg" -OpApplKind == "OpAppl" -LetInKind == "LetIn" -FormalParamKind == "FormalParam" -TheoremKind == "Theorem" -SubstInKind == "SubstIn" -AssumeProveKind == "AssumeProve" -ProofKind == "Proof" -NumeralKind == "Numeral" -DecimalKind == "Decimal" -StringKind == "String" -AtNodeKind == "AtNode" -AssumeKind == "Assume" -InstanceKind == "Instance" -ThmOrAssumpDefKind == "ThmOrAssumpDef" -LabelKind == "Label" -APSubstInKind == "APSubstIn" - -CONSTANT - NodeId, \* The set of all node identifiers. - Node, \* A mapping from NodeId to nodes (which are records). - GlobalContext, \* The initial context. - null, \* A special value not equal to anything else. - debug \* Setting to TRUE causes TLC to print a trace if the - \* algorithm reports an error. - -(***************************************************************************) -(* CONTEXTS *) -(* *) -(* A context is a mapping from names to NodeIds. There are actually three *) -(* different kinds of mappings from names to nodes in the implementation *) -(* that are all represented here as contexts: *) -(* - The symbolTable of the Generator. *) -(* - The context field of a LetInNode *) -(* - The labels field of a LabelNode *) -(***************************************************************************) -IsContext(C) == - (*************************************************************************) - (* True iff C is a context. *) - (*************************************************************************) - /\ DOMAIN C \subseteq STRING - /\ \A str \in DOMAIN C : C[str] \in NodeId - -LookUp(nm, ctxt) == - (*************************************************************************) - (* The value assigned to name nm by context cxt, or null if there is no *) - (* value assigned. *) - (*************************************************************************) - IF nm \in DOMAIN ctxt THEN Node[ctxt[nm]] ELSE null - -Param == [name : STRING, arity : Nat] - (*************************************************************************) - (* The set of parameters, which can appear in operator definitions. *) - (*************************************************************************) - -(***************************************************************************) -(* For simplicity, we assume that argument numbers range from 1 to 9, and *) -(* we define the following mappings from to and from argument numbers to *) -(* their string representations. *) -(***************************************************************************) -NumberOp == {"1", "2", "3", "4", "5", "6", "7", "8", "9"} -NumericVal(numOp) == CASE numOp = "1" -> 1 - [] numOp = "2" -> 2 - [] numOp = "3" -> 3 - [] numOp = "4" -> 4 - [] numOp = "5" -> 5 - [] numOp = "6" -> 6 - [] numOp = "7" -> 7 - [] numOp = "8" -> 8 - [] numOp = "9" -> 9 - -NumToString(num) == CASE num = 1 -> "1" - [] num = 2 -> "2" - [] num = 3 -> "3" - [] num = 4 -> "4" - [] num = 5 -> "5" - [] num = 6 -> "6" - [] num = 7 -> "7" - [] num = 8 -> "8" - [] num = 9 -> "9" - -IsName(op) == - (*************************************************************************) - (* A name is something other than an argument selector that can appear *) - (* in a compound name. *) - (*************************************************************************) - op \in STRING \ ({"<<", ">>", "@", ":", "null"} \cup NumberOp) - - -ArgNum(op, arity) == - (*************************************************************************) - (* The argument number chosen by argument selector op for an operator *) - (* application with arity arguments. It equals -1 if op is not a legal *) - (* argument selector for this arity. *) - (*************************************************************************) - CASE op \in NumberOp -> - IF NumericVal(op) <= arity THEN NumericVal(op) ELSE -1 - [] op = "<<" -> IF arity > 0 THEN 1 ELSE -1 - [] op = ">>" -> CASE arity = 1 -> 1 - [] arity = 2 -> 2 - [] OTHER -> -1 - [] OTHER -> -1 - -Arity(node) == - (*************************************************************************) - (* The arity of a node--that is, the number of arguments it takes. *) - (*************************************************************************) - IF node.kind \in {UserDefinedOpKind, BuiltInKind, ModuleInstanceKind, - ThmOrAssumpDefKind, OpArgKind, LabelKind, - ConstantDeclKind, FormalParamKind} - THEN node.arity - ELSE 0 - -ParamArity(node, i) == - (*************************************************************************) - (* The arity of the i-th parameter of the node of kind *) - (* UserDefinedOpKind, ThmOrAssumpDefKind, ModuleInstanceKind, *) - (* ConstantDeclKind, or FormalParamKind *) - (*************************************************************************) - IF node.kind \in {ConstantDeclKind, FormalParamKind} - THEN 0 - ELSE node.params[i].arity ------------------------------------------------------------------------------ - -(***************************************************************************) -(* The following assumptions define the data types--in particular, the *) -(* record components that each node type must contain. *) -(***************************************************************************) -ASSUME IsContext(GlobalContext) - -ASSUME DOMAIN Node = NodeId - -ASSUME -/\ \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind \in - {ConstantDeclKind, VariableDeclKind, BoundSymbolKind, - UserDefinedOpKind, ModuleInstanceKind, BuiltInKind, - OpArgKind, OpApplKind, LetInKind, FormalParamKind, - TheoremKind, SubstInKind, AssumeProveKind, ProofKind, - NumeralKind, DecimalKind, StringKind, AtNodeKind, - AssumeKind, InstanceKind, ThmOrAssumpDefKind, LabelKind, - APSubstInKind} - -ASSUME -/\ \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind \in {UserDefinedOpKind, BuiltInKind, ModuleInstanceKind, - ThmOrAssumpDefKind, LabelKind, ConstantDeclKind, - FormalParamKind} - => /\ node.name \in STRING - /\ node.arity \in Nat \cup {-1} - /\ (node.arity = -1) => (node.kind = BuiltInKind) - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - node.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind} => - /\ node.body \in NodeId - /\ IsContext(node.labels) - /\ node.params \in Seq(Param) - /\ Len(node.params) = node.arity - /\ node.defined \in BOOLEAN - /\ node.source \in {null} \cup NodeId - \* The original definition (before instantiation) - \* or null if this is it. - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = OpApplKind => - /\ node.operands \in Seq(NodeId) - /\ node.operator \in NodeId - /\ node.unboundedBoundSymbols \in Seq(STRING) - /\ node.boundedBoundSymbols \in Seq(Seq(STRING)) - (**************************************************************) - (* These are actually arrays and arrays of arrays of *) - (* FormalParamNode objects (formerly OpDeclNode objects). *) - (**************************************************************) - /\ node.ranges \in Seq(NodeId) - /\ Len(node.ranges) = Len(node.boundedBoundSymbols) - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = LetInKind => - /\ node.body \in NodeId - /\ IsContext(node.context) - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = OpArgKind => - /\ node.op \in NodeId - /\ IsName(node.name) - /\ (node.arity \in Nat) /\ (node.arity > 0) - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = LabelKind => - /\ node.body \in NodeId - /\ IsContext(node.labels) - /\ node.params \in Seq(Param) - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = SubstInKind => - /\ node.body \in NodeId - /\ node.subst \in STRING \* Just to identify it. - -ASSUME - \A id \in NodeId : - LET node == Node[id] IN - /\ node.kind = AssumeProveKind => - /\ node.assumes\in Seq(NodeId) - /\ node.prove \in NodeId - - -RECURSIVE ExpandNode(_) -ExpandNode(node) == - CASE node.kind \in {UserDefinedOpKind, LetInKind} -> - [node EXCEPT !.body = ExpandNode(Node[@])] - [] node.kind = OpApplKind -> - [node EXCEPT - !.operands = [i \in DOMAIN @ |-> ExpandNode(Node[@[i]])], - !.operator = ExpandNode(Node[@]), - !.ranges = [i \in DOMAIN @ |-> ExpandNode(Node[@[i]])]] - [] OTHER -> node - - ------------------------------------------------------------------------------ -(***************************************************************************) -(* Test Data *) -(* *) -(* The algorithm has been tested on the following sets of data, where each *) -(* operator MCxxx is either substituted for constant parameter xxx or is *) -(* used as initial value of the algorithm's input variable xxx. *) -(***************************************************************************) - - -(***************************** - - -(***************************************************************************) -(* ------------------------ MODULE M ------------------------ *) -(* CONSTANT C *) -(* Op(Arg(_), p) == \A x \in {1,2}, <<y, z>> \in {3} : *) -(* lab(x,y,z) :: LET a + b == <<Arg(a), b>> *) -(* IN 1 + label2 :: p + C *) -(* Foo(u) == "FooBody(u)" *) -(* ============================================================= *) -(* *) -(* Inst(d) == INSTANCE M WITH C <- "expr(d)" *) -(***************************************************************************) - -\* MCNode == -\* 1 :> [kind |-> UserDefinedOpKind, \* Op(Arg(_), p) == ... -\* name |-> "Op", -\* body |-> 3, -\* labels |-> "lab" :> 4, -\* arity |-> 2, -\* params |-> <<[name |-> "Arg", arity |-> 1], -\* [name |-> "p", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 2 :> [kind |-> BuiltInKind, -\* name |-> "$BoundedForall", -\* arity |-> -1 -\* ] -\* @@ -\* 3 :> [kind |-> OpApplKind, \* \A x \in {1,2}, <<y, z>> \in {3} : ... -\* operands |-> << 4 >>, -\* operator |-> 2, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << <<"x">>, <<"y", "z">> >>, -\* ranges |-> << 19, 21 >>] -\* @@ -\* 4 :> [kind |-> LabelKind, \* lab(x,y,z) :: LET a + b == <<Arg(a), b>> -\* name |-> "lab", \* IN 1 + label2 :: p + C -\* body |-> 5, -\* arity |-> 3, -\* params |-> <<[name |-> "x", arity |->0], -\* [name |-> "y", arity |->0], -\* [name |-> "z", arity |->0] >>, -\* labels |-> "label2" :> 15 ] -\* @@ -\* 5 :> [kind |-> LetInKind, \* LET a + b == <<Arg(a), b>> -\* context |-> "+" :> 6, \* IN 1 + label2 :: p + C -\* body |-> 13 ] -\* @@ -\* 6 :> [kind |-> UserDefinedOpKind, \* a + b == <<Arg(a), b>> -\* name |-> "+", -\* body |-> 7, -\* labels |-> << >>, -\* arity |-> 2, -\* params |-> <<[name |-> "a", arity |-> 0], -\* [name |-> "b", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 7 :> [kind |-> OpApplKind, \* <<Arg(a), b>> -\* operands |-> << 9, 12 >>, -\* operator |-> 8, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 8 :> [kind |-> BuiltInKind, -\* name |-> "$Tuple", -\* arity |-> -1 -\* ] -\* @@ -\* 9 :> [kind |-> OpApplKind, \* Arg(a) -\* operands |-> <<11 >>, -\* operator |-> 10, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 10 :> [kind |-> FormalParamKind, -\* name |-> "Arg", -\* arity |-> 1] -\* -\* @@ -\* 11 :> [kind |-> FormalParamKind, -\* name |-> "a", -\* arity |-> 0] -\* @@ -\* 12 :> [kind |-> FormalParamKind, -\* name |-> "b", -\* arity |-> 0] -\* @@ -\* 13 :> [kind |-> OpApplKind, \* 1 + label2 :: p + C -\* operands |-> <<14, 15>>, -\* operator |-> 6, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 14 :> [kind |-> NumeralKind, -\* val |-> 1] -\* @@ -\* 15 :> [kind |-> LabelKind, \* label2 :: p + C -\* name |-> "label2", -\* body |-> 16, -\* arity |-> 0, -\* params |-> <<>>, -\* labels |-> << >>] -\* @@ -\* 16 :> [kind |-> OpApplKind, \* p + C -\* operands |-> <<17, 18>>, -\* operator |-> 6, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 17 :> [kind |-> FormalParamKind, -\* name |-> "p", -\* arity |-> 0] -\* @@ -\* 18 :> [kind |-> ConstantDeclKind, -\* name |-> "C", -\* arity |-> 0 ] -\* @@ -\* 19 :> [kind |-> OpApplKind, \* {1,2} -\* operands |-> << 14, 20 >>, -\* operator |-> 8, \* Actually, specifying <<1, 2>> -\* unboundedBoundSymbols |-> << >>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 20 :> [kind |-> NumeralKind, -\* val |-> 2] -\* @@ -\* 21 :> [kind |-> OpApplKind, \* {1,2} -\* operands |-> << 22>>, -\* operator |-> 8, \* Actually, specifying <<1, 2>> -\* unboundedBoundSymbols |-> << >>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 22 :> [kind |-> NumeralKind, -\* val |-> 3] -\* @@ -\* 23 :> [kind |-> UserDefinedOpKind, \* Foo(u) == "FooBody(u)" -\* name |-> "Foo", -\* body |-> 24, -\* labels |-> << >>, -\* arity |-> 1, -\* params |-> <<[name |-> "u", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 24 :> [kind |-> StringKind, -\* val |-> "FooBody(u)"] -\* @@ -\* 25 :> [kind |-> StringKind, -\* val |-> "string"] -\* @@ -\* 26 :> [kind |-> ModuleInstanceKind, \* Inst(d) == INSTANCE M WITH C <- "expr(d)" -\* name |-> "Inst", -\* arity |-> 1, -\* params |-> <<[name |-> "d", arity |-> 0] >>, -\* defined |-> TRUE ] -\* @@ -\* 27 :> [kind |-> SubstInKind, -\* body |-> 24, -\* subst |-> "expr(d)"] -\* @@ -\* 28 :> [kind |-> UserDefinedOpKind, \* Foo(u) == "FooBody(u)" -\* name |-> "Inst!Foo", -\* body |-> 27, -\* labels |-> << >>, -\* arity |-> 2, -\* params |-> << [name |-> "d", arity |-> 0], -\* [name |-> "u", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> 23 ] -\* @@ -\* 29 :> [kind |-> UserDefinedOpKind, \* Op(Arg(_), p) == ... -\* name |-> "Inst!Op", -\* body |-> 30, -\* labels |-> "lab" :> 4, -\* arity |-> 3, -\* params |-> <<[name |-> "d", arity |-> 0], -\* [name |-> "Arg", arity |-> 1], -\* [name |-> "p", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> 1 ] -\* @@ -\* 30 :> [kind |-> SubstInKind, -\* body |-> 3, -\* subst |-> "expr(d)"] -\* @@ -\* 31 :> [kind |-> StringKind, -\* val |-> "Argm"] -\* -\* MCNodeId == 1..31 -\* -\* MCGlobalContext == -\* "Op" :> 1 -\* @@ -\* "Foo" :> 23 -\* @@ -\* "Inst" :> 26 -\* @@ -\* "Inst!Foo" :> 28 -\* @@ -\* "Inst!Op" :> 29 -\* -\* \* Foo("string") -\* \* MCops == <<"Foo">> -\* \* MCargs == << <<25>>>> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string") -\* \* MCops == <<"Op">> -\* \* MCargs == << <<23, 25>> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3) -\* \* MCops == <<"Op", "lab">> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22 >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!<< -\* \* MCops == <<"Op", "lab", "<<">> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!<<!>> -\* \* MCops == <<"Op", "lab", "<<", ">>">> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!label2 -\* \* MCops == <<"Op", "lab", "label2">> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!label2!<< -\* \* MCops == <<"Op", "lab", "label2", "<<">> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!:!+(3,2) -\* \* MCops == <<"Op", "lab", ":", "+" >> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!lab(1,2,3)!:!+(3,2)!>> -\* \* MCops == <<"Op", "lab", ":", "+", ">>" >> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!(1,2,3) -\* \* MCops == <<"Op", "null" >> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!(1,2,3)!>>!>>!<< -\* \* MCops == <<"Op", "null", ">>", ">>", "<<" >> -\* \* MCargs == << <<23, 25>> , <<14, 20, 22>>, << >>, << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Op(Foo, "string")!<<!>> -\* \* MCops == <<"Op", "<<", ">>" >> -\* \* MCargs == << <<23, 25>>, << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Foo("string") -\* \* MCops == <<"Inst", "Foo">> -\* \* MCargs == << <<31>>, <<25>>>> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string") -\* \* MCops == <<"Inst", "Op">> -\* \* MCargs == << <<31>>, <<23, 25>> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3) -\* \* MCops == <<"Inst", "Op", "lab">> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22 >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!<< -\* \* MCops == <<"Inst", "Op", "lab", "<<">> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!<<!>> -\* \* MCops == <<"Inst", "Op", "lab", "<<", ">>">> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!label2 -\* \* MCops == <<"Inst", "Op", "lab", "label2">> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!label2!<< -\* \* MCops == <<"Inst", "Op", "lab", "label2", "<<">> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!:!+(3,2) -\* \* MCops == <<"Inst", "Op", "lab", ":", "+" >> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!:!+(3,2)!>> -\* \* MCops == <<"Inst", "Op", "lab", ":", "+", ">>" >> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!(1,2,3) -\* \* MCops == <<"Inst", "Op", "null" >> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!(1,2,3)!>>!>>!<< -\* \* MCops == <<"Inst", "Op", "null", ">>", ">>", "<<" >> -\* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>>, << >>, << >>, << >> >> -\* \* MCexpectedArity == 0 -\* -\* \* Inst("Argm")!Op(Foo, "string")!<<!>> -\* \* MCops == <<"Inst", "Op", "<<", ">>" >> -\* \* MCargs == << <<31>>, <<23, 25>>, << >>, << >> >> -\* \* MCexpectedArity == 0 - -*****************************************) - -(***************************************************************************) -(* ------------------------ MODULE M ------------------------ *) -(* CONSTANT C, Arg1(_) *) -(* Op(Arg, p) == \A x \in {1,2}, <<y, z>> \in {3} : *) -(* lab(x,y,z) :: LET a + b == <<Arg1(a), b>> *) -(* IN 1 + label2 :: p + C *) -(* Bar(AOp(_)) == AOp(1) *) -(* Foo(u) == Bar(Arg1) *) -(* Foo2 == Bar(LAMBDA m, n : <<m, n>>) *) -(* THEOREM Thm == ASSUME Arg1(1) , Bar(Arg1) PROVE << C, Bar(Arg1)>> *) -(* UU == lab:: C *) -(* ============================================================= *) -(* *) -(* Foo3 == \A x : LET Bar3 == 1 IN 2 *) -(* Inst(d) == INSTANCE M WITH C <- "expr(d)" *) -(***************************************************************************) - - -MCNode == - 1 :> [kind |-> UserDefinedOpKind, \* Op(Arg, p) == ... - name |-> "Op", - body |-> 3, - labels |-> "lab" :> 4, - arity |-> 2, - params |-> <<[name |-> "Arg", arity |-> 0], - [name |-> "p", arity |-> 0]>>, - defined |-> TRUE, - source |-> null ] -@@ - 2 :> [kind |-> BuiltInKind, - name |-> "$BoundedForall", - arity |-> -1 - ] -@@ - 3 :> [kind |-> OpApplKind, \* \A x \in {1,2}, <<y, z>> \in {3} : ... - operands |-> << 4 >>, - operator |-> 2, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << <<"x">>, <<"y", "z">> >>, - ranges |-> << 19, 21 >>] -@@ - 4 :> [kind |-> LabelKind, \* lab(x,y,z) :: LET a + b == <<Arg(a), b>> - name |-> "lab", \* IN 1 + label2 :: p + C - body |-> 5, - arity |-> 3, - params |-> <<[name |-> "x", arity |->0], - [name |-> "y", arity |->0], - [name |-> "z", arity |->0] >>, - labels |-> "label2" :> 15 ] -@@ - 5 :> [kind |-> LetInKind, \* LET a + b == <<Arg(a), b>> - context |-> "+" :> 6, \* IN 1 + label2 :: p + C - body |-> 13 ] -@@ - 6 :> [kind |-> UserDefinedOpKind, \* a + b == <<Arg(a), b>> - name |-> "+", - body |-> 7, - labels |-> << >>, - arity |-> 2, - params |-> <<[name |-> "a", arity |-> 0], - [name |-> "b", arity |-> 0]>>, - defined |-> TRUE, - source |-> null ] -@@ - 7 :> [kind |-> OpApplKind, \* <<Arg(a), b>> - operands |-> << 9, 12 >>, - operator |-> 8, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ - 8 :> [kind |-> BuiltInKind, - name |-> "$Tuple", - arity |-> -1 - ] -@@ - 9 :> [kind |-> OpApplKind, \* Arg1(a) - operands |-> <<11 >>, - operator |-> 10, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -10 :> [kind |-> ConstantDeclKind, - name |-> "Arg1", - arity |-> 1] - -@@ -11 :> [kind |-> FormalParamKind, - name |-> "a", - arity |-> 0] -@@ -12 :> [kind |-> FormalParamKind, - name |-> "b", - arity |-> 0] -@@ -13 :> [kind |-> OpApplKind, \* 1 + label2 :: p + C - operands |-> <<14, 15>>, - operator |-> 6, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -14 :> [kind |-> NumeralKind, - val |-> 1] -@@ -15 :> [kind |-> LabelKind, \* label2 :: p + C - name |-> "label2", - body |-> 16, - arity |-> 0, - params |-> <<>>, - labels |-> << >>] -@@ -16 :> [kind |-> OpApplKind, \* p + C - operands |-> <<17, 18>>, - operator |-> 6, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -17 :> [kind |-> FormalParamKind, - name |-> "p", - arity |-> 0] -@@ -18 :> [kind |-> ConstantDeclKind, - name |-> "C", - arity |-> 0 ] -@@ -19 :> [kind |-> OpApplKind, \* {1,2} - operands |-> << 14, 20 >>, - operator |-> 8, \* Actually, specifying <<1, 2>> - unboundedBoundSymbols |-> << >>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -20 :> [kind |-> NumeralKind, - val |-> 2] -@@ -21 :> [kind |-> OpApplKind, \* {1,2} - operands |-> << 22>>, - operator |-> 8, \* Actually, specifying <<1, 2>> - unboundedBoundSymbols |-> << >>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -22 :> [kind |-> NumeralKind, - val |-> 3] -@@ -23 :> [kind |-> UserDefinedOpKind, \* Foo(u) == Bar(Arg1) - name |-> "Foo", - body |-> 24, - labels |-> << >>, - arity |-> 1, - params |-> <<[name |-> "u", arity |-> 0]>>, - defined |-> TRUE, - source |-> null ] -@@ -24 :> [kind |-> OpApplKind, \* Bar(Arg1) - operands |-> <<34>>, - operator |-> 32, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -25 :> [kind |-> StringKind, - val |-> "string"] -@@ -26 :> [kind |-> ModuleInstanceKind, \* Inst(d) == INSTANCE M WITH C <- "expr(d)" - name |-> "Inst", - arity |-> 1, - params |-> <<[name |-> "d", arity |-> 0] >>, - defined |-> TRUE ] -@@ -27 :> [kind |-> SubstInKind, - body |-> 24, - subst |-> "expr(d)"] -@@ -28 :> [kind |-> UserDefinedOpKind, \* Foo(u) == "FooBody(u)" - name |-> "Inst!Foo", - body |-> 27, - labels |-> << >>, - arity |-> 2, - params |-> << [name |-> "d", arity |-> 0], - [name |-> "u", arity |-> 0]>>, - defined |-> TRUE, - source |-> 23 ] -@@ -29 :> [kind |-> UserDefinedOpKind, \* Op(Arg, p) == ... - name |-> "Inst!Op", - body |-> 30, - labels |-> "lab" :> 4, - arity |-> 3, - params |-> <<[name |-> "d", arity |-> 0], - [name |-> "Arg", arity |-> 0], - [name |-> "p", arity |-> 0]>>, - defined |-> TRUE, - source |-> 1 ] -@@ -30 :> [kind |-> SubstInKind, - body |-> 3, - subst |-> "expr(d)"] -@@ -31 :> [kind |-> StringKind, - val |-> "Argm"] -@@ -32 :> [kind |-> UserDefinedOpKind, \* Bar(AOp(_)) == AOp(1) - name |-> "Bar", - body |-> 33, - labels |-> << >>, - arity |-> 1, - params |-> <<[name |-> "AOp", arity |-> 1]>>, - defined |-> TRUE, - source |-> null ] -@@ -33 :> [kind |-> OpApplKind, \* Arg1(1) - operands |-> <<14>>, - operator |-> 10, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -34 :> [kind |-> OpArgKind, - op |-> 10, - arity |-> 1, - name |-> "Arg1"] -@@ -35 :> [kind |-> UserDefinedOpKind, \* Foo2 == Bar(LAMBDA m, n : <<m, n>>) - name |-> "Foo2", - body |-> 36, - labels |-> << >>, - arity |-> 0, - params |-> <<>>, - defined |-> TRUE, - source |-> null ] -@@ -36 :> [kind |-> OpApplKind, \* Bar(LAMBDA m, n : <<m, n>>) - operands |-> <<41>>, - operator |-> 32, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -37 :> [kind |-> UserDefinedOpKind, \* LAMBDA m, n : <<m, n>> - name |-> "LAMBDA", - body |-> 38, - labels |-> << >>, - arity |-> 2, - params |-> <<[name |-> "m", arity |-> 0], - [name |-> "n", arity |-> 0]>>, - defined |-> TRUE, - source |-> null ] -@@ -38 :> [kind |-> OpApplKind, \* <<m, n>> - operands |-> << 39, 40 >>, - operator |-> 8, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -39 :> [kind |-> FormalParamKind, - name |-> "m", - arity |-> 0] -@@ -40 :> [kind |-> FormalParamKind, - name |-> "n", - arity |-> 0] -@@ -41 :> [kind |-> OpArgKind, \* LAMBDA m, n : <<m, n>> - op |-> 37, - arity |-> 2, - name |-> "LAMBDA"] -@@ -42 :> [kind |-> UserDefinedOpKind, \* Inst!Foo2 == Bar(LAMBDA m, n : <<m, n>>) - name |-> "Inst!Foo2", - body |-> 43, - labels |-> << >>, - arity |-> 1, - params |-> <<[name |-> "d", arity |-> 0]>>, - defined |-> TRUE, - source |-> 35 ] -@@ -43 :> [kind |-> SubstInKind, - body |-> 36, - subst |-> "expr(d)"] -@@ -44 :> [kind |-> ThmOrAssumpDefKind, \* Thm == ASSUME Arg1(1) ... - name |-> "Thm", - body |-> 45, - labels |-> << >>, - arity |-> 0, - params |-> << >> , - defined |-> TRUE, - source |-> null ] -@@ -45 :> [kind |-> AssumeProveKind, - assumes |-> <<33, 24>>, - prove |-> 46 ] -@@ -46 :> [kind |-> OpApplKind, \* <<c, Bar(Arg1)>> - operands |-> << 59, 24 >>, - operator |-> 8, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -47 :> [kind |-> ThmOrAssumpDefKind, \* Thm == ASSUME Arg1(1) ... - name |-> "Inst!Thm", - body |-> 48, - labels |-> << >>, - arity |-> 1, - params |-> << [name |-> "d", arity |-> 0]>> , - defined |-> TRUE, - source |-> 44 ] -@@ -48 :> [kind |-> SubstInKind, - body |-> 45, - subst |-> "expr(d)"] -@@ -49 :> [kind |-> UserDefinedOpKind, \* Foo3 == \A x : LET ... - name |-> "Foo3", - body |-> 51, - labels |-> << >>, - arity |-> 0, - params |-> <<>>, - defined |-> TRUE, - source |-> null ] -@@ -50 :> [kind |-> LetInKind, \* Foo3 == \A x : LET Bar3 == 1 IN 2 - context |-> "Bar3" :> 53, - body |-> 13 ] -@@ -51 :> [kind |-> OpApplKind, \* \A x : LET Bar3 == 1 IN 2 - operands |-> << 50 >>, - operator |-> 52, - unboundedBoundSymbols |-> <<"x">>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -52 :> [kind |-> BuiltInKind, \* \A x : - name |-> "$UnboundedForall", - arity |-> -1] -@@ -53 :> [kind |-> UserDefinedOpKind, \* Bar3 == 1 - name |-> "Bar3", - body |-> 14, - labels |-> << >>, - arity |-> 0, - params |-> <<>>, - defined |-> TRUE, - source |-> null ] -@@ -54 :> [kind |-> FormalParamKind, \* AOp - name |-> "AOp", - arity |-> 1] -@@ -55 :> [kind |-> UserDefinedOpKind, \* Bar(AOp(_)) == AOp(1) - name |-> "Inst!Bar", - body |-> 56, - labels |-> << >>, - arity |-> 2, - params |-> <<[name |-> "d", arity |-> 0], - [name |-> "AOp", arity |-> 1]>>, - defined |-> TRUE, - source |-> null ] -@@ -56 :> [kind |-> SubstInKind, - body |-> 33, - subst |-> "expr(d)"] -@@ -57 :> [kind |-> UserDefinedOpKind, \* UU == lab:: C - name |-> "UU", - body |-> 58, - labels |-> "lab":> 58, - arity |-> 0, - params |-> <<>>, - defined |-> TRUE, - source |-> null ] -@@ -58 :> [kind |-> LabelKind, \* lab :: C - name |-> "lab", - body |-> 59, - arity |-> 0, - params |-> <<>>, - labels |-> << >>] - -@@ -59 :> [kind |-> OpApplKind, \* C - operands |-> <<>>, - operator |-> 18, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] -@@ -60 :> [kind |-> UserDefinedOpKind, \* UU == lab:: C - name |-> "Inst!UU", - body |-> 58, - labels |-> "lab":> 58, - arity |-> 1, - params |-> <<[name |-> "d", arity |-> 0] >>, - defined |-> TRUE, - source |-> null ] - - - MCNodeId == 1..60 - -MCGlobalContext == - "Op" :> 1 -@@ - "C" :> 18 -@@ - "UU" :> 57 -@@ - "Foo" :> 23 -@@ - "Inst" :> 26 -@@ - "Inst!Foo" :> 28 -@@ - "Inst!Bar" :> 55 -@@ - "Inst!Op" :> 29 -@@ - "Inst!UU" :> 60 -@@ - "Foo2" :> 35 -@@ - "Inst!Foo2" :> 42 -@@ - "Thm" :> 44 -@@ - "Inst!Thm" :> 47 -@@ - "Foo3" :> 49 -@@ - "Bar" :> 32 -@@ - "Arg1" :> 10 -@@ - "AOp" :> 54 -@@ - "p" :> 17 - -\* Foo -\* MCops == <<"Foo">> -\* MCargs == << << >> >> -\* MCexpectedArity == 1 - -\* Op() -\* MCops == <<"Op">> -\* MCargs == << <<>> >> -\* MCexpectedArity == 2 - -\* Op!lab -\* MCops == <<"Op", "lab">> -\* MCargs == << <<>> , <<>> >> -\* MCexpectedArity == 5 - -\* Op!lab!<< -\* MCops == <<"Op", "lab", "<<">> -\* MCargs == << <<>> , <<>> , << >> >> -\* MCexpectedArity == 5 - -\* Op!lab!<<!>> -\* MCops == <<"Op", "lab", "<<", ">>">> -\* MCargs == << << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 5 - -\* Op!lab!label2 -\* MCops == <<"Op", "lab", "label2">> -\* MCargs == << << >> , << >> , << >> >> -\* MCexpectedArity == 5 - -\* Op!lab!label2!<< -\* MCops == <<"Op", "lab", "label2", "<<">> -\* MCargs == << << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 5 - -\* Op!lab!:!+ -\* MCops == <<"Op", "lab", ":", "+" >> -\* MCargs == << << >> , << >> , << >> , << >> >> -\* MCexpectedArity == 7 - -\* Op!lab!:!+ -\* MCops == <<"Op", "lab", ":", "+", ">>" >> -\* MCargs == << << >> , << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 7 - -\* Op!@ -\* MCops == <<"Op", "@" >> -\* MCargs == << << >> , << >> >> -\* MCexpectedArity == 5 - -\* Op!@!>>!>>!<< -\* MCops == <<"Op", "@", ">>", ">>", "<<" >> -\* MCargs == << << >> , << >>, << >>, << >>, << >> >> -\* MCexpectedArity == 5 - -\* Op!<<!>> -\* MCops == <<"Op", "<<", ">>" >> -\* MCargs == << << >>, << >>, << >> >> -\* MCexpectedArity == 2 - -\* Inst!Foo -\* MCops == <<"Inst", "Foo">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 2 - -\* Inst!Op -\* MCops == <<"Inst", "Op">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 3 - -\* Inst!Op!lab -\* MCops == <<"Inst", "Op", "lab">> -\* MCargs == << << >>, << >> , << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!lab!<< -\* MCops == <<"Inst", "Op", "lab", "<<">> -\* MCargs == << << >>, << >> , << >> , << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!lab!<<!>> -\* MCops == <<"Inst", "Op", "lab", "<<", ">>">> -\* MCargs == << << >>, << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!lab!label2 -\* MCops == <<"Inst", "Op", "lab", "label2">> -\* MCargs == << << >>, << >> , << >> , << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!lab!label2!<< -\* MCops == <<"Inst", "Op", "lab", "label2", "<<">> -\* MCargs == << << >>, << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!lab!:!+ -\* MCops == <<"Inst", "Op", "lab", ":", "+" >> -\* MCargs == << << >>, << >> , << >> , << >> , << >> >> -\* MCexpectedArity == 8 - -\* Inst!Op!lab!:!+!>> -\* MCops == <<"Inst", "Op", "lab", ":", "+", ">>" >> -\* MCargs == << << >>, << >> , << >> , << >> , << >>, << >> >> -\* MCexpectedArity == 8 - -\* Inst!Op!@ -\* MCops == <<"Inst", "Op", "@" >> -\* MCargs == << << >>, << >> , << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!@!>>!>>!<< -\* MCops == <<"Inst", "Op", "@", ">>", ">>", "<<" >> -\* MCargs == << << >>, << >> , << >>, << >>, << >>, << >> >> -\* MCexpectedArity == 6 - -\* Inst!Op!<<!>> -\* MCops == <<"Inst", "Op", "<<", ">>" >> -\* MCargs == << << >>, << >>, << >>, << >> >> -\* MCexpectedArity == 3 - -\* Foo!1 -\* MCops == <<"Foo", "1">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 2 - -\* Inst!Foo!1 -\* MCops == <<"Inst", "Foo", "1">> -\* MCargs == << << >>, << >>, << >> >> -\* MCexpectedArity == 3 - -\* Foo2!1 -\* MCops == <<"Foo2", "1">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 2 - -\* Foo2!1!(1, 2) -\* MCops == <<"Foo2", "1", "null">> -\* MCargs == << << >>, << >>, <<14, 20>> >> -\* MCexpectedArity == 0 - -\* Foo2!1!(1, 2)!2 -\* MCops == <<"Foo2", "1", "null", "2">> -\* MCargs == << << >>, << >>, <<14, 20>>, << >> >> -\* MCexpectedArity == 0 - -\* Inst!Foo2!1 -\* MCops == <<"Inst", "Foo2", "1">> -\* MCargs == << << >>, << >>, << >> >> -\* MCexpectedArity == 3 - -\* Inst!Foo2!1 -\* MCops == <<"Inst", "Foo2", "1", "@">> -\* MCargs == << << >>, << >>, << >>, << >> >> -\* MCexpectedArity == 3 - -\* Inst!Foo2!1!2 -\* MCops == <<"Inst", "Foo2", "1", "@", "2">> -\* MCargs == << << >>, << >>, << >>, << >>, << >> >> -\* MCexpectedArity == 3 - -\* Inst("Argm")!Foo2!1!(1, 2) -\* MCops == <<"Inst", "Foo2", "1", "null">> -\* MCargs == << <<31>>, << >>, << >>, <<14, 20>> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Foo2!1!(1, 2)!2 -\* MCops == <<"Inst", "Foo2", "1", "null", "2">> -\* MCargs == << <<31>>, << >>, << >>, <<14, 20>>, << >> >> -\* MCexpectedArity == 0 - -\* Thm!1 -\* MCops == <<"Thm", "1" >> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 0 - -\* Thm!2 -\* MCops == <<"Thm", "2" >> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 0 - -\* Thm!3!<< -\* MCops == <<"Thm", "3", "<<" >> -\* MCargs == << << >>, << >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Thm!1 -\* MCops == <<"Inst", "Thm", "1" >> -\* MCargs == << <<31>>, << >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Thm!2 -\* MCops == <<"Inst", "Thm", "2" >> -\* MCargs == << <<31>>, << >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Thm!3!<< -\* MCops == <<"Inst", "Thm", "3", "<<" >> -\* MCargs == << <<31>>, << >>, << >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!UU -\* MCops == <<"Inst", "UU">> -\* MCargs == << <<31>>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Bar(Arg1)!1<< -\* MCops == <<"Inst", "Bar", "1" >> -\* MCargs == << <<31>>, <<10 >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Bar(Arg1)!1<< -\* MCops == <<"Inst", "Bar", "1" >> -\* MCargs == << <<31>>, <<10 >>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Thm \* Note: doesn't report an error because -\* MCops == <<"Inst", "Thm" >> \* Inst!Thm isn't expanded -\* MCargs == << <<31>>, << >> >> -\* MCexpectedArity == 0 - -\* Inst("Argm")!Thm!: ERROR! -\* MCops == <<"Inst", "Thm", ":" >> -\* MCargs == << <<31>>, << >>, << >> >> -\* MCexpectedArity == 0 - - -\* Foo2 -\* MCops == <<"Foo2">> -\* MCargs == <<<< >> >> -\* MCexpectedArity == 0 - -\* Foo3!(3)!:Bar3 -\* MCops == <<"Foo3", "null", "Bar3">> -\* MCargs == << << >>, <<22>>, << >> >> -\* MCexpectedArity == 0 - -\* Bar(Arg1) -\* \* MCops == <<"Bar">> -\* \* MCargs == << <<10>> >> -\* \* MCexpectedArity == 0 - -\* Arg1(C) -\* MCops == <<"Arg1">> -\* MCargs == << <<18>> >> -\* MCexpectedArity == 0 - -\* AOp -\* MCops == <<"AOp">> -\* MCargs == << <<18 >> >> -\* MCexpectedArity == 0 - -\* C -\* MCops == <<"C">> -\* MCargs == << << >> >> -\* MCexpectedArity == 0 - -\* p -\* MCops == <<"p">> -\* MCargs == << << >> >> -\* MCexpectedArity == 0 - -\* Foo3 -\* MCops == <<"Foo3">> -\* MCargs == << << >> >> -\* MCexpectedArity == 0 - -\***** THIS IS A BUG--NOT HANDLED CORRECTLY ****** -\* UU!lab -\* MCops == <<"UU", "lab">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 0 - -\* Op(2, 2)!(2, 2, 2) -\* MCops == <<"Op", "null">> -\* MCargs == << <<20, 20>>, <<20, 20, 20 >> >> -\* MCexpectedArity == 0 - -\* Foo3!(2) -\* MCops == <<"Foo3", "null">> -\* MCargs == << << >>, <<20>> >> -\* MCexpectedArity == 0 - -\* Op(2, 2)!(2,2,2)!+(2, 2) -\* MCops == <<"Op", "null", "+">> -\* MCargs == << <<20,20 >>, <<20,20,20>> , <<20,20>>>> -\* MCexpectedArity == 0 - -\* MCops == <<"Op">> -\* MCargs == << << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Inst", "Op">> -\* MCargs == << << >> , << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Inst", "Thm">> -\* MCargs == << << >> , << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Inst", "Op", "@", "+">> -\* MCargs == << << >> , << >> , << >> , << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Op", "lab", ":", "+">> -\* MCargs == << << >> , << >>, << >>, << >> >> -\* MCexpectedArity == 7 - -\* MCops == <<"Op", "lab", ":", "+">> -\* MCargs == << << >> , << >>, << >>, << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Foo2">> -\* MCargs == << << >> >> -\* MCexpectedArity == 0 - -\* MCops == <<"Foo3", ":">> -\* MCargs == << << >>, << >> >> -\* MCexpectedArity == 0 - -\* MCops == <<"Op", "lab", ":", "+">> -\* MCargs == << << >>, << >>, << >>, << >> >> -\* MCexpectedArity == -1 - -\* MCops == <<"Inst", "Thm">> -\* MCargs == << <<14 >>, << >> >> -\* MCexpectedArity == 0 - -MCops == <<"Inst", "Thm", ":">> -MCargs == << <<14 >>, << >>, << >> >> -MCexpectedArity == 0 -MCdebug == FALSE \* TRUE - -(********************************* -(***************************************************************************) -(* Module M *) -(* CONSTANT C *) -(* Op(Arg(_), p) == \A x \in {1,2}, <<y, z>> \in {3} : *) -(* lab(x,y,z) :: LET a + b == <<Arg(a), b>> *) -(* IN 1 + label2 :: p + C *) -(* *) -(* Foo(u) == "FooBody(u)" *) -(* Inst(w) == INSTANCE M WITH C <- <<w, CONST>> *) -(***************************************************************************) - -\* MCNode == -\* 1 :> [kind |-> NumeralKind, -\* val |-> 1] -\* @@ -\* 2 :> [kind |-> BuiltInKind, \* \E -\* name |-> "$UnboundedExists", -\* arity |-> -1] -\* -\* @@ -\* 3 :> [kind |-> OpApplKind, \* \E x : Node 1 -\* operands |-> <<1>>, -\* operator |-> 2, -\* unboundedBoundSymbols |-> <<"x">>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 4 :> [kind |-> UserDefinedOpKind, \* Inst!UserOp(p1, OpP) == Node 8 -\* name |-> "Inst!UserOp", -\* body |-> 8, -\* labels |-> "Label1" :> 7, -\* arity |-> 2, -\* params |-> <<[name |-> "p1", arity |-> 0], -\* [name |-> "OpP", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> 40 ] -\* @@ -\* 5 :> [kind |-> ModuleInstanceKind, \* Inst(p1) == INSTANCE -\* name |-> "Inst", -\* arity |-> 1, -\* params |-> <<[name |-> "p1", arity |-> 0] >>, -\* defined |-> TRUE ] -\* @@ -\* 6 :> [kind |-> UserDefinedOpKind, \* 1ArgOp(1OpP(_, _)) == Node 1 -\* name |-> "1ArgOp", -\* body |-> 41, -\* labels |-> << >>, -\* arity |-> 1, -\* params |-> <<[name |-> "1OpP", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 7 :> [kind |-> LabelKind, -\* name |-> "Label1", -\* body |-> 14, -\* arity |-> 1, -\* params |-> <<[name |-> "labParam1", arity |-> 0]>>, -\* labels |-> "Label2" :> 9 -\* ] -\* @@ -\* 8 :> [kind |-> SubstInKind, -\* body |-> 11, -\* subst |-> "x <- something(p1)"] -\* -\* @@ -\* 9 :> [kind |-> LabelKind, -\* name |-> "Label2", -\* body |-> 15, -\* arity |-> 1, -\* params |-> <<[name |-> "labParam2", arity |-> 0]>>, -\* labels |-> << >> -\* ] -\* @@ -\* 10 :> [kind |-> NumeralKind, -\* val |-> 10] -\* @@ -\* 11 :> [kind |-> SubstInKind, -\* body |-> 15, -\* subst |-> "y <- something(p1)"] -\* @@ -\* 12 :> [kind |-> StringKind, -\* val |-> "Body of UserOp (p1, OpP)"] -\* @@ -\* 13 :> [kind |-> StringKind, -\* val |-> "Body of Label2(labParam2)"] -\* @@ -\* 14 :> [kind |-> StringKind, -\* val |-> "Body of Label1(labParam1)"] -\* @@ -\* 15 :> [kind |-> LetInKind, -\* context |-> "1ArgOp" :> 6, -\* body |-> 16] -\* @@ -\* 16 :> [kind |-> StringKind, -\* val |-> "Body of Let/In"] -\* @@ -\* 17 :> [kind |-> UserDefinedOpKind, \* 1ArgOp("1OpP") == Node 1 -\* name |-> "Foo", -\* body |-> 18, -\* labels |-> << >>, -\* arity |-> 0, -\* params |-> << >> , \* <<[name |-> "FooPar1", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null] -\* @@ -\* 18 :> [kind |-> OpApplKind, -\* operands |-> <<42 >>, -\* operator |-> 21, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 19 :> [kind |-> StringKind, -\* val |-> "Arg1"] -\* @@ -\* 20 :> [kind |-> StringKind, -\* val |-> "Arg2"] -\* @@ -\* 21 :> [kind |-> UserDefinedOpKind, \* Foo2 == [rcd-lab1 |-> rcd-comp1, -\* name |-> "Foo2", \* ... -\* body |-> 34, \* rcd-lab3 |-> rcd-comp3] -\* labels |-> << >>, -\* arity |-> 1, -\* params |-> <<[name |-> "p1", arity |-> 1]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 22 :> [kind |-> OpApplKind, -\* operands |-> <<10 (* 25 *) , 28, 31>>, -\* operator |-> 23, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 23 :> [kind |-> BuiltInKind, -\* name |-> "$Except", \* "$Case", \* "$SetOfRcds", -\* arity |-> -1 -\* ] -\* @@ -\* 24 :> [kind |-> BuiltInKind, -\* name |-> "$Pair", -\* arity |-> 2 -\* ] -\* @@ -\* 25 :> [kind |-> OpApplKind, -\* operands |-> <<26,27>>, -\* operator |-> 24, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 26 :> [kind |-> StringKind, -\* val |-> "rcd-lab1"] -\* @@ -\* 27 :> [kind |-> StringKind, -\* val |-> "rcd-comp1"] -\* -\* @@ -\* 28 :> [kind |-> OpApplKind, -\* operands |-> <<29,30>>, -\* operator |-> 24, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 29 :> [kind |-> StringKind, -\* val |-> "rcd-lab2"] -\* @@ -\* 30 :> [kind |-> StringKind, -\* val |-> "rcd-comp2"] -\* @@ -\* 31 :> [kind |-> OpApplKind, -\* operands |-> <<32,33>>, -\* operator |-> 24, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << >>, -\* ranges |-> << >>] -\* @@ -\* 32 :> [kind |-> StringKind, -\* val |-> "rcd-lab3"] -\* @@ -\* 33 :> [kind |-> StringKind, -\* val |-> "rcd-comp3"] -\* @@ -\* 34 :> [kind |-> OpApplKind, -\* operands |-> <<35>>, -\* operator |-> 36, -\* unboundedBoundSymbols |-> <<>>, -\* boundedBoundSymbols |-> << <<"b1", "b2">>, <<"b3">> >>, -\* ranges |-> <<37, 38 >>] -\* @@ -\* 35 :> [kind |-> StringKind, -\* val |-> "Fcn of b1, b2, b3"] -\* @@ -\* 36 :> [kind |-> BuiltInKind, -\* name |-> "$Pair", -\* arity |-> 2 -\* ] -\* @@ -\* 37 :> [kind |-> StringKind, -\* val |-> "Range 1"] -\* @@ -\* 38 :> [kind |-> StringKind, -\* val |-> "Range 2"] -\* @@ -\* 39 :> [kind |-> StringKind, -\* val |-> "Arg3"] -\* @@ -\* 40 :> [kind |-> UserDefinedOpKind, \* Inst!UserOp(p1, OpP) == Node 8 -\* name |-> "UserOp", -\* body |-> 8, -\* labels |-> "Label1" :> 7, -\* arity |-> 1, -\* params |-> <<[name |-> "OpP", arity |-> 1]>>, -\* defined |-> TRUE, -\* source |-> null ] -\* @@ -\* 41 :> [kind |-> StringKind, -\* val |-> "Body of 1ArgOp may dep on (x, y)"] -\* @@ -\* 42 :> [kind |-> OpArgKind, -\* op |-> 43, -\* arity |-> 1, -\* name |-> "Foo3"] -\* @@ -\* 43 :> [kind |-> UserDefinedOpKind, \* 1ArgOp("1OpP") == Node 1 -\* name |-> "Foo3", -\* body |-> 18, -\* labels |-> << >>, -\* arity |-> 0, -\* params |-> << >>, \* <<[name |-> "FooPar1", arity |-> 0]>>, -\* defined |-> TRUE, -\* source |-> null] -\* -\* MCNodeId == 1..43 -\* -\* MCGlobalContext == -\* "Inst!UserOp" :> 4 -\* @@ -\* "Inst" :> 5 -\* @@ -\* "Foo" :> 17 -\* @@ -\* "Foo2" :> 21 -\* @@ -\* "Foo3" :> 43 -\* \* @@ -\* \* "1ArgOp" :> 6 -\* -\* -\* MCops == <<"Inst", "UserOp">> \* , "1">> -\* MCargs == << <<1 >> , <<1>> >> - -\* \* << <<1>>, <<19, 20, 33 >> >> \* <<1>>, <<10>>, << >>, <<4>> >> -\* -\* MCexpectedArity == 0 \* -1 \* 5 -***************************) - ------------------------------------------------------------------------------ -(***************************************************************************) -(* THE ALGORITHM *) -(***************************************************************************) -(************************************** ---algorithm Subexpression -variables - (*************************************************************************) - (* The input variables. *) - (*************************************************************************) - ops = MCops, - args = MCargs, - (***********************************************************************) - (* The sequences op and args described above. *) - (***********************************************************************) - expectedArity = MCexpectedArity, - (***********************************************************************) - (* The arity of the operator expected, or -1 if expecting a definition *) - (* name. It is 0 iff an expression is expected. The result should be *) - (* an OpArg node if expectedArity > 0, it should be an expression node *) - (* if expectedArity = 0, and it should be a UserDefinedOpKind or a *) - (* ThmOrAssumpDefKind if expectedArity < 0. *) - (***********************************************************************) - - (*************************************************************************) - (* The major variables of the algorithm. *) - (*************************************************************************) - substInPrefix = << >> , - (***********************************************************************) - (* The sequence of SubstInNode or APSubstInNode sequence that will be *) - (* appended to body of the resulting OpApplNode *) - (***********************************************************************) - params = << >> , - (***********************************************************************) - (* The sequence of FormalParamNode objects that are the formal *) - (* parameters if this produces a Lambda expression. A Lambda *) - (* expression will be produced iff this is non-empty *) - (***********************************************************************) - allArgs = << >> , - (***********************************************************************) - (* The sequence of all arguments. *) - (***********************************************************************) - curNode = null, - (***********************************************************************) - (* If params = << >>, then the OpDefNode for the OpApplNode that is *) - (* produced. If params # << >>, then the Expr node that will form the *) - (* body of the Lambda expression. *) - (* *) - (* Note: in the Java implementation, this will actually be a ref to *) - (* the node--in terms of this spec, a NodeId. *) - (***********************************************************************) - subExprOf = "null", - (***********************************************************************) - (* The node UserDefinedOpDefKind or ThmOrAssumpDefKind within which *) - (* this subexpression is defined. *) - (***********************************************************************) - result = null, - (***********************************************************************) - (* The actual output node. *) - (***********************************************************************) - - (*************************************************************************) - (* The local variables. *) - (*************************************************************************) - idx = 1, - (***********************************************************************) - (* The element of the arrays op and args that the algorithm is *) - (* currently examining. *) - (***********************************************************************) - mode = "FindingOpName", - (***********************************************************************) - (* The current mode describing what kind of selector it is expecting *) - (* next. Its other possible values are "FollowingLabels" and *) - (* "FindingSubExpr". *) - (***********************************************************************) - prevMode = "", - (***********************************************************************) - (* The mode for the previously examined selector. *) - (***********************************************************************) - curContext = GlobalContext, - (***********************************************************************) - (* The context for looking up operator or label names. *) - (***********************************************************************) - curName = "" , - (***********************************************************************) - (* When looking up an operator name, which may be something like *) - (* "Foo!Bar!Baz", this is the part that has been found so far. *) - (***********************************************************************) - opDefArityFound = 0, - opDefArgs = << >>, - (***********************************************************************) - (* The total arity and the sequence of arguments found so far for the *) - (* current operator--for example, opDefArityFound will equal 2 if the *) - (* algorithm has so far processed "Foo(a, b)!Bar" *) - (***********************************************************************) - firstFindingOpName = TRUE, - (***********************************************************************) - (* True iff have entered the FindingOpName only once (initially). *) - (***********************************************************************) - opNode, - newName, - newNode, - nodeArity, - temp, - tempArgs - - -(***************************************************************************) -(* A macro used for reporting an error and terminating the execution. *) -(***************************************************************************) -macro Error(msg) begin print msg ; - if debug then (**************************************) - (* Force the +cal translator to *) - (* insert a label so the error trace *) - (* shows the final state. *) - (**************************************) - idx := idx ; - idx := idx ; - assert FALSE - else goto Done - end if - end macro ; - - begin - - (*************************************************************************) - (* An assertion that checks that ops and args are consistent with each *) - (* other and with the value of expectedArity. In an implementation, *) - (* some of these should be guaranteed by the context (e.g., Len(ops) = *) - (* Len(args) while others will be checked as part of the processing for *) - (* the particular value of idx. *) - (*************************************************************************) - assert /\ expectedArity \in Int - /\ ops \in Seq(STRING) - /\ args \in Seq(Seq(NodeId)) - /\ Len(ops) = Len(args) - /\ \A i \in 1..Len(ops) : - /\ \/ ops[i] \in {"<<", ">>", "@", ":"} \cup NumberOp - \/ expectedArity # 0 - => args[i] = << >> - /\ (ops[i] = "null") => (Len(args[i]) > 0) ; - - (*************************************************************************) - (* The outer "for" loop on idx. *) - (*************************************************************************) - while idx <= Len(ops) do - if mode = "FindingOpName" then - -\* The following code was modified by LL on 23 Sep 2009 to fix the following -\* bug. The parser produced a bogus error on a reference to an identifier -\* M!N that is imported by an unnamed INSTANCE of a module containing the -\* statement M == INSTANCE ... . The original code essentially just -\* contained the first iteration of the following while loop, and would -\* report an error if it found newNode = null. Thus, it would report -\* an error in the identifier M!N when it found M to be undefined. -\* -\* Corrected by LL on 9 Nov 2009 to handle arguments of those -\* undefined operators. They are put into tempArgs when they are -\* found. - - newNode := null ; - tempArgs := << >> ; - (**********************************************************************) - (* The number of arguments found in the following loop for the *) - (* undefined operators *) - (**********************************************************************) - while newNode = null do - if idx \geq Len(ops) - then Error ("Unknown operator"); - end if; - newName := IF IsName(ops[idx]) - THEN IF curName = "" THEN ops[idx] - ELSE curName \o "!" \o ops[idx] - ELSE null ; - if /\ curName = "" - /\ ~ IsName(ops[idx]) - then (***************************************************************) - (* I think that this error can only happen for idx = 1, and *) - (* should never happen in the implementation because the *) - (* parser should not allow a compound name that doesn't begi *) - (* with a name. *) - (***************************************************************) - Error("Need an operator or label name or step number here") - end if; - newNode := IF newName # null THEN LookUp(newName, curContext) ELSE null ; - if newName = null - then tempArgs := tempArgs \o args[idx]; - idx := idx + 1; - end if; - end while ; - curNode := newNode ; - curName := newName ; - if curNode.kind \in - {UserDefinedOpKind, ThmOrAssumpDefKind, - ModuleInstanceKind, ConstantDeclKind, VariableDeclKind, - FormalParamKind, BuiltInKind, BoundSymbolKind} - then if curNode.kind \in - {ConstantDeclKind, VariableDeclKind, FormalParamKind, - BuiltInKind, BoundSymbolKind} - then if idx # 1 - then Error("Abort: Impossible naming of declaration " - \o "or built-in operator.") - else if Len(ops) # 1 - then Error("Can't take subexpression of this"); - end if - end if - end if ; - nodeArity := Arity(curNode) ; - tempArgs := tempArgs \o args[idx]; - if expectedArity = 0 - then if opDefArityFound + Len(tempArgs) # nodeArity - then Error("Wrong number of arguments") - end if ; - if \E i \in 1..Len(tempArgs[idx]) : - Arity(Node[tempArgs[idx][i]]) # - ParamArity(curNode, i + opDefArityFound) - then Error("Argument has wrong arity") - else opDefArgs := opDefArgs \o tempArgs; - end if ; - else if expectedArity > 0 - then if \E i \in 1..Len(curNode.params) : - curNode.params[i].arity > 0 - then Error("Higher-order operator selected " - \o "as operator argument") - end if -\* else Error( -\* "Abort: Don't yet handle expectedArity < 0") - end if - end if ; - opDefArityFound := nodeArity ; - if curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind, - ConstantDeclKind, VariableDeclKind, - FormalParamKind, BoundSymbolKind} - then if /\ curNode.kind = UserDefinedOpKind - /\ ~ curNode.defined - /\ ~ Len(ops) = 1 - then Error("Can't refer to subexpression of " - \o "operator inside its definition") - end if; - if /\ firstFindingOpName - /\ curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind} - then subExprOf := curNode - end if; - if idx # Len(ops) - then params := params \o curNode.params ; - curName := "" ; - if IsName(ops[idx+1]) - then mode := "FollowingLabels" - else mode := "FindingSubExpr" ; - end if ; - allArgs := allArgs \o opDefArgs ; - opDefArityFound := 0 ; - opDefArgs := << >> ; - newNode := Node[curNode.body] ; - while newNode.kind = SubstInKind do - substInPrefix := substInPrefix \o <<newNode>>; - newNode := Node[newNode.body]; - end while ; - while newNode.kind \in {SubstInKind, APSubstInKind} - (************************************************) - (* Added APSubstInKind test on 13 Nov 2009. *) - (************************************************) - do - substInPrefix := substInPrefix \o <<newNode>>; - newNode := Node[newNode.body]; - end while ; - (********************************************) - (* If the next op is an OpSel, then need to *) - (* skip over SubstInNodes, which are *) - (* invisible to the user. *) - (********************************************) - if mode = "FindingSubExpr" - then curNode := newNode - end if; - end if ; - else \* curNode.kind = ModuleInstanceKind - if (idx = Len(ops)) - then Error("Operator name incomplete") - end if - end if - else Error("Unexpected node kind") ; - end if ; - prevMode := "FindingOpName" ; - - - elsif mode = "FollowingLabels" then - if prevMode = "FindingOpName" - then assert curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind} ; - newNode := LookUp(ops[idx], curNode.labels) ; - else assert curNode.kind = LabelKind ; - newNode := LookUp(ops[idx], curNode.labels) ; - end if ; - if newNode = null - then Error("Label not found") - end if; - curNode := newNode ; - if expectedArity = 0 - then if Len(args[idx]) # curNode.arity - then Error("bad arity") - end if ; - if \E i \in 1..Len(args[idx]) : - Arity(Node[args[idx][i]]) # 0 - then Error("Operator argument given to label") - end if; - allArgs := allArgs \o args[idx] ; - end if; - params := params \o curNode.params ; - if /\ idx < Len(ops) - /\ ~IsName(ops[idx+1]) - then mode := "FindingSubExpr" - end if ; - if \/ mode = "FindingSubExpr" - \/ idx = Len(ops) - then curNode := Node[curNode.body] - end if; - prevMode := "FollowingLabels"; - - - elsif mode = "FindingSubExpr" then - if ops[idx] = ":" then - if \/ prevMode \notin {"FindingOpName", "FollowingLabels"} - \/ ~ \/ /\ idx = Len(ops) - /\ prevMode = "FindingOpName" - \/ /\ idx < Len(ops) - /\ IsName(ops[idx+1]) - then Error("`!:' can be used only after a name and either at the " \o - "end after an operator name or before an operator name.") - end if - - elsif curNode.kind = LetInKind then - if ArgNum(ops[idx], 1) = 1 - then curNode := Node[curNode.body] - else Error("A Let/In has only a single operand") - end if ; - - elsif curNode.kind = OpApplKind then - opNode := Node[curNode.operator] ; - if opNode.kind - \in {FormalParamKind, ConstantDeclKind, UserDefinedOpKind} then - (******************************************************************) - (* Selecting an argument from something of the form Op(...). *) - (******************************************************************) - temp := ArgNum(ops[idx], opNode.arity) ; - if temp = -1 - then Error("Nonexistent operand specified") - else curNode := Node[curNode.operands[temp]] - end if - elsif opNode.kind = BuiltInKind then - \* See configuration/ConfigConstants for a list of all - \* BuiltInKind operators. - if opNode.name \in {"$RcdConstructor", "$SetOfRcds"} then - (*****************************************************************) - (* curNode represents an expression *) - (* [a_1 |-> e_1, ... , a_n |-> e_n] or *) - (* [a_1 : e_1, ... , a_n : e_n] *) - (* Its i-th argument is the $Pair node (a_i, e_i) *) - (*****************************************************************) - temp := ArgNum(ops[idx], Len(curNode.operands)) ; - if temp = -1 - then Error("Incorrect subexpression number") - end if ; - curNode := Node[curNode.operands[temp]] ; - if \/ curNode.kind # OpApplKind - \/ Node[curNode.operator].kind # BuiltInKind - \/ Node[curNode.operator].name # "$Pair" - then Error ("Expecting $Pair(...)") - else curNode := Node[curNode.operands[2]] - end if - - elsif opNode.name \in {"$Case"} then - (*****************************************************************) - (* The i-th clause is a $Pair node, where for the OTHER clause *) - (* the 1st element is null. *) - (*****************************************************************) - if idx = Len(ops) - then Error( "CASE subexpression must be of form !i!j") - end if ; - temp := ArgNum( ops[idx], Len(curNode.operands)) ; - if temp = -1 - then Error("Incorrect subexpression name") - end if ; - curNode := Node[curNode.operands[temp]] ; - if \/ curNode.kind # OpApplKind - \/ Node[curNode.operator].kind # BuiltInKind - \/ Node[curNode.operator].name # "$Pair" - then Error ("Expecting $Pair(...)") - end if ; - idx := idx+1 ; - temp := ArgNum(ops[idx], 2); - if temp = -1 - then Error("Incorrect subexpression name") - end if ; - curNode := Node[curNode.operands[temp]] ; - if curNode = null - then Error("Selecting OTHER") - end if - - elsif opNode.name = "$Except" then - (****************************************************************) - (* For *) - (* [exp_1 ELSE !... = exp_2, ... , !.. = exp_n] *) - (* argument number i chooses exp_i. For i > 1, exp_i is the *) - (* second argument of a $Pair operator. *) - (****************************************************************) - temp := ArgNum(ops[idx], Len(curNode.operands)); - if temp = -1 - then Error("Bad argument selector.") - end if; - curNode := Node[curNode.operands[temp]] ; - if temp > 1 - then if \/ curNode.kind # OpApplKind - \/ Node[curNode.operator].kind # BuiltInKind - \/ Node[curNode.operator].name # "$Pair" - then Error("Unexpected expression node found.") - else curNode := Node[curNode.operands[2]] - end if - end if - - else - (*****************************************************************) - (* Operator handled by standard procedure. *) - (*****************************************************************) - if /\ Len(curNode.unboundedBoundSymbols) = 0 - /\ Len(curNode.boundedBoundSymbols) = 0 - then (**********************************************************) - (* Current subexpression has no bound variables. *) - (**********************************************************) - temp := ArgNum(ops[idx], Len(curNode.operands)) ; - if temp = -1 - then Error("Incorrect subexpression selector") - end if; - curNode := Node[curNode.operands[temp]] ; - else - (**********************************************************) - (* Current subexpression has bound variables. If *) - (* selector is "@" or null, then choosing body and adding *) - (* parameters. Otherwise, must be selecting one of the *) - (* bounds. *) - (**********************************************************) - if ops[idx] \in {"null", "@"} - then (***************************************************) - (* Set temp to the sequence of parameters. *) - (***************************************************) - temp := IF Len(curNode.unboundedBoundSymbols) > 0 - THEN curNode.unboundedBoundSymbols - ELSE SeqSeqToSeq( - curNode.boundedBoundSymbols); - - params := params \o - [i \in 1.. Len(temp) |-> - [name |-> temp[i], arity |-> 0]] ; - allArgs := allArgs \o args[idx] ; - if /\ ops[idx] = "null" - /\ Len(args[idx]) # Len(temp) - then Error("Wrong number of selector arguments"); - end if; - curNode := Node[curNode.operands[1]]; - else temp := ArgNum(ops[idx], Len(curNode.ranges)) ; - if temp = -1 - then Error ("Selecting non-existent range") ; - else curNode := Node[curNode.ranges[temp]] - end if - end if - end if - end if \* opNode.name = ... - - else Error("Applying subexpression chooser to an expr" \o - " with no choosable subexpressions") - - end if \* opNode.kind = ... - - elsif curNode.kind = AssumeProveKind then - temp := ArgNum(ops[idx], 1 + Len(curNode.assumes)) ; - if temp = -1 - then Error("Illegal argument number") - else if temp <= Len(curNode.assumes) - then curNode := Node[curNode.assumes[temp]] - else curNode := Node[curNode.prove] - end if - end if - - elsif curNode.kind = OpArgKind then - (*********************************************************************) - (* The only kind of OpArgNode that has a subpart is a Lambda *) - (* expression. *) - (*********************************************************************) - opNode := Node[curNode.op] ; - if \/ opNode.kind # UserDefinedOpKind - \/ opNode.name # "LAMBDA" then - Error("Selecting from operator argument that has no sub-part") - elsif ops[idx] \notin {"null", "@"} then - Error("Incorrect selection from LAMBDA") - elsif /\ ops[idx] = "null" - /\ Len(args[idx]) # Len(opNode.params) then - Error("Incorrect number of arguments for LAMBDA") - else params := params \o opNode.params ; - allArgs := allArgs \o args[idx] ; - curNode := Node[opNode.body] ; - end if - - elsif curNode.kind \in {UserDefinedOpKind, BuiltInKind} then - Error("Abort: should not have been able to choose this node.") - - elsif curNode.kind \in {AtNodeKind, DecimalKind, NumeralKind, StringKind, - FormalParamKind, ConstantDeclKind, VariableDeclKind, - BoundSymbolKind} then - Error("Selected part has no subexpression") - - elsif curNode.kind = LabelKind then - (*********************************************************************) - (* Skip over label. *) - (*********************************************************************) - curNode := Node[curNode.body] ; - idx := idx - 1 ; - else - Error("Unexpected node kind found in expression") - - end if; \* ops[idx] = ":" - - if idx # Len(ops) - then if IsName(ops[idx+1]) - then while curNode.kind = LabelKind do - curNode := Node[curNode.body] - end while ; - if curNode.kind = LetInKind - then curContext := curNode.context ; - mode := "FindingOpName" ; - firstFindingOpName := FALSE; - else Error("A name not following the selector of a LET") - end if - else if ops[idx+1] = ":" - then Error("!: should not follow an operand selector") - end if ; - end if ; - end if ; \* ops[idx] = ":" - prevMode := "FindingSubExpr"; - - else Error("Bad value of mode") - - end if ; \* mode = ... - - idx := idx + 1; - end while ; - - if curNode.kind = AssumeProveKind - then Error("Selecting ASSUME/PROVE instead of expression") - end if; - - if expectedArity < 0 - then if \/ prevMode # "FindingOpName" - \/ curNode.kind \notin {UserDefinedOpKind, ThmOrAssumpDefKind} - then Error("Should have selected a definition, but didn't.") - end if; - result := curNode ; - goto Finished - end if; - - if expectedArity > 0 - then temp := Len(params) + IF \/ prevMode = "FindingOpName" - \/ curNode.kind = OpArgKind - THEN Arity(curNode) - ELSE 0 ; - if expectedArity # temp - then Error("Expect arity = " \o ToString(expectedArity) - \o ", but found arity = " \o ToString(temp)) - end if - end if; - - - (*************************************************************************) - (* If found an operator def and there are parameters or substitutions, *) - (* then set curNode to the operator applied to new parameters, add those *) - (* parameters to params and add the arguments to allArgs. Note: need to *) - (* do this even if operator takes no parameters because we need to put *) - (* the operator in a LAMBDA expression whose body is an expression *) - (*************************************************************************) - if /\ prevMode = "FindingOpName" - /\ Len(params) + Len(substInPrefix) > 0 - then temp := [i \in 1..Len(curNode.params) |-> - [curNode.params[i] EXCEPT !.name = "New " \o @]] ; - (****************************************************************) - (* temp := new formal parameters for the operator, with the *) - (* same arities as the original parameters. *) - (****************************************************************) - - curNode := [kind |-> OpApplKind, - operands |-> temp, - operator |-> curNode, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] ; - params := params \o temp ; - allArgs := allArgs \o opDefArgs ; - end if ; - - if curNode.kind = OpArgKind - then if expectedArity = 0 then - Error("Selected Operator Argument when expression expected.") - elsif expectedArity # Len(params) + curNode.arity then - Error("Selected operator has wrong arity.") - else - if Len(params) + Len(substInPrefix) > 0 - then (********************************************************) - (* If curNode is a LAMBDA, then this will eventually *) - (* produce an OpArg node whose operator is a LAMBDA *) - (* whose body is an OpApplNode that applies the *) - (* curNode's LAMBDA to parameters of the outer LAMBDA. *) - (* This result can be simplified to a LAMBDA whose body *) - (* is the body of curNode. However, that *) - (* simplification is what one will get by selecting the *) - (* body of the LAMBDA, so we keep this complicated *) - (* expression in this case. *) - (********************************************************) - temp := [i \in 1..curNode.arity |-> - [name |-> "NewParam" \o NumToString(i), - arity |-> 0]] ; - curNode := [kind |-> OpApplKind, - operands |-> temp, - operator |-> Node[curNode.op], - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] ; - params := params \o temp - end if - end if - end if ; - - if curNode.kind \in {UserDefinedOpKind, ConstantDeclKind, VariableDeclKind, - FormalParamKind, BuiltInKind, BoundSymbolKind, - ThmOrAssumpDefKind} then - (***********************************************************************) - (* There are no params or substitutions, so this is an easy case. *) - (***********************************************************************) - if expectedArity > 0 then - result := [kind |-> OpArgKind, - name |-> curNode.name, - op |-> curNode, - arity |-> expectedArity] - elsif expectedArity = 0 then - result := [kind |-> OpApplKind, - operands |-> opDefArgs, - operator |-> curNode, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>, - subExprOf |-> subExprOf] - end if - elsif curNode.kind = OpArgKind then - (***********************************************************************) - (* There are no params or substitutions, so this is an easy case. *) - (***********************************************************************) - result := curNode ; - else (******************************************************************) - (* curNode should be an expression node. *) - (******************************************************************) - temp := Len(substInPrefix) ; - while temp > 0 do - curNode := [kind |-> substInPrefix[temp].kind, - (********************************************) - (* Changed on 13 Nov 2009 from SubstInKind. *) - (********************************************) - body |-> curNode , - subst |-> substInPrefix[temp].subst ] ; - temp := temp - 1; - end while; - - if expectedArity > 0 - then if Len(params) # expectedArity - then Error ("Selection has wrong arity") - end if ; - result := [kind |-> OpArgKind, - op |-> [kind |-> UserDefinedOpKind, - name |-> "LAMBDA", - body |-> curNode, - params |-> params, - arity |-> Len(params), - defined |-> TRUE, - source |-> null], - name |-> "LAMBDA"] - else if Len(params) # Len(allArgs) - then Error("Abort: number of params # num of args") - end if ; - if Len(params) = 0 - then (******************************************************) - (* This is the one case with expectedArity = 0 in *) - (* which the result is not a newly-constructed node. *) - (* In this case, we construct a dummy label node so *) - (* we have a node to which the implementation can *) - (* attach the syntax node. *) - (******************************************************) - result := [kind |-> LabelKind, - name |-> "$Subexpression", - arity |-> 0, - params |-> << >>, - body |-> curNode, - subExprOf |-> subExprOf] - - else result := [kind |-> OpApplKind, - operator |-> [kind |-> UserDefinedOpKind, - name |-> "LAMBDA", - body |-> curNode, - params |-> params, - arity |-> Len(params), - defined |-> TRUE, - source |-> null], - operands |-> allArgs, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>, - subExprOf |-> subExprOf] - end if - end if - - end if; - -Finished: - print "Result: " ; - print result ; - -end algorithm -*********************************************************************) -\* BEGIN TRANSLATION -CONSTANT defaultInitValue -VARIABLES ops, args, expectedArity, substInPrefix, params, allArgs, curNode, - subExprOf, result, idx, mode, prevMode, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, - newNode, nodeArity, temp, tempArgs, pc - -vars == << ops, args, expectedArity, substInPrefix, params, allArgs, curNode, - subExprOf, result, idx, mode, prevMode, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, - newNode, nodeArity, temp, tempArgs, pc >> - -Init == (* Global variables *) - /\ ops = MCops - /\ args = MCargs - /\ expectedArity = MCexpectedArity - /\ substInPrefix = << >> - /\ params = << >> - /\ allArgs = << >> - /\ curNode = null - /\ subExprOf = "null" - /\ result = null - /\ idx = 1 - /\ mode = "FindingOpName" - /\ prevMode = "" - /\ curContext = GlobalContext - /\ curName = "" - /\ opDefArityFound = 0 - /\ opDefArgs = << >> - /\ firstFindingOpName = TRUE - /\ opNode = defaultInitValue - /\ newName = defaultInitValue - /\ newNode = defaultInitValue - /\ nodeArity = defaultInitValue - /\ temp = defaultInitValue - /\ tempArgs = defaultInitValue - /\ pc = "Lbl_1" - -Lbl_1 == /\ pc = "Lbl_1" - /\ Assert(/\ expectedArity \in Int - /\ ops \in Seq(STRING) - /\ args \in Seq(Seq(NodeId)) - /\ Len(ops) = Len(args) - /\ \A i \in 1..Len(ops) : - /\ \/ ops[i] \in {"<<", ">>", "@", ":"} \cup NumberOp - \/ expectedArity # 0 - => args[i] = << >> - /\ (ops[i] = "null") => (Len(args[i]) > 0), - "Failure of assertion at line line 1906, column 3.") - /\ pc' = "Lbl_2" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, idx, mode, - prevMode, curContext, curName, opDefArityFound, - opDefArgs, firstFindingOpName, opNode, newName, - newNode, nodeArity, temp, tempArgs >> - -Lbl_2 == /\ pc = "Lbl_2" - /\ IF idx <= Len(ops) - THEN /\ IF mode = "FindingOpName" - THEN /\ newNode' = null - /\ tempArgs' = << >> - /\ pc' = "Lbl_3" - /\ UNCHANGED << params, allArgs, curNode, idx, - opNode, temp >> - ELSE /\ IF mode = "FollowingLabels" - THEN /\ IF prevMode = "FindingOpName" - THEN /\ Assert(curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind}, - "Failure of assertion at line line 2053, column 13.") - /\ newNode' = LookUp(ops[idx], curNode.labels) - ELSE /\ Assert(curNode.kind = LabelKind, - "Failure of assertion at line line 2055, column 13.") - /\ newNode' = LookUp(ops[idx], curNode.labels) - /\ IF newNode' = null - THEN /\ PrintT("Label not found") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_22" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_23" - /\ UNCHANGED idx - /\ UNCHANGED << params, allArgs, - curNode, opNode, - temp >> - ELSE /\ IF mode = "FindingSubExpr" - THEN /\ IF ops[idx] = ":" - THEN /\ IF \/ prevMode \notin {"FindingOpName", "FollowingLabels"} - \/ ~ \/ /\ idx = Len(ops) - /\ prevMode = "FindingOpName" - \/ /\ idx < Len(ops) - /\ IsName(ops[idx+1]) - THEN /\ PrintT("`!:' can be used only after a name and either at the " \o - "end after an operator name or before an operator name.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_29" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode, - opNode, - temp >> - ELSE /\ IF curNode.kind = LetInKind - THEN /\ IF ArgNum(ops[idx], 1) = 1 - THEN /\ curNode' = Node[curNode.body] - /\ pc' = "Lbl_63" - /\ UNCHANGED idx - ELSE /\ PrintT("A Let/In has only a single operand") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_30" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - /\ UNCHANGED << params, - allArgs, - opNode, - temp >> - ELSE /\ IF curNode.kind = OpApplKind - THEN /\ opNode' = Node[curNode.operator] - /\ IF opNode'.kind - \in {FormalParamKind, ConstantDeclKind, UserDefinedOpKind} - THEN /\ temp' = ArgNum(ops[idx], opNode'.arity) - /\ IF temp' = -1 - THEN /\ PrintT("Nonexistent operand specified") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_31" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ curNode' = Node[curNode.operands[temp']] - /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs >> - ELSE /\ IF opNode'.kind = BuiltInKind - THEN /\ IF opNode'.name \in {"$RcdConstructor", "$SetOfRcds"} - THEN /\ temp' = ArgNum(ops[idx], Len(curNode.operands)) - /\ IF temp' = -1 - THEN /\ PrintT("Incorrect subexpression number") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_32" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_33" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ IF opNode'.name \in {"$Case"} - THEN /\ IF idx = Len(ops) - THEN /\ PrintT("CASE subexpression must be of form !i!j") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_36" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_37" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode, - temp >> - ELSE /\ IF opNode'.name = "$Except" - THEN /\ temp' = ArgNum(ops[idx], Len(curNode.operands)) - /\ IF temp' = -1 - THEN /\ PrintT("Bad argument selector.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_46" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_47" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ IF /\ Len(curNode.unboundedBoundSymbols) = 0 - /\ Len(curNode.boundedBoundSymbols) = 0 - THEN /\ temp' = ArgNum(ops[idx], Len(curNode.operands)) - /\ IF temp' = -1 - THEN /\ PrintT("Incorrect subexpression selector") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_50" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_51" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ IF ops[idx] \in {"null", "@"} - THEN /\ temp' = (IF Len(curNode.unboundedBoundSymbols) > 0 - THEN curNode.unboundedBoundSymbols - ELSE SeqSeqToSeq( - curNode.boundedBoundSymbols)) - /\ params' = params \o - [i \in 1.. Len(temp') |-> - [name |-> temp'[i], arity |-> 0]] - /\ allArgs' = allArgs \o args[idx] - /\ IF /\ ops[idx] = "null" - /\ Len(args[idx]) # Len(temp') - THEN /\ PrintT("Wrong number of selector arguments") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_52" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_53" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ temp' = ArgNum(ops[idx], Len(curNode.ranges)) - /\ IF temp' = -1 - THEN /\ PrintT("Selecting non-existent range") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_54" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ curNode' = Node[curNode.ranges[temp']] - /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs >> - ELSE /\ PrintT("Applying subexpression chooser to an expr" \o - " with no choosable subexpressions") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_55" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode, - temp >> - ELSE /\ IF curNode.kind = AssumeProveKind - THEN /\ temp' = ArgNum(ops[idx], 1 + Len(curNode.assumes)) - /\ IF temp' = -1 - THEN /\ PrintT("Illegal argument number") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_56" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ IF temp' <= Len(curNode.assumes) - THEN /\ curNode' = Node[curNode.assumes[temp']] - ELSE /\ curNode' = Node[curNode.prove] - /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - opNode >> - ELSE /\ IF curNode.kind = OpArgKind - THEN /\ opNode' = Node[curNode.op] - /\ IF \/ opNode'.kind # UserDefinedOpKind - \/ opNode'.name # "LAMBDA" - THEN /\ PrintT("Selecting from operator argument that has no sub-part") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_57" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ IF ops[idx] \notin {"null", "@"} - THEN /\ PrintT("Incorrect selection from LAMBDA") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_58" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ IF /\ ops[idx] = "null" - /\ Len(args[idx]) # Len(opNode'.params) - THEN /\ PrintT("Incorrect number of arguments for LAMBDA") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_59" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode >> - ELSE /\ params' = params \o opNode'.params - /\ allArgs' = allArgs \o args[idx] - /\ curNode' = Node[opNode'.body] - /\ pc' = "Lbl_63" - /\ UNCHANGED idx - ELSE /\ IF curNode.kind \in {UserDefinedOpKind, BuiltInKind} - THEN /\ PrintT("Abort: should not have been able to choose this node.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_60" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ IF curNode.kind \in {AtNodeKind, DecimalKind, NumeralKind, StringKind, - FormalParamKind, ConstantDeclKind, VariableDeclKind, - BoundSymbolKind} - THEN /\ PrintT("Selected part has no subexpression") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_61" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - ELSE /\ IF curNode.kind = LabelKind - THEN /\ curNode' = Node[curNode.body] - /\ idx' = idx - 1 - /\ pc' = "Lbl_63" - ELSE /\ PrintT("Unexpected node kind found in expression") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_62" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED curNode - /\ UNCHANGED << params, - allArgs, - opNode >> - /\ UNCHANGED temp - ELSE /\ PrintT("Bad value of mode") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_68" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << params, - allArgs, - curNode, - opNode, - temp >> - /\ UNCHANGED newNode - /\ UNCHANGED tempArgs - ELSE /\ IF curNode.kind = AssumeProveKind - THEN /\ PrintT("Selecting ASSUME/PROVE instead of expression") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_70" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_71" - /\ UNCHANGED idx - /\ UNCHANGED << params, allArgs, curNode, opNode, newNode, - temp, tempArgs >> - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, subExprOf, - result, mode, prevMode, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, - newName, nodeArity >> - -Lbl_69 == /\ pc = "Lbl_69" - /\ idx' = idx + 1 - /\ pc' = "Lbl_2" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_3 == /\ pc = "Lbl_3" - /\ IF newNode = null - THEN /\ IF idx \geq Len(ops) - THEN /\ PrintT("Unknown operator") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_4" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_5" - /\ UNCHANGED idx - /\ UNCHANGED << curNode, curName >> - ELSE /\ curNode' = newNode - /\ curName' = newName - /\ IF curNode'.kind \in - {UserDefinedOpKind, ThmOrAssumpDefKind, - ModuleInstanceKind, ConstantDeclKind, VariableDeclKind, - FormalParamKind, BuiltInKind, BoundSymbolKind} - THEN /\ IF curNode'.kind \in - {ConstantDeclKind, VariableDeclKind, FormalParamKind, - BuiltInKind, BoundSymbolKind} - THEN /\ IF idx # 1 - THEN /\ PrintT("Abort: Impossible naming of declaration " - \o "or built-in operator.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_8" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ IF Len(ops) # 1 - THEN /\ PrintT("Can't take subexpression of this") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_9" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_10" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_10" - /\ UNCHANGED idx - ELSE /\ PrintT("Unexpected node kind") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_20" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_5 == /\ pc = "Lbl_5" - /\ newName' = IF IsName(ops[idx]) - THEN IF curName = "" THEN ops[idx] - ELSE curName \o "!" \o ops[idx] - ELSE null - /\ IF /\ curName = "" - /\ ~ IsName(ops[idx]) - THEN /\ PrintT("Need an operator or label name or step number here") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_6" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_7" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newNode, nodeArity, temp, - tempArgs >> - -Lbl_6 == /\ pc = "Lbl_6" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1956, column 13.") - /\ pc' = "Lbl_7" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_7 == /\ pc = "Lbl_7" - /\ newNode' = (IF newName # null THEN LookUp(newName, curContext) ELSE null) - /\ IF newName = null - THEN /\ tempArgs' = tempArgs \o args[idx] - /\ idx' = idx + 1 - ELSE /\ TRUE - /\ UNCHANGED << idx, tempArgs >> - /\ pc' = "Lbl_3" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, nodeArity, temp >> - -Lbl_4 == /\ pc = "Lbl_4" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1942, column 13.") - /\ pc' = "Lbl_5" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_10 == /\ pc = "Lbl_10" - /\ nodeArity' = Arity(curNode) - /\ tempArgs' = tempArgs \o args[idx] - /\ IF expectedArity = 0 - THEN /\ IF opDefArityFound + Len(tempArgs') # nodeArity' - THEN /\ PrintT("Wrong number of arguments") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_11" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_12" - /\ UNCHANGED idx - ELSE /\ IF expectedArity > 0 - THEN /\ IF \E i \in 1..Len(curNode.params) : - curNode.params[i].arity > 0 - THEN /\ PrintT("Higher-order operator selected " - \o "as operator argument") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_14" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_15" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_15" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, temp >> - -Lbl_12 == /\ pc = "Lbl_12" - /\ IF \E i \in 1..Len(tempArgs[idx]) : - Arity(Node[tempArgs[idx][i]]) # - ParamArity(curNode, i + opDefArityFound) - THEN /\ PrintT("Argument has wrong arity") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_13" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED opDefArgs - ELSE /\ opDefArgs' = opDefArgs \o tempArgs - /\ pc' = "Lbl_15" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_13 == /\ pc = "Lbl_13" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1990, column 26.") - /\ pc' = "Lbl_15" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_11 == /\ pc = "Lbl_11" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1985, column 25.") - /\ pc' = "Lbl_12" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_14 == /\ pc = "Lbl_14" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1996, column 32.") - /\ pc' = "Lbl_15" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_15 == /\ pc = "Lbl_15" - /\ opDefArityFound' = nodeArity - /\ IF curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind, - ConstantDeclKind, VariableDeclKind, - FormalParamKind, BoundSymbolKind} - THEN /\ IF /\ curNode.kind = UserDefinedOpKind - /\ ~ curNode.defined - /\ ~ Len(ops) = 1 - THEN /\ PrintT("Can't refer to subexpression of " - \o "operator inside its definition") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_16" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_17" - /\ UNCHANGED idx - ELSE /\ IF (idx = Len(ops)) - THEN /\ PrintT("Operator name incomplete") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_19" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_21" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArgs, firstFindingOpName, - opNode, newName, newNode, nodeArity, temp, tempArgs >> - -Lbl_17 == /\ pc = "Lbl_17" - /\ IF /\ firstFindingOpName - /\ curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind} - THEN /\ subExprOf' = curNode - ELSE /\ TRUE - /\ UNCHANGED subExprOf - /\ IF idx # Len(ops) - THEN /\ params' = params \o curNode.params - /\ curName' = "" - /\ IF IsName(ops[idx+1]) - THEN /\ mode' = "FollowingLabels" - ELSE /\ mode' = "FindingSubExpr" - /\ allArgs' = allArgs \o opDefArgs - /\ opDefArityFound' = 0 - /\ opDefArgs' = << >> - /\ newNode' = Node[curNode.body] - /\ pc' = "Lbl_18" - ELSE /\ pc' = "Lbl_21" - /\ UNCHANGED << params, allArgs, mode, curName, - opDefArityFound, opDefArgs, newNode >> - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, curNode, - result, idx, prevMode, curContext, - firstFindingOpName, opNode, newName, nodeArity, temp, - tempArgs >> - -Lbl_18 == /\ pc = "Lbl_18" - /\ IF newNode.kind = SubstInKind - THEN /\ substInPrefix' = substInPrefix \o <<newNode>> - /\ newNode' = Node[newNode.body] - /\ pc' = "Lbl_18" - /\ UNCHANGED curNode - ELSE /\ IF mode = "FindingSubExpr" - THEN /\ curNode' = newNode - ELSE /\ TRUE - /\ UNCHANGED curNode - /\ pc' = "Lbl_21" - /\ UNCHANGED << substInPrefix, newNode >> - /\ UNCHANGED << ops, args, expectedArity, params, allArgs, subExprOf, - result, idx, mode, prevMode, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, - opNode, newName, nodeArity, temp, tempArgs >> - -Lbl_16 == /\ pc = "Lbl_16" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2010, column 25.") - /\ pc' = "Lbl_17" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_19 == /\ pc = "Lbl_19" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2043, column 25.") - /\ pc' = "Lbl_21" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_8 == /\ pc = "Lbl_8" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1974, column 26.") - /\ pc' = "Lbl_10" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_9 == /\ pc = "Lbl_9" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 1977, column 33.") - /\ pc' = "Lbl_10" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_20 == /\ pc = "Lbl_20" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2046, column 9.") - /\ pc' = "Lbl_21" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_21 == /\ pc = "Lbl_21" - /\ prevMode' = "FindingOpName" - /\ pc' = "Lbl_69" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, idx, mode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_23 == /\ pc = "Lbl_23" - /\ curNode' = newNode - /\ IF expectedArity = 0 - THEN /\ IF Len(args[idx]) # curNode'.arity - THEN /\ PrintT("bad arity") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_24" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_25" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_28" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_25 == /\ pc = "Lbl_25" - /\ IF \E i \in 1..Len(args[idx]) : - Arity(Node[args[idx][i]]) # 0 - THEN /\ PrintT("Operator argument given to label") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_26" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_27" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_26 == /\ pc = "Lbl_26" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2068, column 20.") - /\ pc' = "Lbl_27" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_27 == /\ pc = "Lbl_27" - /\ allArgs' = allArgs \o args[idx] - /\ pc' = "Lbl_28" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - curNode, subExprOf, result, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_24 == /\ pc = "Lbl_24" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2064, column 20.") - /\ pc' = "Lbl_25" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_28 == /\ pc = "Lbl_28" - /\ params' = params \o curNode.params - /\ IF /\ idx < Len(ops) - /\ ~IsName(ops[idx+1]) - THEN /\ mode' = "FindingSubExpr" - ELSE /\ TRUE - /\ UNCHANGED mode - /\ IF \/ mode' = "FindingSubExpr" - \/ idx = Len(ops) - THEN /\ curNode' = Node[curNode.body] - ELSE /\ TRUE - /\ UNCHANGED curNode - /\ prevMode' = "FollowingLabels" - /\ pc' = "Lbl_69" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, allArgs, - subExprOf, result, idx, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, - opNode, newName, newNode, nodeArity, temp, tempArgs >> - -Lbl_22 == /\ pc = "Lbl_22" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2059, column 13.") - /\ pc' = "Lbl_23" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_63 == /\ pc = "Lbl_63" - /\ IF idx # Len(ops) - THEN /\ IF IsName(ops[idx+1]) - THEN /\ pc' = "Lbl_64" - /\ UNCHANGED idx - ELSE /\ IF ops[idx+1] = ":" - THEN /\ PrintT("!: should not follow an operand selector") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_66" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_67" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_67" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_64 == /\ pc = "Lbl_64" - /\ IF curNode.kind = LabelKind - THEN /\ curNode' = Node[curNode.body] - /\ pc' = "Lbl_64" - /\ UNCHANGED << idx, mode, curContext, firstFindingOpName >> - ELSE /\ IF curNode.kind = LetInKind - THEN /\ curContext' = curNode.context - /\ mode' = "FindingOpName" - /\ firstFindingOpName' = FALSE - /\ pc' = "Lbl_67" - /\ UNCHANGED idx - ELSE /\ PrintT("A name not following the selector of a LET") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_65" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - /\ UNCHANGED << mode, curContext, - firstFindingOpName >> - /\ UNCHANGED curNode - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, prevMode, curName, - opDefArityFound, opDefArgs, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_65 == /\ pc = "Lbl_65" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2294, column 26.") - /\ pc' = "Lbl_67" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_66 == /\ pc = "Lbl_66" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2297, column 26.") - /\ pc' = "Lbl_67" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_67 == /\ pc = "Lbl_67" - /\ prevMode' = "FindingSubExpr" - /\ pc' = "Lbl_69" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, idx, mode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_29 == /\ pc = "Lbl_29" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2091, column 14.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_30 == /\ pc = "Lbl_30" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2098, column 14.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_31 == /\ pc = "Lbl_31" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2110, column 17.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_33 == /\ pc = "Lbl_33" - /\ curNode' = Node[curNode.operands[temp]] - /\ IF \/ curNode'.kind # OpApplKind - \/ Node[curNode'.operator].kind # BuiltInKind - \/ Node[curNode'.operator].name # "$Pair" - THEN /\ PrintT("Expecting $Pair(...)") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_34" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_35" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_35 == /\ pc = "Lbl_35" - /\ curNode' = Node[curNode.operands[2]] - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_34 == /\ pc = "Lbl_34" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2131, column 18.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_32 == /\ pc = "Lbl_32" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2125, column 18.") - /\ pc' = "Lbl_33" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_37 == /\ pc = "Lbl_37" - /\ temp' = ArgNum( ops[idx], Len(curNode.operands)) - /\ IF temp' = -1 - THEN /\ PrintT("Incorrect subexpression name") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_38" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_39" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_38 == /\ pc = "Lbl_38" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2145, column 18.") - /\ pc' = "Lbl_39" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_39 == /\ pc = "Lbl_39" - /\ curNode' = Node[curNode.operands[temp]] - /\ IF \/ curNode'.kind # OpApplKind - \/ Node[curNode'.operator].kind # BuiltInKind - \/ Node[curNode'.operator].name # "$Pair" - THEN /\ PrintT("Expecting $Pair(...)") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_40" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_41" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_40 == /\ pc = "Lbl_40" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2151, column 18.") - /\ pc' = "Lbl_41" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_41 == /\ pc = "Lbl_41" - /\ idx' = idx+1 - /\ temp' = ArgNum(ops[idx'], 2) - /\ IF temp' = -1 - THEN /\ PrintT("Incorrect subexpression name") - /\ IF debug - THEN /\ pc' = "Lbl_42" - ELSE /\ pc' = "Done" - ELSE /\ pc' = "Lbl_44" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_42 == /\ pc = "Lbl_42" - /\ idx' = idx - /\ pc' = "Lbl_43" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_43 == /\ pc = "Lbl_43" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2156, column 18.") - /\ pc' = "Lbl_44" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_44 == /\ pc = "Lbl_44" - /\ curNode' = Node[curNode.operands[temp]] - /\ IF curNode' = null - THEN /\ PrintT("Selecting OTHER") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_45" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_45 == /\ pc = "Lbl_45" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2160, column 18.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_36 == /\ pc = "Lbl_36" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2141, column 18.") - /\ pc' = "Lbl_37" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_47 == /\ pc = "Lbl_47" - /\ curNode' = Node[curNode.operands[temp]] - /\ IF temp > 1 - THEN /\ IF \/ curNode'.kind # OpApplKind - \/ Node[curNode'.operator].kind # BuiltInKind - \/ Node[curNode'.operator].name # "$Pair" - THEN /\ PrintT("Unexpected expression node found.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_48" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_49" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_63" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_49 == /\ pc = "Lbl_49" - /\ curNode' = Node[curNode.operands[2]] - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_48 == /\ pc = "Lbl_48" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2179, column 26.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_46 == /\ pc = "Lbl_46" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2172, column 19.") - /\ pc' = "Lbl_47" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_51 == /\ pc = "Lbl_51" - /\ curNode' = Node[curNode.operands[temp]] - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_50 == /\ pc = "Lbl_50" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2195, column 25.") - /\ pc' = "Lbl_51" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_53 == /\ pc = "Lbl_53" - /\ curNode' = Node[curNode.operands[1]] - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_52 == /\ pc = "Lbl_52" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2220, column 32.") - /\ pc' = "Lbl_53" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_54 == /\ pc = "Lbl_54" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2225, column 32.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_55 == /\ pc = "Lbl_55" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2232, column 12.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_56 == /\ pc = "Lbl_56" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2240, column 18.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_57 == /\ pc = "Lbl_57" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2255, column 9.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_58 == /\ pc = "Lbl_58" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2257, column 9.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_59 == /\ pc = "Lbl_59" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2260, column 9.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_60 == /\ pc = "Lbl_60" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2267, column 7.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_61 == /\ pc = "Lbl_61" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2272, column 10.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_62 == /\ pc = "Lbl_62" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2281, column 8.") - /\ pc' = "Lbl_63" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_68 == /\ pc = "Lbl_68" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2303, column 8.") - /\ pc' = "Lbl_69" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_70 == /\ pc = "Lbl_70" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2311, column 10.") - /\ pc' = "Lbl_71" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_71 == /\ pc = "Lbl_71" - /\ IF expectedArity < 0 - THEN /\ IF \/ prevMode # "FindingOpName" - \/ curNode.kind \notin {UserDefinedOpKind, ThmOrAssumpDefKind} - THEN /\ PrintT("Should have selected a definition, but didn't.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_72" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_73" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_74" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_73 == /\ pc = "Lbl_73" - /\ result' = curNode - /\ pc' = "Finished" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_72 == /\ pc = "Lbl_72" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2317, column 17.") - /\ pc' = "Lbl_73" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_74 == /\ pc = "Lbl_74" - /\ IF expectedArity > 0 - THEN /\ temp' = (Len(params) + IF \/ prevMode = "FindingOpName" - \/ curNode.kind = OpArgKind - THEN Arity(curNode) - ELSE 0) - /\ IF expectedArity # temp' - THEN /\ PrintT("Expect arity = " \o ToString(expectedArity) - \o ", but found arity = " \o ToString(temp')) - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_75" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_76" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_76" - /\ UNCHANGED << idx, temp >> - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_75 == /\ pc = "Lbl_75" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2329, column 18.") - /\ pc' = "Lbl_76" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_76 == /\ pc = "Lbl_76" - /\ IF /\ prevMode = "FindingOpName" - /\ Len(params) + Len(substInPrefix) > 0 - THEN /\ temp' = [i \in 1..Len(curNode.params) |-> - [curNode.params[i] EXCEPT !.name = "New " \o @]] - /\ curNode' = [kind |-> OpApplKind, - operands |-> temp', - operator |-> curNode, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] - /\ params' = params \o temp' - /\ allArgs' = allArgs \o opDefArgs - ELSE /\ TRUE - /\ UNCHANGED << params, allArgs, curNode, temp >> - /\ IF curNode'.kind = OpArgKind - THEN /\ IF expectedArity = 0 - THEN /\ PrintT("Selected Operator Argument when expression expected.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_77" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ IF expectedArity # Len(params') + curNode'.arity - THEN /\ PrintT("Selected operator has wrong arity.") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_78" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ IF Len(params') + Len(substInPrefix) > 0 - THEN /\ pc' = "Lbl_79" - ELSE /\ pc' = "Lbl_80" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_80" - /\ UNCHANGED idx - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, subExprOf, - result, mode, prevMode, curContext, curName, - opDefArityFound, opDefArgs, firstFindingOpName, - opNode, newName, newNode, nodeArity, tempArgs >> - -Lbl_77 == /\ pc = "Lbl_77" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2363, column 12.") - /\ pc' = "Lbl_80" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_78 == /\ pc = "Lbl_78" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2365, column 12.") - /\ pc' = "Lbl_80" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_79 == /\ pc = "Lbl_79" - /\ temp' = [i \in 1..curNode.arity |-> - [name |-> "NewParam" \o NumToString(i), - arity |-> 0]] - /\ curNode' = [kind |-> OpApplKind, - operands |-> temp', - operator |-> Node[curNode.op], - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>] - /\ params' = params \o temp' - /\ pc' = "Lbl_80" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, allArgs, - subExprOf, result, idx, mode, prevMode, curContext, - curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_80 == /\ pc = "Lbl_80" - /\ IF curNode.kind \in {UserDefinedOpKind, ConstantDeclKind, VariableDeclKind, - FormalParamKind, BuiltInKind, BoundSymbolKind, - ThmOrAssumpDefKind} - THEN /\ IF expectedArity > 0 - THEN /\ result' = [kind |-> OpArgKind, - name |-> curNode.name, - op |-> curNode, - arity |-> expectedArity] - ELSE /\ IF expectedArity = 0 - THEN /\ result' = [kind |-> OpApplKind, - operands |-> opDefArgs, - operator |-> curNode, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>, - subExprOf |-> subExprOf] - ELSE /\ TRUE - /\ UNCHANGED result - /\ pc' = "Finished" - /\ UNCHANGED temp - ELSE /\ IF curNode.kind = OpArgKind - THEN /\ result' = curNode - /\ pc' = "Finished" - /\ UNCHANGED temp - ELSE /\ temp' = Len(substInPrefix) - /\ pc' = "Lbl_81" - /\ UNCHANGED result - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_81 == /\ pc = "Lbl_81" - /\ IF temp > 0 - THEN /\ curNode' = [kind |-> SubstInKind, - body |-> curNode , - subst |-> substInPrefix[temp].subst ] - /\ temp' = temp - 1 - /\ pc' = "Lbl_81" - /\ UNCHANGED idx - ELSE /\ IF expectedArity > 0 - THEN /\ IF Len(params) # expectedArity - THEN /\ PrintT("Selection has wrong arity") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_82" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_83" - /\ UNCHANGED idx - ELSE /\ IF Len(params) # Len(allArgs) - THEN /\ PrintT("Abort: number of params # num of args") - /\ IF debug - THEN /\ idx' = idx - /\ pc' = "Lbl_84" - ELSE /\ pc' = "Done" - /\ UNCHANGED idx - ELSE /\ pc' = "Lbl_85" - /\ UNCHANGED idx - /\ UNCHANGED << curNode, temp >> - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, tempArgs >> - -Lbl_83 == /\ pc = "Lbl_83" - /\ result' = [kind |-> OpArgKind, - op |-> [kind |-> UserDefinedOpKind, - name |-> "LAMBDA", - body |-> curNode, - params |-> params, - arity |-> Len(params), - defined |-> TRUE, - source |-> null], - name |-> "LAMBDA"] - /\ pc' = "Finished" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_85 == /\ pc = "Lbl_85" - /\ IF Len(params) = 0 - THEN /\ result' = [kind |-> LabelKind, - name |-> "$Subexpression", - arity |-> 0, - params |-> << >>, - body |-> curNode, - subExprOf |-> subExprOf] - ELSE /\ result' = [kind |-> OpApplKind, - operator |-> [kind |-> UserDefinedOpKind, - name |-> "LAMBDA", - body |-> curNode, - params |-> params, - arity |-> Len(params), - defined |-> TRUE, - source |-> null], - operands |-> allArgs, - unboundedBoundSymbols |-> <<>>, - boundedBoundSymbols |-> << >>, - ranges |-> << >>, - subExprOf |-> subExprOf] - /\ pc' = "Finished" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, idx, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_82 == /\ pc = "Lbl_82" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2431, column 22.") - /\ pc' = "Lbl_83" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Lbl_84 == /\ pc = "Lbl_84" - /\ idx' = idx - /\ Assert(FALSE, - "Failure of assertion at line line 1892, column 38 of macro called at line 2443, column 22.") - /\ pc' = "Lbl_85" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, mode, prevMode, - curContext, curName, opDefArityFound, opDefArgs, - firstFindingOpName, opNode, newName, newNode, - nodeArity, temp, tempArgs >> - -Finished == /\ pc = "Finished" - /\ PrintT("Result: ") - /\ PrintT(result) - /\ pc' = "Done" - /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, - allArgs, curNode, subExprOf, result, idx, mode, - prevMode, curContext, curName, opDefArityFound, - opDefArgs, firstFindingOpName, opNode, newName, - newNode, nodeArity, temp, tempArgs >> - -Next == Lbl_1 \/ Lbl_2 \/ Lbl_69 \/ Lbl_3 \/ Lbl_5 \/ Lbl_6 \/ Lbl_7 - \/ Lbl_4 \/ Lbl_10 \/ Lbl_12 \/ Lbl_13 \/ Lbl_11 \/ Lbl_14 \/ Lbl_15 - \/ Lbl_17 \/ Lbl_18 \/ Lbl_16 \/ Lbl_19 \/ Lbl_8 \/ Lbl_9 \/ Lbl_20 - \/ Lbl_21 \/ Lbl_23 \/ Lbl_25 \/ Lbl_26 \/ Lbl_27 \/ Lbl_24 \/ Lbl_28 - \/ Lbl_22 \/ Lbl_63 \/ Lbl_64 \/ Lbl_65 \/ Lbl_66 \/ Lbl_67 \/ Lbl_29 - \/ Lbl_30 \/ Lbl_31 \/ Lbl_33 \/ Lbl_35 \/ Lbl_34 \/ Lbl_32 \/ Lbl_37 - \/ Lbl_38 \/ Lbl_39 \/ Lbl_40 \/ Lbl_41 \/ Lbl_42 \/ Lbl_43 \/ Lbl_44 - \/ Lbl_45 \/ Lbl_36 \/ Lbl_47 \/ Lbl_49 \/ Lbl_48 \/ Lbl_46 \/ Lbl_51 - \/ Lbl_50 \/ Lbl_53 \/ Lbl_52 \/ Lbl_54 \/ Lbl_55 \/ Lbl_56 \/ Lbl_57 - \/ Lbl_58 \/ Lbl_59 \/ Lbl_60 \/ Lbl_61 \/ Lbl_62 \/ Lbl_68 \/ Lbl_70 - \/ Lbl_71 \/ Lbl_73 \/ Lbl_72 \/ Lbl_74 \/ Lbl_75 \/ Lbl_76 \/ Lbl_77 - \/ Lbl_78 \/ Lbl_79 \/ Lbl_80 \/ Lbl_81 \/ Lbl_83 \/ Lbl_85 \/ Lbl_82 - \/ Lbl_84 \/ Finished - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) - -Spec == Init /\ [][Next]_vars - -Termination == <>(pc = "Done") - -\* END TRANSLATION - -NotDone == pc # "Done" - (*************************************************************************) - (* To print a trace of an execution that doesn't produce an error, add *) - (* "INVARIANT NotDone" to Subexpression.cfg . *) - (*************************************************************************) -============================================================================= - - -************************* end file Subexpression.tla ****************************/ - +} + +/************************ + * file Tarjan.tla *********************************** + * ------------------------------ MODULE Tarjan -------------------------------- + * (***************************************************************************) + * (* This version of Tarjan's algorithm for computing the strongly *) (* + * connected components of a directed graph was adapted from the version *) (* + * of 27 Mar 2007 on the Wikipedia page *) (* *) (* + * http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm + * *) (* *) (* One modification is that the set of connected components it + * returns *) (* does not contain a singleton {n} unless n has an edge pointing + * to *) (* itself. *) (* *) (* This is an implementation of the algorithm in + * Tarjan.tla with data *) (* structures that correspond to the ones used in the + * algorithm for *) (* constructing dependency components in semantic/Generator. + * *) (* *) (* *) (* I have not rigorously verified this algorithm, but I think + * I understand *) (* why it works. I have tested it only on the 10 graphs at + * the end of *) (* this file. *) + * (***************************************************************************) + * + * EXTENDS Integers, Sequences, TLC + * + * CONSTANT N, \* The number of nodes Neighbors \* A sequence of edges. + * + * Node == 1..N + * + * ASSUME Neighbors \in Seq(Node \X Node) + * + * Min(a, b) == IF a < b THEN a ELSE b + * + * Front(s) == [i \in 1 .. (Len(s)-1) |-> s[i]] + * (*************************************************************************) + * (* The sequence obtained from a sequence s by deleting the last item. *) + * (*************************************************************************) + * + * Last(s) == s[Len(s)] + * (*************************************************************************) + * (* The last item in the sequence s. *) + * (*************************************************************************) + * + * (***************************************************************************) + * (* I believe the algorithm works because it maintains the following *) (* + * invariants (at reasonable points in the code). We say that node *) (* + * nstack[i] precedes nstack[j] iff i < j. *) (* *) (* - A node n is in nstack + * iff n.dfs \geq 0 *) (* *) (* - For all nodes n # m in nstack, if n precedes m + * then: *) (* /\ n.dfs < m.dfs. *) (* /\ there is a path from n to m in the + * graph. *) (* *) (* - For every node n in nstack, *) (* /\ n.lowlink \leq + * n.dfs and *) (* /\ there is a node m in nstack such that *) (* 1. n.lowlink = + * m.dfs. *) (* 2. if m # n then there is a path from n to m in the graph. *) (* + * /\ For every node m in the same connected component as n: *) (* m.examined = + * TRUE implies m is in nstack *) + * (***************************************************************************) + * + * (************************* --algorithm Tarjan2 variables nstack = << >> ; + * (***************************************************************) (* The + * stack of nodes, where nstack[1] is the bottom of the *) (* stack. *) + * (***************************************************************) max_dfs = 0 + * ; (***************************************************************) (* + * Incremented by 1 every time a new element is added to the *) (* stack. *) + * (***************************************************************) + * + * data = [nd \in Node |-> [lowlink |-> -1, dfs |-> -1, examined |-> FALSE, nbrs + * |-> << >>, (*****************************************) (* A sequence of nodes + * to which there *) (* are edges from this node. The *) (* same node may appear + * multiple *) (* times. *) (*****************************************) nxtDep + * |-> -1 ]] ; (***************************************************************) + * (* The information maintained for the nodes. Note that *) (* *) (* - Node nd + * is on nstack iff data[nd].dfs \geq 0, in *) (* which case nstack[data[nd].dfs + * + 1] = nd. *) (* *) (* - nbrs is set from Neighbors by the initialization + * code. *) (* *) (* - nxtDep represents the nextDependency field of the *) (* + * OpDefNode object, where a value of -1 represents *) (* null. Following nxtDep + * pointers leads in a cycle of *) (* the node's connected component. See the + * comments on *) (* the nextDependency field in semantic/OpDefNode. *) + * (***************************************************************) + * + * idx ; \* A counter variable. + * + * procedure tarjan(n) variable nxt ; \* A counter variable nxtnbr ; \* An + * abbreviation + * + * begin data[n].lowlink := max_dfs || data[n].dfs := max_dfs || + * data[n].examined := TRUE ; max_dfs := max_dfs + 1; nstack := Append(nstack, + * n) ; nxt := 1 ; while nxt \leq Len(data[n].nbrs) do nxtnbr := + * data[n].nbrs[nxt] ; if ~ data[nxtnbr].examined then + * (***************************************************************) (* nxtnbr + * is unexamined *) + * (***************************************************************) call + * tarjan(nxtnbr) ; data[n].lowlink := Min(data[n].lowlink, + * data[nxtnbr].lowlink) ; + * + * elsif data[nxtnbr].dfs \geq 0 then + * (**********************************************************) (* nxtnbr is in + * nstack *) (**********************************************************) + * data[n].lowlink := Min(data[n].lowlink, data[nxtnbr].dfs) ; end if ; nxt := + * nxt + 1; end while ; if data[n].lowlink = data[n].dfs then + * (*****************************************************************) (* The + * set of all nodes on nstack from n to the end form a *) (* connected + * component. *) + * (*****************************************************************) nxtnbr := + * Last(nstack) ; \* save last node on stack. while n # Last(nstack) do + * data[Last(nstack)].nxtDep := nstack[Len(nstack)-1] || data[Last(nstack)].dfs + * := -1 ; (*************************************************************) (* + * Make nxtDep field of last node on stack point to next to *) (* last node. *) + * (*************************************************************) nstack := + * Front(nstack) ; end while ; if \/ n # nxtnbr \/ \E i \in 1..Len(data[n].nbrs) + * : n = data[n].nbrs[i] then + * (**********************************************************) (* Form a + * connected component consisting of just n only *) (* if n is a neighbor of + * itself. *) (**********************************************************) + * data[n].nxtDep := nxtnbr; end if; data[n].dfs := -1 ; nstack := Front(nstack) + * ; end if ; data[n].nbrs := << >> ; + * (**********************************************************************) (* + * Can garbage collect the sequence of neighbors. *) + * (**********************************************************************) + * return ; end procedure + * + * begin + * (************************************************************************) (* + * Initialize the nbrs field of data elements from Neighbors. *) + * (************************************************************************) + * idx := 1 ; while idx \leq Len(Neighbors) do with edge = Neighbors[idx] do + * data[edge[1]].nbrs := Append(data[edge[1]].nbrs, edge[2]) ; end with ; idx := + * idx + 1; end while ; + * + * (************************************************************************) (* + * while there is an unexamined node, call tarjan(nd) *) (* for any unexamined + * node nd. *) + * (************************************************************************) + * idx := 1 ; while idx \leq N do if data[idx].lowlink < 0 then + * (***************************************************************) (* idx is + * unexamined *) + * (***************************************************************) call + * tarjan(idx) ; end if; idx := idx + 1 ; end while ; + * + * (************************************************************************) (* + * print result. *) + * (************************************************************************) + * idx := 1 ; while idx \leq N do if data[idx].nxtDep \geq 0 then print <<idx, + * "->", data[idx].nxtDep>> end if ; idx := idx+1; end while end algorithm ) + * + * \* BEGIN TRANSLATION \* END TRANSLATION + * + * \**** Test data + * + * Node1 == {1, 2, 3, 4} + * + * Nbrs1 == << <<1, 2>>, \* components 1 and 3,4 <<1, 2>>, \* components 1 and + * 3,4 <<1, 1>>, <<1, 1>>, <<3, 4>> , <<3, 4>> , <<4, 3>> , <<4, 3>>, <<4, 3>> + * >> + * + * Nbrs2 == << <<1, 2>>, \* components 1 and 3,4 <<1, 1>>, <<1, 3>>, <<3, 4>>, + * <<4, 3>> >> Nbrs3 == << <<1, 2>>, \* components 1 and 3,4 <<1, 1>>, <<3, 1>>, + * <<3, 4>>, <<4, 3>> >> Nbrs4 == << <<1, 3>>, \* <<1, 8>>, \* componetns: + * 2,3,4,5 and 7,8,9 <<1, 9>>, <<1, 9>>, <<1, 9>>, <<3, 2>>, <<3, 2>>, <<2, 4>>, + * <<4, 5>>, <<4, 10>>, <<5, 3>>, <<8, 7>>, <<8, 7>>, <<9, 8>>, <<7, 9>>, <<7, + * 9>>, <<9, 10>>, <<9, 10>>, <<9, 10>> >> + * + * Nbrs5 == << <<1, 8>>, \* components 7,8,9 <<1, 9>>, <<4, 10>>, <<8, 7>>, <<9, + * 8>>, <<7, 9>>, <<9, 10>> >> + * + * Nbrs6 == << <<6, 4>>, \* components 2,3,4,5 <<3, 4>>, <<4, 5>>, <<5, 2>>, + * <<2, 3>>, <<5, 1>>, <<2, 1>> >> + * + * Nbrs7 == << <<1, 7>>, \* 1 component with 1..9 \ {3} <<1, 9>>, <<2, 1>>, <<3, + * 2>>, <<3, 6>>, <<4, 6>>, <<5, 2>>, <<6, 5>>, <<6, 8>>, <<7, 5>>, <<7, 8>>, + * <<8, 4>>, <<8, 10>>, <<9, 7>>, <<9, 10>> >> Nbrs8 == << <<1, 7>>, \* 1 + * component with 1..8 \ {3} <<2, 1>>, <<3, 2>>, <<3, 2>>, <<3, 2>>, <<3, 6>>, + * <<4, 6>>, <<5, 2>>, <<6, 5>>, <<6, 8>>, <<6, 8>>, <<6, 8>>, <<7, 5>>, <<7, + * 8>>, <<8, 4>>, <<8, 10>>, <<9, 7>>, <<9, 10>> >> Nbrs9 == << \* 4,6, 7,8,9,10 + * <<2, 1>>, <<3, 2>>, <<3, 6>>, <<4, 6>>, <<4, 6>>, <<4, 6>>, <<5, 2>>, <<6, + * 5>>, <<6, 8>>, <<7, 5>>, <<7, 5>>, <<7, 5>>, <<7, 5>>, <<7, 8>>, <<8, 4>>, + * <<8, 10>>, <<9, 7>>, <<10, 9>> >> Nbrs == << \* 1, 3, 4, 5 and 6 <<1, 4>>, + * <<2, 1>>, <<2, 3>>, <<2, 3>>, <<2, 3>>, <<2, 5>>, <<3, 4>>, <<4, 1>>, <<4, + * 5>>, <<4, 5>>, <<4, 5>>, <<5, 3>>, <<6, 5>>, <<6, 6>> >> + * + * ============================================================================= + ************************** + * end file Tarjan.tla + ******************************/ + +/************************* + * file Subexpression.tla ********************** last modified on Fri 13 + * November 2009 at 14:11:05 PST by lamport ------------------------ MODULE + * Subexpression --------------------------- + * + * + * (***************************************************************************) + * (* NAMING *) (* *) (* There are four kinds of Nameable Objects: *) (* - + * Expressions *) (* - Operators that take an argument *) (* (and that can + * appear as operator arguments) *) (* - Operator definitions (named in + * BY/USE/HIDE statements) *) (* - ASSUME/PROVEs. *) (* *) (* There are three + * relevant kinds of primitive names that appear in a *) (* TLA+ module. *) (* + * *) (* Defined Module Name (ModuleName): *) (* It appears to the left of "== + * INSTANCE...". It may or may not *) (* contain arguments. *) (* Primitive + * Operator Name (PrimOpName): *) (* It appear to the left of the "==" in a + * definition, theorem *) (* or assumption. It may or may not contain arguments. + * *) (* Label: *) (* It appears before a "::" in an expression. *) (* *) (* + * Examples of possible primitive names are "Foo" and "Bar(x+1, 42)". *) (* *) + * (* The Built-In Operator names (like "SUBSET") will not be considered to *) + * (* be primitive names in the following. *) (* *) (* To these explicit names + * we add the following Operand Selector (OpSel) *) (* names: *) (* - numbers, + * *) (* - "<<", ">>", *) (* - Things of the form (exp_1, ... , exp_n) where the + * exp_i are *) (* expressions or operator arguments and n > 0. *) (* - "@", *) + * (* *) (* A Compound Name is a sequence of primitive names, operand selectors, + * *) (* and ":"s separated by "!"s. *) (* *) (* In TLA+1, the general way of + * naming a non-built-in operator is with *) (* what I will call an Elementary + * Operator Name (ElemOpName) which has *) (* the following syntax. For + * simplicity, I will ignore the "!"s in the *) (* `formal' syntax. *) (* *) (* + * ElemOpName ::= (ModuleName)* PrimOpName *) (* *) (* We consider this to name + * both the operator and its definition (the *) (* expression to the right of + * the "=="). How the two meanings are *) (* disambiguated will be explained + * below. *) (* *) (* If EON is an ElemOpName and Lab_1, ... , Lab_n are a + * sequence of *) (* label names, then EON ! Lab_1 ! ... ! Lab_N names the + * expression *) (* labeled by Lab_N, where each Lab_(i+1) must be the name of a + * labeled *) (* expression within the expression labeled by Lab_i with no + * labels *) (* between Lab_i and Lab_(i+1). Thus a name described by *) (* *) + * (* ElemOpName (Label)* *) (* *) (* describes an operator definition or a + * labeled expression. To such a *) (* name, we can append a sequence of + * OperandSelectors. By rules *) (* described later, the resulting name selects + * a subexpression (or *) (* ASSUME/PROVE node) or Operator (appearing as an + * operator argument) *) (* from the body of the operator definition or labeled + * expression. If *) (* the labeled expression is a LET/IN, then to this name + * can be appended *) (* an ElemOpName defined in the LET part, and the naming + * process can then *) (* be iterated. The full syntax of a General Name is: *) + * (* *) (* OperatorName ::= ElemOpName *) (* | ElemOpName (Label)* ((OpSel)+ | + * ":") ElemOpName *) (* *) (* GeneralName ::= OperatorName (":" | (Label)* + * (OpSeq)* ) *) (* *) (* Note that ":" is used in two ways: *) (* *) (* - An + * OperatorName not followed by ":" names the operator; one *) (* followed by + * ":" names the operator's definition. *) (* - Suppose a general name GN ending + * in a label names a LET/IN *) (* expression and EON is an ElemOpName. Then GN + * !: !EON names *) (* an operator defined in the LET. The general name GN ! Foo + * would *) (* name an expression labeled by Foo inside the IN clause. *) + * (***************************************************************************) + * + * + * (***************************************************************************) + * (* This +cal program describes an algorithm used in generating the *) (* + * semantic tree for a parse tree consisting of a GeneralId node or an *) (* + * OpApplication node whose first child is a GeneralId node. Two examples *) (* + * are *) (* *) (* Foo(x)!Bar!<<!(a,b)!G *) (* Foo(x)!Bar!<<!(a,b)!G(c) *) (* *) + * (* We assume that these are processed to yield two sequences of nodes: *) (* + * op and args. The sequences for the first are *) (* *) (* op = << "Foo", + * "Bar", "<<", "null", "G" >> *) (* args = << <<x>>, << >>, << >>, <<a, b>>, + * <<>> >> *) (* *) (* and for the second are *) (* *) (* op = << "Foo", "Bar", + * "<<", "null", "G" >> *) (* args = << <<x>>, << >>, << >>, <<a, b>>, <<c>> >> + * *) (* *) (* where each symbol in args represents the semantic node produced + * by that *) (* symbol. *) (* *) (* The other input to the algortithm is an + * integer expectedArity. There *) (* are three cases: *) (* *) (* expectedArity + * = 0 : *) (* The parser is expecting an expression. This is the case *) (* + * when the expression occurs in the first part of a USE *) (* or HIDE + * statement. *) (* *) (* expectedArity > 0 : The parser is expecting an + * operator *) (* argument of this arity. *) (* *) (* expectedArity = -1 : *) (* + * The parser is expecting the name of a definition. This is *) (* the case when + * the expression occurs in the DEF clause of a USE *) (* or HIDE or BY + * statement. *) (* *) (* If expectedArity # 0, then args equals a sequence each + * of whose *) (* element is the empty sequence. *) + * (***************************************************************************) + * + * (***************************************************************************) + * (* Note: This spec is assuming that proof-step numbers are treated like *) (* + * operator names. That is, a step *) (* *) (* <3>2. foo > bar *) (* *) (* will + * be represented by a ThmOrAssumpDefKind node just as if it were *) (* *) (* + * THEOREM <3>2 == foo > bar *) (* *) (* If this is not the case, then + * additional code needs to be added to deal *) (* with numbered steps. But + * however it is handled, the "<3>2" will be a *) (* name in the current symbol + * table. *) + * (***************************************************************************) + * + * EXTENDS Integers, Sequences, TLC + * + * (***************************************************************************) + * (* SeqSeqToSeq(ss) is defined to be the concatenation of the sequences *) (* + * that are the elements of the sequence ss. *) + * (***************************************************************************) + * RECURSIVE SeqSeqToSeq(_) SeqSeqToSeq(ss) == IF ss = << >> THEN << >> ELSE + * Head(ss) \o SeqSeqToSeq(Tail(ss)) + * + * (***************************************************************************) + * (* These are kinds of semantic nodes that can be encountered by the *) (* + * algorithm. See tlasany/sematic/ASTConstants.java. *) + * (***************************************************************************) + * ConstantDeclKind == "ConstantDecl" VariableDeclKind == "VariableDecl" + * BoundSymbolKind == "BoundSymbol" UserDefinedOpKind == "UserDefinedOp" + * ModuleInstanceKind == "ModuleInstance" BuiltInKind == "BuiltIn" OpArgKind == + * "OpArg" OpApplKind == "OpAppl" LetInKind == "LetIn" FormalParamKind == + * "FormalParam" TheoremKind == "Theorem" SubstInKind == "SubstIn" + * AssumeProveKind == "AssumeProve" ProofKind == "Proof" NumeralKind == + * "Numeral" DecimalKind == "Decimal" StringKind == "String" AtNodeKind == + * "AtNode" AssumeKind == "Assume" InstanceKind == "Instance" ThmOrAssumpDefKind + * == "ThmOrAssumpDef" LabelKind == "Label" APSubstInKind == "APSubstIn" + * + * CONSTANT NodeId, \* The set of all node identifiers. Node, \* A mapping from + * NodeId to nodes (which are records). GlobalContext, \* The initial context. + * null, \* A special value not equal to anything else. debug \* Setting to TRUE + * causes TLC to print a trace if the \* algorithm reports an error. + * + * (***************************************************************************) + * (* CONTEXTS *) (* *) (* A context is a mapping from names to NodeIds. There + * are actually three *) (* different kinds of mappings from names to nodes in + * the implementation *) (* that are all represented here as contexts: *) (* - + * The symbolTable of the Generator. *) (* - The context field of a LetInNode *) + * (* - The labels field of a LabelNode *) + * (***************************************************************************) + * IsContext(C) == + * (*************************************************************************) + * (* True iff C is a context. *) + * (*************************************************************************) + * /\ DOMAIN C \subseteq STRING /\ \A str \in DOMAIN C : C[str] \in NodeId + * + * LookUp(nm, ctxt) == + * (*************************************************************************) + * (* The value assigned to name nm by context cxt, or null if there is no *) (* + * value assigned. *) + * (*************************************************************************) + * IF nm \in DOMAIN ctxt THEN Node[ctxt[nm]] ELSE null + * + * Param == [name : STRING, arity : Nat] + * (*************************************************************************) + * (* The set of parameters, which can appear in operator definitions. *) + * (*************************************************************************) + * + * (***************************************************************************) + * (* For simplicity, we assume that argument numbers range from 1 to 9, and *) + * (* we define the following mappings from to and from argument numbers to *) + * (* their string representations. *) + * (***************************************************************************) + * NumberOp == {"1", "2", "3", "4", "5", "6", "7", "8", "9"} NumericVal(numOp) + * == CASE numOp = "1" -> 1 [] numOp = "2" -> 2 [] numOp = "3" -> 3 [] numOp = + * "4" -> 4 [] numOp = "5" -> 5 [] numOp = "6" -> 6 [] numOp = "7" -> 7 [] numOp + * = "8" -> 8 [] numOp = "9" -> 9 + * + * NumToString(num) == CASE num = 1 -> "1" [] num = 2 -> "2" [] num = 3 -> "3" + * [] num = 4 -> "4" [] num = 5 -> "5" [] num = 6 -> "6" [] num = 7 -> "7" [] + * num = 8 -> "8" [] num = 9 -> "9" + * + * IsName(op) == + * (*************************************************************************) + * (* A name is something other than an argument selector that can appear *) (* + * in a compound name. *) + * (*************************************************************************) + * op \in STRING \ ({"<<", ">>", "@", ":", "null"} \cup NumberOp) + * + * + * ArgNum(op, arity) == + * (*************************************************************************) + * (* The argument number chosen by argument selector op for an operator *) (* + * application with arity arguments. It equals -1 if op is not a legal *) (* + * argument selector for this arity. *) + * (*************************************************************************) + * CASE op \in NumberOp -> IF NumericVal(op) <= arity THEN NumericVal(op) ELSE + * -1 [] op = "<<" -> IF arity > 0 THEN 1 ELSE -1 [] op = ">>" -> CASE arity = 1 + * -> 1 [] arity = 2 -> 2 [] OTHER -> -1 [] OTHER -> -1 + * + * Arity(node) == + * (*************************************************************************) + * (* The arity of a node--that is, the number of arguments it takes. *) + * (*************************************************************************) + * IF node.kind \in {UserDefinedOpKind, BuiltInKind, ModuleInstanceKind, + * ThmOrAssumpDefKind, OpArgKind, LabelKind, ConstantDeclKind, FormalParamKind} + * THEN node.arity ELSE 0 + * + * ParamArity(node, i) == + * (*************************************************************************) + * (* The arity of the i-th parameter of the node of kind *) (* + * UserDefinedOpKind, ThmOrAssumpDefKind, ModuleInstanceKind, *) (* + * ConstantDeclKind, or FormalParamKind *) + * (*************************************************************************) + * IF node.kind \in {ConstantDeclKind, FormalParamKind} THEN 0 ELSE + * node.params[i].arity + * ----------------------------------------------------------------------------- + * + * (***************************************************************************) + * (* The following assumptions define the data types--in particular, the *) (* + * record components that each node type must contain. *) + * (***************************************************************************) + * ASSUME IsContext(GlobalContext) + * + * ASSUME DOMAIN Node = NodeId + * + * ASSUME /\ \A id \in NodeId : LET node == Node[id] IN /\ node.kind \in + * {ConstantDeclKind, VariableDeclKind, BoundSymbolKind, UserDefinedOpKind, + * ModuleInstanceKind, BuiltInKind, OpArgKind, OpApplKind, LetInKind, + * FormalParamKind, TheoremKind, SubstInKind, AssumeProveKind, ProofKind, + * NumeralKind, DecimalKind, StringKind, AtNodeKind, AssumeKind, InstanceKind, + * ThmOrAssumpDefKind, LabelKind, APSubstInKind} + * + * ASSUME /\ \A id \in NodeId : LET node == Node[id] IN /\ node.kind \in + * {UserDefinedOpKind, BuiltInKind, ModuleInstanceKind, ThmOrAssumpDefKind, + * LabelKind, ConstantDeclKind, FormalParamKind} => /\ node.name \in STRING /\ + * node.arity \in Nat \cup {-1} /\ (node.arity = -1) => (node.kind = + * BuiltInKind) + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN node.kind \in + * {UserDefinedOpKind, ThmOrAssumpDefKind} => /\ node.body \in NodeId /\ + * IsContext(node.labels) /\ node.params \in Seq(Param) /\ Len(node.params) = + * node.arity /\ node.defined \in BOOLEAN /\ node.source \in {null} \cup NodeId + * \* The original definition (before instantiation) \* or null if this is it. + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = OpApplKind + * => /\ node.operands \in Seq(NodeId) /\ node.operator \in NodeId /\ + * node.unboundedBoundSymbols \in Seq(STRING) /\ node.boundedBoundSymbols \in + * Seq(Seq(STRING)) + * (**************************************************************) (* These are + * actually arrays and arrays of arrays of *) (* FormalParamNode objects + * (formerly OpDeclNode objects). *) + * (**************************************************************) /\ + * node.ranges \in Seq(NodeId) /\ Len(node.ranges) = + * Len(node.boundedBoundSymbols) + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = LetInKind => + * /\ node.body \in NodeId /\ IsContext(node.context) + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = OpArgKind => + * /\ node.op \in NodeId /\ IsName(node.name) /\ (node.arity \in Nat) /\ + * (node.arity > 0) + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = LabelKind => + * /\ node.body \in NodeId /\ IsContext(node.labels) /\ node.params \in + * Seq(Param) + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = SubstInKind + * => /\ node.body \in NodeId /\ node.subst \in STRING \* Just to identify it. + * + * ASSUME \A id \in NodeId : LET node == Node[id] IN /\ node.kind = + * AssumeProveKind => /\ node.assumes\in Seq(NodeId) /\ node.prove \in NodeId + * + * + * RECURSIVE ExpandNode(_) ExpandNode(node) == CASE node.kind \in + * {UserDefinedOpKind, LetInKind} -> [node EXCEPT !.body = ExpandNode(Node[@])] + * [] node.kind = OpApplKind -> [node EXCEPT !.operands = [i \in DOMAIN @ |-> + * ExpandNode(Node[@[i]])], !.operator = ExpandNode(Node[@]), !.ranges = [i \in + * DOMAIN @ |-> ExpandNode(Node[@[i]])]] [] OTHER -> node + * + * + * ----------------------------------------------------------------------------- + * (***************************************************************************) + * (* Test Data *) (* *) (* The algorithm has been tested on the following sets + * of data, where each *) (* operator MCxxx is either substituted for constant + * parameter xxx or is *) (* used as initial value of the algorithm's input + * variable xxx. *) + * (***************************************************************************) + * + * + * (***************************** + * + * + * (***************************************************************************) + * (* ------------------------ MODULE M ------------------------ *) (* CONSTANT + * C *) (* Op(Arg(_), p) == \A x \in {1,2}, <<y, z>> \in {3} : *) (* lab(x,y,z) + * :: LET a + b == <<Arg(a), b>> *) (* IN 1 + label2 :: p + C *) (* Foo(u) == + * "FooBody(u)" *) (* + * ============================================================= *) (* *) (* + * Inst(d) == INSTANCE M WITH C <- "expr(d)" *) + * (***************************************************************************) + * + * \* MCNode == \* 1 :> [kind |-> UserDefinedOpKind, \* Op(Arg(_), p) == ... \* + * name |-> "Op", \* body |-> 3, \* labels |-> "lab" :> 4, \* arity |-> 2, \* + * params |-> <<[name |-> "Arg", arity |-> 1], \* [name |-> "p", arity |-> 0]>>, + * \* defined |-> TRUE, \* source |-> null ] \* @@ \* 2 :> [kind |-> + * BuiltInKind, \* name |-> "$BoundedForall", \* arity |-> -1 \* ] \* @@ \* 3 :> + * [kind |-> OpApplKind, \* \A x \in {1,2}, <<y, z>> \in {3} : ... \* operands + * |-> << 4 >>, \* operator |-> 2, \* unboundedBoundSymbols |-> <<>>, \* + * boundedBoundSymbols |-> << <<"x">>, <<"y", "z">> >>, \* ranges |-> << 19, 21 + * >>] \* @@ \* 4 :> [kind |-> LabelKind, \* lab(x,y,z) :: LET a + b == + * <<Arg(a), b>> \* name |-> "lab", \* IN 1 + label2 :: p + C \* body |-> 5, \* + * arity |-> 3, \* params |-> <<[name |-> "x", arity |->0], \* [name |-> "y", + * arity |->0], \* [name |-> "z", arity |->0] >>, \* labels |-> "label2" :> 15 ] + * \* @@ \* 5 :> [kind |-> LetInKind, \* LET a + b == <<Arg(a), b>> \* context + * |-> "+" :> 6, \* IN 1 + label2 :: p + C \* body |-> 13 ] \* @@ \* 6 :> [kind + * |-> UserDefinedOpKind, \* a + b == <<Arg(a), b>> \* name |-> "+", \* body |-> + * 7, \* labels |-> << >>, \* arity |-> 2, \* params |-> <<[name |-> "a", arity + * |-> 0], \* [name |-> "b", arity |-> 0]>>, \* defined |-> TRUE, \* source |-> + * null ] \* @@ \* 7 :> [kind |-> OpApplKind, \* <<Arg(a), b>> \* operands |-> + * << 9, 12 >>, \* operator |-> 8, \* unboundedBoundSymbols |-> <<>>, \* + * boundedBoundSymbols |-> << >>, \* ranges |-> << >>] \* @@ \* 8 :> [kind |-> + * BuiltInKind, \* name |-> "$Tuple", \* arity |-> -1 \* ] \* @@ \* 9 :> [kind + * |-> OpApplKind, \* Arg(a) \* operands |-> <<11 >>, \* operator |-> 10, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 10 :> [kind |-> FormalParamKind, \* name |-> "Arg", \* + * arity |-> 1] \* \* @@ \* 11 :> [kind |-> FormalParamKind, \* name |-> "a", \* + * arity |-> 0] \* @@ \* 12 :> [kind |-> FormalParamKind, \* name |-> "b", \* + * arity |-> 0] \* @@ \* 13 :> [kind |-> OpApplKind, \* 1 + label2 :: p + C \* + * operands |-> <<14, 15>>, \* operator |-> 6, \* unboundedBoundSymbols |-> + * <<>>, \* boundedBoundSymbols |-> << >>, \* ranges |-> << >>] \* @@ \* 14 :> + * [kind |-> NumeralKind, \* val |-> 1] \* @@ \* 15 :> [kind |-> LabelKind, \* + * label2 :: p + C \* name |-> "label2", \* body |-> 16, \* arity |-> 0, \* + * params |-> <<>>, \* labels |-> << >>] \* @@ \* 16 :> [kind |-> OpApplKind, \* + * p + C \* operands |-> <<17, 18>>, \* operator |-> 6, \* unboundedBoundSymbols + * |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges |-> << >>] \* @@ \* 17 + * :> [kind |-> FormalParamKind, \* name |-> "p", \* arity |-> 0] \* @@ \* 18 :> + * [kind |-> ConstantDeclKind, \* name |-> "C", \* arity |-> 0 ] \* @@ \* 19 :> + * [kind |-> OpApplKind, \* {1,2} \* operands |-> << 14, 20 >>, \* operator |-> + * 8, \* Actually, specifying <<1, 2>> \* unboundedBoundSymbols |-> << >>, \* + * boundedBoundSymbols |-> << >>, \* ranges |-> << >>] \* @@ \* 20 :> [kind |-> + * NumeralKind, \* val |-> 2] \* @@ \* 21 :> [kind |-> OpApplKind, \* {1,2} \* + * operands |-> << 22>>, \* operator |-> 8, \* Actually, specifying <<1, 2>> \* + * unboundedBoundSymbols |-> << >>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 22 :> [kind |-> NumeralKind, \* val |-> 3] \* @@ \* 23 :> + * [kind |-> UserDefinedOpKind, \* Foo(u) == "FooBody(u)" \* name |-> "Foo", \* + * body |-> 24, \* labels |-> << >>, \* arity |-> 1, \* params |-> <<[name |-> + * "u", arity |-> 0]>>, \* defined |-> TRUE, \* source |-> null ] \* @@ \* 24 :> + * [kind |-> StringKind, \* val |-> "FooBody(u)"] \* @@ \* 25 :> [kind |-> + * StringKind, \* val |-> "string"] \* @@ \* 26 :> [kind |-> ModuleInstanceKind, + * \* Inst(d) == INSTANCE M WITH C <- "expr(d)" \* name |-> "Inst", \* arity |-> + * 1, \* params |-> <<[name |-> "d", arity |-> 0] >>, \* defined |-> TRUE ] + * \* @@ \* 27 :> [kind |-> SubstInKind, \* body |-> 24, \* subst |-> "expr(d)"] + * \* @@ \* 28 :> [kind |-> UserDefinedOpKind, \* Foo(u) == "FooBody(u)" \* name + * |-> "Inst!Foo", \* body |-> 27, \* labels |-> << >>, \* arity |-> 2, \* + * params |-> << [name |-> "d", arity |-> 0], \* [name |-> "u", arity |-> 0]>>, + * \* defined |-> TRUE, \* source |-> 23 ] \* @@ \* 29 :> [kind |-> + * UserDefinedOpKind, \* Op(Arg(_), p) == ... \* name |-> "Inst!Op", \* body |-> + * 30, \* labels |-> "lab" :> 4, \* arity |-> 3, \* params |-> <<[name |-> "d", + * arity |-> 0], \* [name |-> "Arg", arity |-> 1], \* [name |-> "p", arity |-> + * 0]>>, \* defined |-> TRUE, \* source |-> 1 ] \* @@ \* 30 :> [kind |-> + * SubstInKind, \* body |-> 3, \* subst |-> "expr(d)"] \* @@ \* 31 :> [kind |-> + * StringKind, \* val |-> "Argm"] \* \* MCNodeId == 1..31 \* \* MCGlobalContext + * == \* "Op" :> 1 \* @@ \* "Foo" :> 23 \* @@ \* "Inst" :> 26 \* @@ \* + * "Inst!Foo" :> 28 \* @@ \* "Inst!Op" :> 29 \* \* \* Foo("string") \* \* MCops + * == <<"Foo">> \* \* MCargs == << <<25>>>> \* \* MCexpectedArity == 0 \* \* \* + * Op(Foo, "string") \* \* MCops == <<"Op">> \* \* MCargs == << <<23, 25>> >> \* + * \* MCexpectedArity == 0 \* \* \* Op(Foo, "string")!lab(1,2,3) \* \* MCops == + * <<"Op", "lab">> \* \* MCargs == << <<23, 25>> , <<14, 20, 22 >> >> \* \* + * MCexpectedArity == 0 \* \* \* Op(Foo, "string")!lab(1,2,3)!<< \* \* MCops == + * <<"Op", "lab", "<<">> \* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> + * >> \* \* MCexpectedArity == 0 \* \* \* Op(Foo, "string")!lab(1,2,3)!<<!>> \* + * \* MCops == <<"Op", "lab", "<<", ">>">> \* \* MCargs == << <<23, 25>> , <<14, + * 20, 22>> , << >>, << >> >> \* \* MCexpectedArity == 0 \* \* \* Op(Foo, + * "string")!lab(1,2,3)!label2 \* \* MCops == <<"Op", "lab", "label2">> \* \* + * MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> >> \* \* MCexpectedArity == + * 0 \* \* \* Op(Foo, "string")!lab(1,2,3)!label2!<< \* \* MCops == <<"Op", + * "lab", "label2", "<<">> \* \* MCargs == << <<23, 25>> , <<14, 20, 22>> , << + * >>, << >> >> \* \* MCexpectedArity == 0 \* \* \* Op(Foo, + * "string")!lab(1,2,3)!:!+(3,2) \* \* MCops == <<"Op", "lab", ":", "+" >> \* \* + * MCargs == << <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 >> >> \* \* + * MCexpectedArity == 0 \* \* \* Op(Foo, "string")!lab(1,2,3)!:!+(3,2)!>> \* \* + * MCops == <<"Op", "lab", ":", "+", ">>" >> \* \* MCargs == << <<23, 25>> , + * <<14, 20, 22>> , << >> , <<22, 20 >>, << >> >> \* \* MCexpectedArity == 0 \* + * \* \* Op(Foo, "string")!(1,2,3) \* \* MCops == <<"Op", "null" >> \* \* MCargs + * == << <<23, 25>> , <<14, 20, 22>> >> \* \* MCexpectedArity == 0 \* \* \* + * Op(Foo, "string")!(1,2,3)!>>!>>!<< \* \* MCops == <<"Op", "null", ">>", ">>", + * "<<" >> \* \* MCargs == << <<23, 25>> , <<14, 20, 22>>, << >>, << >>, << >> + * >> \* \* MCexpectedArity == 0 \* \* \* Op(Foo, "string")!<<!>> \* \* MCops == + * <<"Op", "<<", ">>" >> \* \* MCargs == << <<23, 25>>, << >>, << >> >> \* \* + * MCexpectedArity == 0 \* \* \* Inst("Argm")!Foo("string") \* \* MCops == + * <<"Inst", "Foo">> \* \* MCargs == << <<31>>, <<25>>>> \* \* MCexpectedArity + * == 0 \* \* \* Inst("Argm")!Op(Foo, "string") \* \* MCops == <<"Inst", "Op">> + * \* \* MCargs == << <<31>>, <<23, 25>> >> \* \* MCexpectedArity == 0 \* \* \* + * Inst("Argm")!Op(Foo, "string")!lab(1,2,3) \* \* MCops == <<"Inst", "Op", + * "lab">> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22 >> >> \* \* + * MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!<< \* + * \* MCops == <<"Inst", "Op", "lab", "<<">> \* \* MCargs == << <<31>>, <<23, + * 25>> , <<14, 20, 22>> , << >> >> \* \* MCexpectedArity == 0 \* \* \* + * Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!<<!>> \* \* MCops == <<"Inst", + * "Op", "lab", "<<", ">>">> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, + * 22>> , << >>, << >> >> \* \* MCexpectedArity == 0 \* \* \* + * Inst("Argm")!Op(Foo, "string")!lab(1,2,3)!label2 \* \* MCops == <<"Inst", + * "Op", "lab", "label2">> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, + * 22>> , << >> >> \* \* MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, + * "string")!lab(1,2,3)!label2!<< \* \* MCops == <<"Inst", "Op", "lab", + * "label2", "<<">> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << + * >>, << >> >> \* \* MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, + * "string")!lab(1,2,3)!:!+(3,2) \* \* MCops == <<"Inst", "Op", "lab", ":", "+" + * >> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> , <<22, 20 + * >> >> \* \* MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, + * "string")!lab(1,2,3)!:!+(3,2)!>> \* \* MCops == <<"Inst", "Op", "lab", ":", + * "+", ">>" >> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> , << >> , + * <<22, 20 >>, << >> >> \* \* MCexpectedArity == 0 \* \* \* + * Inst("Argm")!Op(Foo, "string")!(1,2,3) \* \* MCops == <<"Inst", "Op", "null" + * >> \* \* MCargs == << <<31>>, <<23, 25>> , <<14, 20, 22>> >> \* \* + * MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, "string")!(1,2,3)!>>!>>!<< + * \* \* MCops == <<"Inst", "Op", "null", ">>", ">>", "<<" >> \* \* MCargs == << + * <<31>>, <<23, 25>> , <<14, 20, 22>>, << >>, << >>, << >> >> \* \* + * MCexpectedArity == 0 \* \* \* Inst("Argm")!Op(Foo, "string")!<<!>> \* \* + * MCops == <<"Inst", "Op", "<<", ">>" >> \* \* MCargs == << <<31>>, <<23, 25>>, + * << >>, << >> >> \* \* MCexpectedArity == 0 + ***************************************** + * ) + * + * (***************************************************************************) + * (* ------------------------ MODULE M ------------------------ *) (* CONSTANT + * C, Arg1(_) *) (* Op(Arg, p) == \A x \in {1,2}, <<y, z>> \in {3} : *) (* + * lab(x,y,z) :: LET a + b == <<Arg1(a), b>> *) (* IN 1 + label2 :: p + C *) (* + * Bar(AOp(_)) == AOp(1) *) (* Foo(u) == Bar(Arg1) *) (* Foo2 == Bar(LAMBDA m, n + * : <<m, n>>) *) (* THEOREM Thm == ASSUME Arg1(1) , Bar(Arg1) PROVE << C, + * Bar(Arg1)>> *) (* UU == lab:: C *) (* + * ============================================================= *) (* *) (* + * Foo3 == \A x : LET Bar3 == 1 IN 2 *) (* Inst(d) == INSTANCE M WITH C <- + * "expr(d)" *) + * (***************************************************************************) + * + * + * MCNode == 1 :> [kind |-> UserDefinedOpKind, \* Op(Arg, p) == ... name |-> + * "Op", body |-> 3, labels |-> "lab" :> 4, arity |-> 2, params |-> <<[name |-> + * "Arg", arity |-> 0], [name |-> "p", arity |-> 0]>>, defined |-> TRUE, source + * |-> null ] + * + * @@ 2 :> [kind |-> BuiltInKind, name |-> "$BoundedForall", arity |-> -1 ] @@ 3 + * :> [kind |-> OpApplKind, \* \A x \in {1,2}, <<y, z>> \in {3} : ... operands + * |-> << 4 >>, operator |-> 2, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << <<"x">>, <<"y", "z">> >>, ranges |-> << 19, 21 + * >>] @@ 4 :> [kind |-> LabelKind, \* lab(x,y,z) :: LET a + b == <<Arg(a), b>> + * name |-> "lab", \* IN 1 + label2 :: p + C body |-> 5, arity |-> 3, params |-> + * <<[name |-> "x", arity |->0], [name |-> "y", arity |->0], [name |-> "z", + * arity |->0] >>, labels |-> "label2" :> 15 ] @@ 5 :> [kind |-> LetInKind, \* + * LET a + b == <<Arg(a), b>> context |-> "+" :> 6, \* IN 1 + label2 :: p + C + * body |-> 13 ] @@ 6 :> [kind |-> UserDefinedOpKind, \* a + b == <<Arg(a), b>> + * name |-> "+", body |-> 7, labels |-> << >>, arity |-> 2, params |-> <<[name + * |-> "a", arity |-> 0], [name |-> "b", arity |-> 0]>>, defined |-> TRUE, + * source |-> null ] @@ 7 :> [kind |-> OpApplKind, \* <<Arg(a), b>> operands |-> + * << 9, 12 >>, operator |-> 8, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 8 :> [kind |-> + * BuiltInKind, name |-> "$Tuple", arity |-> -1 ] @@ 9 :> [kind |-> OpApplKind, + * \* Arg1(a) operands |-> <<11 >>, operator |-> 10, unboundedBoundSymbols |-> + * <<>>, boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 10 :> [kind |-> + * ConstantDeclKind, name |-> "Arg1", arity |-> 1] + * + * @@ 11 :> [kind |-> FormalParamKind, name |-> "a", arity |-> 0] @@ 12 :> [kind + * |-> FormalParamKind, name |-> "b", arity |-> 0] @@ 13 :> [kind |-> + * OpApplKind, \* 1 + label2 :: p + C operands |-> <<14, 15>>, operator |-> 6, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>] @@ 14 :> [kind |-> NumeralKind, val |-> 1] @@ 15 :> [kind |-> LabelKind, + * \* label2 :: p + C name |-> "label2", body |-> 16, arity |-> 0, params |-> + * <<>>, labels |-> << >>] @@ 16 :> [kind |-> OpApplKind, \* p + C operands |-> + * <<17, 18>>, operator |-> 6, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 17 :> [kind |-> + * FormalParamKind, name |-> "p", arity |-> 0] @@ 18 :> [kind |-> + * ConstantDeclKind, name |-> "C", arity |-> 0 ] @@ 19 :> [kind |-> OpApplKind, + * \* {1,2} operands |-> << 14, 20 >>, operator |-> 8, \* Actually, specifying + * <<1, 2>> unboundedBoundSymbols |-> << >>, boundedBoundSymbols |-> << >>, + * ranges |-> << >>] @@ 20 :> [kind |-> NumeralKind, val |-> 2] @@ 21 :> [kind + * |-> OpApplKind, \* {1,2} operands |-> << 22>>, operator |-> 8, \* Actually, + * specifying <<1, 2>> unboundedBoundSymbols |-> << >>, boundedBoundSymbols |-> + * << >>, ranges |-> << >>] @@ 22 :> [kind |-> NumeralKind, val |-> 3] @@ 23 :> + * [kind |-> UserDefinedOpKind, \* Foo(u) == Bar(Arg1) name |-> "Foo", body |-> + * 24, labels |-> << >>, arity |-> 1, params |-> <<[name |-> "u", arity |-> + * 0]>>, defined |-> TRUE, source |-> null ] @@ 24 :> [kind |-> OpApplKind, \* + * Bar(Arg1) operands |-> <<34>>, operator |-> 32, unboundedBoundSymbols |-> + * <<>>, boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 25 :> [kind |-> + * StringKind, val |-> "string"] @@ 26 :> [kind |-> ModuleInstanceKind, \* + * Inst(d) == INSTANCE M WITH C <- "expr(d)" name |-> "Inst", arity |-> 1, + * params |-> <<[name |-> "d", arity |-> 0] >>, defined |-> TRUE ] @@ 27 :> + * [kind |-> SubstInKind, body |-> 24, subst |-> "expr(d)"] @@ 28 :> [kind |-> + * UserDefinedOpKind, \* Foo(u) == "FooBody(u)" name |-> "Inst!Foo", body |-> + * 27, labels |-> << >>, arity |-> 2, params |-> << [name |-> "d", arity |-> 0], + * [name |-> "u", arity |-> 0]>>, defined |-> TRUE, source |-> 23 ] @@ 29 :> + * [kind |-> UserDefinedOpKind, \* Op(Arg, p) == ... name |-> "Inst!Op", body + * |-> 30, labels |-> "lab" :> 4, arity |-> 3, params |-> <<[name |-> "d", arity + * |-> 0], [name |-> "Arg", arity |-> 0], [name |-> "p", arity |-> 0]>>, defined + * |-> TRUE, source |-> 1 ] @@ 30 :> [kind |-> SubstInKind, body |-> 3, subst + * |-> "expr(d)"] @@ 31 :> [kind |-> StringKind, val |-> "Argm"] @@ 32 :> [kind + * |-> UserDefinedOpKind, \* Bar(AOp(_)) == AOp(1) name |-> "Bar", body |-> 33, + * labels |-> << >>, arity |-> 1, params |-> <<[name |-> "AOp", arity |-> 1]>>, + * defined |-> TRUE, source |-> null ] @@ 33 :> [kind |-> OpApplKind, \* Arg1(1) + * operands |-> <<14>>, operator |-> 10, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 34 :> [kind |-> + * OpArgKind, op |-> 10, arity |-> 1, name |-> "Arg1"] @@ 35 :> [kind |-> + * UserDefinedOpKind, \* Foo2 == Bar(LAMBDA m, n : <<m, n>>) name |-> "Foo2", + * body |-> 36, labels |-> << >>, arity |-> 0, params |-> <<>>, defined |-> + * TRUE, source |-> null ] @@ 36 :> [kind |-> OpApplKind, \* Bar(LAMBDA m, n : + * <<m, n>>) operands |-> <<41>>, operator |-> 32, unboundedBoundSymbols |-> + * <<>>, boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 37 :> [kind |-> + * UserDefinedOpKind, \* LAMBDA m, n : <<m, n>> name |-> "LAMBDA", body |-> 38, + * labels |-> << >>, arity |-> 2, params |-> <<[name |-> "m", arity |-> 0], + * [name |-> "n", arity |-> 0]>>, defined |-> TRUE, source |-> null ] @@ 38 :> + * [kind |-> OpApplKind, \* <<m, n>> operands |-> << 39, 40 >>, operator |-> 8, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>] @@ 39 :> [kind |-> FormalParamKind, name |-> "m", arity |-> 0] @@ 40 :> + * [kind |-> FormalParamKind, name |-> "n", arity |-> 0] @@ 41 :> [kind |-> + * OpArgKind, \* LAMBDA m, n : <<m, n>> op |-> 37, arity |-> 2, name |-> + * "LAMBDA"] @@ 42 :> [kind |-> UserDefinedOpKind, \* Inst!Foo2 == Bar(LAMBDA m, + * n : <<m, n>>) name |-> "Inst!Foo2", body |-> 43, labels |-> << >>, arity |-> + * 1, params |-> <<[name |-> "d", arity |-> 0]>>, defined |-> TRUE, source |-> + * 35 ] @@ 43 :> [kind |-> SubstInKind, body |-> 36, subst |-> "expr(d)"] @@ 44 + * :> [kind |-> ThmOrAssumpDefKind, \* Thm == ASSUME Arg1(1) ... name |-> "Thm", + * body |-> 45, labels |-> << >>, arity |-> 0, params |-> << >> , defined |-> + * TRUE, source |-> null ] @@ 45 :> [kind |-> AssumeProveKind, assumes |-> <<33, + * 24>>, prove |-> 46 ] @@ 46 :> [kind |-> OpApplKind, \* <<c, Bar(Arg1)>> + * operands |-> << 59, 24 >>, operator |-> 8, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 47 :> [kind |-> + * ThmOrAssumpDefKind, \* Thm == ASSUME Arg1(1) ... name |-> "Inst!Thm", body + * |-> 48, labels |-> << >>, arity |-> 1, params |-> << [name |-> "d", arity |-> + * 0]>> , defined |-> TRUE, source |-> 44 ] @@ 48 :> [kind |-> SubstInKind, body + * |-> 45, subst |-> "expr(d)"] @@ 49 :> [kind |-> UserDefinedOpKind, \* Foo3 == + * \A x : LET ... name |-> "Foo3", body |-> 51, labels |-> << >>, arity |-> 0, + * params |-> <<>>, defined |-> TRUE, source |-> null ] @@ 50 :> [kind |-> + * LetInKind, \* Foo3 == \A x : LET Bar3 == 1 IN 2 context |-> "Bar3" :> 53, + * body |-> 13 ] @@ 51 :> [kind |-> OpApplKind, \* \A x : LET Bar3 == 1 IN 2 + * operands |-> << 50 >>, operator |-> 52, unboundedBoundSymbols |-> <<"x">>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>] @@ 52 :> [kind |-> + * BuiltInKind, \* \A x : name |-> "$UnboundedForall", arity |-> -1] @@ 53 :> + * [kind |-> UserDefinedOpKind, \* Bar3 == 1 name |-> "Bar3", body |-> 14, + * labels |-> << >>, arity |-> 0, params |-> <<>>, defined |-> TRUE, source |-> + * null ] @@ 54 :> [kind |-> FormalParamKind, \* AOp name |-> "AOp", arity |-> + * 1] @@ 55 :> [kind |-> UserDefinedOpKind, \* Bar(AOp(_)) == AOp(1) name |-> + * "Inst!Bar", body |-> 56, labels |-> << >>, arity |-> 2, params |-> <<[name + * |-> "d", arity |-> 0], [name |-> "AOp", arity |-> 1]>>, defined |-> TRUE, + * source |-> null ] @@ 56 :> [kind |-> SubstInKind, body |-> 33, subst |-> + * "expr(d)"] @@ 57 :> [kind |-> UserDefinedOpKind, \* UU == lab:: C name |-> + * "UU", body |-> 58, labels |-> "lab":> 58, arity |-> 0, params |-> <<>>, + * defined |-> TRUE, source |-> null ] @@ 58 :> [kind |-> LabelKind, \* lab :: C + * name |-> "lab", body |-> 59, arity |-> 0, params |-> <<>>, labels |-> << >>] + * + * @@ 59 :> [kind |-> OpApplKind, \* C operands |-> <<>>, operator |-> 18, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>] @@ 60 :> [kind |-> UserDefinedOpKind, \* UU == lab:: C name |-> + * "Inst!UU", body |-> 58, labels |-> "lab":> 58, arity |-> 1, params |-> + * <<[name |-> "d", arity |-> 0] >>, defined |-> TRUE, source |-> null ] + * + * + * MCNodeId == 1..60 + * + * MCGlobalContext == "Op" :> 1 @@ "C" :> 18 @@ "UU" :> 57 @@ "Foo" :> 23 @@ + * "Inst" :> 26 @@ "Inst!Foo" :> 28 @@ "Inst!Bar" :> 55 @@ "Inst!Op" :> 29 @@ + * "Inst!UU" :> 60 @@ "Foo2" :> 35 @@ "Inst!Foo2" :> 42 @@ "Thm" :> 44 @@ + * "Inst!Thm" :> 47 @@ "Foo3" :> 49 @@ "Bar" :> 32 @@ "Arg1" :> 10 @@ "AOp" :> + * 54 @@ "p" :> 17 + * + * \* Foo \* MCops == <<"Foo">> \* MCargs == << << >> >> \* MCexpectedArity == 1 + * + * \* Op() \* MCops == <<"Op">> \* MCargs == << <<>> >> \* MCexpectedArity == 2 + * + * \* Op!lab \* MCops == <<"Op", "lab">> \* MCargs == << <<>> , <<>> >> \* + * MCexpectedArity == 5 + * + * \* Op!lab!<< \* MCops == <<"Op", "lab", "<<">> \* MCargs == << <<>> , <<>> , + * << >> >> \* MCexpectedArity == 5 + * + * \* Op!lab!<<!>> \* MCops == <<"Op", "lab", "<<", ">>">> \* MCargs == << << >> + * , << >> , << >>, << >> >> \* MCexpectedArity == 5 + * + * \* Op!lab!label2 \* MCops == <<"Op", "lab", "label2">> \* MCargs == << << >> + * , << >> , << >> >> \* MCexpectedArity == 5 + * + * \* Op!lab!label2!<< \* MCops == <<"Op", "lab", "label2", "<<">> \* MCargs == + * << << >> , << >> , << >>, << >> >> \* MCexpectedArity == 5 + * + * \* Op!lab!:!+ \* MCops == <<"Op", "lab", ":", "+" >> \* MCargs == << << >> , + * << >> , << >> , << >> >> \* MCexpectedArity == 7 + * + * \* Op!lab!:!+ \* MCops == <<"Op", "lab", ":", "+", ">>" >> \* MCargs == << << + * >> , << >> , << >> , << >>, << >> >> \* MCexpectedArity == 7 + * + * \* Op!@ \* MCops == <<"Op", "@" >> \* MCargs == << << >> , << >> >> \* + * MCexpectedArity == 5 + * + * \* Op!@!>>!>>!<< \* MCops == <<"Op", "@", ">>", ">>", "<<" >> \* MCargs == << + * << >> , << >>, << >>, << >>, << >> >> \* MCexpectedArity == 5 + * + * \* Op!<<!>> \* MCops == <<"Op", "<<", ">>" >> \* MCargs == << << >>, << >>, + * << >> >> \* MCexpectedArity == 2 + * + * \* Inst!Foo \* MCops == <<"Inst", "Foo">> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 2 + * + * \* Inst!Op \* MCops == <<"Inst", "Op">> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 3 + * + * \* Inst!Op!lab \* MCops == <<"Inst", "Op", "lab">> \* MCargs == << << >>, << + * >> , << >> >> \* MCexpectedArity == 6 + * + * \* Inst!Op!lab!<< \* MCops == <<"Inst", "Op", "lab", "<<">> \* MCargs == << + * << >>, << >> , << >> , << >> >> \* MCexpectedArity == 6 + * + * \* Inst!Op!lab!<<!>> \* MCops == <<"Inst", "Op", "lab", "<<", ">>">> \* + * MCargs == << << >>, << >> , << >> , << >>, << >> >> \* MCexpectedArity == 6 + * + * \* Inst!Op!lab!label2 \* MCops == <<"Inst", "Op", "lab", "label2">> \* MCargs + * == << << >>, << >> , << >> , << >> >> \* MCexpectedArity == 6 + * + * \* Inst!Op!lab!label2!<< \* MCops == <<"Inst", "Op", "lab", "label2", "<<">> + * \* MCargs == << << >>, << >> , << >> , << >>, << >> >> \* MCexpectedArity == + * 6 + * + * \* Inst!Op!lab!:!+ \* MCops == <<"Inst", "Op", "lab", ":", "+" >> \* MCargs + * == << << >>, << >> , << >> , << >> , << >> >> \* MCexpectedArity == 8 + * + * \* Inst!Op!lab!:!+!>> \* MCops == <<"Inst", "Op", "lab", ":", "+", ">>" >> \* + * MCargs == << << >>, << >> , << >> , << >> , << >>, << >> >> \* + * MCexpectedArity == 8 + * + * \* Inst!Op!@ \* MCops == <<"Inst", "Op", "@" >> \* MCargs == << << >>, << >> + * , << >> >> \* MCexpectedArity == 6 + * + * \* Inst!Op!@!>>!>>!<< \* MCops == <<"Inst", "Op", "@", ">>", ">>", "<<" >> \* + * MCargs == << << >>, << >> , << >>, << >>, << >>, << >> >> \* MCexpectedArity + * == 6 + * + * \* Inst!Op!<<!>> \* MCops == <<"Inst", "Op", "<<", ">>" >> \* MCargs == << << + * >>, << >>, << >>, << >> >> \* MCexpectedArity == 3 + * + * \* Foo!1 \* MCops == <<"Foo", "1">> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 2 + * + * \* Inst!Foo!1 \* MCops == <<"Inst", "Foo", "1">> \* MCargs == << << >>, << + * >>, << >> >> \* MCexpectedArity == 3 + * + * \* Foo2!1 \* MCops == <<"Foo2", "1">> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 2 + * + * \* Foo2!1!(1, 2) \* MCops == <<"Foo2", "1", "null">> \* MCargs == << << >>, + * << >>, <<14, 20>> >> \* MCexpectedArity == 0 + * + * \* Foo2!1!(1, 2)!2 \* MCops == <<"Foo2", "1", "null", "2">> \* MCargs == << + * << >>, << >>, <<14, 20>>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst!Foo2!1 \* MCops == <<"Inst", "Foo2", "1">> \* MCargs == << << >>, << + * >>, << >> >> \* MCexpectedArity == 3 + * + * \* Inst!Foo2!1 \* MCops == <<"Inst", "Foo2", "1", "@">> \* MCargs == << << + * >>, << >>, << >>, << >> >> \* MCexpectedArity == 3 + * + * \* Inst!Foo2!1!2 \* MCops == <<"Inst", "Foo2", "1", "@", "2">> \* MCargs == + * << << >>, << >>, << >>, << >>, << >> >> \* MCexpectedArity == 3 + * + * \* Inst("Argm")!Foo2!1!(1, 2) \* MCops == <<"Inst", "Foo2", "1", "null">> \* + * MCargs == << <<31>>, << >>, << >>, <<14, 20>> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Foo2!1!(1, 2)!2 \* MCops == <<"Inst", "Foo2", "1", "null", + * "2">> \* MCargs == << <<31>>, << >>, << >>, <<14, 20>>, << >> >> \* + * MCexpectedArity == 0 + * + * \* Thm!1 \* MCops == <<"Thm", "1" >> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 0 + * + * \* Thm!2 \* MCops == <<"Thm", "2" >> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 0 + * + * \* Thm!3!<< \* MCops == <<"Thm", "3", "<<" >> \* MCargs == << << >>, << >>, + * << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Thm!1 \* MCops == <<"Inst", "Thm", "1" >> \* MCargs == << + * <<31>>, << >>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Thm!2 \* MCops == <<"Inst", "Thm", "2" >> \* MCargs == << + * <<31>>, << >>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Thm!3!<< \* MCops == <<"Inst", "Thm", "3", "<<" >> \* MCargs + * == << <<31>>, << >>, << >>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!UU \* MCops == <<"Inst", "UU">> \* MCargs == << <<31>>, << >> + * >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Bar(Arg1)!1<< \* MCops == <<"Inst", "Bar", "1" >> \* MCargs + * == << <<31>>, <<10 >>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Bar(Arg1)!1<< \* MCops == <<"Inst", "Bar", "1" >> \* MCargs + * == << <<31>>, <<10 >>, << >> >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Thm \* Note: doesn't report an error because \* MCops == + * <<"Inst", "Thm" >> \* Inst!Thm isn't expanded \* MCargs == << <<31>>, << >> + * >> \* MCexpectedArity == 0 + * + * \* Inst("Argm")!Thm!: ERROR! \* MCops == <<"Inst", "Thm", ":" >> \* MCargs == + * << <<31>>, << >>, << >> >> \* MCexpectedArity == 0 + * + * + * \* Foo2 \* MCops == <<"Foo2">> \* MCargs == <<<< >> >> \* MCexpectedArity == + * 0 + * + * \* Foo3!(3)!:Bar3 \* MCops == <<"Foo3", "null", "Bar3">> \* MCargs == << << + * >>, <<22>>, << >> >> \* MCexpectedArity == 0 + * + * \* Bar(Arg1) \* \* MCops == <<"Bar">> \* \* MCargs == << <<10>> >> \* \* + * MCexpectedArity == 0 + * + * \* Arg1(C) \* MCops == <<"Arg1">> \* MCargs == << <<18>> >> \* + * MCexpectedArity == 0 + * + * \* AOp \* MCops == <<"AOp">> \* MCargs == << <<18 >> >> \* MCexpectedArity == + * 0 + * + * \* C \* MCops == <<"C">> \* MCargs == << << >> >> \* MCexpectedArity == 0 + * + * \* p \* MCops == <<"p">> \* MCargs == << << >> >> \* MCexpectedArity == 0 + * + * \* Foo3 \* MCops == <<"Foo3">> \* MCargs == << << >> >> \* MCexpectedArity == + * 0 + * + * \***** THIS IS A BUG--NOT HANDLED CORRECTLY ****** \* UU!lab \* MCops == + * <<"UU", "lab">> \* MCargs == << << >>, << >> >> \* MCexpectedArity == 0 + * + * \* Op(2, 2)!(2, 2, 2) \* MCops == <<"Op", "null">> \* MCargs == << <<20, + * 20>>, <<20, 20, 20 >> >> \* MCexpectedArity == 0 + * + * \* Foo3!(2) \* MCops == <<"Foo3", "null">> \* MCargs == << << >>, <<20>> >> + * \* MCexpectedArity == 0 + * + * \* Op(2, 2)!(2,2,2)!+(2, 2) \* MCops == <<"Op", "null", "+">> \* MCargs == << + * <<20,20 >>, <<20,20,20>> , <<20,20>>>> \* MCexpectedArity == 0 + * + * \* MCops == <<"Op">> \* MCargs == << << >> >> \* MCexpectedArity == -1 + * + * \* MCops == <<"Inst", "Op">> \* MCargs == << << >> , << >> >> \* + * MCexpectedArity == -1 + * + * \* MCops == <<"Inst", "Thm">> \* MCargs == << << >> , << >> >> \* + * MCexpectedArity == -1 + * + * \* MCops == <<"Inst", "Op", "@", "+">> \* MCargs == << << >> , << >> , << >> + * , << >> >> \* MCexpectedArity == -1 + * + * \* MCops == <<"Op", "lab", ":", "+">> \* MCargs == << << >> , << >>, << >>, + * << >> >> \* MCexpectedArity == 7 + * + * \* MCops == <<"Op", "lab", ":", "+">> \* MCargs == << << >> , << >>, << >>, + * << >> >> \* MCexpectedArity == -1 + * + * \* MCops == <<"Foo2">> \* MCargs == << << >> >> \* MCexpectedArity == 0 + * + * \* MCops == <<"Foo3", ":">> \* MCargs == << << >>, << >> >> \* + * MCexpectedArity == 0 + * + * \* MCops == <<"Op", "lab", ":", "+">> \* MCargs == << << >>, << >>, << >>, << + * >> >> \* MCexpectedArity == -1 + * + * \* MCops == <<"Inst", "Thm">> \* MCargs == << <<14 >>, << >> >> \* + * MCexpectedArity == 0 + * + * MCops == <<"Inst", "Thm", ":">> MCargs == << <<14 >>, << >>, << >> >> + * MCexpectedArity == 0 MCdebug == FALSE \* TRUE + * + * (********************************* + * (***************************************************************************) + * (* Module M *) (* CONSTANT C *) (* Op(Arg(_), p) == \A x \in {1,2}, <<y, z>> + * \in {3} : *) (* lab(x,y,z) :: LET a + b == <<Arg(a), b>> *) (* IN 1 + label2 + * :: p + C *) (* *) (* Foo(u) == "FooBody(u)" *) (* Inst(w) == INSTANCE M WITH + * C <- <<w, CONST>> *) + * (***************************************************************************) + * + * \* MCNode == \* 1 :> [kind |-> NumeralKind, \* val |-> 1] \* @@ \* 2 :> [kind + * |-> BuiltInKind, \* \E \* name |-> "$UnboundedExists", \* arity |-> -1] \* + * \* @@ \* 3 :> [kind |-> OpApplKind, \* \E x : Node 1 \* operands |-> <<1>>, + * \* operator |-> 2, \* unboundedBoundSymbols |-> <<"x">>, \* + * boundedBoundSymbols |-> << >>, \* ranges |-> << >>] \* @@ \* 4 :> [kind |-> + * UserDefinedOpKind, \* Inst!UserOp(p1, OpP) == Node 8 \* name |-> + * "Inst!UserOp", \* body |-> 8, \* labels |-> "Label1" :> 7, \* arity |-> 2, \* + * params |-> <<[name |-> "p1", arity |-> 0], \* [name |-> "OpP", arity |-> + * 0]>>, \* defined |-> TRUE, \* source |-> 40 ] \* @@ \* 5 :> [kind |-> + * ModuleInstanceKind, \* Inst(p1) == INSTANCE \* name |-> "Inst", \* arity |-> + * 1, \* params |-> <<[name |-> "p1", arity |-> 0] >>, \* defined |-> TRUE ] + * \* @@ \* 6 :> [kind |-> UserDefinedOpKind, \* 1ArgOp(1OpP(_, _)) == Node 1 \* + * name |-> "1ArgOp", \* body |-> 41, \* labels |-> << >>, \* arity |-> 1, \* + * params |-> <<[name |-> "1OpP", arity |-> 0]>>, \* defined |-> TRUE, \* source + * |-> null ] \* @@ \* 7 :> [kind |-> LabelKind, \* name |-> "Label1", \* body + * |-> 14, \* arity |-> 1, \* params |-> <<[name |-> "labParam1", arity |-> + * 0]>>, \* labels |-> "Label2" :> 9 \* ] \* @@ \* 8 :> [kind |-> SubstInKind, + * \* body |-> 11, \* subst |-> "x <- something(p1)"] \* \* @@ \* 9 :> [kind |-> + * LabelKind, \* name |-> "Label2", \* body |-> 15, \* arity |-> 1, \* params + * |-> <<[name |-> "labParam2", arity |-> 0]>>, \* labels |-> << >> \* ] \* @@ + * \* 10 :> [kind |-> NumeralKind, \* val |-> 10] \* @@ \* 11 :> [kind |-> + * SubstInKind, \* body |-> 15, \* subst |-> "y <- something(p1)"] \* @@ \* 12 + * :> [kind |-> StringKind, \* val |-> "Body of UserOp (p1, OpP)"] \* @@ \* 13 + * :> [kind |-> StringKind, \* val |-> "Body of Label2(labParam2)"] \* @@ \* 14 + * :> [kind |-> StringKind, \* val |-> "Body of Label1(labParam1)"] \* @@ \* 15 + * :> [kind |-> LetInKind, \* context |-> "1ArgOp" :> 6, \* body |-> 16] \* @@ + * \* 16 :> [kind |-> StringKind, \* val |-> "Body of Let/In"] \* @@ \* 17 :> + * [kind |-> UserDefinedOpKind, \* 1ArgOp("1OpP") == Node 1 \* name |-> "Foo", + * \* body |-> 18, \* labels |-> << >>, \* arity |-> 0, \* params |-> << >> , \* + * <<[name |-> "FooPar1", arity |-> 0]>>, \* defined |-> TRUE, \* source |-> + * null] \* @@ \* 18 :> [kind |-> OpApplKind, \* operands |-> <<42 >>, \* + * operator |-> 21, \* unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols + * |-> << >>, \* ranges |-> << >>] \* @@ \* 19 :> [kind |-> StringKind, \* val + * |-> "Arg1"] \* @@ \* 20 :> [kind |-> StringKind, \* val |-> "Arg2"] \* @@ \* + * 21 :> [kind |-> UserDefinedOpKind, \* Foo2 == [rcd-lab1 |-> rcd-comp1, \* + * name |-> "Foo2", \* ... \* body |-> 34, \* rcd-lab3 |-> rcd-comp3] \* labels + * |-> << >>, \* arity |-> 1, \* params |-> <<[name |-> "p1", arity |-> 1]>>, \* + * defined |-> TRUE, \* source |-> null ] \* @@ \* 22 :> [kind |-> OpApplKind, + * \* operands |-> <<10 (* 25 *) , 28, 31>>, \* operator |-> 23, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 23 :> [kind |-> BuiltInKind, \* name |-> "$Except", \* + * "$Case", \* "$SetOfRcds", \* arity |-> -1 \* ] \* @@ \* 24 :> [kind |-> + * BuiltInKind, \* name |-> "$Pair", \* arity |-> 2 \* ] \* @@ \* 25 :> [kind + * |-> OpApplKind, \* operands |-> <<26,27>>, \* operator |-> 24, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 26 :> [kind |-> StringKind, \* val |-> "rcd-lab1"] \* @@ + * \* 27 :> [kind |-> StringKind, \* val |-> "rcd-comp1"] \* \* @@ \* 28 :> + * [kind |-> OpApplKind, \* operands |-> <<29,30>>, \* operator |-> 24, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 29 :> [kind |-> StringKind, \* val |-> "rcd-lab2"] \* @@ + * \* 30 :> [kind |-> StringKind, \* val |-> "rcd-comp2"] \* @@ \* 31 :> [kind + * |-> OpApplKind, \* operands |-> <<32,33>>, \* operator |-> 24, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << >>, \* ranges + * |-> << >>] \* @@ \* 32 :> [kind |-> StringKind, \* val |-> "rcd-lab3"] \* @@ + * \* 33 :> [kind |-> StringKind, \* val |-> "rcd-comp3"] \* @@ \* 34 :> [kind + * |-> OpApplKind, \* operands |-> <<35>>, \* operator |-> 36, \* + * unboundedBoundSymbols |-> <<>>, \* boundedBoundSymbols |-> << <<"b1", "b2">>, + * <<"b3">> >>, \* ranges |-> <<37, 38 >>] \* @@ \* 35 :> [kind |-> StringKind, + * \* val |-> "Fcn of b1, b2, b3"] \* @@ \* 36 :> [kind |-> BuiltInKind, \* name + * |-> "$Pair", \* arity |-> 2 \* ] \* @@ \* 37 :> [kind |-> StringKind, \* val + * |-> "Range 1"] \* @@ \* 38 :> [kind |-> StringKind, \* val |-> "Range 2"] + * \* @@ \* 39 :> [kind |-> StringKind, \* val |-> "Arg3"] \* @@ \* 40 :> [kind + * |-> UserDefinedOpKind, \* Inst!UserOp(p1, OpP) == Node 8 \* name |-> + * "UserOp", \* body |-> 8, \* labels |-> "Label1" :> 7, \* arity |-> 1, \* + * params |-> <<[name |-> "OpP", arity |-> 1]>>, \* defined |-> TRUE, \* source + * |-> null ] \* @@ \* 41 :> [kind |-> StringKind, \* val |-> "Body of 1ArgOp + * may dep on (x, y)"] \* @@ \* 42 :> [kind |-> OpArgKind, \* op |-> 43, \* + * arity |-> 1, \* name |-> "Foo3"] \* @@ \* 43 :> [kind |-> UserDefinedOpKind, + * \* 1ArgOp("1OpP") == Node 1 \* name |-> "Foo3", \* body |-> 18, \* labels |-> + * << >>, \* arity |-> 0, \* params |-> << >>, \* <<[name |-> "FooPar1", arity + * |-> 0]>>, \* defined |-> TRUE, \* source |-> null] \* \* MCNodeId == 1..43 \* + * \* MCGlobalContext == \* "Inst!UserOp" :> 4 \* @@ \* "Inst" :> 5 \* @@ \* + * "Foo" :> 17 \* @@ \* "Foo2" :> 21 \* @@ \* "Foo3" :> 43 \* \* @@ \* \* + * "1ArgOp" :> 6 \* \* \* MCops == <<"Inst", "UserOp">> \* , "1">> \* MCargs == + * << <<1 >> , <<1>> >> + * + * \* \* << <<1>>, <<19, 20, 33 >> >> \* <<1>>, <<10>>, << >>, <<4>> >> \* \* + * MCexpectedArity == 0 \* -1 \* 5 ) + * + * ----------------------------------------------------------------------------- + * (***************************************************************************) + * (* THE ALGORITHM *) + * (***************************************************************************) + * (************************************** --algorithm Subexpression variables + * (*************************************************************************) + * (* The input variables. *) + * (*************************************************************************) + * ops = MCops, args = MCargs, + * (***********************************************************************) (* + * The sequences op and args described above. *) + * (***********************************************************************) + * expectedArity = MCexpectedArity, + * (***********************************************************************) (* + * The arity of the operator expected, or -1 if expecting a definition *) (* + * name. It is 0 iff an expression is expected. The result should be *) (* an + * OpArg node if expectedArity > 0, it should be an expression node *) (* if + * expectedArity = 0, and it should be a UserDefinedOpKind or a *) (* + * ThmOrAssumpDefKind if expectedArity < 0. *) + * (***********************************************************************) + * + * (*************************************************************************) + * (* The major variables of the algorithm. *) + * (*************************************************************************) + * substInPrefix = << >> , + * (***********************************************************************) (* + * The sequence of SubstInNode or APSubstInNode sequence that will be *) (* + * appended to body of the resulting OpApplNode *) + * (***********************************************************************) + * params = << >> , + * (***********************************************************************) (* + * The sequence of FormalParamNode objects that are the formal *) (* parameters + * if this produces a Lambda expression. A Lambda *) (* expression will be + * produced iff this is non-empty *) + * (***********************************************************************) + * allArgs = << >> , + * (***********************************************************************) (* + * The sequence of all arguments. *) + * (***********************************************************************) + * curNode = null, + * (***********************************************************************) (* + * If params = << >>, then the OpDefNode for the OpApplNode that is *) (* + * produced. If params # << >>, then the Expr node that will form the *) (* body + * of the Lambda expression. *) (* *) (* Note: in the Java implementation, this + * will actually be a ref to *) (* the node--in terms of this spec, a NodeId. *) + * (***********************************************************************) + * subExprOf = "null", + * (***********************************************************************) (* + * The node UserDefinedOpDefKind or ThmOrAssumpDefKind within which *) (* this + * subexpression is defined. *) + * (***********************************************************************) + * result = null, + * (***********************************************************************) (* + * The actual output node. *) + * (***********************************************************************) + * + * (*************************************************************************) + * (* The local variables. *) + * (*************************************************************************) + * idx = 1, + * (***********************************************************************) (* + * The element of the arrays op and args that the algorithm is *) (* currently + * examining. *) + * (***********************************************************************) + * mode = "FindingOpName", + * (***********************************************************************) (* + * The current mode describing what kind of selector it is expecting *) (* next. + * Its other possible values are "FollowingLabels" and *) (* "FindingSubExpr". + * *) (***********************************************************************) + * prevMode = "", + * (***********************************************************************) (* + * The mode for the previously examined selector. *) + * (***********************************************************************) + * curContext = GlobalContext, + * (***********************************************************************) (* + * The context for looking up operator or label names. *) + * (***********************************************************************) + * curName = "" , + * (***********************************************************************) (* + * When looking up an operator name, which may be something like *) (* + * "Foo!Bar!Baz", this is the part that has been found so far. *) + * (***********************************************************************) + * opDefArityFound = 0, opDefArgs = << >>, + * (***********************************************************************) (* + * The total arity and the sequence of arguments found so far for the *) (* + * current operator--for example, opDefArityFound will equal 2 if the *) (* + * algorithm has so far processed "Foo(a, b)!Bar" *) + * (***********************************************************************) + * firstFindingOpName = TRUE, + * (***********************************************************************) (* + * True iff have entered the FindingOpName only once (initially). *) + * (***********************************************************************) + * opNode, newName, newNode, nodeArity, temp, tempArgs + * + * + * (***************************************************************************) + * (* A macro used for reporting an error and terminating the execution. *) + * (***************************************************************************) + * macro Error(msg) begin print msg ; if debug then + * (**************************************) (* Force the +cal translator to *) + * (* insert a label so the error trace *) (* shows the final state. *) + * (**************************************) idx := idx ; idx := idx ; assert + * FALSE else goto Done end if end macro ; + * + * begin + * + * (*************************************************************************) + * (* An assertion that checks that ops and args are consistent with each *) (* + * other and with the value of expectedArity. In an implementation, *) (* some + * of these should be guaranteed by the context (e.g., Len(ops) = *) (* + * Len(args) while others will be checked as part of the processing for *) (* + * the particular value of idx. *) + * (*************************************************************************) + * assert /\ expectedArity \in Int /\ ops \in Seq(STRING) /\ args \in + * Seq(Seq(NodeId)) /\ Len(ops) = Len(args) /\ \A i \in 1..Len(ops) : /\ \/ + * ops[i] \in {"<<", ">>", "@", ":"} \cup NumberOp \/ expectedArity # 0 => + * args[i] = << >> /\ (ops[i] = "null") => (Len(args[i]) > 0) ; + * + * (*************************************************************************) + * (* The outer "for" loop on idx. *) + * (*************************************************************************) + * while idx <= Len(ops) do if mode = "FindingOpName" then + * + * \* The following code was modified by LL on 23 Sep 2009 to fix the following + * \* bug. The parser produced a bogus error on a reference to an identifier \* + * M!N that is imported by an unnamed INSTANCE of a module containing the \* + * statement M == INSTANCE ... . The original code essentially just \* contained + * the first iteration of the following while loop, and would \* report an error + * if it found newNode = null. Thus, it would report \* an error in the + * identifier M!N when it found M to be undefined. \* \* Corrected by LL on 9 + * Nov 2009 to handle arguments of those \* undefined operators. They are put + * into tempArgs when they are \* found. + * + * newNode := null ; tempArgs := << >> ; + * (**********************************************************************) (* + * The number of arguments found in the following loop for the *) (* undefined + * operators *) + * (**********************************************************************) + * while newNode = null do if idx \geq Len(ops) then Error ("Unknown operator"); + * end if; newName := IF IsName(ops[idx]) THEN IF curName = "" THEN ops[idx] + * ELSE curName \o "!" \o ops[idx] ELSE null ; if /\ curName = "" /\ ~ + * IsName(ops[idx]) then + * (***************************************************************) (* I think + * that this error can only happen for idx = 1, and *) (* should never happen in + * the implementation because the *) (* parser should not allow a compound name + * that doesn't begi *) (* with a name. *) + * (***************************************************************) Error("Need + * an operator or label name or step number here") end if; newNode := IF newName + * # null THEN LookUp(newName, curContext) ELSE null ; if newName = null then + * tempArgs := tempArgs \o args[idx]; idx := idx + 1; end if; end while ; + * curNode := newNode ; curName := newName ; if curNode.kind \in + * {UserDefinedOpKind, ThmOrAssumpDefKind, ModuleInstanceKind, ConstantDeclKind, + * VariableDeclKind, FormalParamKind, BuiltInKind, BoundSymbolKind} then if + * curNode.kind \in {ConstantDeclKind, VariableDeclKind, FormalParamKind, + * BuiltInKind, BoundSymbolKind} then if idx # 1 then Error("Abort: Impossible + * naming of declaration " \o "or built-in operator.") else if Len(ops) # 1 then + * Error("Can't take subexpression of this"); end if end if end if ; nodeArity + * := Arity(curNode) ; tempArgs := tempArgs \o args[idx]; if expectedArity = 0 + * then if opDefArityFound + Len(tempArgs) # nodeArity then Error("Wrong number + * of arguments") end if ; if \E i \in 1..Len(tempArgs[idx]) : + * Arity(Node[tempArgs[idx][i]]) # ParamArity(curNode, i + opDefArityFound) then + * Error("Argument has wrong arity") else opDefArgs := opDefArgs \o tempArgs; + * end if ; else if expectedArity > 0 then if \E i \in 1..Len(curNode.params) : + * curNode.params[i].arity > 0 then Error("Higher-order operator selected " \o + * "as operator argument") end if \* else Error( \* "Abort: Don't yet handle + * expectedArity < 0") end if end if ; opDefArityFound := nodeArity ; if + * curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind, ConstantDeclKind, + * VariableDeclKind, FormalParamKind, BoundSymbolKind} then if /\ curNode.kind = + * UserDefinedOpKind /\ ~ curNode.defined /\ ~ Len(ops) = 1 then Error("Can't + * refer to subexpression of " \o "operator inside its definition") end if; if + * /\ firstFindingOpName /\ curNode.kind \in {UserDefinedOpKind, + * ThmOrAssumpDefKind} then subExprOf := curNode end if; if idx # Len(ops) then + * params := params \o curNode.params ; curName := "" ; if IsName(ops[idx+1]) + * then mode := "FollowingLabels" else mode := "FindingSubExpr" ; end if ; + * allArgs := allArgs \o opDefArgs ; opDefArityFound := 0 ; opDefArgs := << >> ; + * newNode := Node[curNode.body] ; while newNode.kind = SubstInKind do + * substInPrefix := substInPrefix \o <<newNode>>; newNode := Node[newNode.body]; + * end while ; while newNode.kind \in {SubstInKind, APSubstInKind} + * (************************************************) (* Added APSubstInKind + * test on 13 Nov 2009. *) (************************************************) do + * substInPrefix := substInPrefix \o <<newNode>>; newNode := Node[newNode.body]; + * end while ; (********************************************) (* If the next op + * is an OpSel, then need to *) (* skip over SubstInNodes, which are *) (* + * invisible to the user. *) (********************************************) if + * mode = "FindingSubExpr" then curNode := newNode end if; end if ; else \* + * curNode.kind = ModuleInstanceKind if (idx = Len(ops)) then Error("Operator + * name incomplete") end if end if else Error("Unexpected node kind") ; end if ; + * prevMode := "FindingOpName" ; + * + * + * elsif mode = "FollowingLabels" then if prevMode = "FindingOpName" then assert + * curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind} ; newNode := + * LookUp(ops[idx], curNode.labels) ; else assert curNode.kind = LabelKind ; + * newNode := LookUp(ops[idx], curNode.labels) ; end if ; if newNode = null then + * Error("Label not found") end if; curNode := newNode ; if expectedArity = 0 + * then if Len(args[idx]) # curNode.arity then Error("bad arity") end if ; if \E + * i \in 1..Len(args[idx]) : Arity(Node[args[idx][i]]) # 0 then Error("Operator + * argument given to label") end if; allArgs := allArgs \o args[idx] ; end if; + * params := params \o curNode.params ; if /\ idx < Len(ops) /\ + * ~IsName(ops[idx+1]) then mode := "FindingSubExpr" end if ; if \/ mode = + * "FindingSubExpr" \/ idx = Len(ops) then curNode := Node[curNode.body] end if; + * prevMode := "FollowingLabels"; + * + * + * elsif mode = "FindingSubExpr" then if ops[idx] = ":" then if \/ prevMode + * \notin {"FindingOpName", "FollowingLabels"} \/ ~ \/ /\ idx = Len(ops) /\ + * prevMode = "FindingOpName" \/ /\ idx < Len(ops) /\ IsName(ops[idx+1]) then + * Error("`!:' can be used only after a name and either at the " \o "end after + * an operator name or before an operator name.") end if + * + * elsif curNode.kind = LetInKind then if ArgNum(ops[idx], 1) = 1 then curNode + * := Node[curNode.body] else Error("A Let/In has only a single operand") end if + * ; + * + * elsif curNode.kind = OpApplKind then opNode := Node[curNode.operator] ; if + * opNode.kind \in {FormalParamKind, ConstantDeclKind, UserDefinedOpKind} then + * (******************************************************************) (* + * Selecting an argument from something of the form Op(...). *) + * (******************************************************************) temp := + * ArgNum(ops[idx], opNode.arity) ; if temp = -1 then Error("Nonexistent operand + * specified") else curNode := Node[curNode.operands[temp]] end if elsif + * opNode.kind = BuiltInKind then \* See configuration/ConfigConstants for a + * list of all \* BuiltInKind operators. if opNode.name \in {"$RcdConstructor", + * "$SetOfRcds"} then + * (*****************************************************************) (* + * curNode represents an expression *) (* [a_1 |-> e_1, ... , a_n |-> e_n] or *) + * (* [a_1 : e_1, ... , a_n : e_n] *) (* Its i-th argument is the $Pair node + * (a_i, e_i) *) + * (*****************************************************************) temp := + * ArgNum(ops[idx], Len(curNode.operands)) ; if temp = -1 then Error("Incorrect + * subexpression number") end if ; curNode := Node[curNode.operands[temp]] ; if + * \/ curNode.kind # OpApplKind \/ Node[curNode.operator].kind # BuiltInKind \/ + * Node[curNode.operator].name # "$Pair" then Error ("Expecting $Pair(...)") + * else curNode := Node[curNode.operands[2]] end if + * + * elsif opNode.name \in {"$Case"} then + * (*****************************************************************) (* The + * i-th clause is a $Pair node, where for the OTHER clause *) (* the 1st element + * is null. *) + * (*****************************************************************) if idx = + * Len(ops) then Error( "CASE subexpression must be of form !i!j") end if ; temp + * := ArgNum( ops[idx], Len(curNode.operands)) ; if temp = -1 then + * Error("Incorrect subexpression name") end if ; curNode := + * Node[curNode.operands[temp]] ; if \/ curNode.kind # OpApplKind \/ + * Node[curNode.operator].kind # BuiltInKind \/ Node[curNode.operator].name # + * "$Pair" then Error ("Expecting $Pair(...)") end if ; idx := idx+1 ; temp := + * ArgNum(ops[idx], 2); if temp = -1 then Error("Incorrect subexpression name") + * end if ; curNode := Node[curNode.operands[temp]] ; if curNode = null then + * Error("Selecting OTHER") end if + * + * elsif opNode.name = "$Except" then + * (****************************************************************) (* For *) + * (* [exp_1 ELSE !... = exp_2, ... , !.. = exp_n] *) (* argument number i + * chooses exp_i. For i > 1, exp_i is the *) (* second argument of a $Pair + * operator. *) + * (****************************************************************) temp := + * ArgNum(ops[idx], Len(curNode.operands)); if temp = -1 then Error("Bad + * argument selector.") end if; curNode := Node[curNode.operands[temp]] ; if + * temp > 1 then if \/ curNode.kind # OpApplKind \/ Node[curNode.operator].kind + * # BuiltInKind \/ Node[curNode.operator].name # "$Pair" then Error("Unexpected + * expression node found.") else curNode := Node[curNode.operands[2]] end if end + * if + * + * else (*****************************************************************) (* + * Operator handled by standard procedure. *) + * (*****************************************************************) if /\ + * Len(curNode.unboundedBoundSymbols) = 0 /\ Len(curNode.boundedBoundSymbols) = + * 0 then (**********************************************************) (* + * Current subexpression has no bound variables. *) + * (**********************************************************) temp := + * ArgNum(ops[idx], Len(curNode.operands)) ; if temp = -1 then Error("Incorrect + * subexpression selector") end if; curNode := Node[curNode.operands[temp]] ; + * else (**********************************************************) (* Current + * subexpression has bound variables. If *) (* selector is "@" or null, then + * choosing body and adding *) (* parameters. Otherwise, must be selecting one + * of the *) (* bounds. *) + * (**********************************************************) if ops[idx] \in + * {"null", "@"} then (***************************************************) (* + * Set temp to the sequence of parameters. *) + * (***************************************************) temp := IF + * Len(curNode.unboundedBoundSymbols) > 0 THEN curNode.unboundedBoundSymbols + * ELSE SeqSeqToSeq( curNode.boundedBoundSymbols); + * + * params := params \o [i \in 1.. Len(temp) |-> [name |-> temp[i], arity |-> 0]] + * ; allArgs := allArgs \o args[idx] ; if /\ ops[idx] = "null" /\ Len(args[idx]) + * # Len(temp) then Error("Wrong number of selector arguments"); end if; curNode + * := Node[curNode.operands[1]]; else temp := ArgNum(ops[idx], + * Len(curNode.ranges)) ; if temp = -1 then Error ("Selecting non-existent + * range") ; else curNode := Node[curNode.ranges[temp]] end if end if end if end + * if \* opNode.name = ... + * + * else Error("Applying subexpression chooser to an expr" \o " with no choosable + * subexpressions") + * + * end if \* opNode.kind = ... + * + * elsif curNode.kind = AssumeProveKind then temp := ArgNum(ops[idx], 1 + + * Len(curNode.assumes)) ; if temp = -1 then Error("Illegal argument number") + * else if temp <= Len(curNode.assumes) then curNode := + * Node[curNode.assumes[temp]] else curNode := Node[curNode.prove] end if end if + * + * elsif curNode.kind = OpArgKind then + * (*********************************************************************) (* + * The only kind of OpArgNode that has a subpart is a Lambda *) (* expression. + * *) (*********************************************************************) + * opNode := Node[curNode.op] ; if \/ opNode.kind # UserDefinedOpKind \/ + * opNode.name # "LAMBDA" then Error("Selecting from operator argument that has + * no sub-part") elsif ops[idx] \notin {"null", "@"} then Error("Incorrect + * selection from LAMBDA") elsif /\ ops[idx] = "null" /\ Len(args[idx]) # + * Len(opNode.params) then Error("Incorrect number of arguments for LAMBDA") + * else params := params \o opNode.params ; allArgs := allArgs \o args[idx] ; + * curNode := Node[opNode.body] ; end if + * + * elsif curNode.kind \in {UserDefinedOpKind, BuiltInKind} then Error("Abort: + * should not have been able to choose this node.") + * + * elsif curNode.kind \in {AtNodeKind, DecimalKind, NumeralKind, StringKind, + * FormalParamKind, ConstantDeclKind, VariableDeclKind, BoundSymbolKind} then + * Error("Selected part has no subexpression") + * + * elsif curNode.kind = LabelKind then + * (*********************************************************************) (* + * Skip over label. *) + * (*********************************************************************) + * curNode := Node[curNode.body] ; idx := idx - 1 ; else Error("Unexpected node + * kind found in expression") + * + * end if; \* ops[idx] = ":" + * + * if idx # Len(ops) then if IsName(ops[idx+1]) then while curNode.kind = + * LabelKind do curNode := Node[curNode.body] end while ; if curNode.kind = + * LetInKind then curContext := curNode.context ; mode := "FindingOpName" ; + * firstFindingOpName := FALSE; else Error("A name not following the selector of + * a LET") end if else if ops[idx+1] = ":" then Error("!: should not follow an + * operand selector") end if ; end if ; end if ; \* ops[idx] = ":" prevMode := + * "FindingSubExpr"; + * + * else Error("Bad value of mode") + * + * end if ; \* mode = ... + * + * idx := idx + 1; end while ; + * + * if curNode.kind = AssumeProveKind then Error("Selecting ASSUME/PROVE instead + * of expression") end if; + * + * if expectedArity < 0 then if \/ prevMode # "FindingOpName" \/ curNode.kind + * \notin {UserDefinedOpKind, ThmOrAssumpDefKind} then Error("Should have + * selected a definition, but didn't.") end if; result := curNode ; goto + * Finished end if; + * + * if expectedArity > 0 then temp := Len(params) + IF \/ prevMode = + * "FindingOpName" \/ curNode.kind = OpArgKind THEN Arity(curNode) ELSE 0 ; if + * expectedArity # temp then Error("Expect arity = " \o ToString(expectedArity) + * \o ", but found arity = " \o ToString(temp)) end if end if; + * + * + * (*************************************************************************) + * (* If found an operator def and there are parameters or substitutions, *) (* + * then set curNode to the operator applied to new parameters, add those *) (* + * parameters to params and add the arguments to allArgs. Note: need to *) (* do + * this even if operator takes no parameters because we need to put *) (* the + * operator in a LAMBDA expression whose body is an expression *) + * (*************************************************************************) + * if /\ prevMode = "FindingOpName" /\ Len(params) + Len(substInPrefix) > 0 then + * temp := [i \in 1..Len(curNode.params) |-> [curNode.params[i] EXCEPT !.name = + * "New " \o @]] ; + * (****************************************************************) (* temp := + * new formal parameters for the operator, with the *) (* same arities as the + * original parameters. *) + * (****************************************************************) + * + * curNode := [kind |-> OpApplKind, operands |-> temp, operator |-> curNode, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>] ; params := params \o temp ; allArgs := allArgs \o opDefArgs ; end if ; + * + * if curNode.kind = OpArgKind then if expectedArity = 0 then Error("Selected + * Operator Argument when expression expected.") elsif expectedArity # + * Len(params) + curNode.arity then Error("Selected operator has wrong arity.") + * else if Len(params) + Len(substInPrefix) > 0 then + * (********************************************************) (* If curNode is a + * LAMBDA, then this will eventually *) (* produce an OpArg node whose operator + * is a LAMBDA *) (* whose body is an OpApplNode that applies the *) (* + * curNode's LAMBDA to parameters of the outer LAMBDA. *) (* This result can be + * simplified to a LAMBDA whose body *) (* is the body of curNode. However, that + * *) (* simplification is what one will get by selecting the *) (* body of the + * LAMBDA, so we keep this complicated *) (* expression in this case. *) + * (********************************************************) temp := [i \in + * 1..curNode.arity |-> [name |-> "NewParam" \o NumToString(i), arity |-> 0]] ; + * curNode := [kind |-> OpApplKind, operands |-> temp, operator |-> + * Node[curNode.op], unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << + * >>, ranges |-> << >>] ; params := params \o temp end if end if end if ; + * + * if curNode.kind \in {UserDefinedOpKind, ConstantDeclKind, VariableDeclKind, + * FormalParamKind, BuiltInKind, BoundSymbolKind, ThmOrAssumpDefKind} then + * (***********************************************************************) (* + * There are no params or substitutions, so this is an easy case. *) + * (***********************************************************************) if + * expectedArity > 0 then result := [kind |-> OpArgKind, name |-> curNode.name, + * op |-> curNode, arity |-> expectedArity] elsif expectedArity = 0 then result + * := [kind |-> OpApplKind, operands |-> opDefArgs, operator |-> curNode, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>, subExprOf |-> subExprOf] end if elsif curNode.kind = OpArgKind then + * (***********************************************************************) (* + * There are no params or substitutions, so this is an easy case. *) + * (***********************************************************************) + * result := curNode ; else + * (******************************************************************) (* + * curNode should be an expression node. *) + * (******************************************************************) temp := + * Len(substInPrefix) ; while temp > 0 do curNode := [kind |-> + * substInPrefix[temp].kind, (********************************************) (* + * Changed on 13 Nov 2009 from SubstInKind. *) + * (********************************************) body |-> curNode , subst |-> + * substInPrefix[temp].subst ] ; temp := temp - 1; end while; + * + * if expectedArity > 0 then if Len(params) # expectedArity then Error + * ("Selection has wrong arity") end if ; result := [kind |-> OpArgKind, op |-> + * [kind |-> UserDefinedOpKind, name |-> "LAMBDA", body |-> curNode, params |-> + * params, arity |-> Len(params), defined |-> TRUE, source |-> null], name |-> + * "LAMBDA"] else if Len(params) # Len(allArgs) then Error("Abort: number of + * params # num of args") end if ; if Len(params) = 0 then + * (******************************************************) (* This is the one + * case with expectedArity = 0 in *) (* which the result is not a + * newly-constructed node. *) (* In this case, we construct a dummy label node + * so *) (* we have a node to which the implementation can *) (* attach the + * syntax node. *) (******************************************************) + * result := [kind |-> LabelKind, name |-> "$Subexpression", arity |-> 0, params + * |-> << >>, body |-> curNode, subExprOf |-> subExprOf] + * + * else result := [kind |-> OpApplKind, operator |-> [kind |-> + * UserDefinedOpKind, name |-> "LAMBDA", body |-> curNode, params |-> params, + * arity |-> Len(params), defined |-> TRUE, source |-> null], operands |-> + * allArgs, unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, + * ranges |-> << >>, subExprOf |-> subExprOf] end if end if + * + * end if; + * + * Finished: print "Result: " ; print result ; + * + * end algorithm ) \* BEGIN TRANSLATION CONSTANT defaultInitValue VARIABLES ops, + * args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, + * result, idx, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs, pc + * + * vars == << ops, args, expectedArity, substInPrefix, params, allArgs, curNode, + * subExprOf, result, idx, mode, prevMode, curContext, curName, opDefArityFound, + * opDefArgs, firstFindingOpName, opNode, newName, newNode, nodeArity, temp, + * tempArgs, pc >> + * + * Init == (* Global variables *) /\ ops = MCops /\ args = MCargs /\ + * expectedArity = MCexpectedArity /\ substInPrefix = << >> /\ params = << >> /\ + * allArgs = << >> /\ curNode = null /\ subExprOf = "null" /\ result = null /\ + * idx = 1 /\ mode = "FindingOpName" /\ prevMode = "" /\ curContext = + * GlobalContext /\ curName = "" /\ opDefArityFound = 0 /\ opDefArgs = << >> /\ + * firstFindingOpName = TRUE /\ opNode = defaultInitValue /\ newName = + * defaultInitValue /\ newNode = defaultInitValue /\ nodeArity = + * defaultInitValue /\ temp = defaultInitValue /\ tempArgs = defaultInitValue /\ + * pc = "Lbl_1" + * + * Lbl_1 == /\ pc = "Lbl_1" /\ Assert(/\ expectedArity \in Int /\ ops \in + * Seq(STRING) /\ args \in Seq(Seq(NodeId)) /\ Len(ops) = Len(args) /\ \A i \in + * 1..Len(ops) : /\ \/ ops[i] \in {"<<", ">>", "@", ":"} \cup NumberOp \/ + * expectedArity # 0 => args[i] = << >> /\ (ops[i] = "null") => (Len(args[i]) > + * 0), "Failure of assertion at line line 1906, column 3.") /\ pc' = "Lbl_2" /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_2 == /\ pc = "Lbl_2" /\ IF idx <= Len(ops) THEN /\ IF mode = + * "FindingOpName" THEN /\ newNode' = null /\ tempArgs' = << >> /\ pc' = "Lbl_3" + * /\ UNCHANGED << params, allArgs, curNode, idx, opNode, temp >> ELSE /\ IF + * mode = "FollowingLabels" THEN /\ IF prevMode = "FindingOpName" THEN /\ + * Assert(curNode.kind \in {UserDefinedOpKind, ThmOrAssumpDefKind}, "Failure of + * assertion at line line 2053, column 13.") /\ newNode' = LookUp(ops[idx], + * curNode.labels) ELSE /\ Assert(curNode.kind = LabelKind, "Failure of + * assertion at line line 2055, column 13.") /\ newNode' = LookUp(ops[idx], + * curNode.labels) /\ IF newNode' = null THEN /\ PrintT("Label not found") /\ IF + * debug THEN /\ idx' = idx /\ pc' = "Lbl_22" ELSE /\ pc' = "Done" /\ UNCHANGED + * idx ELSE /\ pc' = "Lbl_23" /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, + * curNode, opNode, temp >> ELSE /\ IF mode = "FindingSubExpr" THEN /\ IF + * ops[idx] = ":" THEN /\ IF \/ prevMode \notin {"FindingOpName", + * "FollowingLabels"} \/ ~ \/ /\ idx = Len(ops) /\ prevMode = "FindingOpName" \/ + * /\ idx < Len(ops) /\ IsName(ops[idx+1]) THEN /\ PrintT("`!:' can be used only + * after a name and either at the " \o "end after an operator name or before an + * operator name.") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_29" ELSE /\ pc' + * = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_63" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs, curNode, opNode, temp >> ELSE /\ IF + * curNode.kind = LetInKind THEN /\ IF ArgNum(ops[idx], 1) = 1 THEN /\ curNode' + * = Node[curNode.body] /\ pc' = "Lbl_63" /\ UNCHANGED idx ELSE /\ PrintT("A + * Let/In has only a single operand") /\ IF debug THEN /\ idx' = idx /\ pc' = + * "Lbl_30" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED curNode /\ + * UNCHANGED << params, allArgs, opNode, temp >> ELSE /\ IF curNode.kind = + * OpApplKind THEN /\ opNode' = Node[curNode.operator] /\ IF opNode'.kind \in + * {FormalParamKind, ConstantDeclKind, UserDefinedOpKind} THEN /\ temp' = + * ArgNum(ops[idx], opNode'.arity) /\ IF temp' = -1 THEN /\ PrintT("Nonexistent + * operand specified") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_31" ELSE /\ + * pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED curNode ELSE /\ curNode' = + * Node[curNode.operands[temp']] /\ pc' = "Lbl_63" /\ UNCHANGED idx /\ UNCHANGED + * << params, allArgs >> ELSE /\ IF opNode'.kind = BuiltInKind THEN /\ IF + * opNode'.name \in {"$RcdConstructor", "$SetOfRcds"} THEN /\ temp' = + * ArgNum(ops[idx], Len(curNode.operands)) /\ IF temp' = -1 THEN /\ + * PrintT("Incorrect subexpression number") /\ IF debug THEN /\ idx' = idx /\ + * pc' = "Lbl_32" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_33" + * /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, curNode >> ELSE /\ IF + * opNode'.name \in {"$Case"} THEN /\ IF idx = Len(ops) THEN /\ PrintT("CASE + * subexpression must be of form !i!j") /\ IF debug THEN /\ idx' = idx /\ pc' = + * "Lbl_36" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_37" /\ + * UNCHANGED idx /\ UNCHANGED << params, allArgs, curNode, temp >> ELSE /\ IF + * opNode'.name = "$Except" THEN /\ temp' = ArgNum(ops[idx], + * Len(curNode.operands)) /\ IF temp' = -1 THEN /\ PrintT("Bad argument + * selector.") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_46" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_47" /\ UNCHANGED idx /\ UNCHANGED + * << params, allArgs, curNode >> ELSE /\ IF /\ + * Len(curNode.unboundedBoundSymbols) = 0 /\ Len(curNode.boundedBoundSymbols) = + * 0 THEN /\ temp' = ArgNum(ops[idx], Len(curNode.operands)) /\ IF temp' = -1 + * THEN /\ PrintT("Incorrect subexpression selector") /\ IF debug THEN /\ idx' = + * idx /\ pc' = "Lbl_50" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_51" /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, curNode >> ELSE /\ + * IF ops[idx] \in {"null", "@"} THEN /\ temp' = (IF + * Len(curNode.unboundedBoundSymbols) > 0 THEN curNode.unboundedBoundSymbols + * ELSE SeqSeqToSeq( curNode.boundedBoundSymbols)) /\ params' = params \o [i \in + * 1.. Len(temp') |-> [name |-> temp'[i], arity |-> 0]] /\ allArgs' = allArgs \o + * args[idx] /\ IF /\ ops[idx] = "null" /\ Len(args[idx]) # Len(temp') THEN /\ + * PrintT("Wrong number of selector arguments") /\ IF debug THEN /\ idx' = idx + * /\ pc' = "Lbl_52" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_53" /\ UNCHANGED idx /\ UNCHANGED curNode ELSE /\ temp' = + * ArgNum(ops[idx], Len(curNode.ranges)) /\ IF temp' = -1 THEN /\ + * PrintT("Selecting non-existent range") /\ IF debug THEN /\ idx' = idx /\ pc' + * = "Lbl_54" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED curNode ELSE /\ + * curNode' = Node[curNode.ranges[temp']] /\ pc' = "Lbl_63" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs >> ELSE /\ PrintT("Applying subexpression + * chooser to an expr" \o " with no choosable subexpressions") /\ IF debug THEN + * /\ idx' = idx /\ pc' = "Lbl_55" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs, curNode, temp >> ELSE /\ IF curNode.kind = + * AssumeProveKind THEN /\ temp' = ArgNum(ops[idx], 1 + Len(curNode.assumes)) /\ + * IF temp' = -1 THEN /\ PrintT("Illegal argument number") /\ IF debug THEN /\ + * idx' = idx /\ pc' = "Lbl_56" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ + * UNCHANGED curNode ELSE /\ IF temp' <= Len(curNode.assumes) THEN /\ curNode' = + * Node[curNode.assumes[temp']] ELSE /\ curNode' = Node[curNode.prove] /\ pc' = + * "Lbl_63" /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, opNode >> ELSE /\ + * IF curNode.kind = OpArgKind THEN /\ opNode' = Node[curNode.op] /\ IF \/ + * opNode'.kind # UserDefinedOpKind \/ opNode'.name # "LAMBDA" THEN /\ + * PrintT("Selecting from operator argument that has no sub-part") /\ IF debug + * THEN /\ idx' = idx /\ pc' = "Lbl_57" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs, curNode >> ELSE /\ IF ops[idx] \notin {"null", + * "@"} THEN /\ PrintT("Incorrect selection from LAMBDA") /\ IF debug THEN /\ + * idx' = idx /\ pc' = "Lbl_58" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs, curNode >> ELSE /\ IF /\ ops[idx] = "null" /\ + * Len(args[idx]) # Len(opNode'.params) THEN /\ PrintT("Incorrect number of + * arguments for LAMBDA") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_59" ELSE + * /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, curNode >> + * ELSE /\ params' = params \o opNode'.params /\ allArgs' = allArgs \o args[idx] + * /\ curNode' = Node[opNode'.body] /\ pc' = "Lbl_63" /\ UNCHANGED idx ELSE /\ + * IF curNode.kind \in {UserDefinedOpKind, BuiltInKind} THEN /\ PrintT("Abort: + * should not have been able to choose this node.") /\ IF debug THEN /\ idx' = + * idx /\ pc' = "Lbl_60" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED + * curNode ELSE /\ IF curNode.kind \in {AtNodeKind, DecimalKind, NumeralKind, + * StringKind, FormalParamKind, ConstantDeclKind, VariableDeclKind, + * BoundSymbolKind} THEN /\ PrintT("Selected part has no subexpression") /\ IF + * debug THEN /\ idx' = idx /\ pc' = "Lbl_61" ELSE /\ pc' = "Done" /\ UNCHANGED + * idx /\ UNCHANGED curNode ELSE /\ IF curNode.kind = LabelKind THEN /\ curNode' + * = Node[curNode.body] /\ idx' = idx - 1 /\ pc' = "Lbl_63" ELSE /\ + * PrintT("Unexpected node kind found in expression") /\ IF debug THEN /\ idx' = + * idx /\ pc' = "Lbl_62" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED + * curNode /\ UNCHANGED << params, allArgs, opNode >> /\ UNCHANGED temp ELSE /\ + * PrintT("Bad value of mode") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_68" + * ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED << params, allArgs, + * curNode, opNode, temp >> /\ UNCHANGED newNode /\ UNCHANGED tempArgs ELSE /\ + * IF curNode.kind = AssumeProveKind THEN /\ PrintT("Selecting ASSUME/PROVE + * instead of expression") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_70" ELSE + * /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_71" /\ UNCHANGED idx /\ + * UNCHANGED << params, allArgs, curNode, opNode, newNode, temp, tempArgs >> /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, subExprOf, result, + * mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, newName, nodeArity >> + * + * Lbl_69 == /\ pc = "Lbl_69" /\ idx' = idx + 1 /\ pc' = "Lbl_2" /\ UNCHANGED << + * ops, args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_3 == /\ pc = "Lbl_3" /\ IF newNode = null THEN /\ IF idx \geq Len(ops) + * THEN /\ PrintT("Unknown operator") /\ IF debug THEN /\ idx' = idx /\ pc' = + * "Lbl_4" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_5" /\ + * UNCHANGED idx /\ UNCHANGED << curNode, curName >> ELSE /\ curNode' = newNode + * /\ curName' = newName /\ IF curNode'.kind \in {UserDefinedOpKind, + * ThmOrAssumpDefKind, ModuleInstanceKind, ConstantDeclKind, VariableDeclKind, + * FormalParamKind, BuiltInKind, BoundSymbolKind} THEN /\ IF curNode'.kind \in + * {ConstantDeclKind, VariableDeclKind, FormalParamKind, BuiltInKind, + * BoundSymbolKind} THEN /\ IF idx # 1 THEN /\ PrintT("Abort: Impossible naming + * of declaration " \o "or built-in operator.") /\ IF debug THEN /\ idx' = idx + * /\ pc' = "Lbl_8" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ IF Len(ops) # + * 1 THEN /\ PrintT("Can't take subexpression of this") /\ IF debug THEN /\ idx' + * = idx /\ pc' = "Lbl_9" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_10" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_10" /\ UNCHANGED idx ELSE /\ + * PrintT("Unexpected node kind") /\ IF debug THEN /\ idx' = idx /\ pc' = + * "Lbl_20" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED << ops, args, + * expectedArity, substInPrefix, params, allArgs, subExprOf, result, mode, + * prevMode, curContext, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_5 == /\ pc = "Lbl_5" /\ newName' = IF IsName(ops[idx]) THEN IF curName = + * "" THEN ops[idx] ELSE curName \o "!" \o ops[idx] ELSE null /\ IF /\ curName = + * "" /\ ~ IsName(ops[idx]) THEN /\ PrintT("Need an operator or label name or + * step number here") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_6" ELSE /\ + * pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_7" /\ UNCHANGED idx /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newNode, nodeArity, + * temp, tempArgs >> + * + * Lbl_6 == /\ pc = "Lbl_6" /\ idx' = idx /\ Assert(FALSE, "Failure of assertion + * at line line 1892, column 38 of macro called at line 1956, column 13.") /\ + * pc' = "Lbl_7" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, result, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_7 == /\ pc = "Lbl_7" /\ newNode' = (IF newName # null THEN + * LookUp(newName, curContext) ELSE null) /\ IF newName = null THEN /\ tempArgs' + * = tempArgs \o args[idx] /\ idx' = idx + 1 ELSE /\ TRUE /\ UNCHANGED << idx, + * tempArgs >> /\ pc' = "Lbl_3" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, nodeArity, temp >> + * + * Lbl_4 == /\ pc = "Lbl_4" /\ idx' = idx /\ Assert(FALSE, "Failure of assertion + * at line line 1892, column 38 of macro called at line 1942, column 13.") /\ + * pc' = "Lbl_5" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, result, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_10 == /\ pc = "Lbl_10" /\ nodeArity' = Arity(curNode) /\ tempArgs' = + * tempArgs \o args[idx] /\ IF expectedArity = 0 THEN /\ IF opDefArityFound + + * Len(tempArgs') # nodeArity' THEN /\ PrintT("Wrong number of arguments") /\ IF + * debug THEN /\ idx' = idx /\ pc' = "Lbl_11" ELSE /\ pc' = "Done" /\ UNCHANGED + * idx ELSE /\ pc' = "Lbl_12" /\ UNCHANGED idx ELSE /\ IF expectedArity > 0 THEN + * /\ IF \E i \in 1..Len(curNode.params) : curNode.params[i].arity > 0 THEN /\ + * PrintT("Higher-order operator selected " \o "as operator argument") /\ IF + * debug THEN /\ idx' = idx /\ pc' = "Lbl_14" ELSE /\ pc' = "Done" /\ UNCHANGED + * idx ELSE /\ pc' = "Lbl_15" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_15" /\ + * UNCHANGED idx /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, result, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, temp >> + * + * Lbl_12 == /\ pc = "Lbl_12" /\ IF \E i \in 1..Len(tempArgs[idx]) : + * Arity(Node[tempArgs[idx][i]]) # ParamArity(curNode, i + opDefArityFound) THEN + * /\ PrintT("Argument has wrong arity") /\ IF debug THEN /\ idx' = idx /\ pc' = + * "Lbl_13" ELSE /\ pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED opDefArgs ELSE /\ + * opDefArgs' = opDefArgs \o tempArgs /\ pc' = "Lbl_15" /\ UNCHANGED idx /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, mode, prevMode, curContext, curName, + * opDefArityFound, firstFindingOpName, opNode, newName, newNode, nodeArity, + * temp, tempArgs >> + * + * Lbl_13 == /\ pc = "Lbl_13" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 1990, column + * 26.") /\ pc' = "Lbl_15" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_11 == /\ pc = "Lbl_11" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 1985, column + * 25.") /\ pc' = "Lbl_12" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_14 == /\ pc = "Lbl_14" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 1996, column + * 32.") /\ pc' = "Lbl_15" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_15 == /\ pc = "Lbl_15" /\ opDefArityFound' = nodeArity /\ IF curNode.kind + * \in {UserDefinedOpKind, ThmOrAssumpDefKind, ConstantDeclKind, + * VariableDeclKind, FormalParamKind, BoundSymbolKind} THEN /\ IF /\ + * curNode.kind = UserDefinedOpKind /\ ~ curNode.defined /\ ~ Len(ops) = 1 THEN + * /\ PrintT("Can't refer to subexpression of " \o "operator inside its + * definition") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_16" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_17" /\ UNCHANGED idx ELSE /\ IF + * (idx = Len(ops)) THEN /\ PrintT("Operator name incomplete") /\ IF debug THEN + * /\ idx' = idx /\ pc' = "Lbl_19" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ + * pc' = "Lbl_21" /\ UNCHANGED idx /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_17 == /\ pc = "Lbl_17" /\ IF /\ firstFindingOpName /\ curNode.kind \in + * {UserDefinedOpKind, ThmOrAssumpDefKind} THEN /\ subExprOf' = curNode ELSE /\ + * TRUE /\ UNCHANGED subExprOf /\ IF idx # Len(ops) THEN /\ params' = params \o + * curNode.params /\ curName' = "" /\ IF IsName(ops[idx+1]) THEN /\ mode' = + * "FollowingLabels" ELSE /\ mode' = "FindingSubExpr" /\ allArgs' = allArgs \o + * opDefArgs /\ opDefArityFound' = 0 /\ opDefArgs' = << >> /\ newNode' = + * Node[curNode.body] /\ pc' = "Lbl_18" ELSE /\ pc' = "Lbl_21" /\ UNCHANGED << + * params, allArgs, mode, curName, opDefArityFound, opDefArgs, newNode >> /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, curNode, result, idx, + * prevMode, curContext, firstFindingOpName, opNode, newName, nodeArity, temp, + * tempArgs >> + * + * Lbl_18 == /\ pc = "Lbl_18" /\ IF newNode.kind = SubstInKind THEN /\ + * substInPrefix' = substInPrefix \o <<newNode>> /\ newNode' = + * Node[newNode.body] /\ pc' = "Lbl_18" /\ UNCHANGED curNode ELSE /\ IF mode = + * "FindingSubExpr" THEN /\ curNode' = newNode ELSE /\ TRUE /\ UNCHANGED curNode + * /\ pc' = "Lbl_21" /\ UNCHANGED << substInPrefix, newNode >> /\ UNCHANGED << + * ops, args, expectedArity, params, allArgs, subExprOf, result, idx, mode, + * prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, nodeArity, temp, tempArgs >> + * + * Lbl_16 == /\ pc = "Lbl_16" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2010, column + * 25.") /\ pc' = "Lbl_17" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_19 == /\ pc = "Lbl_19" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2043, column + * 25.") /\ pc' = "Lbl_21" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_8 == /\ pc = "Lbl_8" /\ idx' = idx /\ Assert(FALSE, "Failure of assertion + * at line line 1892, column 38 of macro called at line 1974, column 26.") /\ + * pc' = "Lbl_10" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, result, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_9 == /\ pc = "Lbl_9" /\ idx' = idx /\ Assert(FALSE, "Failure of assertion + * at line line 1892, column 38 of macro called at line 1977, column 33.") /\ + * pc' = "Lbl_10" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, result, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_20 == /\ pc = "Lbl_20" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2046, column + * 9.") /\ pc' = "Lbl_21" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_21 == /\ pc = "Lbl_21" /\ prevMode' = "FindingOpName" /\ pc' = "Lbl_69" + * /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, idx, mode, curContext, curName, opDefArityFound, + * opDefArgs, firstFindingOpName, opNode, newName, newNode, nodeArity, temp, + * tempArgs >> + * + * Lbl_23 == /\ pc = "Lbl_23" /\ curNode' = newNode /\ IF expectedArity = 0 THEN + * /\ IF Len(args[idx]) # curNode'.arity THEN /\ PrintT("bad arity") /\ IF debug + * THEN /\ idx' = idx /\ pc' = "Lbl_24" ELSE /\ pc' = "Done" /\ UNCHANGED idx + * ELSE /\ pc' = "Lbl_25" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_28" /\ UNCHANGED + * idx /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * subExprOf, result, mode, prevMode, curContext, curName, opDefArityFound, + * opDefArgs, firstFindingOpName, opNode, newName, newNode, nodeArity, temp, + * tempArgs >> + * + * Lbl_25 == /\ pc = "Lbl_25" /\ IF \E i \in 1..Len(args[idx]) : + * Arity(Node[args[idx][i]]) # 0 THEN /\ PrintT("Operator argument given to + * label") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_26" ELSE /\ pc' = "Done" + * /\ UNCHANGED idx ELSE /\ pc' = "Lbl_27" /\ UNCHANGED idx /\ UNCHANGED << ops, + * args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_26 == /\ pc = "Lbl_26" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2068, column + * 20.") /\ pc' = "Lbl_27" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_27 == /\ pc = "Lbl_27" /\ allArgs' = allArgs \o args[idx] /\ pc' = + * "Lbl_28" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * curNode, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_24 == /\ pc = "Lbl_24" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2064, column + * 20.") /\ pc' = "Lbl_25" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_28 == /\ pc = "Lbl_28" /\ params' = params \o curNode.params /\ IF /\ idx + * < Len(ops) /\ ~IsName(ops[idx+1]) THEN /\ mode' = "FindingSubExpr" ELSE /\ + * TRUE /\ UNCHANGED mode /\ IF \/ mode' = "FindingSubExpr" \/ idx = Len(ops) + * THEN /\ curNode' = Node[curNode.body] ELSE /\ TRUE /\ UNCHANGED curNode /\ + * prevMode' = "FollowingLabels" /\ pc' = "Lbl_69" /\ UNCHANGED << ops, args, + * expectedArity, substInPrefix, allArgs, subExprOf, result, idx, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_22 == /\ pc = "Lbl_22" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2059, column + * 13.") /\ pc' = "Lbl_23" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_63 == /\ pc = "Lbl_63" /\ IF idx # Len(ops) THEN /\ IF IsName(ops[idx+1]) + * THEN /\ pc' = "Lbl_64" /\ UNCHANGED idx ELSE /\ IF ops[idx+1] = ":" THEN /\ + * PrintT("!: should not follow an operand selector") /\ IF debug THEN /\ idx' = + * idx /\ pc' = "Lbl_66" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_67" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_67" /\ UNCHANGED idx /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_64 == /\ pc = "Lbl_64" /\ IF curNode.kind = LabelKind THEN /\ curNode' = + * Node[curNode.body] /\ pc' = "Lbl_64" /\ UNCHANGED << idx, mode, curContext, + * firstFindingOpName >> ELSE /\ IF curNode.kind = LetInKind THEN /\ curContext' + * = curNode.context /\ mode' = "FindingOpName" /\ firstFindingOpName' = FALSE + * /\ pc' = "Lbl_67" /\ UNCHANGED idx ELSE /\ PrintT("A name not following the + * selector of a LET") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_65" ELSE /\ + * pc' = "Done" /\ UNCHANGED idx /\ UNCHANGED << mode, curContext, + * firstFindingOpName >> /\ UNCHANGED curNode /\ UNCHANGED << ops, args, + * expectedArity, substInPrefix, params, allArgs, subExprOf, result, prevMode, + * curName, opDefArityFound, opDefArgs, opNode, newName, newNode, nodeArity, + * temp, tempArgs >> + * + * Lbl_65 == /\ pc = "Lbl_65" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2294, column + * 26.") /\ pc' = "Lbl_67" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_66 == /\ pc = "Lbl_66" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2297, column + * 26.") /\ pc' = "Lbl_67" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_67 == /\ pc = "Lbl_67" /\ prevMode' = "FindingSubExpr" /\ pc' = "Lbl_69" + * /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, idx, mode, curContext, curName, opDefArityFound, + * opDefArgs, firstFindingOpName, opNode, newName, newNode, nodeArity, temp, + * tempArgs >> + * + * Lbl_29 == /\ pc = "Lbl_29" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2091, column + * 14.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_30 == /\ pc = "Lbl_30" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2098, column + * 14.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_31 == /\ pc = "Lbl_31" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2110, column + * 17.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_33 == /\ pc = "Lbl_33" /\ curNode' = Node[curNode.operands[temp]] /\ IF + * \/ curNode'.kind # OpApplKind \/ Node[curNode'.operator].kind # BuiltInKind + * \/ Node[curNode'.operator].name # "$Pair" THEN /\ PrintT("Expecting + * $Pair(...)") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_34" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_35" /\ UNCHANGED idx /\ UNCHANGED + * << ops, args, expectedArity, substInPrefix, params, allArgs, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_35 == /\ pc = "Lbl_35" /\ curNode' = Node[curNode.operands[2]] /\ pc' = + * "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * allArgs, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_34 == /\ pc = "Lbl_34" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2131, column + * 18.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_32 == /\ pc = "Lbl_32" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2125, column + * 18.") /\ pc' = "Lbl_33" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_37 == /\ pc = "Lbl_37" /\ temp' = ArgNum( ops[idx], + * Len(curNode.operands)) /\ IF temp' = -1 THEN /\ PrintT("Incorrect + * subexpression name") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_38" ELSE /\ + * pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_39" /\ UNCHANGED idx /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, result, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, tempArgs >> + * + * Lbl_38 == /\ pc = "Lbl_38" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2145, column + * 18.") /\ pc' = "Lbl_39" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_39 == /\ pc = "Lbl_39" /\ curNode' = Node[curNode.operands[temp]] /\ IF + * \/ curNode'.kind # OpApplKind \/ Node[curNode'.operator].kind # BuiltInKind + * \/ Node[curNode'.operator].name # "$Pair" THEN /\ PrintT("Expecting + * $Pair(...)") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_40" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_41" /\ UNCHANGED idx /\ UNCHANGED + * << ops, args, expectedArity, substInPrefix, params, allArgs, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_40 == /\ pc = "Lbl_40" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2151, column + * 18.") /\ pc' = "Lbl_41" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_41 == /\ pc = "Lbl_41" /\ idx' = idx+1 /\ temp' = ArgNum(ops[idx'], 2) /\ + * IF temp' = -1 THEN /\ PrintT("Incorrect subexpression name") /\ IF debug THEN + * /\ pc' = "Lbl_42" ELSE /\ pc' = "Done" ELSE /\ pc' = "Lbl_44" /\ UNCHANGED << + * ops, args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, tempArgs >> + * + * Lbl_42 == /\ pc = "Lbl_42" /\ idx' = idx /\ pc' = "Lbl_43" /\ UNCHANGED << + * ops, args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_43 == /\ pc = "Lbl_43" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2156, column + * 18.") /\ pc' = "Lbl_44" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_44 == /\ pc = "Lbl_44" /\ curNode' = Node[curNode.operands[temp]] /\ IF + * curNode' = null THEN /\ PrintT("Selecting OTHER") /\ IF debug THEN /\ idx' = + * idx /\ pc' = "Lbl_45" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_63" /\ UNCHANGED idx /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_45 == /\ pc = "Lbl_45" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2160, column + * 18.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_36 == /\ pc = "Lbl_36" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2141, column + * 18.") /\ pc' = "Lbl_37" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_47 == /\ pc = "Lbl_47" /\ curNode' = Node[curNode.operands[temp]] /\ IF + * temp > 1 THEN /\ IF \/ curNode'.kind # OpApplKind \/ + * Node[curNode'.operator].kind # BuiltInKind \/ Node[curNode'.operator].name # + * "$Pair" THEN /\ PrintT("Unexpected expression node found.") /\ IF debug THEN + * /\ idx' = idx /\ pc' = "Lbl_48" ELSE /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ + * pc' = "Lbl_49" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_63" /\ UNCHANGED idx /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * subExprOf, result, mode, prevMode, curContext, curName, opDefArityFound, + * opDefArgs, firstFindingOpName, opNode, newName, newNode, nodeArity, temp, + * tempArgs >> + * + * Lbl_49 == /\ pc = "Lbl_49" /\ curNode' = Node[curNode.operands[2]] /\ pc' = + * "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * allArgs, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_48 == /\ pc = "Lbl_48" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2179, column + * 26.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_46 == /\ pc = "Lbl_46" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2172, column + * 19.") /\ pc' = "Lbl_47" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_51 == /\ pc = "Lbl_51" /\ curNode' = Node[curNode.operands[temp]] /\ pc' + * = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * allArgs, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_50 == /\ pc = "Lbl_50" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2195, column + * 25.") /\ pc' = "Lbl_51" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_53 == /\ pc = "Lbl_53" /\ curNode' = Node[curNode.operands[1]] /\ pc' = + * "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * allArgs, subExprOf, result, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_52 == /\ pc = "Lbl_52" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2220, column + * 32.") /\ pc' = "Lbl_53" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_54 == /\ pc = "Lbl_54" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2225, column + * 32.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_55 == /\ pc = "Lbl_55" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2232, column + * 12.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_56 == /\ pc = "Lbl_56" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2240, column + * 18.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_57 == /\ pc = "Lbl_57" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2255, column + * 9.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_58 == /\ pc = "Lbl_58" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2257, column + * 9.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_59 == /\ pc = "Lbl_59" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2260, column + * 9.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_60 == /\ pc = "Lbl_60" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2267, column + * 7.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_61 == /\ pc = "Lbl_61" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2272, column + * 10.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_62 == /\ pc = "Lbl_62" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2281, column + * 8.") /\ pc' = "Lbl_63" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_68 == /\ pc = "Lbl_68" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2303, column + * 8.") /\ pc' = "Lbl_69" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_70 == /\ pc = "Lbl_70" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2311, column + * 10.") /\ pc' = "Lbl_71" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_71 == /\ pc = "Lbl_71" /\ IF expectedArity < 0 THEN /\ IF \/ prevMode # + * "FindingOpName" \/ curNode.kind \notin {UserDefinedOpKind, + * ThmOrAssumpDefKind} THEN /\ PrintT("Should have selected a definition, but + * didn't.") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_72" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_73" /\ UNCHANGED idx ELSE /\ pc' = + * "Lbl_74" /\ UNCHANGED idx /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_73 == /\ pc = "Lbl_73" /\ result' = curNode /\ pc' = "Finished" /\ + * UNCHANGED << ops, args, expectedArity, substInPrefix, params, allArgs, + * curNode, subExprOf, idx, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, temp, tempArgs >> + * + * Lbl_72 == /\ pc = "Lbl_72" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2317, column + * 17.") /\ pc' = "Lbl_73" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_74 == /\ pc = "Lbl_74" /\ IF expectedArity > 0 THEN /\ temp' = + * (Len(params) + IF \/ prevMode = "FindingOpName" \/ curNode.kind = OpArgKind + * THEN Arity(curNode) ELSE 0) /\ IF expectedArity # temp' THEN /\ + * PrintT("Expect arity = " \o ToString(expectedArity) \o ", but found arity = " + * \o ToString(temp')) /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_75" ELSE /\ + * pc' = "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_76" /\ UNCHANGED idx ELSE /\ + * pc' = "Lbl_76" /\ UNCHANGED << idx, temp >> /\ UNCHANGED << ops, args, + * expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, result, + * mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, tempArgs >> + * + * Lbl_75 == /\ pc = "Lbl_75" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2329, column + * 18.") /\ pc' = "Lbl_76" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_76 == /\ pc = "Lbl_76" /\ IF /\ prevMode = "FindingOpName" /\ Len(params) + * + Len(substInPrefix) > 0 THEN /\ temp' = [i \in 1..Len(curNode.params) |-> + * [curNode.params[i] EXCEPT !.name = "New " \o @]] /\ curNode' = [kind |-> + * OpApplKind, operands |-> temp', operator |-> curNode, unboundedBoundSymbols + * |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << >>] /\ params' = + * params \o temp' /\ allArgs' = allArgs \o opDefArgs ELSE /\ TRUE /\ UNCHANGED + * << params, allArgs, curNode, temp >> /\ IF curNode'.kind = OpArgKind THEN /\ + * IF expectedArity = 0 THEN /\ PrintT("Selected Operator Argument when + * expression expected.") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_77" ELSE + * /\ pc' = "Done" /\ UNCHANGED idx ELSE /\ IF expectedArity # Len(params') + + * curNode'.arity THEN /\ PrintT("Selected operator has wrong arity.") /\ IF + * debug THEN /\ idx' = idx /\ pc' = "Lbl_78" ELSE /\ pc' = "Done" /\ UNCHANGED + * idx ELSE /\ IF Len(params') + Len(substInPrefix) > 0 THEN /\ pc' = "Lbl_79" + * ELSE /\ pc' = "Lbl_80" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_80" /\ UNCHANGED + * idx /\ UNCHANGED << ops, args, expectedArity, substInPrefix, subExprOf, + * result, mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, tempArgs >> + * + * Lbl_77 == /\ pc = "Lbl_77" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2363, column + * 12.") /\ pc' = "Lbl_80" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_78 == /\ pc = "Lbl_78" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2365, column + * 12.") /\ pc' = "Lbl_80" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_79 == /\ pc = "Lbl_79" /\ temp' = [i \in 1..curNode.arity |-> [name |-> + * "NewParam" \o NumToString(i), arity |-> 0]] /\ curNode' = [kind |-> + * OpApplKind, operands |-> temp', operator |-> Node[curNode.op], + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>] /\ params' = params \o temp' /\ pc' = "Lbl_80" /\ UNCHANGED << ops, args, + * expectedArity, substInPrefix, allArgs, subExprOf, result, idx, mode, + * prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, tempArgs >> + * + * Lbl_80 == /\ pc = "Lbl_80" /\ IF curNode.kind \in {UserDefinedOpKind, + * ConstantDeclKind, VariableDeclKind, FormalParamKind, BuiltInKind, + * BoundSymbolKind, ThmOrAssumpDefKind} THEN /\ IF expectedArity > 0 THEN /\ + * result' = [kind |-> OpArgKind, name |-> curNode.name, op |-> curNode, arity + * |-> expectedArity] ELSE /\ IF expectedArity = 0 THEN /\ result' = [kind |-> + * OpApplKind, operands |-> opDefArgs, operator |-> curNode, + * unboundedBoundSymbols |-> <<>>, boundedBoundSymbols |-> << >>, ranges |-> << + * >>, subExprOf |-> subExprOf] ELSE /\ TRUE /\ UNCHANGED result /\ pc' = + * "Finished" /\ UNCHANGED temp ELSE /\ IF curNode.kind = OpArgKind THEN /\ + * result' = curNode /\ pc' = "Finished" /\ UNCHANGED temp ELSE /\ temp' = + * Len(substInPrefix) /\ pc' = "Lbl_81" /\ UNCHANGED result /\ UNCHANGED << ops, + * args, expectedArity, substInPrefix, params, allArgs, curNode, subExprOf, idx, + * mode, prevMode, curContext, curName, opDefArityFound, opDefArgs, + * firstFindingOpName, opNode, newName, newNode, nodeArity, tempArgs >> + * + * Lbl_81 == /\ pc = "Lbl_81" /\ IF temp > 0 THEN /\ curNode' = [kind |-> + * SubstInKind, body |-> curNode , subst |-> substInPrefix[temp].subst ] /\ + * temp' = temp - 1 /\ pc' = "Lbl_81" /\ UNCHANGED idx ELSE /\ IF expectedArity + * > 0 THEN /\ IF Len(params) # expectedArity THEN /\ PrintT("Selection has + * wrong arity") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_82" ELSE /\ pc' = + * "Done" /\ UNCHANGED idx ELSE /\ pc' = "Lbl_83" /\ UNCHANGED idx ELSE /\ IF + * Len(params) # Len(allArgs) THEN /\ PrintT("Abort: number of params # num of + * args") /\ IF debug THEN /\ idx' = idx /\ pc' = "Lbl_84" ELSE /\ pc' = "Done" + * /\ UNCHANGED idx ELSE /\ pc' = "Lbl_85" /\ UNCHANGED idx /\ UNCHANGED << + * curNode, temp >> /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, subExprOf, result, mode, prevMode, curContext, curName, + * opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, newNode, + * nodeArity, tempArgs >> + * + * Lbl_83 == /\ pc = "Lbl_83" /\ result' = [kind |-> OpArgKind, op |-> [kind |-> + * UserDefinedOpKind, name |-> "LAMBDA", body |-> curNode, params |-> params, + * arity |-> Len(params), defined |-> TRUE, source |-> null], name |-> "LAMBDA"] + * /\ pc' = "Finished" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, idx, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_85 == /\ pc = "Lbl_85" /\ IF Len(params) = 0 THEN /\ result' = [kind |-> + * LabelKind, name |-> "$Subexpression", arity |-> 0, params |-> << >>, body |-> + * curNode, subExprOf |-> subExprOf] ELSE /\ result' = [kind |-> OpApplKind, + * operator |-> [kind |-> UserDefinedOpKind, name |-> "LAMBDA", body |-> + * curNode, params |-> params, arity |-> Len(params), defined |-> TRUE, source + * |-> null], operands |-> allArgs, unboundedBoundSymbols |-> <<>>, + * boundedBoundSymbols |-> << >>, ranges |-> << >>, subExprOf |-> subExprOf] /\ + * pc' = "Finished" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, + * params, allArgs, curNode, subExprOf, idx, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Lbl_82 == /\ pc = "Lbl_82" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2431, column + * 22.") /\ pc' = "Lbl_83" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Lbl_84 == /\ pc = "Lbl_84" /\ idx' = idx /\ Assert(FALSE, "Failure of + * assertion at line line 1892, column 38 of macro called at line 2443, column + * 22.") /\ pc' = "Lbl_85" /\ UNCHANGED << ops, args, expectedArity, + * substInPrefix, params, allArgs, curNode, subExprOf, result, mode, prevMode, + * curContext, curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, + * newName, newNode, nodeArity, temp, tempArgs >> + * + * Finished == /\ pc = "Finished" /\ PrintT("Result: ") /\ PrintT(result) /\ pc' + * = "Done" /\ UNCHANGED << ops, args, expectedArity, substInPrefix, params, + * allArgs, curNode, subExprOf, result, idx, mode, prevMode, curContext, + * curName, opDefArityFound, opDefArgs, firstFindingOpName, opNode, newName, + * newNode, nodeArity, temp, tempArgs >> + * + * Next == Lbl_1 \/ Lbl_2 \/ Lbl_69 \/ Lbl_3 \/ Lbl_5 \/ Lbl_6 \/ Lbl_7 \/ Lbl_4 + * \/ Lbl_10 \/ Lbl_12 \/ Lbl_13 \/ Lbl_11 \/ Lbl_14 \/ Lbl_15 \/ Lbl_17 \/ + * Lbl_18 \/ Lbl_16 \/ Lbl_19 \/ Lbl_8 \/ Lbl_9 \/ Lbl_20 \/ Lbl_21 \/ Lbl_23 \/ + * Lbl_25 \/ Lbl_26 \/ Lbl_27 \/ Lbl_24 \/ Lbl_28 \/ Lbl_22 \/ Lbl_63 \/ Lbl_64 + * \/ Lbl_65 \/ Lbl_66 \/ Lbl_67 \/ Lbl_29 \/ Lbl_30 \/ Lbl_31 \/ Lbl_33 \/ + * Lbl_35 \/ Lbl_34 \/ Lbl_32 \/ Lbl_37 \/ Lbl_38 \/ Lbl_39 \/ Lbl_40 \/ Lbl_41 + * \/ Lbl_42 \/ Lbl_43 \/ Lbl_44 \/ Lbl_45 \/ Lbl_36 \/ Lbl_47 \/ Lbl_49 \/ + * Lbl_48 \/ Lbl_46 \/ Lbl_51 \/ Lbl_50 \/ Lbl_53 \/ Lbl_52 \/ Lbl_54 \/ Lbl_55 + * \/ Lbl_56 \/ Lbl_57 \/ Lbl_58 \/ Lbl_59 \/ Lbl_60 \/ Lbl_61 \/ Lbl_62 \/ + * Lbl_68 \/ Lbl_70 \/ Lbl_71 \/ Lbl_73 \/ Lbl_72 \/ Lbl_74 \/ Lbl_75 \/ Lbl_76 + * \/ Lbl_77 \/ Lbl_78 \/ Lbl_79 \/ Lbl_80 \/ Lbl_81 \/ Lbl_83 \/ Lbl_85 \/ + * Lbl_82 \/ Lbl_84 \/ Finished \/ (* Disjunct to prevent deadlock on + * termination *) (pc = "Done" /\ UNCHANGED vars) + * + * Spec == Init /\ [][Next]_vars + * + * Termination == <>(pc = "Done") + * + * \* END TRANSLATION + * + * NotDone == pc # "Done" + * (*************************************************************************) + * (* To print a trace of an execution that doesn't produce an error, add *) (* + * "INVARIANT NotDone" to Subexpression.cfg . *) + * (*************************************************************************) + * ============================================================================= + ************************* + * + * end file Subexpression.tla + ****************************/ diff --git a/tlatools/src/tla2sany/semantic/InstanceNode.java b/tlatools/src/tla2sany/semantic/InstanceNode.java index 85425ae746e023758f25176d716d619773022651..c667f07a84470193596e75174f1a4438198a2b10 100644 --- a/tlatools/src/tla2sany/semantic/InstanceNode.java +++ b/tlatools/src/tla2sany/semantic/InstanceNode.java @@ -6,13 +6,15 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class InstanceNode extends LevelNode { /** @@ -397,16 +399,18 @@ public class InstanceNode extends LevelNode { return res; } - public final void walkGaph(Hashtable semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGaph(Hashtable<Integer, ExploreNode> semNodesTable, final ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; - semNodesTable.put(new Integer(myUID), this); + semNodesTable.put(myUID, this); + visitor.preVisit(this); for (int i = 0; i < params.length; i++) { - params[i].walkGraph(semNodesTable); + params[i].walkGraph(semNodesTable, visitor); } - module.walkGraph(semNodesTable); + module.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); } public final String toString(int depth) { diff --git a/tlatools/src/tla2sany/semantic/LabelNode.java b/tlatools/src/tla2sany/semantic/LabelNode.java index e5aed3b70f9f9b2b9d45841dbef39b6bceb2999b..e3b60bbc063e151b89633b81538c961a1c3abb0e 100644 --- a/tlatools/src/tla2sany/semantic/LabelNode.java +++ b/tlatools/src/tla2sany/semantic/LabelNode.java @@ -41,7 +41,11 @@ import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; @@ -50,9 +54,6 @@ import tla2sany.xml.SymbolContext; import util.UniqueString; import util.WrongInvocationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class LabelNode extends ExprNode implements ExploreNode, OpDefOrLabelNode { @@ -282,14 +283,16 @@ public class LabelNode extends ExprNode * The methods for implementing the ExploreNode interface. * *************************************************************************/ @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); - if (body != null) body.walkGraph(semNodesTable); + visitor.preVisit(this); + if (body != null) body.walkGraph(semNodesTable, visitor); for (int i = 0 ; i < params.length; i++) { - params[i].walkGraph(semNodesTable); + params[i].walkGraph(semNodesTable, visitor); } ; + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/LeafProofNode.java b/tlatools/src/tla2sany/semantic/LeafProofNode.java index b87ad1d5637b767244f2a590d870025c3aa0dd9f..c4054b40cc00400109bb5d388ec62e17e0bfc7b6 100644 --- a/tlatools/src/tla2sany/semantic/LeafProofNode.java +++ b/tlatools/src/tla2sany/semantic/LeafProofNode.java @@ -3,14 +3,15 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * This class represents a leaf proof. It is of kind LeafProffKind * ***************************************************************************/ @@ -100,17 +101,19 @@ public class LeafProofNode extends ProofNode { } @Override - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); for (int i = 0; i < facts.length; i++) { - facts[i].walkGraph(semNodesTable); + facts[i].walkGraph(semNodesTable, visitor); } ; /*********************************************************************** * Note: there's no need to walk the defs array because all the nodes * * on it are walked from the nodes under which they appear. * ***********************************************************************/ + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/LetInNode.java b/tlatools/src/tla2sany/semantic/LetInNode.java index 2e619f490649b5f1a3b1bf417b4e9edf1bdc3d61..2e94d23d39dd9a9bf514f7071c7196026b3abb75 100644 --- a/tlatools/src/tla2sany/semantic/LetInNode.java +++ b/tlatools/src/tla2sany/semantic/LetInNode.java @@ -6,15 +6,16 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class LetInNode extends ExprNode implements ExploreNode, LevelConstants { @@ -238,24 +239,26 @@ implements ExploreNode, LevelConstants { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); /*********************************************************************** * Can now walk LET nodes from context, don't need to use opDefs * * (which is incomplete). * ***********************************************************************/ - if (context != null){context.walkGraph(semNodesTable);} ; + if (context != null){context.walkGraph(semNodesTable, visitor);} ; // if (opDefs != null) { // for (int i = 0; i < opDefs.length; i++) { // if (opDefs[i] != null) opDefs[i].walkGraph(semNodesTable); // } // } - if (body != null) body.walkGraph(semNodesTable); + if (body != null) body.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/LevelNode.java b/tlatools/src/tla2sany/semantic/LevelNode.java index 002613d603cdbcf23bfa2197068b24602db9d877..4cb59cea7ab55d03b984e65dd29da8936e12e096 100644 --- a/tlatools/src/tla2sany/semantic/LevelNode.java +++ b/tlatools/src/tla2sany/semantic/LevelNode.java @@ -4,13 +4,13 @@ package tla2sany.semantic; import java.util.HashSet; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; import util.WrongInvocationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * Note: The SANY1 level checking algorithm is specified in the file * * LevelSpec.tla. The handling of recursive operators is explained in the * @@ -1862,7 +1862,7 @@ public int levelChecked = 0 ; // (* I believe this shold be OpDeclNode. (LL, Mar 2007) *) // (*******************************************************************) // param == op.params -// IN /\ n.level = Max(op.level, +// IN /\ n.level = NumMax(op.level, // SetMax({arg[i].level : i \in 1..p}) // (****************************************************************) // (* For an operator parameter, we assume that the weights of *) diff --git a/tlatools/src/tla2sany/semantic/ModuleNode.java b/tlatools/src/tla2sany/semantic/ModuleNode.java index 768f4041d52f030e8aec37dc92e147710d710bbc..d157b75b3d78a43e6e6e348cc421d7d5f919dd99 100644 --- a/tlatools/src/tla2sany/semantic/ModuleNode.java +++ b/tlatools/src/tla2sany/semantic/ModuleNode.java @@ -20,11 +20,13 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.stream.Stream; import org.w3c.dom.Document; import org.w3c.dom.Element; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.semantic.Context.Pair; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; @@ -410,6 +412,14 @@ public class ModuleNode extends SymbolNode { return opDefs; } + public final OpDefNode getOpDef(final String name) { + return getOpDef(UniqueString.uniqueStringOf(name)); + } + + public final OpDefNode getOpDef(final UniqueString name) { + return Stream.of(getOpDefs()).filter(o -> o.getName() == name).findFirst().orElse(null); + } + /************************************************************************* * Returns an array of all ThmOrAssumpDefNode objects created in the * * current module (but not in inner modules). They should appear in the * @@ -1077,17 +1087,18 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st, } @Override - public final void walkGraph (Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph (Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (ctxt != null) { - ctxt.walkGraph(semNodesTable); + ctxt.walkGraph(semNodesTable, visitor); } for (int i = 0; i < topLevelVec.size(); i++) { - ((LevelNode)(topLevelVec.elementAt(i))).walkGraph(semNodesTable); + ((LevelNode)(topLevelVec.elementAt(i))).walkGraph(semNodesTable, visitor); } // for (int i = 0; i < instanceVec.size(); i++) { // ((InstanceNode)(instanceVec.elementAt(i))).walkGraph(semNodesTable); @@ -1098,6 +1109,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st, // for (int i = 0; i < assumptionVec.size(); i++) { // ((AssumeNode)(assumptionVec.elementAt(i))).walkGraph(semNodesTable); // } + visitor.postVisit(this); } public final void print(int indent, int depth, boolean b) { diff --git a/tlatools/src/tla2sany/semantic/NewSymbNode.java b/tlatools/src/tla2sany/semantic/NewSymbNode.java index 6ca5ac858845a72ba821b352b35830716b072761..f5a5897829c704cc9a7ca54dbb6399596f238c9a 100644 --- a/tlatools/src/tla2sany/semantic/NewSymbNode.java +++ b/tlatools/src/tla2sany/semantic/NewSymbNode.java @@ -21,14 +21,15 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class NewSymbNode extends LevelNode { /************************************************************************* @@ -170,11 +171,13 @@ public class NewSymbNode extends LevelNode { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); - if (set != null) { set.walkGraph(semNodesTable); } ; + visitor.preVisit(this); + if (set != null) { set.walkGraph(semNodesTable, visitor); } ; + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/NonLeafProofNode.java b/tlatools/src/tla2sany/semantic/NonLeafProofNode.java index 6f36da65ae40d13df9f33cbf89970d0943629eec..b9819c21642c6ad63950799f8357d76380cd3f81 100644 --- a/tlatools/src/tla2sany/semantic/NonLeafProofNode.java +++ b/tlatools/src/tla2sany/semantic/NonLeafProofNode.java @@ -3,15 +3,16 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import tla2sany.xml.SymbolContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * This class represents a non-leaf node in the tree representing a * * structured proof. * @@ -173,22 +174,24 @@ public class NonLeafProofNode extends ProofNode { } @Override - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); for (int i = 0; i < steps.length; i++) { - steps[i].walkGraph(semNodesTable); + steps[i].walkGraph(semNodesTable, visitor); } ; /*********************************************************************** * Note: there's no need to walk the defs array because all the nodes * * on it are walked from the nodes under which they appear. * ***********************************************************************/ - context.walkGraph(semNodesTable) ; + context.walkGraph(semNodesTable, visitor) ; /********************************************************************* * Walk the ThmOrOpApplDef NumberedProofStepKind nodes. * *********************************************************************/ + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/NumeralNode.java b/tlatools/src/tla2sany/semantic/NumeralNode.java index bd62e9206df6300d2a5f881778718592affb9845..675a09ece57ce0ea5b89a5ebb0b280b6c18028c1 100644 --- a/tlatools/src/tla2sany/semantic/NumeralNode.java +++ b/tlatools/src/tla2sany/semantic/NumeralNode.java @@ -5,14 +5,15 @@ package tla2sany.semantic; import java.math.BigInteger; import java.util.Hashtable; -import tla2sany.explorer.ExploreNode; -import tla2sany.st.TreeNode; -import tla2sany.xml.SymbolContext; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; +import tla2sany.st.TreeNode; +import tla2sany.xml.SymbolContext; + /** * Describes a numeral like 4095. This number is represented by the * values @@ -112,11 +113,13 @@ public class NumeralNode extends ExprNode { // } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/OpApplNode.java b/tlatools/src/tla2sany/semantic/OpApplNode.java index 049a97bb6970f7dbab355dda3bb57fd678417580..06a745392ff055bed8f53405a916f85f645101c1 100644 --- a/tlatools/src/tla2sany/semantic/OpApplNode.java +++ b/tlatools/src/tla2sany/semantic/OpApplNode.java @@ -25,12 +25,15 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; -import tlc2.value.TupleValue; -import tlc2.value.Value; +import tlc2.tool.BuiltInOPs; +import tlc2.value.ITupleValue; +import tlc2.value.IValue; +import tlc2.value.Values; import util.UniqueString; /** @@ -670,7 +673,7 @@ public class OpApplNode extends ExprNode implements ExploreNode { this.levelConstraints.putAll(this.ranges[i].getLevelConstraints()); } for (int i = 0; i < this.operands.length; i++) { - Integer mlevel = new Integer(opDef.getMaxLevel(i)); + Integer mlevel = Integer.valueOf(opDef.getMaxLevel(i)); if (this.operands[i] != null) { Iterator<SymbolNode> iter = this.operands[i].getLevelParams().iterator(); while (iter.hasNext()) { @@ -701,7 +704,7 @@ public class OpApplNode extends ExprNode implements ExploreNode { for (int j = 0; j < this.operands.length; j++) { for (int k = 0; k < alen; k++) { if (opDef.getOpLevelCond(i, j, k)) { - Integer mlevel = new Integer(argDef.getMaxLevel(k)); + Integer mlevel = Integer.valueOf(argDef.getMaxLevel(k)); Iterator<SymbolNode> iter = this.operands[j].getLevelParams().iterator(); while (iter.hasNext()) { this.levelConstraints.put(iter.next(), mlevel); @@ -746,7 +749,7 @@ public class OpApplNode extends ExprNode implements ExploreNode { /*************************************************************** * Need to invoke levelCheck before invoking getMaxLevel. * ***************************************************************/ - Integer mlevel = new Integer(argDef.getMaxLevel(alp.i)); + Integer mlevel = Integer.valueOf(argDef.getMaxLevel(alp.i)); this.levelConstraints.put(alp.param, mlevel); } } // while @@ -774,14 +777,14 @@ public class OpApplNode extends ExprNode implements ExploreNode { int alen = opArg.getArity(); for (int j = 0; j < alen; j++) { ParamAndPosition pap = new ParamAndPosition(opArg, j); - Integer mlevel = new Integer(opDef.getMinMaxLevel(i, j)); + Integer mlevel = Integer.valueOf(opDef.getMinMaxLevel(i, j)); this.argLevelConstraints.put(pap, mlevel); } for (int j = 0; j < this.operands.length; j++) { for (int k = 0; k < alen; k++) { if (opDef.getOpLevelCond(i, j, k)) { ParamAndPosition pap = new ParamAndPosition(opArg, k); - Integer mlevel = new Integer(this.operands[j].getLevel()); + Integer mlevel = Integer.valueOf(this.operands[j].getLevel()); this.argLevelConstraints.put(pap, mlevel); } } @@ -798,7 +801,7 @@ public class OpApplNode extends ExprNode implements ExploreNode { * Have to invoke levelCheck before invoking getLevel. * ***************************************************************/ ParamAndPosition pap = new ParamAndPosition(alp.op, alp.i); - this.argLevelConstraints.put(pap, new Integer(arg.getLevel())); + this.argLevelConstraints.put(pap, Integer.valueOf(arg.getLevel())); } } @@ -1103,6 +1106,11 @@ public class OpApplNode extends ExprNode implements ExploreNode { // "ArgLevelParams: " + this.argLevelParams + "\n" ; // } + + public boolean hasOpcode(final int opCode) { + return opCode == BuiltInOPs.getOpCode(getOperator().getName()); + } + @Override public SemanticNode[] getChildren() { SemanticNode[] res = @@ -1122,30 +1130,31 @@ public class OpApplNode extends ExprNode implements ExploreNode { * and inserts them in the Hashtable semNodesTable for use by the Explorer tool. */ @Override - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (operator != null) { - operator.walkGraph(semNodesTable); + operator.walkGraph(semNodesTable, visitor); } if (unboundedBoundSymbols != null && unboundedBoundSymbols.length > 0) { for (int i = 0; i < unboundedBoundSymbols.length; i++) if (unboundedBoundSymbols[i] != null) - unboundedBoundSymbols[i].walkGraph(semNodesTable); + unboundedBoundSymbols[i].walkGraph(semNodesTable, visitor); } if (operands != null && operands.length > 0) { for (int i = 0; i < operands.length; i++) - if (operands[i] != null) operands[i].walkGraph(semNodesTable); + if (operands[i] != null) operands[i].walkGraph(semNodesTable, visitor); } if (ranges.length > 0) { for (int i = 0; i < ranges.length; i++) - if (ranges[i] != null) ranges[i].walkGraph(semNodesTable); + if (ranges[i] != null) ranges[i].walkGraph(semNodesTable, visitor); } if (boundedBoundSymbols != null && boundedBoundSymbols.length > 0) { @@ -1153,11 +1162,12 @@ public class OpApplNode extends ExprNode implements ExploreNode { if (boundedBoundSymbols[i] != null && boundedBoundSymbols[i].length > 0) { for (int j = 0; j < boundedBoundSymbols[i].length; j++) { if (boundedBoundSymbols[i][j] != null) - boundedBoundSymbols[i][j].walkGraph(semNodesTable); + boundedBoundSymbols[i][j].walkGraph(semNodesTable, visitor); } } } } + visitor.postVisit(this); } // Used in implementation of toString() below @@ -1239,8 +1249,8 @@ public class OpApplNode extends ExprNode implements ExploreNode { } @Override - public String toString(final Value aValue) { - if (aValue instanceof TupleValue && allParams.size() == ((TupleValue) aValue).size()) { + public String toString(final IValue aValue) { + if (aValue instanceof ITupleValue && allParams.size() == ((ITupleValue) aValue).size()) { final StringBuffer result = new StringBuffer(); // The values in aValue are ordered by the varloc of the variable names (see @@ -1259,9 +1269,9 @@ public class OpApplNode extends ExprNode implements ExploreNode { result.append("/\\ "); result.append(sn.getName().toString()); - final Value value = ((TupleValue) aValue).elems[idx++]; + final IValue value = ((ITupleValue) aValue).getElem(idx++); result.append(" = "); - result.append(Value.ppr(value)); + result.append(Values.ppr(value)); result.append("\n"); } return result.toString(); diff --git a/tlatools/src/tla2sany/semantic/OpArgNode.java b/tlatools/src/tla2sany/semantic/OpArgNode.java index b93e2fa1fa9f2812ed19cdad08bb55acd76d3c8b..1f50c9b21241874ce42cbfc34a78960a7e97a38c 100644 --- a/tlatools/src/tla2sany/semantic/OpArgNode.java +++ b/tlatools/src/tla2sany/semantic/OpArgNode.java @@ -7,15 +7,16 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * This class represents operators of arity > 0 used as arguments to * other operators. Such operator instances are used in syntactic @@ -112,11 +113,12 @@ public class OpArgNode extends ExprOrOpArgNode { // } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); /*********************************************************************** * Modified on 28 Mar 2007 by LL to walk the operator node of the * @@ -126,7 +128,8 @@ public class OpArgNode extends ExprOrOpArgNode { * walking the node representing the declaration or definition of the * * operator. * ***********************************************************************/ - if (op != null) {op.walkGraph(semNodesTable) ;} ; + if (op != null) {op.walkGraph(semNodesTable, visitor) ;} ; + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/OpDeclNode.java b/tlatools/src/tla2sany/semantic/OpDeclNode.java index 4820867ef14a49926a1ea903f21e6ec29095b1d9..7475d966ad8ccf21952c38afc7093be71e616b70 100644 --- a/tlatools/src/tla2sany/semantic/OpDeclNode.java +++ b/tlatools/src/tla2sany/semantic/OpDeclNode.java @@ -7,14 +7,15 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * An OpDeclNode can have one of the following kinds: * @@ -140,10 +141,12 @@ public class OpDeclNode extends OpDefOrDeclNode { // } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/OpDefNode.java b/tlatools/src/tla2sany/semantic/OpDefNode.java index b18d843c1a15d46dcd92072fcdaedaf154de2ff6..343c3033db2e88ab724bf57177d46e3dd68e7d8e 100644 --- a/tlatools/src/tla2sany/semantic/OpDefNode.java +++ b/tlatools/src/tla2sany/semantic/OpDefNode.java @@ -39,6 +39,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.Location; import tla2sany.st.TreeNode; @@ -1225,17 +1226,19 @@ public class OpDefNode extends OpDefOrDeclNode * the Explorer tool. */ @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (params != null && params.length > 0) { for (int i = 0; i < params.length; i++) { - if (params[i] != null) params[i].walkGraph(semNodesTable); + if (params[i] != null) params[i].walkGraph(semNodesTable, visitor); } } - if (body != null) body.walkGraph(semNodesTable); - if (stepNode != null) stepNode.walkGraph(semNodesTable); + if (body != null) body.walkGraph(semNodesTable, visitor); + if (stepNode != null) stepNode.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/SemanticNode.java b/tlatools/src/tla2sany/semantic/SemanticNode.java index 45068ff61b594ed5323e920981d471ef8eaca780..5419d08cda79b5160a7b1fe07c168550f2c140e1 100644 --- a/tlatools/src/tla2sany/semantic/SemanticNode.java +++ b/tlatools/src/tla2sany/semantic/SemanticNode.java @@ -5,18 +5,20 @@ package tla2sany.semantic; import java.util.Hashtable; +import java.util.concurrent.atomic.AtomicInteger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.Location; import tla2sany.st.TreeNode; import tla2sany.xml.XMLExportable; -import tlc2.value.Value; -import util.ToolIO; +import tlc2.value.IValue; +import tlc2.value.Values; /** * SemanticNode is the (abstract) superclass of all nodes in the @@ -30,11 +32,11 @@ public abstract class SemanticNode private static final Object[] EmptyArr = new Object[0]; - private static int uid = 0; // the next unique ID for any semantic node + private static final AtomicInteger uid = new AtomicInteger(); // the next unique ID for any semantic node protected static Errors errors; - public int myUID; // the unique ID of THIS semantic node + public final int myUID; // the unique ID of THIS semantic node public TreeNode stn; // the concrete syntax tree node associated with THIS semantic node private Object[] tools; // each tool has a location in this array where // it may store an object for its own purposes @@ -42,7 +44,7 @@ public abstract class SemanticNode // strongly correlated with the Java type of the node public SemanticNode(int kind, TreeNode stn) { - myUID = uid++; + myUID = uid.getAndIncrement(); this.kind = kind; this.stn = stn; this.tools = EmptyArr; @@ -88,7 +90,6 @@ public abstract class SemanticNode this.tools = newTools; } this.tools[toolId] = obj; - ToolIO.registerSemanticNode(this, toolId); } /** @@ -177,10 +178,12 @@ public abstract class SemanticNode * of walkgraph is to find all reachable nodes in the semantic graph * and insert them in a Hashtable for use by the Explorer tool. */ - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } /** @@ -194,10 +197,21 @@ public abstract class SemanticNode " kind: " + (kind == -1 ? "<none>" : kinds[kind]) + getPreCommentsAsString()); } + + public boolean isBuiltIn() { + return Context.isBuiltIn(this); + } + public boolean isStandardModule() { + return StandardModules.isDefinedInStandardModule(this); + } + // YY's code public final Location getLocation() { - return this.stn.getLocation(); + if (this.stn != null) { + return this.stn.getLocation(); + } + return Location.nullLoc; } /** @@ -228,6 +242,36 @@ public abstract class SemanticNode return (loc1.beginColumn() < loc2.beginColumn())?-1:1; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + kind; + result = prime * result + myUID; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + SemanticNode other = (SemanticNode) obj; + if (kind != other.kind) { + return false; + } + if (myUID != other.myUID) { + return false; + } + return true; + } + /*************************************************************************** * XXXXX A test for getLocation() returning null should be added * * to the following two toString methods. * @@ -258,8 +302,8 @@ public abstract class SemanticNode return getLocation().toString(); } - public String toString(final Value aValue) { - return Value.ppr(aValue.toString()); + public String toString(final IValue aValue) { + return Values.ppr(aValue.toString()); } /** diff --git a/tlatools/src/tla2sany/semantic/StandardModules.java b/tlatools/src/tla2sany/semantic/StandardModules.java new file mode 100644 index 0000000000000000000000000000000000000000..3a07ea36216de71b4992e448b93b31b245cc03b2 --- /dev/null +++ b/tlatools/src/tla2sany/semantic/StandardModules.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tla2sany.semantic; + +import java.util.HashSet; +import java.util.Set; + +public class StandardModules { + + private static final Set<String> standardModules = new HashSet<>(); + + static { + // Quick'n'Dirty hack! This breaks if any one of the operators is override by + // the model or a complete standard module has been replaced by a user-defined + // module with the same name. + standardModules.add("FiniteSets"); + standardModules.add("Sequences"); + standardModules.add("Bags"); + standardModules.add("Naturals"); + standardModules.add("Integers"); + standardModules.add("Reals"); + standardModules.add("RealTime"); + standardModules.add("Randomization"); + standardModules.add("TLC"); + } + + private StandardModules() { + // no instances + } + + public static boolean isDefinedInStandardModule(SemanticNode sn) { + if (sn != null && sn.getLocation() != null) { + final String source = sn.getLocation().source(); // source might be null + return standardModules.contains(source); + } + return false; + } +} diff --git a/tlatools/src/tla2sany/semantic/StringNode.java b/tlatools/src/tla2sany/semantic/StringNode.java index 89ca90d926a2804e11b6750cdc1381d2013de5c6..80746864ee8e21279d624291cd9c6c005d855d1c 100644 --- a/tlatools/src/tla2sany/semantic/StringNode.java +++ b/tlatools/src/tla2sany/semantic/StringNode.java @@ -4,15 +4,16 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - /** @@ -84,11 +85,13 @@ public class StringNode extends ExprNode implements ExploreNode { // } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); + visitor.postVisit(this); } final String PrintVersion(String str) { diff --git a/tlatools/src/tla2sany/semantic/Subst.java b/tlatools/src/tla2sany/semantic/Subst.java index 5cf6e9fd761f769b6b37211f25713532888b2788..8f3bd4de55010c74d99707e149c317534cb5a859 100644 --- a/tlatools/src/tla2sany/semantic/Subst.java +++ b/tlatools/src/tla2sany/semantic/Subst.java @@ -6,13 +6,16 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; import tla2sany.xml.XMLExportable; -import org.w3c.dom.Document; -import org.w3c.dom.Element; +import tlc2.tool.coverage.CostModel; public class Subst implements LevelConstants, ASTConstants, ExploreNode, XMLExportable /* interface for exporting into XML */ { @@ -24,6 +27,7 @@ public class Subst implements LevelConstants, ASTConstants, ExploreNode, XMLExpo private ExprOrOpArgNode expr; private TreeNode exprSTN; private boolean implicit; + private CostModel cm = CostModel.DO_NOT_RECORD; /* Constructors */ public Subst(OpDeclNode odn, ExprOrOpArgNode exp, TreeNode exSTN, boolean imp) { @@ -49,6 +53,13 @@ public class Subst implements LevelConstants, ASTConstants, ExploreNode, XMLExpo public final void setExprSTN(TreeNode stn) { this.exprSTN = stn; } public final boolean isImplicit() { return this.implicit; } + + public final CostModel getCM() { return this.cm; } + + public final Subst setCM(final CostModel cm) { + this.cm = cm; + return this; + } public static ExprOrOpArgNode getSub(Object param, Subst[] subs) { for (int i = 0; i < subs.length; i++) { @@ -229,9 +240,11 @@ public class Subst implements LevelConstants, ASTConstants, ExploreNode, XMLExpo public final String levelDataToString() { return "Dummy level string"; } - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - if (op != null) op.walkGraph(semNodesTable); - if (expr != null) expr.walkGraph(semNodesTable); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + visitor.preVisit(this); + if (op != null) op.walkGraph(semNodesTable, visitor); + if (expr != null) expr.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); } public final String toString(int depth) { diff --git a/tlatools/src/tla2sany/semantic/SubstInNode.java b/tlatools/src/tla2sany/semantic/SubstInNode.java index 8d8c757e8312784ada75834420d758c823e3e10b..e1de6219a3995def4cf6e237be98cfe8144804c0 100644 --- a/tlatools/src/tla2sany/semantic/SubstInNode.java +++ b/tlatools/src/tla2sany/semantic/SubstInNode.java @@ -24,16 +24,17 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class SubstInNode extends ExprNode { /** * For a SubstInNode object s that has the WITH clause @@ -82,7 +83,7 @@ public class SubstInNode extends ExprNode { * substitutions is to be produced. */ public SubstInNode(TreeNode treeNode, SymbolTable instancerST, - Vector instanceeDecls, ModuleNode ingmn, ModuleNode edmn) + Vector<OpDeclNode> instanceeDecls, ModuleNode ingmn, ModuleNode edmn) throws AbortException { super(SubstInKind, treeNode); this.instantiatingModule = ingmn; @@ -132,17 +133,17 @@ public class SubstInNode extends ExprNode { * OpApplNode or an OpArgNode substituted for each CONSTANT of * VARIABLE OpDeclNode in vector v. */ - final void constructSubst(Vector instanceeDecls, SymbolTable instancerST, + final void constructSubst(Vector<OpDeclNode> instanceeDecls, SymbolTable instancerST, TreeNode treeNode) throws AbortException { - Vector vtemp = new Vector(); + Vector<Subst> vtemp = new Vector<>(); // for each CONSTANT or VARIABLE declared in module being // instantiated (the instancee) for ( int i = 0; i < instanceeDecls.size(); i++ ) { // Get the OpDeclNode for the CONSTANT or VARIABLE being // substituted for, i.e. "c" in" c <- e" - OpDeclNode decl = (OpDeclNode)instanceeDecls.elementAt(i); + OpDeclNode decl = instanceeDecls.elementAt(i); // Try to resolve the name in the instancer module so we can see // if it is recognized as an operator, and if so, what kind of @@ -264,10 +265,10 @@ public class SubstInNode extends ExprNode { * possible, because X is not defined in the instantiating module, * then we have an error. */ - final void matchAll(Vector decls) { + final void matchAll(Vector<OpDeclNode> decls) { for (int i = 0; i < decls.size(); i++) { // Get the name of the i'th operator that must be substituted for - UniqueString opName = ((OpDeclNode)decls.elementAt(i)).getName(); + UniqueString opName = decls.elementAt(i).getName(); // See if it is represented in the substitutions array int j; @@ -279,7 +280,7 @@ public class SubstInNode extends ExprNode { if ( j >= this.substs.length ) { errors.addError(stn.getLocation(), "Substitution missing for symbol " + opName + " declared at " + - ((OpDeclNode)(decls.elementAt(i))).getTreeNode().getLocation() + + decls.elementAt(i).getTreeNode().getLocation() + " \nand instantiated in module " + instantiatingModule.getName() + "." ); } } @@ -505,18 +506,20 @@ public class SubstInNode extends ExprNode { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (this.substs != null) { for (int i = 0; i < this.substs.length; i++) { - if (this.substs[i] != null) this.substs[i].walkGraph(semNodesTable); + if (this.substs[i] != null) this.substs[i].walkGraph(semNodesTable, visitor); } } - if (this.body != null) this.body.walkGraph(semNodesTable); + if (this.body != null) this.body.walkGraph(semNodesTable, visitor); + visitor.postVisit(this); return; } diff --git a/tlatools/src/tla2sany/semantic/SymbolNode.java b/tlatools/src/tla2sany/semantic/SymbolNode.java index 907e7af38585de542964efd09bb97073455ca4e8..b5ca60576480ad4a822342723d10a1171422bf52 100644 --- a/tlatools/src/tla2sany/semantic/SymbolNode.java +++ b/tlatools/src/tla2sany/semantic/SymbolNode.java @@ -2,12 +2,12 @@ // Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. package tla2sany.semantic; -import tla2sany.st.TreeNode; -import util.UniqueString; - import org.w3c.dom.Document; import org.w3c.dom.Element; +import tla2sany.st.TreeNode; +import util.UniqueString; + /** * Abstract class extended by classes that represent the meaning of an * identifier, including generalized IDs. diff --git a/tlatools/src/tla2sany/semantic/SymbolTable.java b/tlatools/src/tla2sany/semantic/SymbolTable.java index 167d1e75a82ec6284e7f6d56ae959449e6f7f6c7..864320ad87eac4f6fc269b5ff57c610ac7fb5344 100644 --- a/tlatools/src/tla2sany/semantic/SymbolTable.java +++ b/tlatools/src/tla2sany/semantic/SymbolTable.java @@ -88,14 +88,15 @@ public class SymbolTable implements ASTConstants { * Looks up `name' in the symbol table and returns the node it finds, or * * null if there is no entry for `name'. * *************************************************************************/ - public final SymbolNode resolveSymbol(UniqueString name) { - for (int c = contextStack.size()-1; c >= 0; c-- ) { - Context ct = (Context)contextStack.elementAt(c); - SymbolNode r = ct.getSymbol( name ); - if (r != null) return r; - } - return null; - } + public final SymbolNode resolveSymbol(UniqueString name) { + for (int c = contextStack.size() - 1; c >= 0; c--) { + Context ct = (Context) contextStack.elementAt(c); + SymbolNode r = ct.getSymbol(name); + if (r != null) + return r; + } + return null; + } public final ModuleNode resolveModule(UniqueString name) { ModuleName modName = new ModuleName(name); diff --git a/tlatools/src/tla2sany/semantic/TheoremNode.java b/tlatools/src/tla2sany/semantic/TheoremNode.java index c50b3591c660ff1fc9e0e85291d1eb98cc5c6a1e..7b07e72372603313e677ad6f34bac6b7e69c2c92 100644 --- a/tlatools/src/tla2sany/semantic/TheoremNode.java +++ b/tlatools/src/tla2sany/semantic/TheoremNode.java @@ -15,16 +15,17 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - /** * This class represents a theorem */ @@ -373,13 +374,15 @@ public class TheoremNode extends LevelNode { } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); if (theoremExprOrAssumeProve != null) - {theoremExprOrAssumeProve.walkGraph(semNodesTable);} ; - if (proof != null) {proof.walkGraph(semNodesTable);} ; + {theoremExprOrAssumeProve.walkGraph(semNodesTable, visitor);} ; + if (proof != null) {proof.walkGraph(semNodesTable, visitor);} ; + visitor.postVisit(this); } /* MR: this does not do anything diff --git a/tlatools/src/tla2sany/semantic/ThmOrAssumpDefNode.java b/tlatools/src/tla2sany/semantic/ThmOrAssumpDefNode.java index c0dad86488d61413b3e844dd5d34110ef2c1b8d1..3e64c84fc28e76e9371ddc7ff9b9e6a8fa8e0bd0 100644 --- a/tlatools/src/tla2sany/semantic/ThmOrAssumpDefNode.java +++ b/tlatools/src/tla2sany/semantic/ThmOrAssumpDefNode.java @@ -27,7 +27,11 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; @@ -35,9 +39,6 @@ import tla2sany.xml.SymbolContext; import util.UniqueString; import util.WrongInvocationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * This node represents the definition of Foo in * * * @@ -581,11 +582,13 @@ public class ThmOrAssumpDefNode extends SymbolNode } @Override - public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public final void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); - if(this.body != null) {this.body.walkGraph(semNodesTable) ;} ; + visitor.preVisit(this); + if(this.body != null) {this.body.walkGraph(semNodesTable, visitor) ;} ; + visitor.postVisit(this); } @Override diff --git a/tlatools/src/tla2sany/semantic/UseOrHideNode.java b/tlatools/src/tla2sany/semantic/UseOrHideNode.java index 7fb248d776c140ed4d69963e98bcb2b47c2bc305..1aaf34381d3942ed06a7cffeaa614b7f5c0331ec 100644 --- a/tlatools/src/tla2sany/semantic/UseOrHideNode.java +++ b/tlatools/src/tla2sany/semantic/UseOrHideNode.java @@ -4,15 +4,16 @@ package tla2sany.semantic; import java.util.Hashtable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /*************************************************************************** * This class represents a USE or HIDE statement. It is of kind * * UseKind or HideKind. * @@ -115,17 +116,19 @@ public class UseOrHideNode extends LevelNode { } @Override - public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable) { - Integer uid = new Integer(myUID); + public void walkGraph(Hashtable<Integer, ExploreNode> semNodesTable, ExplorerVisitor visitor) { + Integer uid = Integer.valueOf(myUID); if (semNodesTable.get(uid) != null) return; semNodesTable.put(uid, this); + visitor.preVisit(this); for (int i = 0; i < facts.length; i++) { - facts[i].walkGraph(semNodesTable); + facts[i].walkGraph(semNodesTable, visitor); } ; /*********************************************************************** * Note: there's no need to walk the defs array because all the nodes * * on it are walked from the nodes under which they appear. * ***********************************************************************/ + visitor.postVisit(this); } /* diff --git a/tlatools/src/tla2sany/st/Location.java b/tlatools/src/tla2sany/st/Location.java index 8daad5cd8b11c203e27580acfae969306fe19eb9..ffa60fb24cbe2dbc2924cff660de0c40b2db4f10 100644 --- a/tlatools/src/tla2sany/st/Location.java +++ b/tlatools/src/tla2sany/st/Location.java @@ -8,8 +8,6 @@ import java.util.regex.Pattern; import pcal.PCalLocation; import pcal.Region; - -import tlc2.output.EC; import util.Assert; import util.UniqueString; @@ -21,7 +19,7 @@ import util.UniqueString; * @author Leslie Lamport, Simon Zambrovski * @version $Id$ */ -public final class Location +public final class Location implements Comparable<Location> { // strings used in toString() and Regex private static final String LINE = "line "; @@ -94,7 +92,12 @@ public final class Location protected UniqueString name; protected int bLine, bColumn, eLine, eColumn; - /** + public Location(final String fName, final String bl, final String bc, final String el, final String ec) { + this(UniqueString.uniqueStringOf(fName), Integer.valueOf(bl), Integer.valueOf(bc), Integer.valueOf(el), + Integer.valueOf(ec)); + } + + /** * Constructs a location * @param fName name of the source * @param bl begin line @@ -218,6 +221,11 @@ public final class Location } } + public static Location parseCoordinates(final String source, final String coordinates) { + final String[] c = coordinates.split(" "); + return new Location(source, c[0], c[1], c[2], c[3]); + } + /** * Returns an array of {@link Location} that can be parsed * from the input. More precisely, this method returns all @@ -295,6 +303,10 @@ public final class Location return this.eLine; } + public final int[] getCoordinates() { + return new int[] { bLine, bColumn, eLine, eColumn }; + } + /** * gets the end column number of this location. */ @@ -308,7 +320,7 @@ public final class Location */ public final String source() { - return name.toString(); + return name != null ? name.toString() : null; } /** @@ -357,6 +369,21 @@ public final class Location return false; } + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + bColumn; + result = prime * result + bLine; + result = prime * result + eColumn; + result = prime * result + eLine; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + /** * Translates the {@link Location} into a PCal {@link Region} adjusting the * 1-based offset to a 0-based one. @@ -367,4 +394,64 @@ public final class Location return new pcal.Region(new PCalLocation(bLine - 1, bColumn - 1), new PCalLocation(eLine - 1, eColumn - 1)); } + + @Override + public int compareTo(final Location other) { + if (this.equals(other)) { + return 0; + } + if (this.name.compareTo(other.name) != 0) { + return this.name.compareTo(other.name); + } + + if (this.bLine > other.bLine) { + return 1; + } else if (this.bLine < other.bLine) { + return -1; + } + + if (this.bColumn > other.bColumn) { + return 1; + } else if (this.bColumn < other.bColumn) { + return -1; + } + + if (this.eLine > other.eLine) { + return 1; + } else if (this.eLine < other.eLine) { + return -1; + } + + if (this.eColumn < other.eColumn) { + return -1; + } + return 1; + } + + /** + * @return true if other is a location within this location (same module file + * and the range of chars is within this range of chars). + */ + public boolean includes(final Location other) { + if (this.name != other.name) { + return false; + } + if (this.bLine > other.bLine) { + return false; + } + if (this.eLine < other.eLine) { + return false; + } + if (this.bColumn > other.bColumn) { + return false; + } + if (this.eColumn < other.eColumn) { + return false; + } + return true; + } + + public String linesAndColumns() { + return toString().replaceAll(OF_MODULE + ".*", ""); + } } diff --git a/tlatools/src/tla2sany/xml/SymbolContext.java b/tlatools/src/tla2sany/xml/SymbolContext.java index 57d900392eafb02590b53d1840e91b8eeebc398a..c4100a4aca75d7dd705c861e728c1115e2b5e44f 100644 --- a/tlatools/src/tla2sany/xml/SymbolContext.java +++ b/tlatools/src/tla2sany/xml/SymbolContext.java @@ -1,11 +1,11 @@ package tla2sany.xml; -import tla2sany.semantic.SymbolNode; -import tla2sany.semantic.TheoremNode; -import tla2sany.semantic.AssumeNode; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; + +import tla2sany.semantic.AssumeNode; +import tla2sany.semantic.SymbolNode; +import tla2sany.semantic.TheoremNode; /* TL * This class is used to track the occurrence of SymbolNodes diff --git a/tlatools/src/tla2sany/xml/XMLExportable.java b/tlatools/src/tla2sany/xml/XMLExportable.java index dfa93113d97fd4671ebff6cc25b222e2e4e4f69b..95bd1b99b6c65a3755291dd58f0c9cc3d5c951b2 100644 --- a/tlatools/src/tla2sany/xml/XMLExportable.java +++ b/tlatools/src/tla2sany/xml/XMLExportable.java @@ -2,12 +2,13 @@ package tla2sany.xml; +import org.w3c.dom.Document; + /** * an interface for being able to export XML content */ import org.w3c.dom.Element; -import org.w3c.dom.Document; public interface XMLExportable { diff --git a/tlatools/src/tla2sany/xml/XMLExporter.java b/tlatools/src/tla2sany/xml/XMLExporter.java index 6a1ba8ec40e469ae1210598af9ba70c2d27882fe..7ab4275c31657024f600c117e3552a69748bbed8 100644 --- a/tlatools/src/tla2sany/xml/XMLExporter.java +++ b/tlatools/src/tla2sany/xml/XMLExporter.java @@ -3,48 +3,16 @@ package tla2sany.xml; +import java.io.ByteArrayOutputStream; + /** * a tool for exporting the loaded modules to XML format */ import java.io.PrintStream; -import java.io.ByteArrayOutputStream; -import java.util.Iterator; +import java.net.URL; import java.util.LinkedList; -import tla2sany.drivers.SANY; -import tla2sany.drivers.FrontEndException; -import tla2sany.configuration.Configuration; -import tla2sany.explorer.Explorer; -import tla2sany.explorer.ExplorerQuitException; -import tla2sany.modanalyzer.ParseUnit; -import tla2sany.modanalyzer.SpecObj; -import tla2sany.parser.ParseException; -import tla2sany.semantic.AbortException; -import tla2sany.semantic.BuiltInLevel; -import tla2sany.semantic.Context; -import tla2sany.semantic.Errors; -import tla2sany.semantic.ExternalModuleTable; -import tla2sany.semantic.Generator; -import tla2sany.semantic.ModuleNode; -import tla2sany.semantic.SemanticNode; -import tla2sany.st.Location; -import tla2sany.semantic.ModuleNode; -import util.FileUtil; -import util.ToolIO; -import util.UniqueString; -import util.FilenameToStream; -import util.SimpleFilenameToStream; -import tla2sany.semantic.SymbolNode; -import tla2sany.semantic.AssumeNode; -import tla2sany.semantic.TheoremNode; -import tla2sany.semantic.InstanceNode; -import tla2sany.semantic.OpDeclNode; -import tla2sany.semantic.OpDefNode; - - -// XML packages -import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -53,16 +21,23 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.validation.SchemaFactory; import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; -import org.xml.sax.SAXException; -import java.net.URL; -import java.net.MalformedURLException; -import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import tla2sany.drivers.FrontEndException; +import tla2sany.drivers.SANY; +import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.ExternalModuleTable; +import tla2sany.semantic.ModuleNode; +import util.FileUtil; +import util.FilenameToStream; +import util.SimpleFilenameToStream; +import util.ToolIO; public class XMLExporter { diff --git a/tlatools/src/tla2sany/xml/XMLExportingException.java b/tlatools/src/tla2sany/xml/XMLExportingException.java index f988a2db7b49462ca5de510d5a44a7747b5d724d..50521ff22ec8bb8932745d9abe7f764058b02a30 100644 --- a/tlatools/src/tla2sany/xml/XMLExportingException.java +++ b/tlatools/src/tla2sany/xml/XMLExportingException.java @@ -2,7 +2,8 @@ // Copyright (c) 2013 INRIA-MSR. All rights reserved. package tla2sany.xml; -import java.io.*; +import java.io.PrintWriter; +import java.io.StringWriter; /** * an exception for erroes in the exporter diff --git a/tlatools/src/tla2tex/TokenizeSpec.java b/tlatools/src/tla2tex/TokenizeSpec.java index 3b3f10a5442db77ccc5abf38b292dad2ad22f84c..993d631d2d1373e7223fb7415e27683960e65d6a 100644 --- a/tlatools/src/tla2tex/TokenizeSpec.java +++ b/tlatools/src/tla2tex/TokenizeSpec.java @@ -469,9 +469,6 @@ package tla2tex; import java.util.Hashtable; import java.util.Vector; -import pcal.MappingObject.EndTLAToken; -import pcal.PCalLocation; - /** * @author lamport * diff --git a/tlatools/src/tlc2/TLC.java b/tlatools/src/tlc2/TLC.java index 0b63b84ddcb982a7453d2edb2f293cc7d5d70eb1..bc31ed61f1251cbd3324e493d2c9484d0168636b 100644 --- a/tlatools/src/tlc2/TLC.java +++ b/tlatools/src/tlc2/TLC.java @@ -12,23 +12,24 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.Enumeration; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.TimeZone; import model.InJarFilenameToStream; import model.ModelInJar; -import tla2sany.modanalyzer.ParseUnit; -import tla2sany.modanalyzer.SpecObj; import tlc2.output.EC; import tlc2.output.MP; -import tlc2.tool.AbstractChecker; -import tlc2.tool.Cancelable; import tlc2.tool.DFIDModelChecker; +import tlc2.tool.ITool; import tlc2.tool.ModelChecker; import tlc2.tool.Simulator; import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; +import tlc2.tool.fp.FPSetFactory; +import tlc2.tool.impl.Tool; import tlc2.tool.management.ModelCheckerMXWrapper; import tlc2.tool.management.TLCStandardMBean; import tlc2.util.DotStateWriter; @@ -37,9 +38,10 @@ import tlc2.util.IStateWriter; import tlc2.util.NoopStateWriter; import tlc2.util.RandomGenerator; import tlc2.util.StateWriter; -import tlc2.value.EnumerableValue; -import tlc2.value.Value; +import tlc2.value.RandomEnumerableValues; +import util.Assert.TLCRuntimeException; import util.DebugPrinter; +import util.ExecutionStatisticsCollector; import util.FileUtil; import util.FilenameToStream; import util.MailSender; @@ -92,18 +94,14 @@ public class TLC /** * The number of traces/behaviors to generate in simulation mode */ - public static long traceNum = Long.MAX_VALUE; + private static long traceNum = Long.MAX_VALUE; private String traceFile = null; private int traceDepth; private FilenameToStream resolver; - private SpecObj specObj; // flag if the welcome message is already printed private boolean welcomePrinted; - // handle to the cancellable instance (MC or Simulator) - private Cancelable instance; - private FPSetConfiguration fpSetConfiguration; /** @@ -126,11 +124,8 @@ public class TLC fromChkpt = null; resolver = null; - fpIndex = 0; + fpIndex = new Random().nextInt(FP64.Polys.length); traceDepth = 100; - - // instance is not set - instance = null; fpSetConfiguration = new FPSetConfiguration(); } @@ -186,7 +181,7 @@ public class TLC * stored in the class FP64. * o -view: apply VIEW (if provided) when printing out states. * o -gzip: control if gzip is applied to value input/output stream. - * Defaults to use gzip. + * Defaults to off if not specified * o -debug: debbuging information (non-production use) * o -tool: tool mode (put output codes on console) * o -checkpoint num: interval for check pointing (in minutes) @@ -202,41 +197,92 @@ public class TLC */ public static void main(String[] args) throws Exception { - TLC tlc = new TLC(); + final TLC tlc = new TLC(); - // handle parameters - if (tlc.handleParameters(args)) - { - final MailSender ms = new MailSender(); - if (MODEL_PART_OF_JAR) { - tlc.setResolver(new InJarFilenameToStream(ModelInJar.PATH)); - } else { - tlc.setResolver(new SimpleFilenameToStream()); - } - ms.setModelName(tlc.getModelName()); - ms.setSpecName(tlc.getSpecName()); + // Try to parse parameters. + if (!tlc.handleParameters(args)) { + // This is a tool failure. We must exit with a non-zero exit + // code or else we will mislead system tools and scripts into + // thinking everything went smoothly. + // + // FIXME: handleParameters should return an error object (or + // null), where the error object contains an error message. + // This makes handleParameters a function we can test. + System.exit(1); + } + + if (!tlc.checkEnvironment()) { + System.exit(1); + } - // call the actual processing method - tlc.process(); + // Setup how spec files will be resolved in the filesystem. + if (MODEL_PART_OF_JAR) { + // There was not spec file given, it instead exists in the + // .jar file being executed. So we need to use a special file + // resolver to parse it. + tlc.setResolver(new InJarFilenameToStream(ModelInJar.PATH)); + } else { + // The user passed us a spec file directly. To ensure we can + // recover it during semantic parsing, we must include its + // parent directory as a library path in the file resolver. + // + // If the spec file has no parent directory, use the "standard" + // library paths provided by SimpleFilenameToStream. + final String dir = FileUtil.parseDirname(tlc.getMainFile()); + if (!dir.isEmpty()) { + tlc.setResolver(new SimpleFilenameToStream(dir)); + } else { + tlc.setResolver(new SimpleFilenameToStream()); + } + } + + // Setup MailSender *before* calling tlc.process. The MailSender's task it to + // write the MC.out file. The MC.out file is e.g. used by CloudTLC to feed + // progress back to the Toolbox (see CloudDistributedTLCJob). + final MailSender ms = new MailSender(); + ms.setModelName(tlc.getModelName()); + ms.setSpecName(tlc.getSpecName()); - // Send logged output by email - boolean success = ms.send(tlc.getModuleFiles()); - - // In case sending the mail has failed, we treat this as an error. - // This is needed when TLC runs on another host and email is - // the only means for the user to get access to the model checking - // results. - // With distributed TLC and CloudDistributedTLCJob in particular, - // the cloud node is immediately turned off once the TLC process has - // finished. If we were to shutdown the node even when sending out - // the email has failed, the result would be lost. - if (!success) { - System.exit(1); - } + // Execute TLC. + final int errorCode = tlc.process(); + + // Send logged output by email. + // + // This is needed when TLC runs on another host and email is + // the only means for the user to get access to the model + // checking results. + boolean mailSent = ms.send(tlc.getModuleFiles()); + + // Treat failure to send mail as a tool failure. + // + // With distributed TLC and CloudDistributedTLCJob in particular, + // the cloud node is immediately turned off once the TLC process + // has finished. If we were to shutdown the node even when sending + // out the email has failed, the result would be lost. + if (!mailSent) { + System.exit(1); } - // terminate - System.exit(0); + + // Be explicit about tool success. + System.exit(EC.ExitStatus.errorConstantToExitStatus(errorCode)); } + + // false if the environment (JVM, OS, ...) makes model checking impossible. + // Might also result in warnings. + private boolean checkEnvironment() { + // Not a reasons to refuse startup but warn about non-ideal garbage collector. + // See https://twitter.com/lemmster/status/1089656514892070912 for actual + // performance penalty. + if (!TLCRuntime.getInstance().isThroughputOptimizedGC()) { + MP.printWarning(EC.TLC_ENVIRONMENT_JVM_GC); + } + + return true; + } + + public static void setTraceNum(int aTraceNum) { + traceNum = aTraceNum; + } /** * This method handles parameter arguments and prepares the actual call @@ -277,9 +323,6 @@ public class TLC traceFile = arg.replace("file=", ""); } } - for (int i = 0; i < simArgs.length; i++) { - - } } } else if (args[index].equals("-modelcheck")) { @@ -308,7 +351,7 @@ public class TLC } else if (args[index].equals("-terse")) { index++; - Value.expand = false; + TLCGlobals.expand = false; } else if (args[index].equals("-continue")) { index++; @@ -717,7 +760,7 @@ public class TLC } mainFile = args[index++]; int len = mainFile.length(); - if (mainFile.startsWith(".tla", len - 4)) + if (mainFile.endsWith(".tla")) { mainFile = mainFile.substring(0, len - 4); } @@ -740,19 +783,40 @@ public class TLC return false; } } + + // The functionality to start TLC from an (absolute) path /path/to/spec/file.tla + // seems to have eroded over the years which is why this block of code is a + // clutch. It essentially massages the variable values for mainFile, specDir and + // the user dir to make the code below - as well as the FilenameToStream resolver - + // work. Original issues was https://github.com/tlaplus/tlaplus/issues/24. + final File f = new File(mainFile); + String specDir = ""; + if (f.isAbsolute()) { + specDir = f.getParent() + FileUtil.separator; + mainFile = f.getName(); + // Not setting user dir causes a ConfigFileException when the resolver + // tries to read the .cfg file later in the game. + ToolIO.setUserDir(specDir); + } + if (configFile == null) { configFile = mainFile; } + if (cleanup && fromChkpt == null) + { + // clean up the states directory only when not recovering + FileUtil.deleteDir(TLCGlobals.metaRoot, true); + } + startTime = System.currentTimeMillis(); // Check if mainFile is an absolute or relative file system path. If it is // absolute, the parent gets used as TLC's meta directory (where it stores // states...). Otherwise, no meta dir is set causing states etc. to be stored in // the current directory. - final File f = new File(mainFile); - metadir = FileUtil.makeMetaDir(new Date(startTime), f.isAbsolute() ? f.getParent() : "", fromChkpt); + metadir = FileUtil.makeMetaDir(new Date(startTime), specDir, fromChkpt); if (dumpFile != null) { if (dumpFile.startsWith("${metadir}")) { @@ -809,9 +873,8 @@ public class TLC /** * The processing method */ - public void process() + public int process() { - ToolIO.cleanToolObjects(TLCGlobals.ToolId); // UniqueString.initialize(); // a JMX wrapper that exposes runtime statistics @@ -827,31 +890,11 @@ public class TLC // We must recover the intern var table as early as possible UniqueString.internTbl.recover(fromChkpt); } - if (cleanup && fromChkpt == null) - { - // clean up the states directory only when not recovering - FileUtil.deleteDir(TLCGlobals.metaRoot, true); - } FP64.Init(fpIndex); - - - final TLCRuntime tlcRuntime = TLCRuntime.getInstance(); - final long offHeapMemory = tlcRuntime.getNonHeapPhysicalMemory() / 1024L / 1024L; - final String arch = tlcRuntime.getArchitecture().name(); - - final Runtime runtime = Runtime.getRuntime(); - final long heapMemory = runtime.maxMemory() / 1024L / 1024L; - final String cores = Integer.toString(runtime.availableProcessors()); - - final String vendor = System.getProperty("java.vendor"); - final String version = System.getProperty("java.version"); - - final String osName = System.getProperty("os.name"); - final String osVersion = System.getProperty("os.version"); - final String osArch = System.getProperty("os.arch"); final RandomGenerator rng = new RandomGenerator(); // Start checking: + final int result; if (isSimulate) { // random simulation @@ -863,67 +906,63 @@ public class TLC { rng.setSeed(seed, aril); } - MP.printMessage(EC.TLC_MODE_SIMU, - new String[] { String.valueOf(seed), String.valueOf(TLCGlobals.getNumWorkers()), - TLCGlobals.getNumWorkers() == 1 ? "" : "s", cores, osName, osVersion, osArch, vendor, - version, arch, Long.toString(heapMemory), Long.toString(offHeapMemory) }); - Simulator simulator = new Simulator(mainFile, configFile, traceFile, deadlock, traceDepth, - traceNum, rng, seed, true, resolver, specObj); + printStartupBanner(EC.TLC_MODE_SIMU, getSimulationRuntime(seed)); + + Simulator simulator = new Simulator(mainFile, configFile, traceFile, deadlock, traceDepth, + traceNum, rng, seed, resolver, TLCGlobals.getNumWorkers()); TLCGlobals.simulator = simulator; -// The following statement moved to Spec.processSpec by LL on 10 March 2011 -// MP.printMessage(EC.TLC_STARTING); - instance = simulator; - simulator.simulate(); + result = simulator.simulate(); } else { if (noSeed) { seed = rng.nextLong(); } - EnumerableValue.setRandom(seed); + // Replace seed with tlc2.util.FP64.Polys[fpIndex]? + // + No need to print seed in startup-banner for BFS and DFS + // - Only 131 different seeds + // RandomEnumerableValues.setSeed(tlc2.util.FP64.Polys[fpIndex]); + RandomEnumerableValues.setSeed(seed); - final String[] parameters = new String[] { String.valueOf(TLCGlobals.getNumWorkers()), - TLCGlobals.getNumWorkers() == 1 ? "" : "s", cores, osName, osVersion, osArch, vendor, version, - arch, Long.toString(heapMemory), Long.toString(offHeapMemory), - Long.toString(EnumerableValue.getRandomSeed()) }; - + // Print startup banner before SANY writes its output. + printStartupBanner(isBFS() ? EC.TLC_MODE_MC : EC.TLC_MODE_MC_DFS, getModelCheckingRuntime(fpIndex, fpSetConfiguration)); + // model checking - AbstractChecker mc = null; - if (TLCGlobals.DFIDMax == -1) + final ITool tool = new Tool(mainFile, configFile, resolver); + + if (isBFS()) { - MP.printMessage(EC.TLC_MODE_MC, parameters); - mc = new ModelChecker(mainFile, configFile, metadir, stateWriter, deadlock, fromChkpt, resolver, specObj, fpSetConfiguration); - modelCheckerMXWrapper = new ModelCheckerMXWrapper((ModelChecker) mc, this); + TLCGlobals.mainChecker = new ModelChecker(tool, metadir, stateWriter, deadlock, fromChkpt, + FPSetFactory.getFPSetInitialized(fpSetConfiguration, metadir, mainFile), startTime); + modelCheckerMXWrapper = new ModelCheckerMXWrapper((ModelChecker) TLCGlobals.mainChecker, this); + result = TLCGlobals.mainChecker.modelCheck(); } else { - MP.printMessage(EC.TLC_MODE_MC_DFS, parameters); - mc = new DFIDModelChecker(mainFile, configFile, metadir, stateWriter, deadlock, fromChkpt, true, resolver, specObj); + TLCGlobals.mainChecker = new DFIDModelChecker(tool, metadir, stateWriter, deadlock, fromChkpt, startTime); + result = TLCGlobals.mainChecker.modelCheck(); } - TLCGlobals.mainChecker = mc; -// The following statement moved to Spec.processSpec by LL on 10 March 2011 -// MP.printMessage(EC.TLC_STARTING); - instance = mc; - mc.modelCheck(); - } + return result; } catch (Throwable e) { if (e instanceof StackOverflowError) { System.gc(); - MP.printError(EC.SYSTEM_STACK_OVERFLOW, e); + return MP.printError(EC.SYSTEM_STACK_OVERFLOW, e); } else if (e instanceof OutOfMemoryError) { System.gc(); - MP.printError(EC.SYSTEM_OUT_OF_MEMORY, e); + return MP.printError(EC.SYSTEM_OUT_OF_MEMORY, e); + } else if (e instanceof TLCRuntimeException) { + return MP.printTLCRuntimeException((TLCRuntimeException) e); } else if (e instanceof RuntimeException) { // SZ 29.07.2009 // printing the stack trace of the runtime exceptions - MP.printError(EC.GENERAL, e); + return MP.printError(EC.GENERAL, e); // e.printStackTrace(); } else { - MP.printError(EC.GENERAL, e); + return MP.printError(EC.GENERAL, e); } } finally { @@ -943,6 +982,73 @@ public class TLC MP.flush(); } } + + private static boolean isBFS() { + return TLCGlobals.DFIDMax == -1; + } + + public static Map<String, String> getSimulationRuntime(final long seed) { + final Runtime runtime = Runtime.getRuntime(); + final long heapMemory = runtime.maxMemory() / 1024L / 1024L; + + final TLCRuntime tlcRuntime = TLCRuntime.getInstance(); + final long offHeapMemory = tlcRuntime.getNonHeapPhysicalMemory() / 1024L / 1024L; + final long pid = tlcRuntime.pid(); + + final Map<String, String> result = new LinkedHashMap<>(); + result.put("seed", String.valueOf(seed)); + result.put("workers", String.valueOf(TLCGlobals.getNumWorkers())); + result.put("plural", TLCGlobals.getNumWorkers() == 1 ? "" : "s"); + result.put("cores", Integer.toString(runtime.availableProcessors())); + result.put("osName", System.getProperty("os.name")); + result.put("osVersion", System.getProperty("os.version")); + result.put("osArch", System.getProperty("os.arch")); + result.put("jvmVendor", System.getProperty("java.vendor")); + result.put("jvmVersion", System.getProperty("java.version")); + result.put("jvmArch", tlcRuntime.getArchitecture().name()); + result.put("jvmHeapMem", Long.toString(heapMemory)); + result.put("jvmOffHeapMem", Long.toString(offHeapMemory)); + result.put("jvmPid", pid == -1 ? "" : String.valueOf(pid)); + return result; + } + + public static Map<String, String> getModelCheckingRuntime(final int fpIndex, final FPSetConfiguration fpSetConfig) { + final Runtime runtime = Runtime.getRuntime(); + final long heapMemory = runtime.maxMemory() / 1024L / 1024L; + + final TLCRuntime tlcRuntime = TLCRuntime.getInstance(); + final long offHeapMemory = tlcRuntime.getNonHeapPhysicalMemory() / 1024L / 1024L; + final long pid = tlcRuntime.pid(); + + // TODO Better to use Class#getSimpleName provided we would have access to the + // Class instance instead of just its name. However, loading the class here is + // overkill and might interfere if other parts of TLC pull off class-loading + // tricks. + final String fpSetClassSimpleName = fpSetConfig.getImplementation() + .substring(fpSetConfig.getImplementation().lastIndexOf(".") + 1); + + final String stateQueueClassSimpleName = ModelChecker.getStateQueueName(); + + // fpSetClassSimpleName and stateQueueClassSimpleName ignored in DFS mode. + final Map<String, String> result = new LinkedHashMap<>(); + result.put("workers", String.valueOf(TLCGlobals.getNumWorkers())); + result.put("plural", TLCGlobals.getNumWorkers() == 1 ? "" : "s"); + result.put("cores", Integer.toString(runtime.availableProcessors())); + result.put("osName", System.getProperty("os.name")); + result.put("osVersion", System.getProperty("os.version")); + result.put("osArch", System.getProperty("os.arch")); + result.put("jvmVendor", System.getProperty("java.vendor")); + result.put("jvmVersion", System.getProperty("java.version")); + result.put("jvmArch", tlcRuntime.getArchitecture().name()); + result.put("jvmHeapMem", Long.toString(heapMemory)); + result.put("jvmOffHeapMem", Long.toString(offHeapMemory)); + result.put("seed", Long.toString(RandomEnumerableValues.getSeed())); + result.put("fpidx", Integer.toString(fpIndex)); + result.put("jvmPid", pid == -1 ? "" : String.valueOf(pid)); + result.put("fpset", fpSetClassSimpleName); + result.put("queue", stateQueueClassSimpleName); + return result; + } /** * @return The given milliseconds runtime converted into human readable form @@ -971,15 +1077,16 @@ public class TLC public List<File> getModuleFiles() { final List<File> result = new ArrayList<File>(); - if (instance instanceof ModelChecker) { - ModelChecker mc = (ModelChecker) instance; - final Enumeration<ParseUnit> parseUnitContext = mc.specObj.parseUnitContext - .elements(); - while (parseUnitContext.hasMoreElements()) { - ParseUnit pu = (ParseUnit) parseUnitContext.nextElement(); - File resolve = resolver.resolve(pu.getFileName(), false); - result.add(resolve); + if (TLCGlobals.mainChecker instanceof ModelChecker) { + final ModelChecker mc = (ModelChecker) TLCGlobals.mainChecker; + result.addAll(mc.getModuleFiles(resolver)); + if (ModelInJar.hasCfg()) { + result.add(ModelInJar.getCfg()); } + // It might be desirable to include tlc.jfr - a flight recording aka profiling + // at the JVM level here. This doesn't work though as the recording get created + // after the termination of the JVM. A recording can also be several hundred + // MBs large. } return result; } @@ -995,28 +1102,6 @@ public class TLC ToolIO.setDefaultResolver(resolver); } - /** - * Set external specification object - * @param specObj spec object created external SANY run - */ - public void setSpecObject(SpecObj specObj) - { - this.specObj = specObj; - } - - /** - * Delegate cancellation request to the instance - * @param flag - */ - public void setCanceledFlag(boolean flag) - { - if (this.instance != null) - { - this.instance.setCancelFlag(flag); - DebugPrinter.print("Cancel flag set to " + flag); - } - } - /** * Print out an error message, with usage hint * @param msg, message to print @@ -1044,6 +1129,41 @@ public class TLC } } + private void printStartupBanner(final int mode, final Map<String, String> parameters) { + MP.printMessage(mode, parameters.values().toArray(new String[parameters.size()])); + + final Map<String, String> udc = new LinkedHashMap<>(); + // First indicate the version (to make parsing forward compatible) + udc.put("ver", TLCGlobals.getRevisionOrDev()); + + // Simulation, DFS or BFS mode. + udc.put("mode", mode2String(mode)); + + parameters.remove("plural"); // damn hack! + // "pid", "seed", and "fpidx" have no relevance for us. + parameters.remove("jvmPid"); + parameters.remove("fpidx"); + parameters.remove("seed"); + udc.putAll(parameters); + + // True if TLC is run from within the Toolbox. + udc.put("toolbox", Boolean.toString(TLCGlobals.tool)); + new ExecutionStatisticsCollector().collect(udc); + } + + private static String mode2String(final int mode) { + switch (mode) { + case EC.TLC_MODE_MC: + return "bfs"; + case EC.TLC_MODE_MC_DFS: + return "dfs"; + case EC.TLC_MODE_SIMU: + return "simulation"; + default: + return "unknown"; + } + } + /** * */ @@ -1057,6 +1177,10 @@ public class TLC return fpSetConfiguration; } + public String getMainFile() { + return mainFile; + } + public String getModelName() { return System.getProperty(MailSender.MODEL_NAME, this.mainFile); } diff --git a/tlatools/src/tlc2/TLCGlobals.java b/tlatools/src/tlc2/TLCGlobals.java index f5c9c75cb76ffcbf7273c8bd7693728f98088896..8c588e65bd3a9ee296cb96063230bab7c254eafb 100644 --- a/tlatools/src/tlc2/TLCGlobals.java +++ b/tlatools/src/tlc2/TLCGlobals.java @@ -7,7 +7,6 @@ import java.util.Enumeration; import java.util.jar.Attributes; import java.util.jar.Manifest; -import tla2sany.semantic.FrontEnd; import tlc2.tool.AbstractChecker; import tlc2.tool.Simulator; @@ -21,8 +20,10 @@ import tlc2.tool.Simulator; public class TLCGlobals { - // The current version of TLC - public static String versionOfTLC = "Version 2.13 of 18 July 2018"; + public static final int DEFAULT_CHECKPOINT_DURATION = (30 * 60 * 1000) + 42; + + // The current version of TLC + public static String versionOfTLC = "Version 2.14 of 10 July 2019"; // The bound for set enumeration, used for pretty printing public static int enumBound = 2000; @@ -89,9 +90,16 @@ public class TLCGlobals // The main simulator object (null if mainChecker non-null) public static Simulator simulator = null; + // Char to indent nested coverage information. + public static final char coverageIndent = '|'; + // Enable collecting coverage information public static int coverageInterval = -1; + public static final boolean isCoverageEnabled() { + return coverageInterval >= 0; + } + // Depth for depth-first iterative deepening public static int DFIDMax = -1; @@ -109,7 +117,7 @@ public class TLCGlobals // The time interval to checkpoint. (in milliseconds) public static long chkptDuration = Integer.getInteger( - TLCGlobals.class.getName() + ".chkpt", 30 * 60 * 1000); + TLCGlobals.class.getName() + ".chkpt", DEFAULT_CHECKPOINT_DURATION); // MAK 08.2012: centralized checkpoint code and added disabling and // externally forced checkpoints @@ -118,7 +126,12 @@ public class TLCGlobals forceChkpt = true; } private static long lastChkpt = System.currentTimeMillis(); - + + public static boolean chkptExplicitlyEnabled() { + // Assumption is that a user will always select a different value. + return chkptDuration > 0 && chkptDuration != DEFAULT_CHECKPOINT_DURATION; + } + /** * IMPORTANT NOTE: The method is unsynchronized. It is the caller's * responsibility to ensure that only a single thread calls this method. @@ -156,9 +169,6 @@ public class TLCGlobals // The flag to control if gzip is applied to Value input/output stream. public static boolean useGZIP = false; - // The tool id number for TLC2. - public static int ToolId = FrontEnd.getToolId(); - // debugging field public static boolean debug = false; @@ -190,4 +200,10 @@ public class TLCGlobals } return null; } + + public static String getRevisionOrDev() { + return TLCGlobals.getRevision() == null ? "development" : TLCGlobals.getRevision(); + } + + public static boolean expand = true; } diff --git a/tlatools/src/tlc2/module/AnySet.java b/tlatools/src/tlc2/module/AnySet.java index a666e8a2b7639df2e340f8e51c480adcfb6997c4..dd9263c8f52dd84296fbb4ad5a8ba178cdb5f284 100644 --- a/tlatools/src/tlc2/module/AnySet.java +++ b/tlatools/src/tlc2/module/AnySet.java @@ -7,9 +7,10 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.value.UserObj; -import tlc2.value.UserValue; -import tlc2.value.Value; +import tlc2.value.Values; +import tlc2.value.impl.UserObj; +import tlc2.value.impl.UserValue; +import tlc2.value.impl.Value; public class AnySet extends UserObj { @@ -24,7 +25,7 @@ public class AnySet extends UserObj public final int compareTo(Value val) { - throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "ANY", Value.ppr(val.toString()) }); + throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "ANY", Values.ppr(val.toString()) }); } public final boolean member(Value val) @@ -37,7 +38,7 @@ public class AnySet extends UserObj return false; } - public final StringBuffer toString(StringBuffer sb, int offset) + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { return sb.append("ANY"); } diff --git a/tlatools/src/tlc2/module/Bags.java b/tlatools/src/tlc2/module/Bags.java index 81fddf3aa8279449005cef3a50eb7702c20e7725..255edfad01dc424fe0ef6d9d28f60f89651ef2da 100644 --- a/tlatools/src/tlc2/module/Bags.java +++ b/tlatools/src/tlc2/module/Bags.java @@ -8,16 +8,18 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalControl; import tlc2.tool.EvalException; -import tlc2.tool.TLARegistry; +import tlc2.tool.impl.TLARegistry; import tlc2.util.Vect; -import tlc2.value.Applicable; -import tlc2.value.BoolValue; -import tlc2.value.FcnRcdValue; -import tlc2.value.IntValue; -import tlc2.value.SetEnumValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; -import tlc2.value.ValueVec; +import tlc2.value.Values; +import tlc2.value.impl.Applicable; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueVec; import util.Assert; public class Bags implements ValueConstants @@ -37,37 +39,37 @@ public class Bags implements ValueConstants public static Value EmptyBag() { - return EmptyFcn; + return FcnRcdValue.EmptyFcn; } - public static BoolValue IsABag(final Value b) + public static IBoolValue IsABag(final Value b) { - final FcnRcdValue fcn = FcnRcdValue.convert(b); + final FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); if (fcn == null) { // MAK 02/23/2018 Changed to return ValFalse instead of exception when Value is not a bag. //throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "IsBag", // "a function with a finite domain", Value.ppr(b.toString()) }); - return ValFalse; + return BoolValue.ValFalse; } final Value[] vals = fcn.values; for (int i = 0; i < vals.length; i++) { if (!(vals[i] instanceof IntValue) || ((IntValue) vals[i]).val <= 0) { - return ValFalse; + return BoolValue.ValFalse; } } - return ValTrue; + return BoolValue.ValTrue; } public static IntValue BagCardinality(Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); + FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); if (fcn == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagCardinality", - "a function with a finite domain", Value.ppr(b.toString()) }); + "a function with a finite domain", Values.ppr(b.toString()) }); } int num = 0; Value[] vals = fcn.values; @@ -82,20 +84,20 @@ public class Bags implements ValueConstants } else { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagCardinality", "a bag", - Value.ppr(b.toString()) }); + Values.ppr(b.toString()) }); } } else { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagCardinality", "a bag", - Value.ppr(b.toString()) }); + Values.ppr(b.toString()) }); } } return IntValue.gen(num); } - public static BoolValue BagIn(final Value e, final Value b) + public static IBoolValue BagIn(final Value e, final Value b) { - final FcnRcdValue fcn = FcnRcdValue.convert(b); + final FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); final Value[] values = fcn.values; final Value[] domain = fcn.getDomainAsValues(); for (int i = 0; i < domain.length; i++) @@ -104,18 +106,18 @@ public class Bags implements ValueConstants { if (values[i] instanceof IntValue) { - return (((IntValue) values[i]).val > 0) ? ValTrue : ValFalse; + return (((IntValue) values[i]).val > 0) ? BoolValue.ValTrue : BoolValue.ValFalse; } throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "BagIn", "bag", - Value.ppr(b.toString()) }); + Values.ppr(b.toString()) }); } } - return ValFalse; + return BoolValue.ValFalse; } public static IntValue CopiesIn(final Value e, final Value b) { - final FcnRcdValue fcn = FcnRcdValue.convert(b); + final FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); final Value[] values = fcn.values; final Value[] domain = fcn.getDomainAsValues(); for (int i = 0; i < domain.length; i++) @@ -127,32 +129,32 @@ public class Bags implements ValueConstants return (IntValue) values[i]; } throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "CopiesIn", "bag", - Value.ppr(b.toString()) }); + Values.ppr(b.toString()) }); } } - return ValZero; + return IntValue.ValZero; } public static Value BagCup(Value b1, Value b2) { - FcnRcdValue fcn1 = FcnRcdValue.convert(b1); - FcnRcdValue fcn2 = FcnRcdValue.convert(b2); - if (!IsABag(fcn1).val) + FcnRcdValue fcn1 = (FcnRcdValue) b1.toFcnRcd(); + FcnRcdValue fcn2 = (FcnRcdValue) b2.toFcnRcd(); + if (!IsABag(fcn1).getVal()) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "(+)", "bag", - Value.ppr(b1.toString()) }); + Values.ppr(b1.toString()) }); } - if (!IsABag(fcn2).val) + if (!IsABag(fcn2).getVal()) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "(+)", "bag", - Value.ppr(b2.toString()) }); + Values.ppr(b2.toString()) }); } Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; Value[] domain2 = fcn2.getDomainAsValues(); Value[] values2 = fcn2.values; - Vect dVec = new Vect(domain1.length); - Vect vVec = new Vect(domain1.length); + Vect<Value> dVec = new Vect<>(domain1.length); + Vect<Value> vVec = new Vect<>(domain1.length); for (int i = 0; i < domain1.length; i++) { dVec.addElement(domain1[i]); @@ -190,24 +192,24 @@ public class Bags implements ValueConstants public static Value BagDiff(Value b1, Value b2) { - FcnRcdValue fcn1 = FcnRcdValue.convert(b1); - FcnRcdValue fcn2 = FcnRcdValue.convert(b2); + FcnRcdValue fcn1 = (FcnRcdValue) b1.toFcnRcd(); + FcnRcdValue fcn2 = (FcnRcdValue) b2.toFcnRcd(); if (fcn1 == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "(-)", "bag", - Value.ppr(b1.toString()) }); + Values.ppr(b1.toString()) }); } if (fcn2 == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "(-)", "bag", - Value.ppr(b2.toString()) }); + Values.ppr(b2.toString()) }); } Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; Value[] domain2 = fcn2.getDomainAsValues(); Value[] values2 = fcn2.values; - Vect dVec = new Vect(domain1.length); - Vect vVec = new Vect(domain1.length); + Vect<Value> dVec = new Vect<>(domain1.length); + Vect<Value> vVec = new Vect<>(domain1.length); for (int i = 0; i < domain1.length; i++) { int v1 = ((IntValue) values1[i]).val; @@ -238,11 +240,11 @@ public class Bags implements ValueConstants public static Value BagUnion(final Value s) { - final SetEnumValue s1 = SetEnumValue.convert(s); + final SetEnumValue s1 = (SetEnumValue) s.toSetEnum(); if (s1 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagUnion", - "a finite enumerable set", Value.ppr(s.toString()) }); + "a finite enumerable set", Values.ppr(s.toString()) }); } // MAK 02/20/2018: // Need to normalize s in cases where it is an unnormalized set of identical @@ -254,17 +256,17 @@ public class Bags implements ValueConstants ValueVec elems = s1.elems; int sz = elems.size(); if (sz == 0) { - return EmptyFcn; + return FcnRcdValue.EmptyFcn; } if (sz == 1) { return elems.elementAt(0); } ValueVec dVec = new ValueVec(); ValueVec vVec = new ValueVec(); - FcnRcdValue fcn = FcnRcdValue.convert(elems.elementAt(0)); + FcnRcdValue fcn = (FcnRcdValue) elems.elementAt(0).toFcnRcd(); if (fcn == null) { - throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Value.ppr(s.toString())); + throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Values.ppr(s.toString())); } Value[] domain = fcn.getDomainAsValues(); Value[] values = fcn.values; @@ -275,11 +277,11 @@ public class Bags implements ValueConstants } for (int i = 1; i < sz; i++) { - fcn = FcnRcdValue.convert(elems.elementAt(i)); + fcn = (FcnRcdValue) elems.elementAt(i).toFcnRcd(); if (fcn == null) { - throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Value.ppr(s.toString())); + throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Values.ppr(s.toString())); } domain = fcn.getDomainAsValues(); values = fcn.values; @@ -314,20 +316,20 @@ public class Bags implements ValueConstants return new FcnRcdValue(dom, vals, false); } - public static BoolValue SqSubseteq(Value b1, Value b2) + public static IBoolValue SqSubseteq(Value b1, Value b2) { - FcnRcdValue fcn1 = FcnRcdValue.convert(b1); - FcnRcdValue fcn2 = FcnRcdValue.convert(b2); + FcnRcdValue fcn1 = (FcnRcdValue) b1.toFcnRcd(); + FcnRcdValue fcn2 = (FcnRcdValue) b2.toFcnRcd(); if (fcn1 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "\\sqsubseteq", - "a function with a finite domain", Value.ppr(b1.toString()) }); + "a function with a finite domain", Values.ppr(b1.toString()) }); } if (fcn2 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "\\sqsubseteq", - "a function with a finite domain", Value.ppr(b2.toString()) }); + "a function with a finite domain", Values.ppr(b2.toString()) }); } Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; @@ -346,9 +348,9 @@ public class Bags implements ValueConstants } } if (v1 > 0) - return ValFalse; + return BoolValue.ValFalse; } - return ValTrue; + return BoolValue.ValTrue; } public static Value BagOfAll(Value f, Value b) @@ -356,13 +358,13 @@ public class Bags implements ValueConstants if (!(f instanceof Applicable)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", "BagOfAll", "operator", - Value.ppr(f.toString()) }); + Values.ppr(f.toString()) }); } - FcnRcdValue fcn = FcnRcdValue.convert(b); + FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); if (fcn == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "BagOfAll", - "function with a finite domain", Value.ppr(b.toString()) }); + "function with a finite domain", Values.ppr(b.toString()) }); } Applicable ff = (Applicable) f; ValueVec dVec = new ValueVec(); @@ -405,7 +407,7 @@ public class Bags implements ValueConstants /****** // For now, we do not override SubBag. So, We are using the TLA+ definition. public static Value SubBag(Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); + FcnRcdValue fcn = b.toFcnRcd(); if (fcn == null) { String msg = "Applying SubBag to the following value, which is\n" + "not a function with a finite domain:\n" + Value.ppr(b.toString()); @@ -417,22 +419,22 @@ public class Bags implements ValueConstants public static Value BagToSet(Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); + FcnRcdValue fcn = (FcnRcdValue) b.toFcnRcd(); if (fcn == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagToSet", - "a function with a finite domain", Value.ppr(b.toString()) }); + "a function with a finite domain", Values.ppr(b.toString()) }); } return fcn.getDomain(); } public static Value SetToBag(Value b) { - SetEnumValue s1 = SetEnumValue.convert(b); + SetEnumValue s1 = (SetEnumValue) b.toSetEnum(); if (s1 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagToSet", - "a function with a finite domain", Value.ppr(b.toString()) }); + "a function with a finite domain", Values.ppr(b.toString()) }); } // The following `if' added by LL on 5 Mar 2012 to correct a bug found by Tom Rodeheffer, // in which SetToBag creates a function with multiple copies of the elements in its @@ -446,7 +448,7 @@ public class Bags implements ValueConstants for (int i = 0; i < elems.size(); i++) { domain[i] = elems.elementAt(i); - values[i] = ValOne; + values[i] = IntValue.ValOne; } return new FcnRcdValue(domain, values, s1.isNormalized()); } diff --git a/tlatools/src/tlc2/module/FiniteSets.java b/tlatools/src/tlc2/module/FiniteSets.java index bf6fbf5ecaf71054a6128cb4206993daeeacfe74..76b45c3fcf98fa10543cc9de31ce12a209eadfb6 100644 --- a/tlatools/src/tlc2/module/FiniteSets.java +++ b/tlatools/src/tlc2/module/FiniteSets.java @@ -7,19 +7,21 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.value.BoolValue; -import tlc2.value.Enumerable; -import tlc2.value.IntValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; +import tlc2.value.Values; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.Value; public class FiniteSets implements ValueConstants { public static final long serialVersionUID = 20160822L; - public static BoolValue IsFiniteSet(Value val) + public static IBoolValue IsFiniteSet(Value val) { - return val.isFinite() ? ValTrue : ValFalse; + return val.isFinite() ? BoolValue.ValTrue : BoolValue.ValFalse; } public static IntValue Cardinality(Value val) @@ -28,7 +30,7 @@ public class FiniteSets implements ValueConstants { return IntValue.gen(((Enumerable) val).size()); } - throw new EvalException(EC.TLC_MODULE_COMPUTING_CARDINALITY, Value.ppr(val.toString())); + throw new EvalException(EC.TLC_MODULE_COMPUTING_CARDINALITY, Values.ppr(val.toString())); } // SZ 16.07.2009: commented the following code out, since it is not a part of FiniteSets @@ -49,7 +51,7 @@ public class FiniteSets implements ValueConstants } public static Value listToSet(Value list) { - TupleValue tv = TupleValue.convert(list); + TupleValue tv = list.toTuple() if (tv == null) { throw new EvalException("listToSet"); } @@ -61,7 +63,7 @@ public class FiniteSets implements ValueConstants } public static Value appendSetToList(Value list, Value set) { - TupleValue tv = TupleValue.convert(list); + TupleValue tv = list.toTuple(); if (tv == null || IsFiniteSet(set) == ValFalse) { throw new EvalException("appendSetToList"); } @@ -81,7 +83,7 @@ public class FiniteSets implements ValueConstants } public static Value deleteSetFromList(Value set, Value list) { - TupleValue tv = TupleValue.convert(list); + TupleValue tv = list.toTuple(); if (tv == null) { throw new EvalException("deleteSetFromList"); } @@ -99,7 +101,7 @@ public class FiniteSets implements ValueConstants } public static Value keepSetFromList(Value set, Value list) { - TupleValue tv = TupleValue.convert(list); + TupleValue tv = list.toTuple() if (tv == null) { throw new EvalException("keepSetFromList"); } diff --git a/tlatools/src/tlc2/module/Integers.java b/tlatools/src/tlc2/module/Integers.java index db0a17d4f25c210c8984f20481caa905b0558a6e..25117605d676498b66c352afb911531db0c02928 100644 --- a/tlatools/src/tlc2/module/Integers.java +++ b/tlatools/src/tlc2/module/Integers.java @@ -7,15 +7,17 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.tool.TLARegistry; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.IntervalValue; -import tlc2.value.ModelValue; -import tlc2.value.UserObj; -import tlc2.value.UserValue; -import tlc2.value.Value; +import tlc2.tool.impl.TLARegistry; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; +import tlc2.value.Values; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.UserObj; +import tlc2.value.impl.UserValue; +import tlc2.value.impl.Value; public class Integers extends UserObj implements ValueConstants { @@ -69,36 +71,36 @@ public class Integers extends UserObj implements ValueConstants return Naturals.Times(x, y); } - public static BoolValue LT(Value x, Value y) + public static IBoolValue LT(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", "<", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", "<", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val < ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val < ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } - public static BoolValue LE(Value x, Value y) + public static IBoolValue LE(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", "<=", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", "<=", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val <= ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val <= ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } public static BoolValue GT(Value x, Value y) @@ -106,31 +108,31 @@ public class Integers extends UserObj implements ValueConstants if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", ">", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", ">", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val > ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val > ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } - public static BoolValue GEQ(Value x, Value y) + public static IBoolValue GEQ(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", ">=", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", ">=", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val >= ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val >= ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } public static IntervalValue DotDot(IntValue x, IntValue y) @@ -192,7 +194,7 @@ public class Integers extends UserObj implements ValueConstants { throw new EvalException(EC.TLC_MODULE_NULL_POWER_NULL); } - return ValOne; + return IntValue.ValOne; } long res = x.val; for (int i = 1; i < y.val; i++) @@ -222,7 +224,7 @@ public class Integers extends UserObj implements ValueConstants } if (val instanceof ModelValue) return 1; - throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Int", Value.ppr(val.toString()) }); + throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Int", Values.ppr(val.toString()) }); } public final boolean member(Value val) @@ -233,7 +235,7 @@ public class Integers extends UserObj implements ValueConstants { return ((ModelValue) val).modelValueMember(this); } - throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Value.ppr(val.toString()), "Int" }); + throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "Int" }); } public final boolean isFinite() @@ -241,7 +243,7 @@ public class Integers extends UserObj implements ValueConstants return false; } - public final StringBuffer toString(StringBuffer sb, int offset) + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { return sb.append("Int"); } diff --git a/tlatools/src/tlc2/module/Naturals.java b/tlatools/src/tlc2/module/Naturals.java index 1add6f45b66018cb93afcfbbe31a04533ffbc17d..d03f7cb41d781242302111fcdad46417afe82a0c 100644 --- a/tlatools/src/tlc2/module/Naturals.java +++ b/tlatools/src/tlc2/module/Naturals.java @@ -7,15 +7,17 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.tool.TLARegistry; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.IntervalValue; -import tlc2.value.ModelValue; -import tlc2.value.UserObj; -import tlc2.value.UserValue; -import tlc2.value.Value; +import tlc2.tool.impl.TLARegistry; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; +import tlc2.value.Values; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.UserObj; +import tlc2.value.impl.UserValue; +import tlc2.value.impl.Value; public class Naturals extends UserObj implements ValueConstants { @@ -90,70 +92,70 @@ public class Naturals extends UserObj implements ValueConstants return IntValue.gen((int) res); } - public static BoolValue LT(Value x, Value y) + public static IBoolValue LT(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", "<", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", "<", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val < ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val < ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } - public static BoolValue LE(Value x, Value y) + public static IBoolValue LE(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", "<=", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", "<=", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val <= ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val <= ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } - public static BoolValue GT(Value x, Value y) + public static IBoolValue GT(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", ">", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { // On 21 May 2012 LL corrected following call, which was reporting the first argument. throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", ">", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val > ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val > ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } - public static BoolValue GEQ(Value x, Value y) + public static IBoolValue GEQ(Value x, Value y) { if (!(x instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "first", ">", "integer", - Value.ppr(x.toString()) }); + Values.ppr(x.toString()) }); } if (!(y instanceof IntValue)) { // On 21 May 2012 LL corrected following call, which was reporting the first argument. throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR_AN, new String[] { "second", ">", "integer", - Value.ppr(y.toString()) }); + Values.ppr(y.toString()) }); } - return (((IntValue) x).val >= ((IntValue) y).val) ? ValTrue : ValFalse; + return (((IntValue) x).val >= ((IntValue) y).val) ? BoolValue.ValTrue : BoolValue.ValFalse; } public static IntervalValue DotDot(IntValue x, IntValue y) @@ -203,7 +205,7 @@ public class Naturals extends UserObj implements ValueConstants { throw new EvalException(EC.TLC_MODULE_NULL_POWER_NULL); } - return ValOne; + return IntValue.ValOne; } long res = n1; for (int i = 1; i < n2; i++) @@ -232,7 +234,7 @@ public class Naturals extends UserObj implements ValueConstants } if (val instanceof ModelValue) return 1; - throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Nat", Value.ppr(val.toString()) }); + throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Nat", Values.ppr(val.toString()) }); } public final boolean member(Value val) @@ -242,7 +244,7 @@ public class Naturals extends UserObj implements ValueConstants if (val instanceof ModelValue) return ((ModelValue) val).modelValueMember(this); - throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Value.ppr(val.toString()), "Nat" }); + throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "Nat" }); } public final boolean isFinite() @@ -250,7 +252,7 @@ public class Naturals extends UserObj implements ValueConstants return false; } - public final StringBuffer toString(StringBuffer sb, int offset) + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { return sb.append("Nat"); } diff --git a/tlatools/src/tlc2/module/Randomization.java b/tlatools/src/tlc2/module/Randomization.java index 04bb449d25e8a91e5c40658353e9791998abcf32..7916353238a52cdd884dcfd2272dac16068a3f64 100644 --- a/tlatools/src/tlc2/module/Randomization.java +++ b/tlatools/src/tlc2/module/Randomization.java @@ -27,13 +27,13 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.value.Enumerable; -import tlc2.value.EnumerableValue; -import tlc2.value.IntValue; -import tlc2.value.StringValue; -import tlc2.value.SubsetValue; -import tlc2.value.Value; import tlc2.value.ValueConstants; +import tlc2.value.Values; +import tlc2.value.impl.EnumerableValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.SubsetValue; +import tlc2.value.impl.Value; public class Randomization implements ValueConstants { @@ -42,40 +42,40 @@ public class Randomization implements ValueConstants { public static Value RandomSubset(final Value v1, final Value v2) { if (!(v1 instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "first", "RandomSubset", "nonnegative integer", Value.ppr(v1.toString()) }); + new String[] { "first", "RandomSubset", "nonnegative integer", Values.ppr(v1.toString()) }); } - if (!(v2 instanceof Enumerable)) { + if (!(v2 instanceof EnumerableValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSubset", "a finite set", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSubset", "a finite set", Values.ppr(v2.toString()) }); } - return ((Enumerable) v2).getRandomSubset(((IntValue) v1).val); + return ((EnumerableValue) v2).getRandomSubset(((IntValue) v1).val); } public static Value RandomSetOfSubsets(final Value v1, final Value v2, final Value v3) { // first parameter if (!(v1 instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v1.toString()) }); + new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Values.ppr(v1.toString()) }); } final int numberOfPicks = ((IntValue) v1).val; if (numberOfPicks < 0) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v1.toString()) }); + new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Values.ppr(v1.toString()) }); } // second parameter if (!(v2 instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Values.ppr(v2.toString()) }); } final int n = ((IntValue) v2).val; if (n < 0) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Values.ppr(v2.toString()) }); } // third parameter - if (!(v3 instanceof Enumerable)) { + if (!(v3 instanceof EnumerableValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "third", "RandomSetOfSubsets", "finite set", Value.ppr(v3.toString()) }); + new String[] { "third", "RandomSetOfSubsets", "finite set", Values.ppr(v3.toString()) }); } final EnumerableValue ev = (EnumerableValue) v3; if (31 - Integer.numberOfLeadingZeros(numberOfPicks) + 1 > ev.size() && numberOfPicks > (1 << ev.size())) { @@ -89,12 +89,12 @@ public class Randomization implements ValueConstants { // second parameter (now that we know third is enumerable) if (ev.size() < n) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Values.ppr(v2.toString()) }); } final double probability = (1d * n) / ev.size(); if (probability < 0d || 1d < probability) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Values.ppr(v2.toString()) }); } return new SubsetValue(ev).getRandomSetOfSubsets(numberOfPicks, probability); } @@ -103,17 +103,17 @@ public class Randomization implements ValueConstants { // first parameter if (!(v1 instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Value.ppr(v1.toString()) }); + new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Values.ppr(v1.toString()) }); } final int numberOfPicks = ((IntValue) v1).val; if (numberOfPicks < 0) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Value.ppr(v1.toString()) }); + new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Values.ppr(v1.toString()) }); } // second parameter if (!(v2 instanceof StringValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSubsetSetProbability", "string literal representing a probability", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSubsetSetProbability", "string literal representing a probability", Values.ppr(v2.toString()) }); } double probability; @@ -121,16 +121,16 @@ public class Randomization implements ValueConstants { probability = Double.valueOf(((StringValue) v2).getVal().toString()); } catch (NumberFormatException nfe) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Values.ppr(v2.toString()) }); } if (probability < 0d || 1d < probability) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Value.ppr(v2.toString()) }); + new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Values.ppr(v2.toString()) }); } // third parameter - if (!(v3 instanceof Enumerable)) { + if (!(v3 instanceof EnumerableValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, - new String[] { "third", "RandomSubsetSetProbability", "finite set", Value.ppr(v3.toString()) }); + new String[] { "third", "RandomSubsetSetProbability", "finite set", Values.ppr(v3.toString()) }); } final EnumerableValue ev = (EnumerableValue) v3; if (31 - Integer.numberOfLeadingZeros(numberOfPicks) + 1 > ev.size() && numberOfPicks > (1 << ev.size())) { diff --git a/tlatools/src/tlc2/module/Sequences.java b/tlatools/src/tlc2/module/Sequences.java index 858837d12ddb95ab4c832d71db38b1fa42c342f2..2569b6e05467d6acd4d68a33f902b6607a3d4894 100644 --- a/tlatools/src/tlc2/module/Sequences.java +++ b/tlatools/src/tlc2/module/Sequences.java @@ -8,20 +8,22 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalControl; import tlc2.tool.EvalException; -import tlc2.tool.TLARegistry; -import tlc2.value.Applicable; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.ModelValue; -import tlc2.value.OpLambdaValue; -import tlc2.value.OpRcdValue; -import tlc2.value.StringValue; -import tlc2.value.TupleValue; -import tlc2.value.UserObj; -import tlc2.value.UserValue; -import tlc2.value.Value; +import tlc2.tool.impl.TLARegistry; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; -import tlc2.value.ValueVec; +import tlc2.value.Values; +import tlc2.value.impl.Applicable; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.OpLambdaValue; +import tlc2.value.impl.OpRcdValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.UserObj; +import tlc2.value.impl.UserValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueVec; import util.Assert; import util.UniqueString; @@ -38,7 +40,7 @@ public class Sequences extends UserObj implements ValueConstants this.size = size; } - static + static { // This entry in TLARegistry defines a mapping from TLA+' infix // operator \o to the Java method tlc2.module.Sequences.Concat(Value, Value) @@ -60,18 +62,18 @@ public class Sequences extends UserObj implements ValueConstants return IntValue.gen(((StringValue) s).length()); } - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq != null) { return IntValue.gen(seq.size()); } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "\b", "Len", "sequence", - Value.ppr(s.toString()) }); + throw new EvalException(EC.TLC_MODULE_ONE_ARGUMENT_ERROR, new String[] { "Len", "sequence", + Values.ppr(s.toString()) }); } public static Value Head(Value s) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq != null) { if (seq.size() == 0) @@ -80,8 +82,8 @@ public class Sequences extends UserObj implements ValueConstants } return seq.elems[0]; } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "\b", "Head", "sequence", - Value.ppr(s.toString()) }); + throw new EvalException(EC.TLC_MODULE_ONE_ARGUMENT_ERROR, new String[] { "Head", "sequence", + Values.ppr(s.toString()) }); } public static Value Tail(Value s) @@ -95,7 +97,7 @@ public class Sequences extends UserObj implements ValueConstants return new StringValue(str.substring(1)); } - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq != null) { if (seq.size() == 0) @@ -107,17 +109,17 @@ public class Sequences extends UserObj implements ValueConstants System.arraycopy(seq.elems, 1, vals, 0, vals.length); return new TupleValue(vals); } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "\b", "Tail", "sequence", - Value.ppr(s.toString()) }); + throw new EvalException(EC.TLC_MODULE_ONE_ARGUMENT_ERROR, new String[] { "Tail", "sequence", + Values.ppr(s.toString()) }); } public static Value Cons(Value v, Value s) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "Cons(v, s)", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } int len = seq.size(); Value[] values = new Value[len + 1]; @@ -128,11 +130,11 @@ public class Sequences extends UserObj implements ValueConstants public static Value Append(Value s, Value v) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "Append(v, s)", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } int len = seq.size(); Value[] values = new Value[len + 1]; @@ -148,24 +150,24 @@ public class Sequences extends UserObj implements ValueConstants if (!(s2 instanceof StringValue)) { throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "t \\o s", "string", - Value.ppr(s2.toString()) }); + Values.ppr(s2.toString()) }); } UniqueString u1 = ((StringValue) s1).val; UniqueString u2 = ((StringValue) s2).val; return new StringValue(u1.concat(u2)); } - TupleValue seq1 = TupleValue.convert(s1); + TupleValue seq1 = (TupleValue) s1.toTuple(); if (seq1 == null) { throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "s \\o t", "sequence", - Value.ppr(s1.toString()) }); + Values.ppr(s1.toString()) }); } - TupleValue seq2 = TupleValue.convert(s2); + TupleValue seq2 = (TupleValue) s2.toTuple(); if (seq2 == null) { throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "t \\o s", "sequence", - Value.ppr(s2.toString()) }); + Values.ppr(s2.toString()) }); } int len1 = seq1.size(); int len2 = seq2.size(); @@ -191,16 +193,16 @@ public class Sequences extends UserObj implements ValueConstants */ public static Value SelectInSeq(Value s, Value test) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "SelectInSeq", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } if (!(test instanceof Applicable)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SelectInSeq", "function", - Value.ppr(test.toString()) }); + Values.ppr(test.toString()) }); } int len = seq.size(); Applicable ftest = (Applicable) test; @@ -209,20 +211,20 @@ public class Sequences extends UserObj implements ValueConstants { args[0] = seq.elems[i]; Value val = ftest.apply(args, EvalControl.Clear); - if (!(val instanceof BoolValue)) + if (!(val instanceof IBoolValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SelectInSeq", - "boolean-valued function", Value.ppr(test.toString()) }); + "boolean-valued function", Values.ppr(test.toString()) }); } if (((BoolValue) val).val) return IntValue.gen(i + 1); } - return ValZero; + return IntValue.ValZero; } /** Not in the standard interface. public static Value Remove(Value s, Value index) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = s.toTuple() if (seq != null) { if (index instanceof IntValue) { int ridx = ((IntValue)index).val; @@ -268,23 +270,23 @@ public class Sequences extends UserObj implements ValueConstants } if (! isString) { - seq = TupleValue.convert(s); + seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "SubSeq", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } } if (!(m instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SubSeq", "natural number", - Value.ppr(m.toString()) }); + Values.ppr(m.toString()) }); } if (!(n instanceof IntValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "third", "SubSeq", "natural number", - Value.ppr(n.toString()) }); + Values.ppr(n.toString()) }); } int beg = ((IntValue) m).val; int end = ((IntValue) n).val; @@ -293,7 +295,7 @@ public class Sequences extends UserObj implements ValueConstants return new StringValue("") ; } else { - return EmptyTuple; + return TupleValue.EmptyTuple; } } @@ -303,12 +305,12 @@ public class Sequences extends UserObj implements ValueConstants { throw new EvalException(EC.TLC_MODULE_ARGUMENT_NOT_IN_DOMAIN, new String[] { "second", "SubSeq", "first", - Value.ppr(s.toString()), Value.ppr(m.toString()) }); + Values.ppr(s.toString()), Values.ppr(m.toString()) }); } if (end < 1 || end > len) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_NOT_IN_DOMAIN, new String[] { "third", "SubSeq", "first", - Value.ppr(s.toString()), Value.ppr(n.toString()) }); + Values.ppr(s.toString()), Values.ppr(n.toString()) }); } if (isString) { @@ -324,19 +326,19 @@ public class Sequences extends UserObj implements ValueConstants public static Value SelectSeq(Value s, Value test) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "SelectSeq", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } int len = seq.size(); if (len == 0) - return EmptyTuple; + return TupleValue.EmptyTuple; if (!(test instanceof OpLambdaValue) && !(test instanceof OpRcdValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SelectSeq", "operator", - Value.ppr(test.toString()) }); + Values.ppr(test.toString()) }); } ValueVec vals = new ValueVec(); Applicable ftest = (Applicable) test; @@ -345,14 +347,14 @@ public class Sequences extends UserObj implements ValueConstants { args[0] = seq.elems[i]; Value val = ftest.apply(args, EvalControl.Clear); - if (val instanceof BoolValue) + if (val instanceof IBoolValue) { if (((BoolValue) val).val) vals.addElement(args[0]); } else { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SelectSeq", - "boolean-valued operator", Value.ppr(test.toString()) }); + "boolean-valued operator", Values.ppr(test.toString()) }); } } Value[] elems = new Value[vals.size()]; @@ -381,19 +383,19 @@ public class Sequences extends UserObj implements ValueConstants } // SZ Jul 14, 2009: // replaced the message with a standard one, thrown by mismatch of compared elements - throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { Value.ppr(this.toString()), - Value.ppr(s.toString()) }); + throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { Values.ppr(this.toString()), + Values.ppr(s.toString()) }); } public final boolean member(Value s) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { if (s instanceof ModelValue) return ((ModelValue) s).modelValueMember(this); - throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Value.ppr(s.toString()), - Value.ppr(this.toString()) }); + throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(s.toString()), + Values.ppr(this.toString()) }); } int len = seq.size(); if (len > this.size) @@ -411,17 +413,17 @@ public class Sequences extends UserObj implements ValueConstants return this.size != Integer.MAX_VALUE; } - public final StringBuffer toString(StringBuffer sb, int offset) + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { if (this.size == Integer.MAX_VALUE) { sb = sb.append("Seq("); - sb = this.range.toString(sb, offset); + sb = this.range.toString(sb, offset, swallow); sb = sb.append(")"); } else { sb = sb.append("BSeq("); - sb = this.range.toString(sb, offset); + sb = this.range.toString(sb, offset, swallow); sb = sb.append(", "); sb = sb.append(this.size); sb = sb.append(")"); @@ -431,16 +433,16 @@ public class Sequences extends UserObj implements ValueConstants public static Value Insert(Value s, Value v, Value test) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "Insert", "sequence", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } if (!(test instanceof Applicable)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SubSeq", "function", - Value.ppr(test.toString()) }); + Values.ppr(test.toString()) }); } int len = seq.size(); Applicable ftest = (Applicable) test; @@ -452,10 +454,10 @@ public class Sequences extends UserObj implements ValueConstants { args[1] = seq.elems[idx - 1]; Value val = ftest.apply(args, EvalControl.Clear); - if (!(val instanceof BoolValue)) + if (!(val instanceof IBoolValue)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "third", "Insert", - "boolean-valued operator", Value.ppr(test.toString()) }); + "boolean-valued operator", Values.ppr(test.toString()) }); } if (((BoolValue) val).val && v.compareTo(args[1]) < 0) { diff --git a/tlatools/src/tlc2/module/Strings.java b/tlatools/src/tlc2/module/Strings.java index 6eb17b95a79026b41ad0be8f400debe9e83dea8c..befa29a1aca8d1dff3b545a851da7e1b04e14476 100644 --- a/tlatools/src/tlc2/module/Strings.java +++ b/tlatools/src/tlc2/module/Strings.java @@ -7,11 +7,12 @@ package tlc2.module; import tlc2.output.EC; import tlc2.tool.EvalException; -import tlc2.value.ModelValue; -import tlc2.value.StringValue; -import tlc2.value.UserObj; -import tlc2.value.UserValue; -import tlc2.value.Value; +import tlc2.value.Values; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.UserObj; +import tlc2.value.impl.UserValue; +import tlc2.value.impl.Value; public class Strings extends UserObj { @@ -32,7 +33,7 @@ public class Strings extends UserObj } if (val instanceof ModelValue) return 1; - throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "STRING", Value.ppr(val.toString()) }); + throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "STRING", Values.ppr(val.toString()) }); } public final boolean member(Value val) @@ -41,7 +42,7 @@ public class Strings extends UserObj return true; if (val instanceof ModelValue) return ((ModelValue) val).modelValueMember(this); - throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Value.ppr(val.toString()), "STRING" }); + throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "STRING" }); } public final boolean isFinite() @@ -49,7 +50,7 @@ public class Strings extends UserObj return false; } - public final StringBuffer toString(StringBuffer sb, int offset) + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { return sb.append("STRING"); } diff --git a/tlatools/src/tlc2/module/TLC.java b/tlatools/src/tlc2/module/TLC.java index 5cdd4bcc9f49a47c269a0c15bf2cebf2b24add93..45e058f1502af366937a689ab9e01698e5c212fa 100644 --- a/tlatools/src/tlc2/module/TLC.java +++ b/tlatools/src/tlc2/module/TLC.java @@ -13,30 +13,37 @@ import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.EvalControl; import tlc2.tool.EvalException; -import tlc2.tool.TLARegistry; +import tlc2.tool.ModelChecker; +import tlc2.tool.TLCState; +import tlc2.tool.impl.TLARegistry; import tlc2.util.IdThread; -import tlc2.value.Applicable; -import tlc2.value.BoolValue; -import tlc2.value.FcnRcdValue; -import tlc2.value.IntValue; -import tlc2.value.IntervalValue; -import tlc2.value.RecordValue; -import tlc2.value.SetEnumValue; -import tlc2.value.SetOfFcnsValue; -import tlc2.value.SetOfRcdsValue; -import tlc2.value.SetOfTuplesValue; -import tlc2.value.StringValue; -import tlc2.value.TupleValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; import tlc2.value.ValueConstants; -import tlc2.value.ValueVec; +import tlc2.value.Values; +import tlc2.value.impl.Applicable; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.RecordValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.SetOfFcnsValue; +import tlc2.value.impl.SetOfRcdsValue; +import tlc2.value.impl.SetOfTuplesValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueVec; import util.Assert; import util.ToolIO; +import util.UniqueString; public class TLC implements ValueConstants { public static final long serialVersionUID = 20160822L; + private static final long startTime = System.currentTimeMillis(); + public static BufferedWriter OUTPUT; static @@ -60,15 +67,15 @@ public class TLC implements ValueConstants */ public static Value Print(Value v1, Value v2) { - Value v1c = v1.deepCopy(); - Value v2c = v2.deepCopy(); + Value v1c = (Value) v1.deepCopy(); + Value v2c = (Value) v2.deepCopy(); v1c.deepNormalize(); v2c.deepNormalize(); if (OUTPUT == null) { - ToolIO.out.println(Value.ppr(v1c.toString()) + " " + Value.ppr(v2c.toString())); + ToolIO.out.println(Values.ppr(v1c.toStringUnchecked()) + " " + Values.ppr(v2c.toStringUnchecked())); } else { try { - OUTPUT.write(Value.ppr(v1c.toString()) + " " + Value.ppr(v2c.toString()) + "\n"); + OUTPUT.write(Values.ppr(v1c.toStringUnchecked()) + " " + Values.ppr(v2c.toStringUnchecked()) + "\n"); } catch (IOException e) { MP.printError(EC.GENERAL, e); } @@ -81,27 +88,27 @@ public class TLC implements ValueConstants * * Modified on 22 June 2011 by LL. See comment on the Print method */ - public static Value PrintT(Value v1) + public static Value PrintT(Value v1) { - Value v1c = v1.deepCopy(); + Value v1c = (Value) v1.deepCopy(); v1c.deepNormalize(); if (OUTPUT == null) { - String ppr = Value.ppr(v1c.toString()); + String ppr = Values.ppr(v1c.toStringUnchecked()); ToolIO.out.println(ppr); } else { try { - OUTPUT.write(Value.ppr(v1c.toString("\n"))); + OUTPUT.write(Values.ppr(v1c.toStringUnchecked("\n"))); } catch (IOException e) { MP.printError(EC.GENERAL, e); } } - return ValTrue; + return BoolValue.ValTrue; } /* Returns the string value of the string representation of v. */ public static Value ToString(Value v) { - return new StringValue(v.toString()); + return new StringValue(v.toStringUnchecked()); } /** @@ -110,11 +117,11 @@ public class TLC implements ValueConstants */ public static Value Assert(Value v1, Value v2) { - if ((v1 instanceof BoolValue) && ((BoolValue) v1).val) + if ((v1 instanceof IBoolValue) && ((BoolValue) v1).val) { return v1; } - throw new EvalException(EC.TLC_VALUE_ASSERT_FAILED, Value.ppr(v2.toString())); + throw new EvalException(EC.TLC_VALUE_ASSERT_FAILED, Values.ppr(v2.toString())); } /** @@ -138,13 +145,13 @@ public class TLC implements ValueConstants Value res = null; if (th instanceof IdThread) { - res = ((IdThread) th).getLocalValue(idx); + res = (Value) ((IdThread) th).getLocalValue(idx); } else if (TLCGlobals.mainChecker != null) { - res = tlc2.TLCGlobals.mainChecker.getValue(0, idx); + res = (Value) tlc2.TLCGlobals.mainChecker.getValue(0, idx); } else { - res = tlc2.TLCGlobals.simulator.getLocalValue(idx); + res = (Value) tlc2.TLCGlobals.simulator.getLocalValue(idx); } if (res == null) { @@ -152,12 +159,75 @@ public class TLC implements ValueConstants } return res; } + } else if (vidx instanceof StringValue) { + return TLCGetStringValue(vidx); } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "\b" /* delete the space*/, "TLCGet", - "nonnegative integer", Value.ppr(vidx.toString()) }); + throw new EvalException(EC.TLC_MODULE_ONE_ARGUMENT_ERROR, new String[] { "TLCGet", + "nonnegative integer", Values.ppr(vidx.toString()) }); } - public static Value TLCSet(Value vidx, Value val) + private static final Value TLCGetStringValue(final Value vidx) { + final StringValue sv = (StringValue) vidx; + if (UniqueString.uniqueStringOf("diameter") == sv.val) { + try { + return IntValue.gen(TLCGlobals.mainChecker.getProgress()); + } catch (ArithmeticException e) { + throw new EvalException(EC.TLC_MODULE_OVERFLOW, + Long.toString(TLCGlobals.mainChecker.getProgress())); + } catch (NullPointerException npe) { + // TLCGlobals.mainChecker is null while the spec is parsed. A constant + // expression referencing one of the named values here would thus result in an + // NPE. + throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val)); + } + } else if (UniqueString.uniqueStringOf("distinct") == sv.val) { + try { + return IntValue.gen(Math.toIntExact(TLCGlobals.mainChecker.getDistinctStatesGenerated())); + } catch (ArithmeticException e) { + throw new EvalException(EC.TLC_MODULE_OVERFLOW, + Long.toString(TLCGlobals.mainChecker.getDistinctStatesGenerated())); + } catch (NullPointerException npe) { + throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val)); + } + } else if (UniqueString.uniqueStringOf("queue") == sv.val) { + try { + return IntValue.gen(Math.toIntExact(TLCGlobals.mainChecker.getStateQueueSize())); + } catch (ArithmeticException e) { + throw new EvalException(EC.TLC_MODULE_OVERFLOW, + Long.toString(TLCGlobals.mainChecker.getStateQueueSize())); + } catch (NullPointerException npe) { + throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val)); + } + } else if (UniqueString.uniqueStringOf("duration") == sv.val) { + try { + final int duration = (int) ((System.currentTimeMillis() - startTime) / 1000L); + return IntValue.gen(Math.toIntExact(duration)); + } catch (ArithmeticException e) { + throw new EvalException(EC.TLC_MODULE_OVERFLOW, + Long.toString(((System.currentTimeMillis() - startTime) / 1000L))); + } + } else if (UniqueString.uniqueStringOf("level") == sv.val) { + // Contrary to "diameter", "level" is not monotonically increasing. "diameter" is + // because it calls tlc2.tool.TLCTrace.getLevelForReporting(). "level" is the height + // stores as part of the state that is currently explored. + final TLCState currentState = IdThread.getCurrentState(); + if (currentState != null) { + return IntValue.gen(currentState.getLevel()); + } else { + if (TLCGlobals.mainChecker == null) { + // Be consistent with TLCGet("diameter") when TLCGet("level") appears as + // constant substitution. + throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val)); + } + // Not an IdThread implies that TLCGet("level") is part of the initial predicate + // where the level is 0. + return IntValue.gen(0); + } + } + throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val)); + } + + public static Value TLCSet(Value vidx, Value val) { if (vidx instanceof IntValue) { @@ -175,18 +245,44 @@ public class TLC implements ValueConstants { tlc2.TLCGlobals.simulator.setLocalValue(idx, val); } - return ValTrue; + return BoolValue.ValTrue; } + } else if (vidx instanceof StringValue) { + final StringValue sv = (StringValue) vidx; + if (UniqueString.uniqueStringOf("exit") == sv.val) { + if (val == BoolValue.ValTrue) { + TLCGlobals.mainChecker.stop(); + } + return BoolValue.ValTrue; + } else if (UniqueString.uniqueStringOf("pause") == sv.val) { + // Provisional TLCSet("pause", TRUE) implementation that suspends BFS model + // checking until enter is pressed on system.in. Either use in spec as: + // TLCSet("pause", guard) + // but it might be better guarded by IfThenElse for performance reasons: + // IF guard THEN TLCSet("pause", TRUE) ELSE TRUE + if (val == BoolValue.ValTrue && TLCGlobals.mainChecker instanceof ModelChecker) { + final ModelChecker mc = (ModelChecker) TLCGlobals.mainChecker; + synchronized (mc.theStateQueue) { + ToolIO.out.println("Press enter to resume model checking."); + ToolIO.out.flush(); + try { + System.in.read(); + } catch (IOException e) { + throw new EvalException(EC.GENERAL, e.getMessage()); + } + } + } + return BoolValue.ValTrue; + } } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "TLCSet", "nonnegative integer", - Value.ppr(vidx.toString()) }); + Values.ppr(vidx.toString()) }); } public static Value MakeFcn(Value d, Value e) { - Value[] dom = new Value[1]; - Value[] vals = new Value[1]; + Value[] dom = new Value[1]; + Value[] vals = new Value[1]; dom[0] = d; vals[0] = e; return new FcnRcdValue(dom, vals, true); @@ -198,24 +294,24 @@ public class TLC implements ValueConstants */ public static Value CombineFcn(Value f1, Value f2) { - FcnRcdValue fcn1 = FcnRcdValue.convert(f1); - FcnRcdValue fcn2 = FcnRcdValue.convert(f2); + FcnRcdValue fcn1 = (FcnRcdValue) f1.toFcnRcd(); + FcnRcdValue fcn2 = (FcnRcdValue) f2.toFcnRcd(); if (fcn1 == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "@@", "function", - Value.ppr(f1.toString()) }); + Values.ppr(f1.toString()) }); } if (fcn2 == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "@@", "function", - Value.ppr(f2.toString()) }); + Values.ppr(f2.toString()) }); } ValueVec dom = new ValueVec(); ValueVec vals = new ValueVec(); - Value[] vals1 = fcn1.values; - Value[] vals2 = fcn2.values; + Value [] vals1 = fcn1.values; + Value [] vals2 = fcn2.values; - Value[] dom1 = fcn1.domain; + Value [] dom1 = fcn1.domain; if (dom1 == null) { IntervalValue intv1 = fcn1.intv; @@ -234,13 +330,13 @@ public class TLC implements ValueConstants } int len1 = dom.size(); - Value[] dom2 = fcn2.domain; + Value [] dom2 = fcn2.domain; if (dom2 == null) { IntervalValue intv2 = fcn2.intv; for (int i = intv2.low; i <= intv2.high; i++) { - Value val = IntValue.gen(i); + Value val = IntValue.gen(i); boolean found = false; for (int j = 0; j < len1; j++) { @@ -260,7 +356,7 @@ public class TLC implements ValueConstants { for (int i = 0; i < dom2.length; i++) { - Value val = dom2[i]; + Value val = dom2[i]; boolean found = false; for (int j = 0; j < len1; j++) { @@ -278,8 +374,8 @@ public class TLC implements ValueConstants } } - Value[] domain = new Value[dom.size()]; - Value[] values = new Value[dom.size()]; + Value [] domain = new Value[dom.size()]; + Value [] values = new Value[dom.size()]; for (int i = 0; i < domain.length; i++) { domain[i] = dom.elementAt(i); @@ -290,24 +386,24 @@ public class TLC implements ValueConstants public static Value SortSeq(Value s, Value cmp) { - TupleValue seq = TupleValue.convert(s); + TupleValue seq = (TupleValue) s.toTuple(); if (seq == null) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "first", "SortSeq", "natural number", - Value.ppr(s.toString()) }); + Values.ppr(s.toString()) }); } if (!(cmp instanceof Applicable)) { throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SortSeq", "function", - Value.ppr(cmp.toString()) }); + Values.ppr(cmp.toString()) }); } Applicable fcmp = (Applicable) cmp; - Value[] elems = seq.elems; + Value [] elems = seq.elems; int len = elems.length; if (len == 0) return seq; - Value[] args = new Value[2]; - Value[] newElems = new Value[len]; + Value [] args = new Value[2]; + Value [] newElems = new Value[len]; newElems[0] = elems[0]; for (int i = 1; i < len; i++) { @@ -327,37 +423,37 @@ public class TLC implements ValueConstants return new TupleValue(newElems); } - private static boolean compare(Applicable fcmp, Value[] args) + private static boolean compare(Applicable fcmp, Value [] args) { - Value res = fcmp.apply(args, EvalControl.Clear); - if (res instanceof BoolValue) + Value res = fcmp.apply(args, EvalControl.Clear); + if (res instanceof IBoolValue) { return ((BoolValue) res).val; } - throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SortSeq", "noolean function", - Value.ppr(res.toString()) }); + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "SortSeq", "boolean function", + Values.ppr(res.toString()) }); } // Returns a set of size n! where n = |s|. public static Value Permutations(Value s) { - SetEnumValue s1 = SetEnumValue.convert(s); + SetEnumValue s1 = (SetEnumValue) s.toSetEnum(); if (s1 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "Permutations", - "a finite set", Value.ppr(s.toString()) }); + "a finite set", Values.ppr(s.toString()) }); } s1.normalize(); ValueVec elems = s1.elems; int len = elems.size(); if (len == 0) { - Value[] elems1 = { EmptyFcn }; + Value[] elems1 = { FcnRcdValue.EmptyFcn }; return new SetEnumValue(elems1, true); } int factorial = 1; - Value[] domain = new Value[len]; + Value [] domain = new Value[len]; int[] idxArray = new int[len]; boolean[] inUse = new boolean[len]; for (int i = 0; i < len; i++) @@ -371,7 +467,7 @@ public class TLC implements ValueConstants ValueVec fcns = new ValueVec(factorial); _done: while (true) { - Value[] vals = new Value[len]; + Value [] vals = new Value[len]; for (int i = 0; i < len; i++) { vals[i] = domain[idxArray[i]]; @@ -416,22 +512,22 @@ public class TLC implements ValueConstants return new SetEnumValue(fcns, false); } - public static Value RandomElement(Value val) + public static Value RandomElement(Value val) { switch (val.getKind()) { case SETOFFCNSVALUE: { SetOfFcnsValue sfv = (SetOfFcnsValue) val; sfv.normalize(); - SetEnumValue domSet = SetEnumValue.convert(sfv.domain); + SetEnumValue domSet = (SetEnumValue) sfv.domain.toSetEnum(); if (domSet == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "RandomElement", - "a finite set", Value.ppr(val.toString()) }); + "a finite set", Values.ppr(val.toString()) }); } domSet.normalize(); ValueVec elems = domSet.elems; - Value[] dom = new Value[elems.size()]; - Value[] vals = new Value[elems.size()]; + Value [] dom = new Value[elems.size()]; + Value [] vals = new Value[elems.size()]; for (int i = 0; i < dom.length; i++) { dom[i] = elems.elementAt(i); @@ -442,7 +538,7 @@ public class TLC implements ValueConstants case SETOFRCDSVALUE: { SetOfRcdsValue srv = (SetOfRcdsValue) val; srv.normalize(); - Value[] vals = new Value[srv.names.length]; + Value [] vals = new Value[srv.names.length]; for (int i = 0; i < vals.length; i++) { vals[i] = RandomElement(srv.values[i]); @@ -452,7 +548,7 @@ public class TLC implements ValueConstants case SETOFTUPLESVALUE: { SetOfTuplesValue stv = (SetOfTuplesValue) val; stv.normalize(); - Value[] vals = new Value[stv.sets.length]; + Value [] vals = new Value[stv.sets.length]; for (int i = 0; i < vals.length; i++) { vals[i] = RandomElement(stv.sets[i]); @@ -460,11 +556,11 @@ public class TLC implements ValueConstants return new TupleValue(vals); } default: { - SetEnumValue enumVal = SetEnumValue.convert(val); + SetEnumValue enumVal = (SetEnumValue) val.toSetEnum(); if (enumVal == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "RandomElement", - "a finite set", Value.ppr(val.toString()) }); + "a finite set", Values.ppr(val.toString()) }); } return enumVal.randomElement(); } @@ -484,12 +580,12 @@ public class TLC implements ValueConstants * @param val * @return */ - public static Value TLCEval(Value val) { - Value evalVal = SetEnumValue.convert(val); + public static Value TLCEval(Value val) { + Value evalVal = val.toSetEnum(); if (evalVal != null) { return evalVal; } - evalVal = FcnRcdValue.convert(val); + evalVal = val.toFcnRcd(); if (evalVal != null) { return evalVal; } @@ -498,7 +594,7 @@ public class TLC implements ValueConstants } /* public static Value FApply(Value f, Value op, Value base) { - FcnRcdValue fcn = FcnRcdValue.convert(f); + FcnRcdValue fcn = f.toFcnRcd(); if (fcn == null) { String msg = "The first argument of FApply must be a " + "function with finite domain, but instead it is\n" + @@ -521,7 +617,7 @@ public class TLC implements ValueConstants } public static Value FSum(Value f) { - FcnRcdValue fcn = FcnRcdValue.convert(f); + FcnRcdValue fcn = f.toFcnRcd(); if (fcn == null) { String msg = "The argument of FSum should be a function; " + "but instead it is:\n" + Value.ppr(f.toString()); diff --git a/tlatools/src/tlc2/module/TransitiveClosure.java b/tlatools/src/tlc2/module/TransitiveClosure.java index f6d5b134d804857e041c5a00381a56539cc1d6fe..b04c3f83f51669638582835aafbb21f507b5ca2d 100644 --- a/tlatools/src/tlc2/module/TransitiveClosure.java +++ b/tlatools/src/tlc2/module/TransitiveClosure.java @@ -10,13 +10,14 @@ import java.util.Hashtable; import tlc2.output.EC; import tlc2.tool.EvalException; import tlc2.util.Vect; -import tlc2.value.Enumerable; -import tlc2.value.SetEnumValue; -import tlc2.value.TupleValue; -import tlc2.value.Value; import tlc2.value.ValueConstants; -import tlc2.value.ValueEnumeration; -import tlc2.value.ValueVec; +import tlc2.value.Values; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueEnumeration; +import tlc2.value.impl.ValueVec; public class TransitiveClosure implements ValueConstants { @@ -28,21 +29,21 @@ public class TransitiveClosure implements ValueConstants if (!(rel instanceof Enumerable)) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "TransitiveClosure", - "an enumerable set", Value.ppr(rel.toString()) }); + "an enumerable set", Values.ppr(rel.toString()) }); } int maxLen = 2 * rel.size(); boolean[][] matrix = new boolean[maxLen][maxLen]; ValueEnumeration elems = ((Enumerable) rel).elements(); - Vect elemList = new Vect(); - Hashtable fps = new Hashtable(); + Vect<Value> elemList = new Vect<>(); + Hashtable<Value, Integer> fps = new Hashtable<>(); int cnt = 0; Value elem = null; while ((elem = elems.nextElement()) != null) { - TupleValue tv = TupleValue.convert(elem); + TupleValue tv = (TupleValue) elem.toTuple(); if (tv == null || tv.size() != 2) { - throw new EvalException(EC.TLC_MODULE_TRANSITIVE_CLOSURE, Value.ppr(elem.toString())); + throw new EvalException(EC.TLC_MODULE_TRANSITIVE_CLOSURE, Values.ppr(elem.toString())); } Value elem1 = tv.elems[0]; Value elem2 = tv.elems[1]; @@ -93,9 +94,9 @@ public class TransitiveClosure implements ValueConstants { if (matrix[i][j]) { - Value elem1 = (Value) elemList.elementAt(i); - Value elem2 = (Value) elemList.elementAt(j); - Value newElem = new TupleValue(elem1, elem2); + Value elem1 = (Value) elemList.elementAt(i); + Value elem2 = (Value) elemList.elementAt(j); + Value newElem = new TupleValue(elem1, elem2); newElems.addElement(newElem); } } diff --git a/tlatools/src/tlc2/output/EC.java b/tlatools/src/tlc2/output/EC.java index a64038cddcd05e58ff039d4a9aea526a4ac71f68..fee1868abb3ccd5671c39d42c5c413c9041d4584 100644 --- a/tlatools/src/tlc2/output/EC.java +++ b/tlatools/src/tlc2/output/EC.java @@ -1,5 +1,8 @@ package tlc2.output; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Interface containing the error code constants @@ -8,6 +11,9 @@ package tlc2.output; */ public interface EC { + // This is reserved so that an optional error code can be safely represented in a single int + public static final int NO_ERROR = 0; + // Check and CheckImpl // check if the TLC option is the same for params public static final int CHECK_FAILED_TO_CHECK = 3000; @@ -110,6 +116,7 @@ public interface EC public static final int TLC_VALUE_ASSERT_FAILED = 2132; public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE = 2154; public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED = 2168; + public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH = 2400; public static final int TLC_FP_NOT_IN_SET = 2133; public static final int TLC_FP_VALUE_ALREADY_ON_DISK = 2166; @@ -134,6 +141,7 @@ public interface EC * an "a" into an "an". This doesn't work on the Toolbox's console. Hence, LL added * the following message type on 21 May 2012. */ public static final int TLC_MODULE_ARGUMENT_ERROR_AN = 2266; + public static final int TLC_MODULE_ONE_ARGUMENT_ERROR = 2283; public static final int TLC_ARGUMENT_MISMATCH = 2170; public static final int TLC_PARSING_FAILED2 = 2171; public static final int TLC_PARSING_FAILED = 3002; @@ -214,6 +222,7 @@ public interface EC public static final int TLC_LIVE_STATE_PREDICATE_NON_BOOL = 2250; public static final int TLC_LIVE_CANNOT_EVAL_FORMULA = 2251; public static final int TLC_LIVE_ENCOUNTERED_NONBOOL_PREDICATE = 2252; + public static final int TLC_LIVE_FORMULA_TAUTOLOGY = 2253; public static final int TLC_EXPECTED_VALUE = 2215; @@ -228,7 +237,13 @@ public interface EC public static final int TLC_STATE_PRINT3 = 2218; // This seems to be a "Stuttering" message from a liveness-error trace public static final int TLC_SANY_END = 2219; public static final int TLC_SANY_START = 2220; + public static final int TLC_COVERAGE_MISMATCH = 2776; public static final int TLC_COVERAGE_VALUE = 2221; + public static final int TLC_COVERAGE_VALUE_COST = 2775; + public static final int TLC_COVERAGE_NEXT = 2772; + public static final int TLC_COVERAGE_INIT = 2773; + public static final int TLC_COVERAGE_PROPERTY = 2774; + public static final int TLC_COVERAGE_END_OVERHEAD = 2777; // config file errors public static final int TLC_CONFIG_VALUE_NOT_ASSIGNED_TO_CONSTANT_PARAM = 2222; @@ -265,4 +280,131 @@ public interface EC public static final int TLC_COUNTER_EXAMPLE = 2264; public static final int TLC_INTEGER_TOO_BIG = 2265; + public static final int TLC_TRACE_TOO_LONG = 2282; + + public static final int TLC_ENVIRONMENT_JVM_GC = 2401; + + + //**************************************************************// + // Mapping error constants above to process exit/return values. // + // Because Linux and macOS only support 8-bit exit values, this // + // mapping is necessary. // + //**************************************************************// + + public static class ExitStatus { + + public static final int ERROR = 255; + public static final int SUCCESS = 0; + + // (Safety/Liveness) Violations + public static final int VIOLATION_ASSUMPTION = 10; + public static final int VIOLATION_DEADLOCK = VIOLATION_ASSUMPTION + 1; + public static final int VIOLATION_SAFETY = VIOLATION_DEADLOCK + 1; + public static final int VIOLATION_LIVENESS = VIOLATION_SAFETY + 1; + public static final int VIOLATION_ASSERT = VIOLATION_LIVENESS + 1; + + // Evaluation failures + public static final int FAILURE_SPEC_EVAL = 75; + public static final int FAILURE_SAFETY_EVAL = FAILURE_SPEC_EVAL + 1; + public static final int FAILURE_LIVENESS_EVAL = FAILURE_SAFETY_EVAL + 1; + + // Errors + public static final int ERROR_SPEC_PARSE = 150; + public static final int ERROR_CONFIG_PARSE = ERROR_SPEC_PARSE + 1; + public static final int ERROR_STATESPACE_TOO_LARGE = ERROR_CONFIG_PARSE + 1; + public static final int ERROR_SYSTEM = ERROR_STATESPACE_TOO_LARGE + 1; + + /** + * Returns an exit status for an error code. + */ + public static int errorConstantToExitStatus(final int ec) { + // TODO Allocate a range of exit status to indicate classes of errors. + // For a great example of potential classes see: https://github.com/tlaplus/tlaplus/pull/308#discussion_r285840112 + switch (ec) { + case NO_ERROR: + return SUCCESS; + + // failures + + case TLC_LIVE_FORMULA_TAUTOLOGY: + return FAILURE_LIVENESS_EVAL; + + case TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT: + case TLC_STATES_AND_NO_NEXT_ACTION: + case TLC_NESTED_EXPRESSION: + case TLC_FINGERPRINT_EXCEPTION: + return FAILURE_SPEC_EVAL; + + case TLC_INVARIANT_EVALUATION_FAILED: + case TLC_INVARIANT_VIOLATED_LEVEL: + return FAILURE_SAFETY_EVAL; + + // violations + + case TLC_INVARIANT_VIOLATED_INITIAL: + case TLC_INVARIANT_VIOLATED_BEHAVIOR: + return VIOLATION_SAFETY; + + case TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR: + case TLC_ACTION_PROPERTY_EVALUATION_FAILED: + case TLC_TEMPORAL_PROPERTY_VIOLATED: + case TLC_PROPERTY_VIOLATED_INITIAL: + return VIOLATION_LIVENESS; + + case TLC_DEADLOCK_REACHED: + return VIOLATION_DEADLOCK; + + case TLC_ASSUMPTION_FALSE: + case TLC_ASSUMPTION_EVALUATION_ERROR: + return VIOLATION_ASSUMPTION; + + case TLC_VALUE_ASSERT_FAILED: + return VIOLATION_ASSERT; + + // errors + case TLC_CONFIG_VALUE_NOT_ASSIGNED_TO_CONSTANT_PARAM: + case TLC_CONFIG_RHS_ID_APPEARED_AFTER_LHS_ID: + case TLC_CONFIG_WRONG_SUBSTITUTION: + case TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS: + case TLC_CONFIG_UNDEFINED_OR_NO_OPERATOR: + case TLC_CONFIG_SUBSTITUTION_NON_CONSTANT: + case TLC_CONFIG_ID_DOES_NOT_APPEAR_IN_SPEC: + case TLC_CONFIG_NOT_BOTH_SPEC_AND_INIT: + case TLC_CONFIG_ID_REQUIRES_NO_ARG: + case TLC_CONFIG_SPECIFIED_NOT_DEFINED: + case TLC_CONFIG_ID_HAS_VALUE: + case TLC_CONFIG_MISSING_INIT: + case TLC_CONFIG_MISSING_NEXT: + case TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT: + case TLC_CONFIG_OP_NO_ARGS: + case TLC_CONFIG_OP_NOT_IN_SPEC: + case TLC_CONFIG_OP_IS_EQUAL: + case TLC_CONFIG_SPEC_IS_TRIVIAL: + case TLC_CANT_HANDLE_SUBSCRIPT: + case TLC_CANT_HANDLE_CONJUNCT: + case TLC_CANT_HANDLE_TOO_MANY_NEXT_STATE_RELS: + case TLC_CONFIG_PROPERTY_NOT_CORRECTLY_DEFINED: + case TLC_CONFIG_OP_ARITY_INCONSISTENT: + case TLC_CONFIG_NO_STATE_TYPE: + case TLC_CANT_HANDLE_REAL_NUMBERS: // might also be in the spec + case TLC_NO_MODULES: + return ERROR_CONFIG_PARSE; + + case TLC_PARSING_FAILED2: + case TLC_PARSING_FAILED: + return ERROR_SPEC_PARSE; + + default: + return 255; + } + } + + private static final Set<Integer> knownExitValues = Stream.of(SUCCESS, FAILURE_LIVENESS_EVAL, FAILURE_SPEC_EVAL, + FAILURE_SAFETY_EVAL, VIOLATION_SAFETY, VIOLATION_LIVENESS, VIOLATION_DEADLOCK, VIOLATION_ASSUMPTION, + VIOLATION_ASSERT, ERROR_CONFIG_PARSE, ERROR_SPEC_PARSE).collect(Collectors.toSet()); + + public static boolean exitStatusToCrash(final int exitStatus) { + return !knownExitValues.contains(exitStatus); + } + } } diff --git a/tlatools/src/tlc2/output/MP.java b/tlatools/src/tlc2/output/MP.java index dfc9fd956bd7a0f68a4ca7a21fe42e63801fbae5..3bdc6f94c7a5f0759161f9a8ec7fc168b7edb347 100644 --- a/tlatools/src/tlc2/output/MP.java +++ b/tlatools/src/tlc2/output/MP.java @@ -16,6 +16,7 @@ import util.Assert; import util.DebugPrinter; import util.Set; import util.ToolIO; +import util.Assert.TLCRuntimeException; /** * This class is used in the following way to support the replacements of the @@ -165,7 +166,7 @@ public class MP * @param parameters string of parameters to be replaced in the message * @return the formatted message */ - private synchronized static String getMessage(int messageClass, int messageCode, String[] parameters) + public synchronized static String getMessage(int messageClass, int messageCode, String[] parameters) { if (parameters == null) @@ -616,6 +617,10 @@ public class MP b.append("Overflow when computing %1%"); break; + case EC.TLC_MODULE_ONE_ARGUMENT_ERROR: + b.append("The argument of %1% should be a %2%, but instead it is:\n%3%"); + break; + case EC.TLC_MODULE_ARGUMENT_ERROR: b.append("The %1% argument of %2% should be a %3%, but instead it is:\n%4%"); break; @@ -675,7 +680,10 @@ public class MP case EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED: b.append("Loading %1% operator override from %2% with signature: %3%."); break; - case EC.TLC_FEATURE_UNSUPPORTED: + case EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH: + b.append("Failed to match %1% operator override from %2% with signature: %3%."); + break; + case EC.TLC_FEATURE_UNSUPPORTED: b.append("%1%"); break; case EC.TLC_FEATURE_UNSUPPORTED_LIVENESS_SYMMETRY: @@ -713,6 +721,9 @@ public class MP case EC.TLC_LIVE_ENCOUNTERED_NONBOOL_PREDICATE: b.append("Encountered an action predicate that's not a boolean."); break; + case EC.TLC_LIVE_FORMULA_TAUTOLOGY: + b.append("Temporal formula is a tautology (its negation is unsatisfiable)."); + break; case EC.TLC_EXPECTED_VALUE: b.append("TLC expected a %1% value, but did not find one. %2%"); @@ -765,57 +776,88 @@ public class MP /*------------------------------------------- */ // TLC distributed case EC.TLC_DISTRIBUTED_SERVER_RUNNING: - b.append("TLC server at %1% is ready (").append(SDF.format(new Date())).append(")"); + b.append("TLC server at %1% is ready (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_WORKER_REGISTERED: - b.append("Registration for worker at %1% completed (").append(SDF.format(new Date())).append(")"); + b.append("Registration for worker at %1% completed (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_WORKER_DEREGISTERED: - b.append("TLC worker %1% disconnected (").append(SDF.format(new Date())).append(")"); + b.append("TLC worker %1% disconnected (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_WORKER_STATS: //new Date() + " Worker: " + name + " Sent: " + sentStates + " Rcvd: " + receivedStates - b.append("Worker: %1% Sent: %2% Rcvd: %3% CacheRatio: %4% (").append(SDF.format(new Date())).append(")"); + b.append("Worker: %1% Sent: %2% Rcvd: %3% CacheRatio: %4% (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_SERVER_NOT_RUNNING: - b.append("TLCServer is gone due to %1%, exiting worker... (").append(SDF.format(new Date())).append(")"); + b.append("TLCServer is gone due to %1%, exiting worker... (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_SERVER_FINISHED: - b.append("TLCServer has finished, exiting worker... (").append(SDF.format(new Date())).append(")"); + b.append("TLCServer has finished, exiting worker... (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_VM_VERSION: b.append( "VM does not allow to get the UnicastRef port.\nWorker will be identified with port 0 in output (") - .append(SDF.format(new Date())).append(")"); + .append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_WORKER_LOST: - b.append("TLC worker connection lost %1% (").append(SDF.format(new Date())).append(")"); + b.append("TLC worker connection lost %1% (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_EXCEED_BLOCKSIZE: - b.append("Trying to limit max block size (to recover from transport failure): %1% (").append(SDF.format(new Date())).append(")"); + b.append("Trying to limit max block size (to recover from transport failure): %1% (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_SERVER_FPSET_REGISTERED: - b.append("%1% out of %2% FPSet server(s) registered (").append(SDF.format(new Date())).append(")"); + b.append("%1% out of %2% FPSet server(s) registered (").append(now()).append(")"); break; case EC.TLC_DISTRIBUTED_SERVER_FPSET_WAITING: - b.append("Waiting for %1% FPSet server(s) to register (").append(SDF.format(new Date())).append(")"); + b.append("Waiting for %1% FPSet server(s) to register (").append(now()).append(")"); break; /*------------------------------------------- */ case EC.TLC_STARTING: - b.append("Starting... (").append(SDF.format(new Date())).append(")"); + b.append("Starting... (").append(now()).append(")"); break; case EC.TLC_FINISHED: - b.append("Finished in %1% at (").append(SDF.format(new Date())).append(")"); - break; + b.append("Finished in %1% at (").append(now()).append(")"); + break; + /* + * The two startup banners below are parsed by the Toolbox in + * org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider. + * startupMessagePattern. Remember to update when the banners below + * get changed + * (see org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProviderTest)!!! + */ case EC.TLC_MODE_MC: - b.append("Running breadth-first search Model-Checking with seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); + b.append("Running breadth-first search Model-Checking with fp %13% and seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory"); + if (!"".equals(parameters[13])) { + b.append(" [pid: %14%]"); + } else { + // Make sure subsequent parameters, %15%... are processed below in the + // replaceString method. replaceString terminates if a string is not present, + // thus we replace %14% with the zero-length string to not change the output but + // to make replaceString happy. + b.append("%14%"); + } + b.append(" (%4% %5% %6%, %7% %8% %9%, %15%, %16%)."); break; case EC.TLC_MODE_MC_DFS: - b.append("Running depth-first search Model-Checking with seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); + b.append("Running depth-first search Model-Checking with fp %13% and seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory"); + if (!"".equals(parameters[13])) { + b.append(" [pid: %14%]"); + } else { + // see TLC_MODE_MC above. + b.append("%14%"); + } + b.append(" (%4% %5% %6%, %7% %8% %9%)."); break; case EC.TLC_MODE_SIMU: - b.append("Running Random Simulation with seed %1% with %2% worker%3% on %4% cores with %11%MB heap and %12%MB offheap memory (%5% %6% %7%, %8% %9% %10%)."); + b.append("Running Random Simulation with seed %1% with %2% worker%3% on %4% cores with %11%MB heap and %12%MB offheap memory"); + if (!"".equals(parameters[12])) { + b.append(" [pid: %13%]"); + } else { + // see TLC_MODE_MC above. + b.append("%13%"); + } + b.append(" (%5% %6% %7%, %8% %9% %10%)."); break; case EC.TLC_COMPUTING_INIT: b.append("Computing initial states..."); @@ -824,30 +866,37 @@ public class MP b.append("Computed %1% initial states..."); break; case EC.TLC_INIT_GENERATED1: - b.append("Finished computing initial states: %1% distinct state%2% generated."); + b.append("Finished computing initial states: %1% distinct state%2% generated at ") + .append(now()).append("."); break; case EC.TLC_INIT_GENERATED2: - b.append("Finished computing initial states: %1% state%2% generated, with %3% of them distinct."); + b.append("Finished computing initial states: %1% state%2% generated, with %3% of them distinct at ") + .append(now()).append("."); break; case EC.TLC_INIT_GENERATED3: - b.append("Finished computing initial states: %1% states generated.\n" - + "Because TLC recovers from a previous checkpoint, only %2% of them require further exploration."); + b.append("Finished computing initial states: %1% states generated.\n" + + "Because TLC recovers from a previous checkpoint, only %2% of them require further exploration at ") + .append(now()).append("."); break; case EC.TLC_INIT_GENERATED4: b.append("Finished computing initial states: %1% states generated, with %2% of them distinct."); break; case EC.TLC_CHECKING_TEMPORAL_PROPS: b.append("Checking %3%temporal properties for the %1% state space with %2% total distinct states at (") - .append(SDF.format(new Date())).append(")"); + .append(now()).append(")"); break; case EC.TLC_CHECKING_TEMPORAL_PROPS_END: - b.append("Finished checking temporal properties in %1% at " + SDF.format(new Date())); + b.append("Finished checking temporal properties in %1% at " + now()); break; case EC.TLC_SUCCESS: b.append("Model checking completed. No error has been found.\n" - + " Estimates of the probability that TLC did not check all reachable states\n" - + " because two distinct states had the same fingerprint:\n" + " calculated (optimistic): %1%\n" - + " based on the actual fingerprints: %2%"); + + " Estimates of the probability that TLC did not check all reachable states\n"); + if (parameters.length == 1) { + b.append(" because two distinct states had the same fingerprint:\n" + " calculated (optimistic): %1%"); + } else { + b.append(" because two distinct states had the same fingerprint:\n" + + " calculated (optimistic): %1%\n" + " based on the actual fingerprints: %2%"); + } break; case EC.TLC_SEARCH_DEPTH: b.append("The depth of the complete state graph search is %1%."); @@ -859,7 +908,7 @@ public class MP b.append("Checkpointing of run %1%"); break; case EC.TLC_CHECKPOINT_END: - b.append("Checkpointing completed at (").append(SDF.format(new Date())).append(")"); + b.append("Checkpointing completed at (").append(now()).append(")"); break; case EC.TLC_CHECKPOINT_RECOVER_START: b.append("Starting recovery from checkpoint %1%"); @@ -882,12 +931,11 @@ public class MP break; case EC.TLC_PROGRESS_STATS: if (parameters.length == 4) { - b.append("Progress(%1%) at " + SDF.format(new Date()) + ": %2% states generated, " + b.append("Progress(%1%) at " + now() + ": %2% states generated, " + "%3% distinct states found, " + "%4% states left on queue."); } else if (parameters.length == 6) { - b.append("Progress(%1%) at " + SDF.format(new Date()) + ": %2% states generated (" - + df.format(Long.valueOf(parameters[4])) + " s/min), %3% distinct states found (" - + df.format(Long.valueOf(parameters[5])) + " ds/min), %4% states left on queue."); + b.append("Progress(%1%) at " + now() + ": %2% states generated (" + + "%5% s/min), %3% distinct states found (%6% ds/min), %4% states left on queue."); } break; case EC.TLC_PROGRESS_START_STATS_DFID: @@ -897,7 +945,7 @@ public class MP if (TLCGlobals.tool) { // same format as model checking progress reporting for easier parsing by the toolbox - b.append("Progress(" + NOT_APPLICABLE_VAL + ") at " + SDF.format(new Date()) + b.append("Progress(" + NOT_APPLICABLE_VAL + ") at " + now() + ": %1% states generated, %2% distinct states found, " + NOT_APPLICABLE_VAL + " states left on queue."); } else @@ -909,7 +957,7 @@ public class MP if (TLCGlobals.tool) { // same format as model checking progress reporting for easier parsing by the toolbox - b.append("Progress(" + NOT_APPLICABLE_VAL + ") at " + SDF.format(new Date()) + b.append("Progress(" + NOT_APPLICABLE_VAL + ") at " + now() + ": %1% states generated, " + NOT_APPLICABLE_VAL + " distinct states found, " + NOT_APPLICABLE_VAL + " states left on queue."); } else @@ -919,15 +967,34 @@ public class MP break; case EC.TLC_COVERAGE_START: - b.append("The coverage statistics at " + SDF.format(new Date())); + b.append("The coverage statistics at " + now()); break; case EC.TLC_COVERAGE_VALUE: b.append(" %1%: %2%"); break; - + case EC.TLC_COVERAGE_VALUE_COST: + b.append(" %1%: %2%:%3%"); + break; + case EC.TLC_COVERAGE_INIT: + b.append("%1%: %2%:%3%"); + break; + case EC.TLC_COVERAGE_NEXT: + b.append("%1%: %2%:%3%"); + break; + case EC.TLC_COVERAGE_PROPERTY: + b.append("%1%"); + break; + case EC.TLC_COVERAGE_MISMATCH: + b.append( + "CostModel lookup failed for expression <%1%>. Reporting costs into <%2%> instead (Safety and Liveness checking is unaffected. Please report a bug.)"); + break; case EC.TLC_COVERAGE_END: b.append("End of statistics."); break; + case EC.TLC_COVERAGE_END_OVERHEAD: + b.append("End of statistics (please note that for performance reasons large models\n" + + "are best checked with coverage and cost statistics disabled)."); + break; /* ************************************************************************ */ // errors evaluating the config file and the MC file @@ -1004,6 +1071,11 @@ public class MP b.append("The specification contains more than one conjunct of the form [][Next]_v," + "\nbut TLC can handle only specifications with one next-state relation."); break; + case EC.TLC_TRACE_TOO_LONG: + b.append("The specification contains one or more behaviors with 65536 or more states," + + "\nbut TLC can only handle behaviors of length up to 65535 states. The last\n" + + "state in the behavior is:\n%1%"); + break; case EC.TLC_CONFIG_PROPERTY_NOT_CORRECTLY_DEFINED: b.append("The property %1% is not correctly defined."); break; @@ -1029,6 +1101,10 @@ public class MP case EC.TLC_ENCOUNTERED_FORMULA_IN_PREDICATE: b.append("TLC encountered a temporal formula (%1%) when evaluating" + " a predicate or action.\n%2%"); break; + case EC.TLC_ENVIRONMENT_JVM_GC: + b.append( + "Please run the Java VM which executes TLC with a throughput optimized garbage collector by passing the \"-XX:+UseParallelGC\" property."); + break; /* ************************************************************************ */ // state printing @@ -1200,9 +1276,9 @@ public class MP * Prints the error for a given error code * @param errorCode */ - public static void printError(int errorCode) + public static int printError(int errorCode) { - printError(errorCode, EMPTY_PARAMS); + return printError(errorCode, EMPTY_PARAMS); } /** @@ -1210,9 +1286,9 @@ public class MP * @param errorCode * @param parameter */ - public static void printError(int errorCode, String parameter) + public static int printError(int errorCode, String parameter) { - printError(errorCode, new String[] { parameter }); + return printError(errorCode, new String[] { parameter }); } /** @@ -1221,13 +1297,14 @@ public class MP * @param parameters a list of string parameters to be inserted into the message, by replacing * %i% with the i-th parameter in the array */ - public static void printError(int errorCode, String[] parameters) + public static int printError(int errorCode, String[] parameters) { recorder.record(errorCode, (Object[]) parameters); // write the output DebugPrinter.print("entering printError(int, String[]) with errorCode " + errorCode); //$NON-NLS-1$ ToolIO.out.println(getMessage(ERROR, errorCode, parameters)); DebugPrinter.print("leaving printError(int, String[])"); //$NON-NLS-1$ + return errorCode; } /** @@ -1352,13 +1429,14 @@ public class MP * @param errorCode * @param cause */ - public static void printError(int errorCode, Throwable cause) + public static int printError(int errorCode, Throwable cause) { if (errorCode == EC.GENERAL) { printError(errorCode, "", cause); } else { printError(errorCode, cause.getMessage(), cause, true); } + return errorCode; } /** @@ -1386,7 +1464,7 @@ public class MP * @param parameters a list of string parameters to be inserted into the message, by replacing * %i% with the i-th parameter in the array */ - public static void printMessage(int errorCode, String[] parameters) + public static void printMessage(int errorCode, String... parameters) { recorder.record(errorCode, (Object[]) parameters); DebugPrinter.print("entering printMessage(int, String[]) with errorCode " + errorCode); //$NON-NLS-1$ @@ -1395,6 +1473,20 @@ public class MP DebugPrinter.print("leaving printError(int, String[]) with errorCode "); //$NON-NLS-1$ } + public static int printTLCRuntimeException(final TLCRuntimeException tre) { + if (tre.parameters != null) { + recorder.record(tre.errorCode, (Object[]) new Object[] {tre}); + DebugPrinter.print("entering printTLCRuntimeException(TLCRuntimeException) with errorCode " + tre.errorCode); //$NON-NLS-1$ + // write the output + ToolIO.out.println(getMessage(ERROR, tre.errorCode, tre.parameters)); + DebugPrinter.print("leaving printTLCRuntimeException(TLCRuntimeException) with errorCode "); //$NON-NLS-1$ + } else { + // Legacy code path except actual errorCode instead of EC.General. + printError(tre.errorCode, tre); + } + return tre.errorCode; + } + /** * Prints the state * @param parameters @@ -1449,7 +1541,7 @@ public class MP * @param errorCode * @param parameters */ - public static void printWarning(int errorCode, String[] parameters) + public static void printWarning(int errorCode, String... parameters) { recorder.record(errorCode, (Object[]) parameters); DebugPrinter.print("entering printWarning(int, String[]) with errorCode " + errorCode); //$NON-NLS-1$ @@ -1550,4 +1642,18 @@ public class MP public static void setRecorder(MPRecorder aRecorder) { recorder = aRecorder; } + + private static String now() { + if (Boolean.getBoolean(MP.class.getName() + ".noTimestamps")) { + // Return NOW if requested by setting -Dtlc2.output.MP.noTimestamps=true on the + // command-line. Can be useful if one wants to compare TLC's output from + // multiple executions. + return "NOW"; + } + return SDF.format(new Date()); + } + + public static String format(final long l) { + return df.format(l); + } } diff --git a/tlatools/src/tlc2/output/messages.properties b/tlatools/src/tlc2/output/messages.properties index 6e118859bce31c2ce34f9bc422bb4802b3d7d981..648e4c06b0491a31f0c33d698b38e77f4ba4e489 100644 --- a/tlatools/src/tlc2/output/messages.properties +++ b/tlatools/src/tlc2/output/messages.properties @@ -22,7 +22,7 @@ and the optional GENERAL-SWITCHES are:\n\ -fp num: use the num'th irreducible polynomial from the list \n\ \tstored in the class FP64.\n\ -gzip: control if gzip is applied to value input/output stream.\n\ - \tDefaults to use gzip.\n\ + \tDefaults to off if not specified\n\ -metadir path: store metadata in the directory at path\n\ \tDefaults to SPEC-directory/states if not specified\n\ -recover id: recover from the checkpoint with id\n\ diff --git a/tlatools/src/tlc2/tool/AbstractChecker.java b/tlatools/src/tlc2/tool/AbstractChecker.java index 86fdd34dff6eb040b27b101dbfcd61a46ab71699..692192452bd8883cd191719e39414e5cdc69d94e 100644 --- a/tlatools/src/tlc2/tool/AbstractChecker.java +++ b/tlatools/src/tlc2/tool/AbstractChecker.java @@ -1,16 +1,17 @@ package tlc2.tool; -import java.io.File; import java.io.IOException; -import java.util.Hashtable; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Timer; +import java.util.TimerTask; -import tla2sany.modanalyzer.SpecObj; -import tla2sany.semantic.SemanticNode; -import tla2sany.st.Location; +import tlc2.TLC; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import tlc2.output.OutputCollector; +import tlc2.tool.coverage.CostModelCreator; import tlc2.tool.liveness.AddAndCheckLiveCheck; import tlc2.tool.liveness.ILiveCheck; import tlc2.tool.liveness.LiveCheck; @@ -18,19 +19,17 @@ import tlc2.tool.liveness.Liveness; import tlc2.tool.liveness.NoOpLiveCheck; import tlc2.util.IStateWriter; import tlc2.util.IdThread; -import tlc2.util.ObjLongTable; import tlc2.util.statistics.ConcurrentBucketStatistics; import tlc2.util.statistics.DummyBucketStatistics; import tlc2.util.statistics.IBucketStatistics; -import tlc2.value.Value; +import tlc2.value.IValue; import util.DebugPrinter; -import util.FilenameToStream; /** * The abstract checker * @author Simon Zambrovski */ -public abstract class AbstractChecker implements Cancelable +public abstract class AbstractChecker { /** * True when unit tests explicitly request to use @@ -45,30 +44,21 @@ public abstract class AbstractChecker implements Cancelable protected TLCState predErrState; protected TLCState errState; + protected int errorCode; protected boolean done; protected boolean keepCallStack; - protected boolean checkDeadlock; - protected boolean checkLiveness; - protected String fromChkpt; - public String metadir; - public Tool tool; - public final SpecObj specObj; - public Action[] invariants; - public Action[] impliedActions; - public Action[] impliedInits; - public Action[] actions; + protected final boolean checkDeadlock; + protected final boolean checkLiveness; + protected final String fromChkpt; + public final String metadir; + public final ITool tool; protected final IStateWriter allStateWriter; - protected boolean cancellationFlag; protected IWorker[] workers; protected final ILiveCheck liveCheck; - - protected final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() { - protected Integer initialValue() { - return 1; - } - }; - - protected static final int INITIAL_CAPACITY = 16; + /** + * Timestamp of when model checking started. + */ + protected final long startTime; /** * Constructor of the abstract model checker @@ -81,20 +71,14 @@ public abstract class AbstractChecker implements Cancelable * @param resolver * @param spec - pre-built specification object (e.G. from calling SANY from the tool previously) */ - public AbstractChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, - boolean preprocess, FilenameToStream resolver, SpecObj spec) throws EvalException, IOException - { - this.cancellationFlag = false; - - this.checkDeadlock = deadlock; - - final File f = new File(specFile); - this.tool = new Tool(f.isAbsolute() ? f.getParent() : "", specFile, configFile, resolver); - - this.specObj = this.tool.init(preprocess, spec); + public AbstractChecker(ITool tool, String metadir, final IStateWriter stateWriter, + boolean deadlock, String fromChkpt, final long startTime) throws EvalException, IOException { + this.tool = tool; + + this.checkDeadlock = deadlock; this.checkLiveness = !this.tool.livenessIsTrue(); - OutputCollector.setModuleNode(this.tool.rootModule); + OutputCollector.setModuleNode(this.tool.getRootModule()); // moved to file utilities this.metadir = metadir; @@ -102,17 +86,19 @@ public abstract class AbstractChecker implements Cancelable this.errState = null; this.predErrState = null; this.done = false; + this.errorCode = EC.NO_ERROR; this.keepCallStack = false; this.fromChkpt = fromChkpt; this.allStateWriter = stateWriter; + + this.startTime = startTime; - this.impliedInits = this.tool.getImpliedInits(); // implied-inits to be checked - this.invariants = this.tool.getInvariants(); // invariants to be checked - this.impliedActions = this.tool.getImpliedActions(); // implied-actions to be checked - this.actions = this.tool.getActions(); // the sub-actions - + if (TLCGlobals.isCoverageEnabled()) { + CostModelCreator.create(this.tool); + } + if (this.checkLiveness) { if (tool.hasSymmetry()) { // raise warning... @@ -126,14 +112,21 @@ public abstract class AbstractChecker implements Cancelable "DiskGraphsOutDegree"); } if (LIVENESS_TESTING_IMPLEMENTATION) { - this.liveCheck = new AddAndCheckLiveCheck(this.tool, this.actions, this.metadir, stats); + this.liveCheck = new AddAndCheckLiveCheck(this.tool, this.metadir, stats); } else { - this.liveCheck = new LiveCheck(this.tool, this.actions, this.metadir, stats, stateWriter); + this.liveCheck = new LiveCheck(this.tool, this.metadir, stats, stateWriter); } report("liveness checking initialized"); } else { this.liveCheck = new NoOpLiveCheck(this.tool, this.metadir); } + + scheduleTermination(new TimerTask() { + @Override + public void run() { + AbstractChecker.this.stop(); + } + }); } public final void setDone() @@ -145,7 +138,7 @@ public abstract class AbstractChecker implements Cancelable * Set the error state. * <strong>Note:</note> this method must be protected by lock */ - public boolean setErrState(TLCState curState, TLCState succState, boolean keep) + public boolean setErrState(TLCState curState, TLCState succState, boolean keep, int errorCode) { assert Thread.holdsLock(this) : "Caller thread has to hold monitor!"; if (!TLCGlobals.continuation && this.done) @@ -153,6 +146,7 @@ public abstract class AbstractChecker implements Cancelable IdThread.resetCurrentState(); this.predErrState = curState; this.errState = (succState == null) ? curState : succState; + this.errorCode = errorCode; this.done = true; this.keepCallStack = keep; return true; @@ -165,59 +159,43 @@ public abstract class AbstractChecker implements Cancelable protected void reportCoverage(IWorker[] workers) { // Without actions (empty spec) there won't be any statistics anyway. - if (TLCGlobals.coverageInterval >= 0 && this.actions.length > 0) + if (TLCGlobals.isCoverageEnabled() && this.tool.getActions().length > 0) { - MP.printMessage(EC.TLC_COVERAGE_START); - // First collecting all counts from all workers: - ObjLongTable counts = this.tool.getPrimedLocs(); - OutputCollector.setModuleNode(this.tool.rootModule); - Hashtable<String, Location> locationTable = new Hashtable<String, Location>(); - for (int i = 0; i < workers.length; i++) - { - ObjLongTable counts1 = workers[i].getCounts(); - ObjLongTable.Enumerator keys = counts1.keys(); - Object key; - while ((key = keys.nextElement()) != null) - { - String loc = ((SemanticNode) key).getLocation().toString(); - counts.add(loc, counts1.get(key)); - locationTable.put(loc, ((SemanticNode) key).getLocation()); - } - } - // Reporting: - Object[] skeys = counts.sortStringKeys(); - for (int i = 0; i < skeys.length; i++) - { - long val = counts.get(skeys[i]); - //MP.printMessage(EC.TLC_COVERAGE_VALUE, new String[] { skeys[i].toString(), String.valueOf(val) }); - Location location = locationTable.get(skeys[i]); - if(location != null){ - OutputCollector.putLineCount(location, val); - } - } - MP.printMessage(EC.TLC_COVERAGE_END); + CostModelCreator.report(this.tool, this.startTime); } } - public static final void reportSuccess(final long numOfDistinctStates, final double actualProb, final long numOfGenStates) throws IOException - { - // shown as 'calculated' in Toolbox - final double optimisticProb = numOfDistinctStates * ((numOfGenStates - numOfDistinctStates) / Math.pow(2, 64)); - /* The following code added by LL on 3 Aug 2009 to print probabilities - * to only one decimal point. Removed by LL on 17 April 2012 because it - * seemed to report probabilities > 10-4 as probability 0. - */ - // final PrintfFormat fmt = new PrintfFormat("val = %.1G"); - // final String optimisticProbStr = fmt.sprintf(optimisticProb); - // final String actualProbStr = fmt.sprintf(actualProb); - - // Following two lines added by LL on 17 April 2012 - final String optimisticProbStr = "val = " + ProbabilityToString(optimisticProb, 2); - // shown as 'observed' in Toolbox - final String actualProbStr = "val = " + ProbabilityToString(actualProb, 2); - MP.printMessage(EC.TLC_SUCCESS, new String[] { optimisticProbStr, actualProbStr }); + public static final double calculateOptimisticProbability(final long numOfDistinctStates, final long numOfGenStates) { + return numOfDistinctStates * ((numOfGenStates - numOfDistinctStates) / Math.pow(2, 64)); } + public static final void reportSuccess(final long numOfDistinctStates, final long numOfGenStates) + throws IOException { + final double optimisticProb = calculateOptimisticProbability(numOfDistinctStates, numOfGenStates); + MP.printMessage(EC.TLC_SUCCESS, new String[] { "val = " + ProbabilityToString(optimisticProb, 2) }); + } + + public static final void reportSuccess(final long numOfDistinctStates, final long actualDistance, + final long numOfGenStates) throws IOException { + // Prevent div-by-zero when calculating collision probabilities when no states + // are generated. + if (numOfDistinctStates == numOfGenStates && numOfGenStates == 0) { + // When the number of states is zero, printing a collision probability is + // useless anyway. But the Toolbox will probably crash if omitted. + MP.printMessage(EC.TLC_SUCCESS, new String[] { "val = 0.0", "val = 0.0" }); + return; + } + // shown as 'calculated' in Toolbox + final String optimisticProbStr = "val = " + + ProbabilityToString(calculateOptimisticProbability(numOfDistinctStates, numOfGenStates), 2); + + // shown as 'observed' in Toolbox + final BigDecimal actualProb = BigDecimal.valueOf(1d).divide(BigDecimal.valueOf(actualDistance), + new MathContext(2)); + final String actualProbStr = "val = " + ProbabilityToString(actualProb.doubleValue(), 2); + MP.printMessage(EC.TLC_SUCCESS, new String[] { optimisticProbStr, actualProbStr }); + } + /** * This method added by LL on 17 April 2012 to replace the use of the PrintfFormat * method in reportSuccess. @@ -391,10 +369,10 @@ public abstract class AbstractChecker implements Cancelable /** * Initialize the model checker - * @return + * @return an error code, or <code>EC.NO_ERROR</code> on success * @throws Throwable */ - public abstract boolean doInit(boolean ignoreCancel) throws Throwable; + public abstract int doInit(boolean ignoreCancel) throws Throwable; /** * I believe this method is called after the initial states are computed @@ -403,17 +381,11 @@ public abstract class AbstractChecker implements Cancelable * Create the partial state space for given starting state up * to the given depth or the number of states. */ - public final boolean runTLC(int depth) throws Exception + public final int runTLC(int depth) throws Exception { - // SZ Feb 23, 2009: exit if canceled - if (this.cancellationFlag) - { - return false; - } - if (depth < 2) { - return true; + return EC.NO_ERROR; } workers = startWorkers(this, depth); @@ -453,11 +425,13 @@ public abstract class AbstractChecker implements Cancelable // SZ Feb 23, 2009: exit if canceled // added condition to run in the cycle // while (true) { - while (!this.cancellationFlag) + int result = EC.NO_ERROR; + while (true) { - if (!this.doPeriodicWork()) + result = this.doPeriodicWork(); + if (result != EC.NO_ERROR) { - return false; + return result; } synchronized (this) { @@ -484,21 +458,16 @@ public abstract class AbstractChecker implements Cancelable { workers[i].join(); } - return true; - } - - public void setCancelFlag(boolean flag) - { - this.cancellationFlag = flag; + return EC.NO_ERROR; } - public final void setAllValues(int idx, Value val) { + public final void setAllValues(int idx, IValue val) { for (int i = 0; i < this.workers.length; i++) { workers[i].setLocalValue(idx, val); } } - public final Value getValue(int i, int idx) { + public final IValue getValue(int i, int idx) { return workers[i].getLocalValue(idx); } @@ -524,10 +493,10 @@ public abstract class AbstractChecker implements Cancelable * Check liveness: check liveness properties on the partial state graph. * Checkpoint: checkpoint three data structures: the state set, the * state queue, and the state trace. - * @return + * @return an error code, or <code>EC.NO_ERROR</code> on success * @throws Exception */ - public abstract boolean doPeriodicWork() throws Exception; + public abstract int doPeriodicWork() throws Exception; /** * Method called from the main worker loop @@ -539,7 +508,55 @@ public abstract class AbstractChecker implements Cancelable /** * Main method of the model checker + * @return an error code, or <code>EC.NO_ERROR</code> on success * @throws Exception */ - public abstract void modelCheck() throws Exception; + final public int modelCheck() throws Exception { + final int result = modelCheckImpl(); + return (result != EC.NO_ERROR) ? result : errorCode; + } + + protected abstract int modelCheckImpl() throws Exception; + + public int getProgress() { + return -1; + } + + public void stop() { + throw new UnsupportedOperationException("stop not implemented"); + } + + public void suspend() { + throw new UnsupportedOperationException("suspend not implemented"); + } + + public void resume() { + throw new UnsupportedOperationException("resume not implemented"); + } + + static void scheduleTermination(final TimerTask tt) { + // Stops model checker after the given time in seconds. If model checking + // terminates before stopAfter seconds, the timer task will never run. + // Contrary to TLCSet("exit",...) this does not require a spec modification. Is + // is likely of little use for regular TLC users. In other words, this is meant + // to be a developer only feature and thus configured via a system property and + // not a regular TLC parameter. + final long stopAfter = Long.getLong(TLC.class.getName() + ".stopAfter", -1L); + if (stopAfter > 0) { + final Timer stopTimer = new Timer("TLCStopAfterTimer"); + stopTimer.schedule(tt, stopAfter * 1000L); // seconds to milliseconds. + } + } + + protected boolean isTimeBound() { + return Long.getLong(TLC.class.getName() + ".stopAfter", -1L) != -1; + } + + public long getStateQueueSize() { + return -1; + } + + public long getDistinctStatesGenerated() { + return -1; + } } diff --git a/tlatools/src/tlc2/tool/Action.java b/tlatools/src/tlc2/tool/Action.java index f3afd7edee48fcf79207766616a2eba61f940402..0a756b6a49810ccc66f5d130a2d25d21bff1f1db 100644 --- a/tlatools/src/tlc2/tool/Action.java +++ b/tlatools/src/tlc2/tool/Action.java @@ -5,12 +5,17 @@ package tlc2.tool; import java.io.Serializable; +import tla2sany.semantic.OpDefNode; import tla2sany.semantic.SemanticNode; +import tla2sany.st.Location; +import tla2sany.st.SyntaxTreeConstants; +import tla2sany.st.TreeNode; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; import util.UniqueString; public final class Action implements ToolGlobals, Serializable { - public static final UniqueString UNNAMED_ACTION = UniqueString.uniqueStringOf("UnnamedAction"); + private static final UniqueString UNNAMED_ACTION = UniqueString.uniqueStringOf("UnnamedAction"); /* A TLA+ action. */ @@ -18,24 +23,34 @@ public final class Action implements ToolGlobals, Serializable { public final SemanticNode pred; // Expression of the action public final Context con; // Context of the action private final UniqueString actionName; + private OpDefNode opDef = null; + public CostModel cm = CostModel.DO_NOT_RECORD; /* Constructors */ public Action(SemanticNode pred, Context con) { this(pred, con, UNNAMED_ACTION); } - public Action(SemanticNode pred, Context con, UniqueString actionName) { + private Action(SemanticNode pred, Context con, UniqueString actionName) { this.pred = pred; this.con = con; this.actionName = actionName; } + public Action(SemanticNode pred, Context con, OpDefNode opDef) { + // opDef null when action not declared, i.e. Spec == x = 0 /\ ... + // See test64 and test64a and others. + this(pred, con, opDef != null ? opDef.getName() : UNNAMED_ACTION); + this.opDef = opDef; + } + /* Returns a string representation of this action. */ public final String toString() { return "<Action " + pred.toString() + ">"; } public final String getLocation() { + // It is possible that actionName is "Action" but lets ignore it for now. if (actionName != UNNAMED_ACTION && actionName != null && !"".equals(actionName.toString())) { // If known, print the action name instead of the generic string "Action". return "<" + actionName + " " + pred.getLocation() + ">"; @@ -49,4 +64,35 @@ public final class Action implements ToolGlobals, Serializable { public final UniqueString getName() { return actionName; } + + /** + * @return The OpDefNode corresponding to this Action or <code>null</code> if + * the Action is not explicitly declared. I.e. "Spec == x = 42 /\ [][x' + * = x + 1]_x". + */ + public final OpDefNode getOpDef() { + return this.opDef; + } + + public final boolean isDeclared() { + // Spec == x = 0 /\ [][x' = x + 1]_x has no declared actions. + return getDeclaration() != Location.nullLoc; + } + + /** + * @return The {@link Location} of the <code>Action</code>'s declaration or + * <code>Location.nullLoc</code> if {@link #isDeclared()} is + * false. + */ + public Location getDeclaration() { + if (this.opDef != null) { + final TreeNode tn = opDef.getTreeNode(); + if (tn != null && tn.one() != null && tn.one().length >= 1) { + final TreeNode treeNode = tn.one()[0]; + assert treeNode.isKind(SyntaxTreeConstants.N_IdentLHS); + return treeNode.getLocation(); + } + } + return Location.nullLoc; + } } diff --git a/tlatools/src/tlc2/tool/Cancelable.java b/tlatools/src/tlc2/tool/Cancelable.java deleted file mode 100644 index 0cdc618662ca8fcdc782bbd38cffa09cbe433350..0000000000000000000000000000000000000000 --- a/tlatools/src/tlc2/tool/Cancelable.java +++ /dev/null @@ -1,15 +0,0 @@ -package tlc2.tool; - -/** - * The interface for a cancelable. - * @author Simon Zambrovski - * @version $Id$ - */ -public interface Cancelable -{ - /** - * Sets the flag to cancel the instance - * @param flag cancellation flag - */ - public void setCancelFlag(boolean flag); -} diff --git a/tlatools/src/tlc2/tool/CheckImpl.java b/tlatools/src/tlc2/tool/CheckImpl.java index 4c36423eff9e8600bf720eb959f9daff9707dadb..608724c3f7acacb4938efabebc491de30e9e3429 100644 --- a/tlatools/src/tlc2/tool/CheckImpl.java +++ b/tlatools/src/tlc2/tool/CheckImpl.java @@ -6,6 +6,7 @@ package tlc2.tool; import java.io.IOException; import tlc2.TLCGlobals; +import tlc2.output.EC; import tlc2.output.StatePrinter; import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; @@ -31,15 +32,15 @@ public abstract class CheckImpl extends ModelChecker { * @param fpMemSize : This parameter added by Yuan Yu on 6 Apr 2010 * because same parameter was added to the ModelChecker constructor. */ - public CheckImpl(String specFile, String configFile, String metadir, boolean deadlock, + public CheckImpl(ITool tool, String metadir, boolean deadlock, int depth, String fromChkpt, final FPSetConfiguration fpSetConfig) throws IOException { // SZ Feb 20, 2009: patched due to changes to ModelCheker - super(specFile, configFile, metadir, new NoopStateWriter(), deadlock, fromChkpt, null, null, fpSetConfig); // no name resolver and no specobj + super(tool, metadir, new NoopStateWriter(), deadlock, fromChkpt, fpSetConfig, System.currentTimeMillis()); // no name resolver and no specobj this.depth = depth; this.curState = null; this.coverSet = FPSetFactory.getFPSet(); - this.coverSet.init(TLCGlobals.getNumWorkers(), this.metadir, specFile+"_cs"); + this.coverSet.init(TLCGlobals.getNumWorkers(), this.metadir, tool.getRootFile()+"_cs"); this.stateEnum = null; } @@ -69,10 +70,11 @@ public abstract class CheckImpl extends ModelChecker { this.doInit(false); } ToolIO.out.println("Creating a partial state space of depth " + - this.depth + " ... "); - if (!this.runTLC(this.depth)) { + this.depth + " ... "); + final int result = this.runTLC(this.depth); + if (result != EC.NO_ERROR) { ToolIO.out.println("\nExit: failed to create the partial state space."); - System.exit(1); + System.exit(EC.ExitStatus.errorConstantToExitStatus(result)); } ToolIO.out.println("completed."); this.lastTraceTime = System.currentTimeMillis(); @@ -93,8 +95,9 @@ public abstract class CheckImpl extends ModelChecker { int depth1= this.trace.getLevel(st.uid) + depth; this.theStateQueue = new DiskStateQueue(this.metadir); this.theStateQueue.enqueue(st); - if (!this.runTLC(depth1)) { - System.exit(1); + final int result = this.runTLC(depth1); + if (result != EC.NO_ERROR) { + System.exit(EC.ExitStatus.errorConstantToExitStatus(result)); } } @@ -116,9 +119,9 @@ public abstract class CheckImpl extends ModelChecker { StatePrinter.printState(s1); return false; } - int cnt = this.impliedActions.length; + int cnt = this.tool.getImpliedActions().length; for (int i = 0; i < cnt; i++) { - if (!this.tool.isValid(this.impliedActions[i], s0, s1)) { + if (!this.tool.isValid(this.tool.getImpliedActions()[i], s0, s1)) { ToolIO.out.println("Error: Action property " + this.tool.getImpliedActNames()[i] + " is violated."); StatePrinter.printState(s0); @@ -139,12 +142,11 @@ public abstract class CheckImpl extends ModelChecker { boolean seen = this.coverSet.put(fp); if (!seen) { if (!this.theFPSet.contains(fp)) { - long loc = this.trace.writeState(this.curState, fp); - state.uid = loc; + state.uid = this.trace.writeState(this.curState, fp); // Check invariant properties of the state: - int cnt = this.invariants.length; + int cnt = this.tool.getInvariants().length; for (int j = 0; j < cnt; j++) { - if (!this.tool.isValid(this.invariants[j], state)) { + if (!this.tool.isValid(this.tool.getInvariants()[j], state)) { // We get here because of invariant violation: ToolIO.out.println("Error: Invariant " + this.tool.getInvNames()[j] + " is violated. The behavior up to this point is:"); diff --git a/tlatools/src/tlc2/tool/CheckImplFile.java b/tlatools/src/tlc2/tool/CheckImplFile.java index bfc563898676cc3d844e564f8e14ec102e2b8b28..14589f908cc7e51e2d995faabecb1de88c7ac29a 100644 --- a/tlatools/src/tlc2/tool/CheckImplFile.java +++ b/tlatools/src/tlc2/tool/CheckImplFile.java @@ -19,6 +19,7 @@ import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.fp.FPSetConfiguration; +import tlc2.tool.impl.Tool; import tlc2.util.FP64; import util.Assert; import util.FileUtil; @@ -39,10 +40,10 @@ public class CheckImplFile extends CheckImpl * to ModelChecker constructor. * */ - public CheckImplFile(String specFile, String configFile, String metadir, boolean deadlock, int depth, String fromChkpt, + public CheckImplFile(ITool tool, String metadir, boolean deadlock, int depth, String fromChkpt, String traceFile, final FPSetConfiguration fpSetConfig) throws IOException { - super(specFile, configFile, metadir, deadlock, depth, fromChkpt, fpSetConfig); + super(tool, metadir, deadlock, depth, fromChkpt, fpSetConfig); this.traceFile = traceFile; this.states = null; this.sidx = 0; @@ -311,7 +312,8 @@ public class CheckImplFile extends CheckImpl FP64.Init(0); // Start the checker: - CheckImplFile checker = new CheckImplFile(mainFile, configFile, metadir, deadlock, + final ITool tool = new Tool(mainFile, configFile); + CheckImplFile checker = new CheckImplFile(tool, metadir, deadlock, depth, fromChkpt, traceFile, new FPSetConfiguration()); checker.init(); while (true) { diff --git a/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java b/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java new file mode 100644 index 0000000000000000000000000000000000000000..cd2a95a479d2459c8e71bc74798e778625f2cf0e --- /dev/null +++ b/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import java.io.IOException; + +import tlc2.TLCGlobals; +import tlc2.util.LongVec; + +/** + * This implementation of a Trace is concurrent in that multiple workers can add + * states to it whereas with {@link TLCTrace} concurrent adds/appends block and + * are serialized. The latter has been identified to be a scalability bottleneck + * of bread-first search (safety checking). + * <p> + * {@link ConcurrentTLCTrace} - in comparison to {@link TLCTrace} - maintains + * one trace file per worker and thus supports concurrent appends: Each worker + * adds/appends an entry to its (dedicate) file. When a counter-example has to be + * created, the actual error-trace gets created from the union of all (partial) + * trace files. + */ +public class ConcurrentTLCTrace extends TLCTrace { + + private final Worker workers[]; + + public ConcurrentTLCTrace(String metadir, String specFile, TraceApp tool) throws IOException { + super(metadir, specFile, tool); + this.workers = new Worker[TLCGlobals.getNumWorkers()]; + } + + public Worker addWorker(Worker worker) { + this.workers[worker.myGetId()] = worker; + return worker; + } + + /** + * @see ConcurrentTLCTrace#getLevel() + */ + public final int getLevelForReporting() throws IOException { + return getLevel(); + } + + public synchronized final int getLevel() throws IOException { + int maxLevel = 1; // With a single, init state the level/progress/diameter is 1, not 0! + for (Worker worker : workers) { + maxLevel = Math.max(maxLevel, worker.getMaxLevel()); + } + return maxLevel; + } + + private TLCStateInfo[] getTrace(final TLCState state) throws IOException { + final LongVec fps = new LongVec(); + + // Starting at the given start fingerprint (which is the end of the + // trace from the point of the initial states), the sequence of + // predecessors fingerprints are reconstructed from the trace files up to + // an initial state. + synchronized (this) { + Record record = Record.getPredecessor(state, this.workers); + while (!record.isInitial()) { + fps.addElement(record.fp); + record = record.getPredecessor(); + } + // The fp of the final initial state. + fps.addElement(record.fp); + assert 0 <= fps.size() && fps.size() <= getLevel(); + } + + return getTrace(fps); + } + + /** + * Write out a sequence of states that reaches s2 from an initial state, + * according to the spec. s2 is a next state of s1. + * + * @param s1 + * may not be null. + * @param s2 + * may be null. + * @throws IOException + * @throws WorkerException + */ + public void printTrace(final TLCState s1, final TLCState s2) throws IOException, WorkerException { + if (s1.isInitial()) { + printTrace(s1, s2, new TLCStateInfo[0]); + } else { + printTrace(s1, s2, getTrace(s1)); + } + } + + /* Checkpoint. */ + + public synchronized void beginChkpt() throws IOException { + for (Worker worker : workers) { + worker.beginChkpt(); + } + } + + public void commitChkpt() throws IOException { + for (Worker worker : workers) { + worker.commitChkpt(); + } + } + + public void recover() throws IOException { + // TODO Check that the number of disk .st files is >= workers.length. If it is + // lower, TLC runs with fewer workers than when the checkpoint was taken. Take + // this case into account. + + for (Worker worker : workers) { + worker.recover(); + } + } + + /* Enumerator */ + + public synchronized Enumerator elements() throws IOException { + final Worker.Enumerator[] enums = new Worker.Enumerator[workers.length]; + for (int j = 0; j < workers.length; j++) { + enums[j] = workers[j].elements(); + } + return new Enumerator() { + private int idx = 0; + + @Override + public long nextPos() { + if (idx >= workers.length) { + return -1L; + } + if (enums[idx].hasMoreFP()) { + return 42L; + } else if (idx + 1 >= workers.length) { + return -1L; + } else { + idx = idx + 1; + return enums[idx].hasMoreFP() ? 42L : -1L; + } + } + + @Override + public long nextFP() throws IOException { + if (!enums[idx].hasMoreFP()) { + idx = idx + 1; + } + return enums[idx].nextFP(); + } + + @Override + public void close() throws IOException { + for (Worker.Enumerator enumerator : enums) { + enumerator.close(); + } + } + + @Override + public void reset(long i) throws IOException { + idx = 0; + } + }; + } + + public static class Record { + + + static Record getPredecessor(final TLCState state, final Worker[] workers) throws IOException { + Record record = workers[state.workerId].readStateRecord(state.uid); + record.workers = workers; + return record.getPredecessor(); + } + + private final long ptr; + private final int worker; + private final long fp; + private Worker[] workers; + + public Record(final long ptr, final int worker, final long fp) { + this.ptr = ptr; + this.worker = worker; + this.fp = fp; + } + + public Worker getWorker() { + return this.workers[this.worker]; + } + + public boolean isInitial() { + return ptr == 1L; + } + + @Override + public String toString() { + return "Record [ptr=" + ptr + ", worker=" + worker + ", fp=" + fp + ", initial=" + isInitial() + "]"; + } + + Record getPredecessor() throws IOException { + final Record record = getWorker().readStateRecord(this.ptr); + record.workers = this.workers; + return record; + } + } +} diff --git a/tlatools/src/tlc2/tool/DFIDModelChecker.java b/tlatools/src/tlc2/tool/DFIDModelChecker.java index f79042e7a9650e0b08416b8434a89d18a3cd0279..8b0f2d1e7eec8fb16a694ff22d39b708df6b1871 100644 --- a/tlatools/src/tlc2/tool/DFIDModelChecker.java +++ b/tlatools/src/tlc2/tool/DFIDModelChecker.java @@ -7,7 +7,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ExprNode; import tla2sany.semantic.OpDeclNode; import tlc2.TLCGlobals; @@ -19,10 +18,8 @@ import tlc2.tool.liveness.LiveException; import tlc2.util.IStateWriter; import tlc2.util.IdThread; import tlc2.util.LongVec; -import tlc2.util.ObjLongTable; import tlc2.util.SetOfStates; import util.FileUtil; -import util.FilenameToStream; import util.UniqueString; /** @@ -42,20 +39,28 @@ public class DFIDModelChecker extends AbstractChecker public FPIntSet theFPSet; // the set of reachable states (SZ: note the type) private final AtomicLong numOfGenStates; + protected final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() { + protected Integer initialValue() { + return 1; + } + }; + + protected static final int INITIAL_CAPACITY = 16; + /** * Constructor for running DFID + * @param startTime * @param resolver */ - public DFIDModelChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, - boolean preprocess, FilenameToStream resolver, SpecObj specObj) throws EvalException, IOException - { + public DFIDModelChecker(ITool tool, String metadir, final IStateWriter stateWriter, + boolean deadlock, String fromChkpt, long startTime) throws EvalException, IOException { // call the abstract constructor - super(specFile, configFile, metadir, stateWriter, deadlock, fromChkpt, preprocess, resolver, specObj); + super(tool, metadir, stateWriter, deadlock, fromChkpt, startTime); this.theInitStates = null; this.theInitFPs = null; this.theFPSet = new MemFPIntSet(); // init the state set - this.theFPSet.init(TLCGlobals.getNumWorkers(), this.metadir, specFile); + this.theFPSet.init(TLCGlobals.getNumWorkers(), this.metadir, this.tool.getRootFile()); // Initialize all the workers: this.workers = new DFIDWorker[TLCGlobals.getNumWorkers()]; @@ -66,15 +71,22 @@ public class DFIDModelChecker extends AbstractChecker * This method does model checking on a TLA+ spec. All the visited * states are stored in the variable theFPSet. */ - public void modelCheck() throws Exception + @Override + protected int modelCheckImpl() throws Exception { + int result = EC.NO_ERROR; boolean recovered = this.recover(); try { - if (!this.checkAssumptions()) - return; - if (!this.doInit(false)) - return; + if (this.checkLiveness && liveCheck.getNumChecker() == 0) { + return MP.printError(EC.TLC_LIVE_FORMULA_TAUTOLOGY); + } + result = this.checkAssumptions(); + if (result != EC.NO_ERROR) + return result; + result = this.doInit(false); + if (result != EC.NO_ERROR) + return result; } catch (Throwable e) { // Initial state computation fails with an exception: @@ -94,11 +106,11 @@ public class DFIDModelChecker extends AbstractChecker this.doInit(true); } catch (Throwable e1) { - MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); + result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); } this.printSummary(false); this.cleanup(false); - return; + return result; } if (recovered) @@ -112,15 +124,15 @@ public class DFIDModelChecker extends AbstractChecker } // Return if there is no next state predicate: - if (this.actions.length == 0) + if (this.tool.getActions().length == 0) { this.reportSuccess(); this.printSummary(true); this.cleanup(true); - return; + return result; } - boolean success = false; + result = EC.GENERAL; try { boolean terminated = false; @@ -142,13 +154,13 @@ public class DFIDModelChecker extends AbstractChecker String.valueOf(this.numOfGenStates), String.valueOf(theFPSet.size()) }); // SZ Jul 10, 2009: what for? // ToolIO.out.flush(); - success = liveCheck.finalCheck(); - if (!success) - return; + result = liveCheck.finalCheck(tool); + if (result != EC.NO_ERROR) + return result; } // We get here because the checking has been completed. - success = true; + result = EC.NO_ERROR; this.reportSuccess(); } else if (this.keepCallStack) { @@ -156,7 +168,7 @@ public class DFIDModelChecker extends AbstractChecker this.tool.setCallStack(); try { - this.doNext(this.predErrState, this.predErrState.fingerPrint(), true, new ObjLongTable(10), + this.doNext(this.predErrState, this.predErrState.fingerPrint(), true, new StateVec(1), new LongVec()); } catch (Throwable e) { @@ -171,12 +183,12 @@ public class DFIDModelChecker extends AbstractChecker String.valueOf(this.numOfGenStates), String.valueOf(this.theFPSet.size()) }); FPIntSet.incLevel(); - success = this.runTLC(level); + result = this.runTLC(level); // Recent done flag before after the workers have checked the // current level in preparation for the next level. this.done = false; - if (!success) - return; + if (result != EC.NO_ERROR) + return result; // Check if we should stop at this level: for (int i = 0; i < this.workers.length; i++) @@ -198,16 +210,21 @@ public class DFIDModelChecker extends AbstractChecker } terminated = terminated || !moreLevel; } + return result; } catch (Exception e) { // Assert.printStack(e); - success = false; - if (!(e instanceof LiveException)) + if (e instanceof LiveException) + { + result = ((LiveException)e).errorCode; + } else { - MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 + result = MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 } + return result; } finally { + final boolean success = result == EC.NO_ERROR; this.printSummary(success); this.cleanup(success); } @@ -215,7 +232,7 @@ public class DFIDModelChecker extends AbstractChecker /* Check the assumptions. * This code is a clone of the same method in ModelChecker */ - public final boolean checkAssumptions() + public final int checkAssumptions() { ExprNode[] assumps = this.tool.getAssumptions(); boolean[] isAxiom = this.tool.getAssumptionIsAxiom(); @@ -225,23 +242,21 @@ public class DFIDModelChecker extends AbstractChecker { if ((!isAxiom[i]) && !this.tool.isValid(assumps[i])) { - MP.printError(EC.TLC_ASSUMPTION_FALSE, assumps[i].toString()); - return false; + return MP.printError(EC.TLC_ASSUMPTION_FALSE, assumps[i].toString()); } } catch (Exception e) { // Assert.printStack(e); - MP.printError(EC.TLC_ASSUMPTION_EVALUATION_ERROR, + return MP.printError(EC.TLC_ASSUMPTION_EVALUATION_ERROR, new String[] { assumps[i].toString(), e.getMessage() }); - return false; } } - return true; + return EC.NO_ERROR; } /* Compute the set of initial states. */ // SZ Feb 23, 2009: added ignore cancel flag - public final boolean doInit(boolean ignoreCancel) throws Throwable + public final int doInit(boolean ignoreCancel) throws Throwable { TLCState curState = null; try @@ -260,8 +275,7 @@ public class DFIDModelChecker extends AbstractChecker // Check if the state is a legal state if (!this.tool.isGoodState(curState)) { - MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL, curState.toString()); - return false; + return MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL, curState.toString()); } boolean inModel = this.tool.isInModel(curState); int status = FPIntSet.NEW; @@ -280,32 +294,31 @@ public class DFIDModelChecker extends AbstractChecker // build behavior graph for liveness checking if (this.checkLiveness) { - liveCheck.addInitState(curState, fp); + liveCheck.addInitState(tool, curState, fp); } } } // Check properties of the state: if (status == FPIntSet.NEW) { - for (int j = 0; j < this.invariants.length; j++) + for (int j = 0; j < this.tool.getInvariants().length; j++) { - if (!this.tool.isValid(this.invariants[j], curState)) + if (!this.tool.isValid(this.tool.getInvariants()[j], curState)) { // We get here because of invariant violation: MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { this.tool.getInvNames()[j], curState.toString() }); if (!TLCGlobals.continuation) - return false; + return EC.TLC_INVARIANT_VIOLATED_INITIAL; } } - for (int j = 0; j < this.impliedInits.length; j++) + for (int j = 0; j < this.tool.getImpliedInits().length; j++) { - if (!this.tool.isValid(this.impliedInits[j], curState)) + if (!this.tool.isValid(this.tool.getImpliedInits()[j], curState)) { // We get here because of implied-inits violation: - MP.printError(EC.TLC_PROPERTY_VIOLATED_INITIAL, new String[] { + return MP.printError(EC.TLC_PROPERTY_VIOLATED_INITIAL, new String[] { this.tool.getImpliedInitNames()[j], curState.toString() }); - return false; } } } @@ -326,13 +339,12 @@ public class DFIDModelChecker extends AbstractChecker // Assert.printStack(e); if (e instanceof OutOfMemoryError) { - MP.printError(EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT); - return false; + return MP.printError(EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT); } this.errState = curState; throw e; } - return true; + return EC.NO_ERROR; } /** @@ -342,7 +354,7 @@ public class DFIDModelChecker extends AbstractChecker * not been done in nextStates. Return true if it finds a leaf * successor of curState. */ - public final boolean doNext(TLCState curState, long cfp, boolean isLeaf, ObjLongTable counts, StateVec states, + public final boolean doNext(TLCState curState, long cfp, boolean isLeaf, StateVec states, LongVec fps) throws Throwable { boolean deadLocked = true; @@ -359,9 +371,9 @@ public class DFIDModelChecker extends AbstractChecker int k = 0; boolean allSuccDone = true; boolean allSuccNonLeaf = true; - for (int i = 0; i < this.actions.length; i++) + for (int i = 0; i < this.tool.getActions().length; i++) { - StateVec nextStates = this.tool.getNextStates(this.actions[i], curState); + StateVec nextStates = this.tool.getNextStates(this.tool.getActions()[i], curState); int sz = nextStates.size(); this.numOfGenStates.getAndAdd(sz); deadLocked = deadLocked && (sz == 0); @@ -373,31 +385,26 @@ public class DFIDModelChecker extends AbstractChecker if (!this.tool.isGoodState(succState)) { synchronized (this) { - if (this.setErrState(curState, succState, false)) { + final int errorCode = EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT; + if (this.setErrState(curState, succState, false, errorCode)) { final Set<OpDeclNode> unassigned = succState.getUnassigned(); String[] parameters; - if (this.actions.length == 1) { + if (this.tool.getActions().length == 1) { parameters = new String[] { unassigned.size() > 1 ? "s are" : " is", unassigned.stream().map(n -> n.getName().toString()) .collect(Collectors.joining(", ")) }; } else { - parameters = new String[] { this.actions[i].getName().toString(), + parameters = new String[] { this.tool.getActions()[i].getName().toString(), unassigned.size() > 1 ? "s are" : " is", unassigned.stream().map(n -> n.getName().toString()) .collect(Collectors.joining(", ")) }; } - this.printTrace(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, - parameters, curState, succState); + this.printTrace(errorCode, parameters, curState, succState); } } return allSuccNonLeaf; } - if (TLCGlobals.coverageInterval >= 0) - { - ((TLCStateMutSource) succState).addCounts(counts); - } - boolean inModel = (this.tool.isInModel(succState) && this.tool.isInActions(curState, succState)); int status = FPIntSet.NEW; if (inModel) @@ -429,10 +436,10 @@ public class DFIDModelChecker extends AbstractChecker { try { - int len = this.invariants.length; + int len = this.tool.getInvariants().length; for (k = 0; k < len; k++) { - if (!tool.isValid(this.invariants[k], succState)) + if (!tool.isValid(this.tool.getInvariants()[k], succState)) { // We get here because of invariant violation: synchronized (this) @@ -444,7 +451,7 @@ public class DFIDModelChecker extends AbstractChecker break; } else { - if (this.setErrState(curState, succState, false)) + if (this.setErrState(curState, succState, false, EC.TLC_INVARIANT_VIOLATED_BEHAVIOR)) { this.printTrace(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, new String[] { this.tool.getInvNames()[k] }, curState, @@ -461,7 +468,7 @@ public class DFIDModelChecker extends AbstractChecker } catch (Exception e) { synchronized (this) { - if (this.setErrState(curState, succState, true)) + if (this.setErrState(curState, succState, true, EC.TLC_INVARIANT_EVALUATION_FAILED)) { this.printTrace(EC.TLC_INVARIANT_EVALUATION_FAILED, new String[] { this.tool .getInvNames()[k] }, curState, succState); @@ -475,10 +482,10 @@ public class DFIDModelChecker extends AbstractChecker // even if succState is not new. try { - int len = this.impliedActions.length; + int len = this.tool.getImpliedActions().length; for (k = 0; k < len; k++) { - if (!tool.isValid(this.impliedActions[k], curState, succState)) + if (!tool.isValid(this.tool.getImpliedActions()[k], curState, succState)) { // We get here because of implied-action violation: synchronized (this) @@ -492,9 +499,8 @@ public class DFIDModelChecker extends AbstractChecker break; } else { - if (this.setErrState(curState, succState, false)) + if (this.setErrState(curState, succState, false, EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR)) { - this.printTrace(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, new String[] { this.tool.getImpliedActNames()[k] }, curState, succState); @@ -510,7 +516,7 @@ public class DFIDModelChecker extends AbstractChecker } catch (Exception e) { synchronized (this) { - if (this.setErrState(curState, succState, true)) + if (this.setErrState(curState, succState, true, EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED)) { this.printTrace(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, new String[] { this.tool .getImpliedActNames()[k] }, curState, succState); @@ -530,7 +536,7 @@ public class DFIDModelChecker extends AbstractChecker { synchronized (this) { - if (this.setErrState(curState, null, false)) + if (this.setErrState(curState, null, false, EC.TLC_DEADLOCK_REACHED)) { this.printTrace(EC.TLC_DEADLOCK_REACHED, null, curState, null); this.notify(); @@ -547,7 +553,7 @@ public class DFIDModelChecker extends AbstractChecker liveNextStates.put(curStateFP, curState); this.allStateWriter.writeState(curState, curState, true, IStateWriter.Visualization.STUTTERING); // Add curState to the behavior graph: - liveCheck.addNextState(curState, curStateFP, liveNextStates); + liveCheck.addNextState(tool, curState, curStateFP, liveNextStates); // Poor man's version of a controller. If necessary, try e.g. // PID controller instead. @@ -573,19 +579,23 @@ public class DFIDModelChecker extends AbstractChecker boolean keep = ((e instanceof StackOverflowError) || (e instanceof OutOfMemoryError)); synchronized (this) { - if (this.setErrState(curState, succState, !keep)) + final int errorCode; + if (e instanceof StackOverflowError) + { + errorCode = EC.SYSTEM_STACK_OVERFLOW; + } else if (e instanceof OutOfMemoryError) + { + errorCode = EC.SYSTEM_OUT_OF_MEMORY; + } else + { + errorCode = EC.GENERAL; + } + + if (this.setErrState(curState, succState, !keep, errorCode)) { String[] parameters = null; - int errorCode; - if (e instanceof StackOverflowError) - { - errorCode = EC.SYSTEM_STACK_OVERFLOW; - } else if (e instanceof OutOfMemoryError) - { - errorCode = EC.SYSTEM_OUT_OF_MEMORY; - } else + if (errorCode == EC.GENERAL) { - errorCode = EC.GENERAL; // LL changed error message on 7 April 2012 parameters = new String[] { MP.ECGeneralMsg("computing the set of next states", e) }; @@ -607,9 +617,9 @@ public class DFIDModelChecker extends AbstractChecker * Set the error state. * <strong>Note:</note> this method must be protected by lock */ - public boolean setErrState(TLCState curState, TLCState succState, boolean keep) + public boolean setErrState(TLCState curState, TLCState succState, boolean keep, int errorCode) { - boolean result = super.setErrState(curState, succState, keep); + boolean result = super.setErrState(curState, succState, keep, errorCode); if (!result) { return false; @@ -638,16 +648,18 @@ public class DFIDModelChecker extends AbstractChecker * Checkpoint: checkpoint three data structures: the state set, the * state queue, and the state trace. */ - public final boolean doPeriodicWork() throws Exception + @Override + public final int doPeriodicWork() throws Exception { synchronized (this.theFPSet) { // Run liveness checking, if needed: if (this.checkLiveness) { - if (!liveCheck.check(false)) + final int result = liveCheck.check(tool, false); + if (result != EC.NO_ERROR) { - return false; + return result; } } @@ -672,7 +684,7 @@ public class DFIDModelChecker extends AbstractChecker MP.printMessage(EC.TLC_CHECKPOINT_END); } } - return true; + return EC.NO_ERROR; } public final boolean recover() throws IOException diff --git a/tlatools/src/tlc2/tool/DFIDWorker.java b/tlatools/src/tlc2/tool/DFIDWorker.java index bf2b06412942d1438fe32bdb4e33e6b5c17198cf..5b7c1be71c2456ca20759703284d5713b6e8bb7c 100644 --- a/tlatools/src/tlc2/tool/DFIDWorker.java +++ b/tlatools/src/tlc2/tool/DFIDWorker.java @@ -9,7 +9,6 @@ import tlc2.output.StatePrinter; import tlc2.tool.fp.dfid.FPIntSet; import tlc2.util.IdThread; import tlc2.util.LongVec; -import tlc2.util.ObjLongTable; import tlc2.util.RandomGenerator; public class DFIDWorker extends IdThread implements IWorker { @@ -29,7 +28,6 @@ public class DFIDWorker extends IdThread implements IWorker { private TLCState[] theInitStates; private long[] theInitFPs; private int initLen; - private ObjLongTable astCounts; private int toLevel; private int curLevel; private int stopCode; @@ -55,15 +53,12 @@ public class DFIDWorker extends IdThread implements IWorker { this.theInitFPs = new long[this.initLen]; System.arraycopy(this.tlc.theInitStates, 0, this.theInitStates, 0, this.initLen); System.arraycopy(this.tlc.theInitFPs, 0, this.theInitFPs, 0, this.initLen); - this.astCounts = new ObjLongTable(10); this.toLevel = toLevel; this.curLevel = 0; this.stopCode = 0; this.moreLevel = false; } - public final ObjLongTable getCounts() { return this.astCounts; } - public final void setStop(int code) { this.stopCode = code; } public final boolean isTerminated() { return this.stopCode == 2; } @@ -170,7 +165,6 @@ public class DFIDWorker extends IdThread implements IWorker { this.succFPStack[0].reset(); boolean isLeaf = this.toLevel < 2; boolean noLeaf = this.tlc.doNext(curState, cfp, isLeaf, - this.astCounts, this.succStateStack[0], this.succFPStack[0]); this.moreLevel = this.moreLevel || !noLeaf; @@ -196,7 +190,6 @@ public class DFIDWorker extends IdThread implements IWorker { this.succFPStack[this.curLevel].reset(); isLeaf = (this.curLevel >= this.toLevel-1); noLeaf = this.tlc.doNext(curState, cfp, isLeaf, - this.astCounts, this.succStateStack[this.curLevel], this.succFPStack[this.curLevel]); this.moreLevel = this.moreLevel || !noLeaf; @@ -210,7 +203,7 @@ public class DFIDWorker extends IdThread implements IWorker { // Assert.printStack(e); this.tlc.setStop(2); synchronized(this.tlc) { - if (this.tlc.setErrState(curState, null, true)) { + if (this.tlc.setErrState(curState, null, true, EC.GENERAL)) { MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 } this.tlc.setDone(); diff --git a/tlatools/src/tlc2/tool/Defns.java b/tlatools/src/tlc2/tool/Defns.java index 848f688ac0dfe520500b1d7f0d3e7964c2d79e2b..39e463ed8d02839241014151004f2beff1a360d5 100644 --- a/tlatools/src/tlc2/tool/Defns.java +++ b/tlatools/src/tlc2/tool/Defns.java @@ -47,6 +47,12 @@ public class Defns implements ToolGlobals, Serializable this.table = new Object[defnIdx + 32]; } + Defns(Defns other) { + this.defnIdx = other.defnIdx; + this.table = new Object[other.table.length]; + System.arraycopy(other.table, 0, this.table, 0, other.table.length); + } + /** * Returns the definition of key if its definition exists. * Otherwise, returns null. @@ -111,4 +117,8 @@ public class Defns implements ToolGlobals, Serializable { this.defnIdx = index; } + + public Defns snapshot() { + return new Defns(this); + } } diff --git a/tlatools/src/tlc2/tool/EvalControl.java b/tlatools/src/tlc2/tool/EvalControl.java index 0626219697c97133187adaf154de66c288ba6f0f..c7062adcb7ed03fb078ad16fe649db416aef12ef 100644 --- a/tlatools/src/tlc2/tool/EvalControl.java +++ b/tlatools/src/tlc2/tool/EvalControl.java @@ -21,8 +21,8 @@ public class EvalControl { */ public static final int Enabled = 1 << 2; /** - * Evaluation in the scope of {@link Tool#getInitStates()} or - * {@link Tool#getInitStates(IStateFunctor)}. In other words set during the + * Evaluation in the scope of {@link ITool#getInitStates()} or + * {@link ITool#getInitStates(IStateFunctor)}. In other words set during the * generation of initial states. */ public static final int Init = 1 << 3; diff --git a/tlatools/src/tlc2/tool/FingerprintException.java b/tlatools/src/tlc2/tool/FingerprintException.java index 7bf07e43612f685c6018fdc6c9c4d0d4f5b1910c..8d468ebbcff6e3d85e20e149d62759485efcddda 100644 --- a/tlatools/src/tlc2/tool/FingerprintException.java +++ b/tlatools/src/tlc2/tool/FingerprintException.java @@ -26,21 +26,21 @@ package tlc2.tool; -import tlc2.value.Value; import tla2sany.semantic.SemanticNode; +import tlc2.value.IValue; public class FingerprintException extends RuntimeException { - final public Value value; + final public IValue value; final public FingerprintException next; - private FingerprintException(Throwable initCauseThrowable, Value value, FingerprintException next) { + private FingerprintException(Throwable initCauseThrowable, IValue value, FingerprintException next) { initCause(initCauseThrowable); this.value = value; this.next = next; } - public static FingerprintException getNewHead(Value v, Throwable t){ + public static FingerprintException getNewHead(IValue v, Throwable t){ FingerprintException fpe = null; if(t instanceof FingerprintException) fpe = ((FingerprintException) t).prependNewHead(v); @@ -49,14 +49,14 @@ public class FingerprintException extends RuntimeException { return fpe; } - private static FingerprintException createNewHead(Value value, Throwable initCauseThrowable){ + private static FingerprintException createNewHead(IValue value, Throwable initCauseThrowable){ if(value == null || initCauseThrowable == null) return null; else return new FingerprintException(initCauseThrowable, value, null); } - private FingerprintException prependNewHead(Value value){ + private FingerprintException prependNewHead(IValue value){ if(value == null) return null; else diff --git a/tlatools/src/tlc2/tool/IActionItemList.java b/tlatools/src/tlc2/tool/IActionItemList.java new file mode 100644 index 0000000000000000000000000000000000000000..e02279024302ef6fce51329234b3db350e5421ee --- /dev/null +++ b/tlatools/src/tlc2/tool/IActionItemList.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import tla2sany.semantic.SemanticNode; +import tlc2.tool.coverage.CostModel; +import tlc2.util.Context; + +public interface IActionItemList { + + /** + * predicate of a conjunction + */ + int CONJUNCT = 0; + /** + * predicate + */ + int PRED = -1; + /** + * UNCHANGED predicate + */ + int UNCHANGED = -2; + /** + * pred' # pred + */ + int CHANGED = -3; + + IActionItemList cons(SemanticNode exprOrOpArgNode, Context c, CostModel cm, int ailconst); +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/IContextEnumerator.java b/tlatools/src/tlc2/tool/IContextEnumerator.java new file mode 100644 index 0000000000000000000000000000000000000000..258abbea9d3afff40a929a35a0e0467f8e5e2223 --- /dev/null +++ b/tlatools/src/tlc2/tool/IContextEnumerator.java @@ -0,0 +1,9 @@ +package tlc2.tool; + +import tlc2.util.Context; + +public interface IContextEnumerator { + + Context nextElement(); + +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/ITool.java b/tlatools/src/tlc2/tool/ITool.java new file mode 100644 index 0000000000000000000000000000000000000000..8c09e43110c7da49051b1374d04d6f11cc742ea8 --- /dev/null +++ b/tlatools/src/tlc2/tool/ITool.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import java.io.File; +import java.util.List; + +import tla2sany.semantic.ExprNode; +import tla2sany.semantic.ExprOrOpArgNode; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.SymbolNode; +import tlc2.tool.coverage.CostModel; +import tlc2.util.Context; +import tlc2.util.ObjLongTable; +import tlc2.util.Vect; +import tlc2.value.IFcnLambdaValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import util.FilenameToStream; + +public interface ITool extends TraceApp { + + void setCallStack(); + + CallStack getCallStack(); + + /** + * This method returns the set of all possible actions of the + * spec, and sets the actions field of this object. In fact, we + * could simply treat the next predicate as one "giant" action. + * But for efficiency, we preprocess the next state predicate by + * splitting it into a set of actions for the maximum prefix + * of disjunction and existential quantification. + */ + Action[] getActions(); + + /* + * This method returns the set of possible initial states that + * satisfies the initial state predicate. Initial state predicate + * can be under-specified. Too many possible initial states will + * probably make tools like TLC useless. + */ + StateVec getInitStates(); + + void getInitStates(IStateFunctor functor); + + /* Create the state specified by pred. */ + TLCState makeState(SemanticNode pred); + + /** + * This method returns the set of next states when taking the action + * in the given state. + */ + StateVec getNextStates(Action action, TLCState state); + + IValue eval(SemanticNode expr, Context c, TLCState s0); + + IValue eval(SemanticNode expr, Context c, TLCState s0, TLCState s1, int control); + + IValue eval(SemanticNode expr, Context c, TLCState s0, TLCState s1, int control, CostModel cm); + + /** + * This method determines if the argument is a valid state. A state + * is good iff it assigns legal explicit values to all the global + * state variables. + */ + boolean isGoodState(TLCState state); + + /* This method determines if a state satisfies the model constraints. */ + boolean isInModel(TLCState state) throws EvalException; + + /* This method determines if a pair of states satisfy the action constraints. */ + boolean isInActions(TLCState s1, TLCState s2) throws EvalException; + + /** + * This method determines if an action is enabled in the given state. + * More precisely, it determines if (act.pred /\ (sub' # sub)) is + * enabled in the state s and context act.con. + */ + TLCState enabled(SemanticNode pred, Context c, TLCState s0, TLCState s1, ExprNode subscript, final int ail); + TLCState enabled(SemanticNode pred, Context c, TLCState s0, TLCState s1); + TLCState enabled(SemanticNode pred, IActionItemList acts, Context c, TLCState s0, TLCState s1); + TLCState enabled(SemanticNode pred, IActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm); + + /* This method determines if the action predicate is valid in (s0, s1). */ + boolean isValid(Action act, TLCState s0, TLCState s1); + + /* Returns true iff the predicate is valid in the state. */ + boolean isValid(Action act, TLCState state); + + /* Returns true iff the predicate is valid in the state. */ + boolean isValid(Action act); + + boolean isValid(ExprNode expr); + + /* Reconstruct the initial state whose fingerprint is fp. */ + TLCStateInfo getState(long fp); + + /** + * Reconstruct the next state of state s whose fingerprint is fp. + * + * @return Returns the TLCState wrapped in TLCStateInfo. TLCStateInfo stores + * the stateNumber (relative to the given sinfo) and a pointer to + * the predecessor. + */ + TLCStateInfo getState(long fp, TLCStateInfo sinfo); + + /* Reconstruct the next state of state s whose fingerprint is fp. */ + TLCStateInfo getState(long fp, TLCState s); + + /* Reconstruct the info for s1. */ + TLCStateInfo getState(TLCState s1, TLCState s); + + /* Return the set of all permutations under the symmetry assumption. */ + IMVPerm[] getSymmetryPerms(); + + boolean hasSymmetry(); + + Context getFcnContext(IFcnLambdaValue fcn, ExprOrOpArgNode[] args, Context c, TLCState s0, TLCState s1, int control); + + Context getFcnContext(IFcnLambdaValue fcn, ExprOrOpArgNode[] args, Context c, TLCState s0, TLCState s1, int control, + CostModel cm); + + IContextEnumerator contexts(OpApplNode appl, Context c, TLCState s0, TLCState s1, int control); + + Vect<Action> getInitStateSpec(); + + Action[] getInvariants(); + + ObjLongTable<SemanticNode> getPrimedLocs(); + + Context getOpContext(OpDefNode odn, ExprOrOpArgNode[] args, Context ctx, boolean b); + + ExprNode[] getAssumptions(); + + boolean[] getAssumptionIsAxiom(); + + String[] getInvNames(); + + String[] getImpliedActNames(); + + String getRootFile(); + + ModuleNode getRootModule(); + + String getConfigFile(); + + String getSpecDir(); + + String[] getImpliedInitNames(); + + /** + * Initial predicate of the liveness property Prop (see impliedActions above). + * Most common used when checking if a Spec implements another one, i.e. ASpec + * => BSpec. + * <p> + * See the following tests:<br> + * tlc2.tool.suite.Test55 + * <ul> + * <li>Action line 7, col 1 to line 7, col 41 of module test55</li> + * <li>Action line 7, col 1 to line 7, col 41 of module test55</li> + * </ul> + * tlc2.tool.suite.Test63 + * <ul> + * <li>Action line 52, col 1 to line 52, col 21 of module test63</li> + * </ul> + */ + Action[] getImpliedInits(); + + /** + * Checking a liveness property Prop (declared by the PROPERTY keyword in the + * config file) means to verify Spec => Prop. An implied action is the [][A]_x + * (A \/ x' = x) part of Prop where A is an action and x is a variable. + * + * See the following tests:<br> + * tlc2.tool.suite.Test52 + * <ul> + * <li></li> + * <li></li> + * </ul> + * tlc2.tool.suite.Test56 + * <ul> + * <li></li> + * </ul> + */ + Action[] getImpliedActions(); + + boolean livenessIsTrue(); + + Action[] getImpliedTemporals(); + + Action[] getTemporals(); + + Object lookup(SymbolNode opNode, Context con, boolean b); + + Object lookup(SymbolNode operator); + + Object getVal(ExprOrOpArgNode expr, Context con, boolean b); + + Action getNextStateSpec(); + + SemanticNode getViewSpec(); + + int getId(); + + List<File> getModuleFiles(FilenameToStream resolver); + +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/IWorker.java b/tlatools/src/tlc2/tool/IWorker.java index 6e2ddc1f328733126b0fbe1fbbcc8185bf290403..58bfc7cdbb6f3ac0f84e39dde91c82109183cafd 100644 --- a/tlatools/src/tlc2/tool/IWorker.java +++ b/tlatools/src/tlc2/tool/IWorker.java @@ -1,8 +1,7 @@ package tlc2.tool; import tlc2.TLCGlobals; -import tlc2.util.ObjLongTable; -import tlc2.value.Value; +import tlc2.value.IValue; /** * A common interface for workers @@ -15,12 +14,6 @@ public interface IWorker */ public int myGetId(); - /** - * extracted from Worker and DFID worker - * used in the {@link AbstractChecker#reportCoverage(IWorker[])} - */ - public ObjLongTable getCounts(); - // see Thread public void start(); @@ -29,7 +22,7 @@ public interface IWorker // see IdThread - public Value getLocalValue(int idx); + public IValue getLocalValue(int idx); - public void setLocalValue(int idx, Value val); + public void setLocalValue(int idx, IValue val); } diff --git a/tlatools/src/tlc2/tool/ModelChecker.java b/tlatools/src/tlc2/tool/ModelChecker.java index 4c0e7589301c8f01aa5669fa823c87c5cca51d62..ac740d5573214ed9eb32742e083d459e6a7db67c 100644 --- a/tlatools/src/tlc2/tool/ModelChecker.java +++ b/tlatools/src/tlc2/tool/ModelChecker.java @@ -6,11 +6,14 @@ package tlc2.tool; +import java.io.File; import java.io.IOException; +import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.stream.Collectors; -import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ExprNode; import tla2sany.semantic.OpDeclNode; import tlc2.TLCGlobals; @@ -21,10 +24,10 @@ import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; import tlc2.tool.fp.FPSetFactory; import tlc2.tool.liveness.LiveCheck; +import tlc2.tool.queue.DiskByteArrayQueue; import tlc2.tool.queue.DiskStateQueue; import tlc2.tool.queue.IStateQueue; import tlc2.util.IStateWriter; -import tlc2.util.ObjLongTable; import tlc2.util.SetOfStates; import tlc2.util.statistics.BucketStatistics; import util.Assert; @@ -44,6 +47,7 @@ import util.UniqueString; public class ModelChecker extends AbstractChecker { + protected static final boolean coverage = TLCGlobals.isCoverageEnabled(); /** * If the state/ dir should be cleaned up after a successful model run */ @@ -52,14 +56,10 @@ public class ModelChecker extends AbstractChecker private long numberOfInitialStates; public FPSet theFPSet; // the set of reachable states (SZ: note the type) public IStateQueue theStateQueue; // the state queue - public TLCTrace trace; // the trace file + public final ConcurrentTLCTrace trace; // the trace file // used to calculate the spm metric public long distinctStatesPerMinute, statesPerMinute = 0L; protected long oldNumOfGenStates, oldFPSetSize = 0L; - /** - * Timestamp of when model checking started. - */ - private final long startTime = System.currentTimeMillis(); /** * The ratio between time spend on safety checking and liveness checking. */ @@ -70,37 +70,42 @@ public class ModelChecker extends AbstractChecker private boolean forceLiveCheck = false; /* Constructors */ + public ModelChecker(ITool tool, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, + final Future<FPSet> future, long startTime) throws EvalException, IOException, InterruptedException, ExecutionException { + this(tool, metadir, stateWriter, deadlock, fromChkpt, startTime); + this.theFPSet = future.get(); + } + + public ModelChecker(ITool tool, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, + final FPSetConfiguration fpSetConfig, long startTime) throws EvalException, IOException { + this(tool, metadir, stateWriter, deadlock, fromChkpt, startTime); + this.theFPSet = FPSetFactory.getFPSet(fpSetConfig).init(TLCGlobals.getNumWorkers(), metadir, tool.getRootFile()); + } + /** * The only used constructor of the TLA+ model checker * SZ Feb 20, 2009 * @param resolver name resolver to be able to load files (specs and configs) from managed environments * @param specObj external SpecObj added to enable to work on existing specification - * Modified on 6 Apr 2010 by Yuan Yu to add fpMemSize parameter. */ - public ModelChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, - FilenameToStream resolver, SpecObj specObj, final FPSetConfiguration fpSetConfig) throws EvalException, IOException - { + private ModelChecker(ITool tool, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, + long startTime) throws EvalException, IOException { // call the abstract constructor - super(specFile, configFile, metadir, stateWriter, deadlock, fromChkpt, true, resolver, specObj); + super(tool, metadir, stateWriter, deadlock, fromChkpt, startTime); - // SZ Feb 20, 2009: this is a selected alternative - this.theStateQueue = new DiskStateQueue(this.metadir); + this.theStateQueue = useByteArrayQueue() + ? new DiskByteArrayQueue(this.metadir) + : new DiskStateQueue(this.metadir); // this.theStateQueue = new MemStateQueue(this.metadir); - //TODO why used to div by 20? - this.theFPSet = FPSetFactory.getFPSet(fpSetConfig); - - // initialize the set - this.theFPSet.init(TLCGlobals.getNumWorkers(), this.metadir, specFile); - // Finally, initialize the trace file: - this.trace = new TLCTrace(this.metadir, specFile, this.tool); + this.trace = new ConcurrentTLCTrace(this.metadir, this.tool.getRootFile(), this.tool); // Initialize all the workers: this.workers = new Worker[TLCGlobals.getNumWorkers()]; for (int i = 0; i < this.workers.length; i++) { - this.workers[i] = new Worker(i, this); + this.workers[i] = this.trace.addWorker(new Worker(i, this, this.metadir, this.tool.getRootFile())); } } @@ -110,29 +115,37 @@ public class ModelChecker extends AbstractChecker * next states have not been explored are stored in the variable * theStateQueue. */ - public void modelCheck() throws Exception + @Override + protected int modelCheckImpl() throws Exception { + int result = EC.NO_ERROR; report("entering modelCheck()"); // needed to calculate state/minute in final progress report - boolean recovered = this.recover(); + boolean recovered = this.recover(); if (!recovered) { + if (this.checkLiveness && liveCheck.getNumChecker() == 0) { + return MP.printError(EC.TLC_LIVE_FORMULA_TAUTOLOGY); + } + // We start from scratch. Initialize the state queue and the - // state set to contain all the initial states. - if (!this.checkAssumptions()) - return; + // state set to contain all the initial states. + result = this.checkAssumptions(); + if (result != EC.NO_ERROR) + return result; try { report("doInit(false)"); MP.printMessage(EC.TLC_COMPUTING_INIT); - // SZ Feb 23, 2009: do not ignore cancel on creation of the init states - if (!this.doInit(false)) + // SZ Feb 23, 2009: do not ignore cancel on creation of the init states + result = this.doInit(false); + if (result != EC.NO_ERROR) { report("exiting, because init failed"); - return; + return result; } } catch (Throwable e) { @@ -170,15 +183,15 @@ public class ModelChecker extends AbstractChecker // SZ Feb 23, 2009: ignore cancel on error reporting this.doInit(true); } catch (FingerprintException fe){ - MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{fe.getTrace(), fe.getRootCause().getMessage()}); + result = MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{fe.getTrace(), fe.getRootCause().getMessage()}); } catch (Throwable e1) { // Assert.printStack(e); - MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); + result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); } this.printSummary(false, startTime); this.cleanup(false); report("exiting, because init failed with exception"); - return; + return result; } long statesGenerated = getStatesGenerated(); @@ -196,28 +209,28 @@ public class ModelChecker extends AbstractChecker report("init processed"); // Finished if there is no next state predicate: - if (this.actions.length == 0) + if (this.tool.getActions().length == 0) { if (this.theStateQueue.isEmpty()) { reportSuccess(this.theFPSet, getStatesGenerated()); this.printSummary(true, startTime); } else { - MP.printError(EC.TLC_STATES_AND_NO_NEXT_ACTION); + result = MP.printError(EC.TLC_STATES_AND_NO_NEXT_ACTION); } this.cleanup(true); report("exiting with actions.length == 0"); - return; + return result; } - boolean success = false; + result = EC.GENERAL; try { report("running TLC"); - success = this.runTLC(Integer.MAX_VALUE); - if (!success) + result = this.runTLC(Integer.MAX_VALUE); + if (result != EC.NO_ERROR) { report("TLC terminated with error"); - return; + return result; } if (this.errState == null) { @@ -228,22 +241,24 @@ public class ModelChecker extends AbstractChecker // Liveness checking can take a substantial amount of time // and thus give the user some clues at what stage safety // checking is. - MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { String.valueOf(this.trace.getLevelForReporting()), - String.valueOf(getStatesGenerated()), String.valueOf(theFPSet.size()), - String.valueOf(this.theStateQueue.size()) }); + MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { + String.valueOf(this.trace.getLevelForReporting()), + MP.format(getStatesGenerated()), + MP.format(theFPSet.size()), + MP.format(this.theStateQueue.size()) }); report("checking liveness"); - success = liveCheck.finalCheck(); + result = liveCheck.finalCheck(tool); report("liveness check complete"); - if (!success) + if (result != EC.NO_ERROR) { report("exiting error status on liveness check"); - return; + return result; } } // We get here because the checking has been completed. - success = true; + result = EC.NO_ERROR; reportSuccess(this.theFPSet, getStatesGenerated()); } else if (this.keepCallStack) { @@ -251,25 +266,28 @@ public class ModelChecker extends AbstractChecker this.tool.setCallStack(); try { - this.doNext(this.predErrState, new ObjLongTable(10), new Worker(4223, this)); + // Not adding newly created Worker to trace#addWorker because it is not supposed + // to rewrite the trace file but to reconstruct actual states referenced by + // their fingerprints in the trace. + this.doNext(this.predErrState, this.checkLiveness ? new SetOfStates() : null, + new Worker(4223, this, this.metadir, tool.getRootFile())); } catch (FingerprintException e) { - MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{e.getTrace(), e.getRootCause().getMessage()}); + result = MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{e.getTrace(), e.getRootCause().getMessage()}); } catch (Throwable e) { // Assert.printStack(e); - MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); + result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString()); } } } catch (Exception e) { report("TLC terminated with error"); // Assert.printStack(e); - success = false; - MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 + result = MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 } finally { - + final boolean success = result == EC.NO_ERROR; this.printSummary(success, startTime); if (this.checkLiveness) { @@ -285,19 +303,21 @@ public class ModelChecker extends AbstractChecker } this.cleanup(success); - } - report("exiting modelCheck()"); + report("exiting modelCheck()"); + } + + return result; } /** * Check the assumptions. */ - public boolean checkAssumptions() + public int checkAssumptions() { ExprNode[] assumps = this.tool.getAssumptions(); boolean[] isAxiom = this.tool.getAssumptionIsAxiom(); - boolean assumptionsAreTRUE = true; + int assumptionsError = EC.NO_ERROR; for (int i = 0; i < assumps.length; i++) { try @@ -305,22 +325,17 @@ public class ModelChecker extends AbstractChecker if ((!isAxiom[i]) && !this.tool.isValid(assumps[i])) { OutputCollector.addViolatedAssumption(assumps[i]); - MP.printError(EC.TLC_ASSUMPTION_FALSE, assumps[i].toString()); - //return false; - assumptionsAreTRUE = false; + assumptionsError = MP.printError(EC.TLC_ASSUMPTION_FALSE, assumps[i].toString()); } } catch (Exception e) { // Assert.printStack(e); OutputCollector.addViolatedAssumption(assumps[i]); - MP.printError(EC.TLC_ASSUMPTION_EVALUATION_ERROR, + assumptionsError = MP.printError(EC.TLC_ASSUMPTION_EVALUATION_ERROR, new String[] { assumps[i].toString(), e.getMessage() }); - //return false; - assumptionsAreTRUE = false; } } - //return true; - return assumptionsAreTRUE; + return assumptionsError; } /** @@ -328,14 +343,8 @@ public class ModelChecker extends AbstractChecker * @return status, if false, the processing should be stopped * @throws Throwable */ - public final boolean doInit(boolean ignoreCancel) throws Throwable + public final int doInit(boolean ignoreCancel) throws Throwable { - // SZ Feb 23, 2009: cancel flag set, quit - if (!ignoreCancel && this.cancellationFlag) - { - return false; - } - // Generate the initial states. // // The functor is passed to getInitStates() to - instead of adding all @@ -344,7 +353,15 @@ public class ModelChecker extends AbstractChecker // it to the queue, fingerprint set and trace file. This avoids // allocating memory for StateVec (which depending on the number of init // states can grow to be GBs) and the subsequent loop over StateVec. - final DoInitFunctor functor = new DoInitFunctor(); + final DoInitFunctor functor; + if (ignoreCancel) { + // Rerunning state space exploration to reconstruct the error stack to determine + // what caused Tool to fail to evaluate the init predicate expressions. Thus, + // re-check all invariants even if state is already known (= part of theFPSet). + functor = new DoInitFunctor(ignoreCancel); + } else { + functor = new DoInitFunctor(); + } try { this.tool.getInitStates(functor); } catch (DoInitFunctor.InvariantViolatedException ive) { @@ -376,37 +393,14 @@ public class ModelChecker extends AbstractChecker * * This method is called from the workers on every step */ - public final boolean doNext(TLCState curState, ObjLongTable counts, final Worker worker) throws Throwable + public final boolean doNext(TLCState curState, final SetOfStates liveNextStates, final Worker worker) throws Throwable { - // SZ Feb 23, 2009: cancel the calculation - if (this.cancellationFlag) - { - return false; - } - boolean deadLocked = true; TLCState succState = null; - SetOfStates liveNextStates = null; - int unseenSuccessorStates = 0; - - if (this.checkLiveness) - { - liveNextStates = new SetOfStates(INITIAL_CAPACITY * threadLocal.get()); - } - try { - int k = 0; - // <-- - // <-- - for (int i = 0; i < this.actions.length; i++) + for (int i = 0; i < this.tool.getActions().length; i++) { - // SZ Feb 23, 2009: cancel the calculation - if (this.cancellationFlag) - { - return false; - } - //TODO Implement IStateFunctor pattern for getNextStates() too // to reduce memory and runtime overhead of allocating and // looping StateVec. However - contrary to doInit() - doNext() @@ -416,213 +410,41 @@ public class ModelChecker extends AbstractChecker // of nextStates in a single invocation // (LiveCheck#addNextState(..). If this limitation is ever // removed, the functor pattern could be applied to doNext too. - StateVec nextStates = this.tool.getNextStates(this.actions[i], curState); - int sz = nextStates.size(); + // Other problems are access to worker and curState. A stateless functor has no + // access to curState and worker except when it uses thread local storage. + final Action action = this.tool.getActions()[i]; + final StateVec nextStates = this.tool.getNextStates(action, curState); + final int sz = nextStates.size(); worker.incrementStatesGenerated(sz); deadLocked = deadLocked && (sz == 0); - SUCCESSORS: for (int j = 0; j < sz; j++) + for (int j = 0; j < sz; j++) { succState = nextStates.elementAt(j); - succState.level = (short) ((short) 1 + curState.level); - assert succState.level >= 1; // Check if succState is a legal state. if (!this.tool.isGoodState(succState)) { - synchronized (this) { - if (this.setErrState(curState, succState, false)) - { - final Set<OpDeclNode> unassigned = succState.getUnassigned(); - if (this.actions.length == 1) { - MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, - new String[] { unassigned.size() > 1 ? "s are" : " is", - unassigned.stream().map(n -> n.getName().toString()) - .collect(Collectors.joining(", ")) }); - } else { - MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, - new String[] { this.actions[i].getName().toString(), - unassigned.size() > 1 ? "s are" : " is", - unassigned.stream().map(n -> n.getName().toString()) - .collect(Collectors.joining(", ")) }); - } - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); - } - return true; - } - } - if (TLCGlobals.coverageInterval >= 0) - { - ((TLCStateMutSource) succState).addCounts(counts); + return doNextSetErr(curState, succState, action); } final boolean inModel = (this.tool.isInModel(succState) && this.tool.isInActions(curState, succState)); boolean seen = false; if (inModel) { - long fp = succState.fingerPrint(); - seen = this.theFPSet.put(fp); - // Write out succState when needed: - this.allStateWriter.writeState(curState, succState, !seen, this.actions[i]); - if (!seen) - { - // Write succState to trace only if it satisfies the - // model constraints. Do not enqueue it yet, but wait - // for implied actions and invariants to be checked. - // Those checks - if violated - will cause model checking - // to terminate. Thus we cannot let concurrent workers start - // exploring this new state. Conversely, the state has to - // be in the trace in case either invariant or implied action - // checks want to print the trace. - long loc = this.trace.writeState(curState, fp, worker); - succState.uid = loc; - unseenSuccessorStates++; - } - // For liveness checking: - if (this.checkLiveness) - { - liveNextStates.put(fp, succState); - } + seen = isSeenState(curState, worker, succState, liveNextStates, action); } // Check if succState violates any invariant: if (!seen) { - try - { - int len = this.invariants.length; - INVARIANTS: for (k = 0; k < len; k++) - { - // SZ Feb 23, 2009: cancel the calculation - if (this.cancellationFlag) - { - return false; - } - - if (!tool.isValid(this.invariants[k], succState)) - { - // We get here because of invariant violation: - synchronized (this) - { - if (TLCGlobals.continuation) - { - MP.printError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, - this.tool.getInvNames()[k]); - this.trace.printTrace(curState, succState); - break INVARIANTS; - } else - { - if (this.setErrState(curState, succState, false)) - { - MP.printError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, this.tool - .getInvNames()[k]); - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); - } - return true; - } - } - } - } - if (k < len) { - if (inModel && !seen) { - // Even though the state violates an - // invariant, add it to the queue. After - // all, the user selected to continue model - // checking even if an invariant is - // violated. - this.theStateQueue.sEnqueue(succState); - } - // Continue with next successor iff an - // invariant is violated and - // TLCGlobals.continuation is true. - continue SUCCESSORS; - } - } catch (Exception e) - { - synchronized (this) { - if (this.setErrState(curState, succState, true)) - { - MP.printError(EC.TLC_INVARIANT_EVALUATION_FAILED, new String[] { - this.tool.getInvNames()[k], - (e.getMessage() == null) ? e.toString() : e.getMessage() }); - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); - } - throw e; - } - } + if (doNextCheckInvariants(curState, succState, inModel, seen)) { + return true; + } } // Check if the state violates any implied action. We need to do it // even if succState is not new. - try - { - int len = this.impliedActions.length; - IMPLIED: for (k = 0; k < len; k++) - { - // SZ Feb 23, 2009: cancel the calculation - if (this.cancellationFlag) - { - return false; - } - - if (!tool.isValid(this.impliedActions[k], curState, succState)) - { - // We get here because of implied-action violation: - synchronized (this) - { - if (TLCGlobals.continuation) - { - MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, this.tool - .getImpliedActNames()[k]); - this.trace.printTrace(curState, succState); - break IMPLIED; - } else - { - if (this.setErrState(curState, succState, false)) - { - MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, this.tool - .getImpliedActNames()[k]); - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); - } - return true; - } - } - } - } - if (k < len) { - if (inModel && !seen) { - // Even though the state violates an - // invariant, add it to the queue. After - // all, the user selected to continue model - // checking even if an implied action is - // violated. - this.theStateQueue.sEnqueue(succState); - } - // Continue with next successor iff an - // implied action is violated and - // TLCGlobals.continuation is true. - continue SUCCESSORS; - } - } catch (Exception e) - { - synchronized (this) { - if (this.setErrState(curState, succState, true)) - { - MP.printError(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, new String[] { - this.tool.getImpliedActNames()[k], - (e.getMessage() == null) ? e.toString() : e.getMessage() }); - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); - } - throw e; - } - } + if (doNextCheckImplied(curState, succState, inModel, seen)) { + return true; + } if (inModel && !seen) { // The state is inModel, unseen and neither invariants // nor implied actions are violated. It is thus eligible @@ -636,69 +458,201 @@ public class ModelChecker extends AbstractChecker // Check for deadlock: if (deadLocked && this.checkDeadlock) { - synchronized (this) - { - if (this.setErrState(curState, null, false)) - { - MP.printError(EC.TLC_DEADLOCK_REACHED); - this.trace.printTrace(curState, null); - this.theStateQueue.finishAll(); - this.notify(); - } - } - return true; + return doNextSetErr(curState, null, false, EC.TLC_DEADLOCK_REACHED, null); } - // Finally, add curState into the behavior graph for liveness checking: - if (this.checkLiveness) - { - final long curStateFP = curState.fingerPrint(); - - // Add the stuttering step: - liveNextStates.put(curStateFP, curState); - this.allStateWriter.writeState(curState, curState, true, IStateWriter.Visualization.STUTTERING); + return false; + } catch (final Throwable e) + { + doNextFailed(curState, succState, e); + throw e; + } + } - liveCheck.addNextState(curState, curStateFP, liveNextStates); + private final boolean isSeenState(final TLCState curState, final Worker worker, final TLCState succState, + final SetOfStates liveNextStates, final Action action) throws IOException { + final long fp = succState.fingerPrint(); + final boolean seen = this.theFPSet.put(fp); + // Write out succState when needed: + this.allStateWriter.writeState(curState, succState, !seen, action); + if (!seen) + { + // Write succState to trace only if it satisfies the + // model constraints. Do not enqueue it yet, but wait + // for implied actions and invariants to be checked. + // Those checks - if violated - will cause model checking + // to terminate. Thus we cannot let concurrent workers start + // exploring this new state. Conversely, the state has to + // be in the trace in case either invariant or implied action + // checks want to print the trace. + worker.writeState(curState, fp, succState); + if (coverage) { + action.cm.incSecondary(); + } + } + // For liveness checking: + if (this.checkLiveness) + { + liveNextStates.put(fp, succState); + } + return seen; + } - // Poor man's version of a controller. If necessary, try e.g. - // PID controller instead. - final int multiplier = threadLocal.get(); - if (liveNextStates.capacity() > (multiplier * INITIAL_CAPACITY)) { - // Increase initial size for as long as the set has to grow - threadLocal.set(multiplier + 1); + private final boolean doNextCheckInvariants(final TLCState curState, final TLCState succState, final boolean inModel, final boolean seen) throws IOException, WorkerException, Exception { + int k = 0; + try + { + for (k = 0; k < this.tool.getInvariants().length; k++) + { + if (!tool.isValid(this.tool.getInvariants()[k], succState)) + { + // We get here because of invariant violation: + if (TLCGlobals.continuation) { + synchronized (this) + { + MP.printError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, + this.tool.getInvNames()[k]); + this.trace.printTrace(curState, succState); + return false; + } + } else { + return doNextSetErr(curState, succState, false, + EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, this.tool.getInvNames()[k]); + } } - } - worker.setOutDegree(unseenSuccessorStates); - return false; - } catch (Throwable e) + } + } catch (Exception e) + { + doNextEvalFailed(curState, succState, EC.TLC_INVARIANT_EVALUATION_FAILED, + this.tool.getInvNames()[k], e); + } + return false; + } + + private final boolean doNextCheckImplied(final TLCState curState, final TLCState succState, final boolean inModel, boolean seen) throws IOException, WorkerException, Exception { + int k = 0; + try { - // Assert.printStack(e); - boolean keep = ((e instanceof StackOverflowError) || (e instanceof OutOfMemoryError) - || (e instanceof AssertionError)); - synchronized (this) + for (k = 0; k < this.tool.getImpliedActions().length; k++) { - if (this.setErrState(curState, succState, !keep)) + if (!tool.isValid(this.tool.getImpliedActions()[k], curState, succState)) { - if (e instanceof StackOverflowError) + // We get here because of implied-action violation: + if (TLCGlobals.continuation) { - MP.printError(EC.SYSTEM_STACK_OVERFLOW, e); - } else if (e instanceof OutOfMemoryError) - { - MP.printError(EC.SYSTEM_OUT_OF_MEMORY, e); - } else if (e instanceof AssertionError) - { - MP.printError(EC.TLC_BUG, e); - } else if (e.getMessage() != null) - { - MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 - } - this.trace.printTrace(curState, succState); - this.theStateQueue.finishAll(); - this.notify(); + synchronized (this) + { + MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, this.tool + .getImpliedActNames()[k]); + this.trace.printTrace(curState, succState); + return false; + } + } else { + return doNextSetErr(curState, succState, false, + EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, + this.tool.getImpliedActNames()[k]); + } + } + } + } catch (Exception e) + { + doNextEvalFailed(curState, succState, EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, + this.tool.getImpliedActNames()[k], e); + } + return false; + } + + private final boolean doNextSetErr(TLCState curState, TLCState succState, boolean keep, int ec, String param) throws IOException, WorkerException { + synchronized (this) + { + if (this.setErrState(curState, succState, keep, ec)) + { + if (param == null) { + MP.printError(ec); + } else { + MP.printError(ec, param); + } + this.trace.printTrace(curState, succState); + this.theStateQueue.finishAll(); + this.notify(); + } + } + return true; + } + + private final boolean doNextSetErr(TLCState curState, TLCState succState, Action action) throws IOException, WorkerException { + synchronized (this) { + final int errorCode = EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT; + if (this.setErrState(curState, succState, false, errorCode)) + { + final Set<OpDeclNode> unassigned = succState.getUnassigned(); + if (this.tool.getActions().length == 1) { + MP.printError(errorCode, + new String[] { unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }); + } else { + MP.printError(errorCode, + new String[] { action.getName().toString(), + unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }); } + this.trace.printTrace(curState, succState); + this.theStateQueue.finishAll(); + this.notify(); + } + return true; + } + } + + private final void doNextEvalFailed(TLCState curState, TLCState succState, int ec, String param, Exception e) + throws IOException, WorkerException, Exception { + synchronized (this) { + if (this.setErrState(curState, succState, true, ec)) + { + MP.printError(ec, new String[] { param, (e.getMessage() == null) ? e.toString() : e.getMessage() }); + this.trace.printTrace(curState, succState); + this.theStateQueue.finishAll(); + this.notify(); } throw e; } - } + } + + private final void doNextFailed(TLCState curState, TLCState succState, Throwable e) + throws IOException, WorkerException, Throwable { + // Assert.printStack(e); + final boolean keep = ((e instanceof StackOverflowError) || (e instanceof OutOfMemoryError) + || (e instanceof AssertionError)); + synchronized (this) + { + final int ec; + if (e instanceof StackOverflowError) + { + ec = EC.SYSTEM_STACK_OVERFLOW; + } else if (e instanceof OutOfMemoryError) + { + ec = EC.SYSTEM_OUT_OF_MEMORY; + } else if (e instanceof AssertionError) + { + ec = EC.TLC_BUG; + } else + { + ec = EC.GENERAL; + } + + if (this.setErrState(curState, succState, !keep, ec)) + { + if (!(ec == EC.GENERAL && e.getMessage() == null)) + { + MP.printError(ec, e); + } + this.trace.printTrace(curState, succState); + this.theStateQueue.finishAll(); + this.notify(); + } + } + } /** * Things need to be done here: @@ -706,7 +660,8 @@ public class ModelChecker extends AbstractChecker * Create checkpoint: checkpoint three data structures: the state set, * the state queue, and the state trace. */ - public final boolean doPeriodicWork() throws Exception + @Override + public final int doPeriodicWork() throws Exception { // Remember if checkpointing should be run. doCheckPoint() when called // internally diffs the time expired since its last invocation which is @@ -718,7 +673,7 @@ public class ModelChecker extends AbstractChecker // Do not suspend the state queue if neither check-pointing nor // liveness-checking is going to happen. Suspending is expensive. // It stops all workers. - return true; + return EC.NO_ERROR; } if (this.theStateQueue.suspendAll()) @@ -728,9 +683,11 @@ public class ModelChecker extends AbstractChecker // runtime dedicated to liveness checking. if (this.checkLiveness && (runtimeRatio < TLCGlobals.livenessRatio || forceLiveCheck)) { - final long preLivenessChecking = System.currentTimeMillis(); - if (!liveCheck.check(forceLiveCheck)) { - return false; + final long preLivenessChecking = System.currentTimeMillis(); + final int result = liveCheck.check(tool, forceLiveCheck); + if (result != EC.NO_ERROR) + { + return result; } forceLiveCheck = false; updateRuntimeRatio(System.currentTimeMillis() - preLivenessChecking); @@ -740,36 +697,39 @@ public class ModelChecker extends AbstractChecker if (createCheckPoint) { // Checkpoint: - MP.printMessage(EC.TLC_CHECKPOINT_START, this.metadir); - - // start checkpointing: - this.theStateQueue.beginChkpt(); - this.trace.beginChkpt(); - this.theFPSet.beginChkpt(); - this.theStateQueue.resumeAll(); - UniqueString.internTbl.beginChkpt(this.metadir); - if (this.checkLiveness) - { - liveCheck.beginChkpt(); - } - // commit checkpoint: - this.theStateQueue.commitChkpt(); - this.trace.commitChkpt(); - this.theFPSet.commitChkpt(); - UniqueString.internTbl.commitChkpt(this.metadir); - if (this.checkLiveness) - { - liveCheck.commitChkpt(); - } - MP.printMessage(EC.TLC_CHECKPOINT_END); + checkpoint(); } else { // Just resume worker threads when checkpointing is skipped this.theStateQueue.resumeAll(); } } - return true; + return EC.NO_ERROR; } + protected void checkpoint() throws IOException { + // start checkpointing: + MP.printMessage(EC.TLC_CHECKPOINT_START, this.metadir); + this.theStateQueue.beginChkpt(); + this.trace.beginChkpt(); + this.theFPSet.beginChkpt(); + this.theStateQueue.resumeAll(); + UniqueString.internTbl.beginChkpt(this.metadir); + if (this.checkLiveness) + { + liveCheck.beginChkpt(); + } + // commit checkpoint: + this.theStateQueue.commitChkpt(); + this.trace.commitChkpt(); + this.theFPSet.commitChkpt(); + UniqueString.internTbl.commitChkpt(this.metadir); + if (this.checkLiveness) + { + liveCheck.commitChkpt(); + } + MP.printMessage(EC.TLC_CHECKPOINT_END); + } + public void forceLiveCheck() { forceLiveCheck = true; } @@ -819,7 +779,7 @@ public class ModelChecker extends AbstractChecker MP.printMessage(EC.TLC_CHECKPOINT_RECOVER_START, this.fromChkpt); this.trace.recover(); this.theStateQueue.recover(); - this.theFPSet.recover(); + this.theFPSet.recover(this.trace); if (this.checkLiveness) { // Liveness checking requires the initial states to be @@ -830,7 +790,7 @@ public class ModelChecker extends AbstractChecker // https://github.com/tlaplus/tlaplus/issues/22 this.tool.getInitStates(new IStateFunctor() { public Object addElement(TLCState state) { - liveCheck.addInitState(state, state.fingerPrint()); + liveCheck.addInitState(tool, state, state.fingerPrint()); return true; } }); @@ -847,13 +807,24 @@ public class ModelChecker extends AbstractChecker private final void cleanup(boolean success) throws IOException { + boolean vetoCleanup = VETO_CLEANUP; + + // If model checking is not done, checkpoints are (explicitly) enabled, and + // either and error has been found or time-bound model checking is enabled, take + // a snapshot to allow users to continue model checking if needed. + if (TLCGlobals.chkptExplicitlyEnabled() + && !theStateQueue.isEmpty() && (this.errState != null || isTimeBound())) { + checkpoint(); + vetoCleanup = true; + } + this.theFPSet.close(); this.trace.close(); if (this.checkLiveness) { liveCheck.close(); } this.allStateWriter.close(); - if (!VETO_CLEANUP) { + if (!vetoCleanup) { FileUtil.deleteDir(this.metadir, success); } } @@ -876,7 +847,7 @@ public class ModelChecker extends AbstractChecker String.valueOf(this.theFPSet.size()), String.valueOf(this.theStateQueue.size()) }); if (success) { - MP.printMessage(EC.TLC_SEARCH_DEPTH, String.valueOf(this.trace.getLevelForFinalReporting())); + MP.printMessage(EC.TLC_SEARCH_DEPTH, String.valueOf(this.trace.getLevelForReporting())); // Aggregate outdegree from statistics maintained by individual workers. final BucketStatistics aggOutDegree = new BucketStatistics("State Graph OutDegree"); @@ -913,16 +884,26 @@ public class ModelChecker extends AbstractChecker distinctStatesPerMinute = (long) ((fpSetSize - oldFPSetSize) / factor); oldFPSetSize = fpSetSize; - MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { String.valueOf(this.trace.getLevelForReporting()), - String.valueOf(l), String.valueOf(fpSetSize), - String.valueOf(this.theStateQueue.size()), String.valueOf(statesPerMinute), String.valueOf(distinctStatesPerMinute) }); + MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { + String.valueOf(this.trace.getLevelForReporting()), + MP.format(l), + MP.format(fpSetSize), + MP.format(this.theStateQueue.size()), + MP.format(statesPerMinute), + MP.format(distinctStatesPerMinute) }); } public static final void reportSuccess(final FPSet anFpSet, final long numOfGenStates) throws IOException { - final long fpSetSize = anFpSet.size(); - final double actualProb = anFpSet.checkFPs(); - reportSuccess(fpSetSize, actualProb, numOfGenStates); + final long numOfDistinctStates = anFpSet.size(); + final double optimisticProb = calculateOptimisticProbability(numOfDistinctStates, numOfGenStates); + if (optimisticProb < 1E-10) { + // If the optimistic probability is sufficiently low, don't waste time + // calculating the actual probability. + reportSuccess(numOfDistinctStates, numOfGenStates); + } else { + reportSuccess(numOfDistinctStates, anFpSet.checkFPs(), numOfGenStates); + } } /** @@ -997,6 +978,16 @@ public class ModelChecker extends AbstractChecker { DebugPrinter.print(e); } + + private static boolean useByteArrayQueue() { + return Boolean.getBoolean(ModelChecker.class.getName() + ".BAQueue"); + } + + public static String getStateQueueName() { + // Ideally, this wouldn't hard-code the simple name of the classes but we don't + // have access to the class file yet. + return useByteArrayQueue() ? "DiskByteArrayQueue" : "DiskStateQueue"; + } public long getStatesGenerated() { long sum = numberOfInitialStates; @@ -1005,7 +996,63 @@ public class ModelChecker extends AbstractChecker } return sum; } - + + /* (non-Javadoc) + * @see tlc2.tool.AbstractChecker#getProgress() + */ + @Override + public int getProgress() { + try { + return trace.getLevelForReporting(); + } catch (IOException e) { + // The modelchecker trace file might be closed already (e.g. it + // gets closed at the end of the modelchecker run) + return -1; + } + } + + /* (non-Javadoc) + * @see tlc2.tool.AbstractChecker#stop() + */ + @Override + public void stop() { + synchronized (this) { + this.setDone(); + this.theStateQueue.finishAll(); + this.notifyAll(); + } + } + + public void suspend() { + synchronized (this) { + this.theStateQueue.suspendAll(); + this.notifyAll(); + } + } + + public void resume() { + synchronized (this) { + this.theStateQueue.resumeAll(); + this.notifyAll(); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.AbstractChecker#getStateQueueSize() + */ + @Override + public long getStateQueueSize() { + return theStateQueue.size(); + } + + /* (non-Javadoc) + * @see tlc2.tool.AbstractChecker#getDistinctStatesGenerated() + */ + @Override + public long getDistinctStatesGenerated() { + return theFPSet.size(); + } + /** * An implementation of {@link IStateFunctor} for * {@link ModelChecker#doInit(boolean)}. @@ -1027,7 +1074,17 @@ public class ModelChecker extends AbstractChecker * know the actual outcome when all init states have been processed. * This outcome is stored as returnValue. */ - private boolean returnValue = true; + private int returnValue = EC.NO_ERROR; + + private final boolean forceChecks; + + public DoInitFunctor() { + this(false); + } + + public DoInitFunctor(boolean forceChecks) { + this.forceChecks = forceChecks; + } /* (non-Javadoc) * @see tlc2.tool.IStateFunctor#addElement(tlc2.tool.TLCState) @@ -1044,7 +1101,8 @@ public class ModelChecker extends AbstractChecker // states have been generated. Thus, the functor simply ignores // subsequent states once a violation has been recorded. if (errState != null) { - returnValue = false; + if (returnValue == EC.NO_ERROR) + returnValue = EC.TLC_INITIAL_STATE; return returnValue; } @@ -1053,7 +1111,7 @@ public class ModelChecker extends AbstractChecker if (!tool.isGoodState(curState)) { MP.printError(EC.TLC_INITIAL_STATE, new String[]{ "current state is not a legal state", curState.toString() }); this.errState = curState; - returnValue = false; + returnValue = EC.TLC_INITIAL_STATE; throw new InvariantViolatedException(); } boolean inModel = tool.isInModel(curState); @@ -1063,42 +1121,42 @@ public class ModelChecker extends AbstractChecker seen = theFPSet.put(fp); if (!seen) { allStateWriter.writeState(curState); - curState.uid = trace.writeState(fp); + ((Worker) workers[0]).writeState(curState, fp); theStateQueue.enqueue(curState); // build behavior graph for liveness checking if (checkLiveness) { - liveCheck.addInitState(curState, fp); + liveCheck.addInitState(tool, curState, fp); } } } // Check properties of the state: OutputCollector.setInitialState(curState); - if (!seen) { - for (int j = 0; j < invariants.length; j++) { - if (!tool.isValid(invariants[j], curState)) { + if (!seen || forceChecks) { + for (int j = 0; j < tool.getInvariants().length; j++) { + if (!tool.isValid(tool.getInvariants()[j], curState)) { // We get here because of invariant violation: MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { tool.getInvNames()[j].toString(), curState.toString() }); if (!TLCGlobals.continuation) { this.errState = curState; - returnValue = false; + returnValue = EC.TLC_INVARIANT_VIOLATED_INITIAL; throw new InvariantViolatedException(); } } } - for (int j = 0; j < impliedInits.length; j++) { - if (!tool.isValid(impliedInits[j], curState)) { + for (int j = 0; j < tool.getImpliedInits().length; j++) { + if (!tool.isValid(tool.getImpliedInits()[j], curState)) { // We get here because of implied-inits violation: MP.printError(EC.TLC_PROPERTY_VIOLATED_INITIAL, new String[] { tool.getImpliedInitNames()[j], curState.toString() }); this.errState = curState; - returnValue = false; + returnValue = EC.TLC_PROPERTY_VIOLATED_INITIAL; throw new InvariantViolatedException(); } } } - } catch (InvariantViolatedException | Assert.TLCRuntimeException e) { + } catch (InvariantViolatedException | Assert.TLCRuntimeException | EvalException e) { // IVE gets thrown above when an Invariant is violated. TLCRuntimeException gets // thrown when Tool fails to evaluate a statement because of e.g. too large sets // or type errors such as in DoInitFunctorInvariantMinimalErrorStackTest test. @@ -1107,7 +1165,7 @@ public class ModelChecker extends AbstractChecker throw e; } catch (OutOfMemoryError e) { MP.printError(EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT); - returnValue = false; + returnValue = EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT; return returnValue; } catch (Throwable e) { // Assert.printStack(e); @@ -1117,5 +1175,9 @@ public class ModelChecker extends AbstractChecker return returnValue; } } + + public List<File> getModuleFiles(FilenameToStream resolver) { + return this.tool.getModuleFiles(resolver); + } } \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/SimulationWorker.java b/tlatools/src/tlc2/tool/SimulationWorker.java new file mode 100644 index 0000000000000000000000000000000000000000..cd30ab8cd3692009fcd9f90a4af9ca9e9df67924 --- /dev/null +++ b/tlatools/src/tlc2/tool/SimulationWorker.java @@ -0,0 +1,412 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * William Schultz - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import java.io.PrintWriter; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.LongAdder; + +import tlc2.output.EC; +import tlc2.tool.liveness.ILiveCheck; +import tlc2.util.RandomGenerator; +import util.FileUtil; + +/** + * A SimulationWorker repeatedly checks random traces of a spec. + * + * It is constructed with an initial seed which it uses to initialize its + * internal random number generator. A simulation worker continually generates + * random traces, even if it encounters errors of any kind i.e. + * invariant/liveness violations, evaluation errors, etc. A worker communicates + * these errors by pushing its results onto a result queue, that is provided to + * it at construction time. + * + * Workers may terminate in two possible ways. They will terminate if they + * receive an "interruption" signal, and they will terminate if they reach their + * maximum trace count limit. Otherwise, they will continue to run forever, + * generating new traces. It is the job of an external thread/client to + * determine if the errors produced are cause for termination or can be ignored. + * + * Upon termination due to any cause, a worker thread will always push a final + * OK result onto its result queue. This acts as a way to signal external + * clients that this thread has terminated. + */ +public class SimulationWorker extends Thread { + + // This worker's local source of randomness. + final RandomGenerator localRng; + + // The state currently being processed. + TLCState curState; + + // Stores a trace generated by this worker. + StateVec stateTrace; + + // A unique id for this worker thread. + private int id; + + // The set of initial states for the spec. + private final StateVec initStates; + + // The queue that the worker places its results onto. + private final BlockingQueue<SimulationWorkerResult> resultQueue; + + // Tracks the number of traces that have been generated so far. + private int traceCnt = 0; + + // The maximum number of traces this worker should generate before terminating. + private final long maxTraceNum; + + // The maximum length of any generated trace. + private final long maxTraceDepth; + + // Should this worker check traces for deadlock. + private final boolean checkDeadlock; + + // The base name of the file that this worker writes out generated traces to. If it is null, + // no trace files are generated. + private final String traceFile; + + // A counter that tracks the number of generated states/traces. This counter may be + // shared among workers, so its count may be greater than the number of states/traces + // generated by this worker alone. It is the duty of this worker, though, to + // update it whenever it generates a new state or trace. + private final LongAdder numOfGenStates; + private final LongAdder numOfGenTraces; + + private final ITool tool; + private final ILiveCheck liveCheck; + + /** + * Encapsulates information about an error produced by a simulation worker. + */ + public static class SimulationWorkerError { + + public SimulationWorkerError(int errorCode, String[] parameters, TLCState state, StateVec stateTrace, + Exception e) { + this.errorCode = errorCode; + this.parameters = parameters; + this.state = state; + this.stateTrace = stateTrace; + this.exception = e; + } + + // The error code to report. + public int errorCode; + + // Any additional information to be included in a reported error string. + public String[] parameters; + + // The TLC state associated with the error. + public TLCState state; + + // The TLC trace associated with the error. + public StateVec stateTrace; + + // An exception associated with the error. + public Exception exception; + } + + + /** + * Encapsulates information about a result produced by a simulation worker. + * + * A result can either be an error or OK (indicating no error). Each result is + * associated with a specific worker. + */ + public static class SimulationWorkerResult { + + /** + * Constructs an OK result. + */ + static SimulationWorkerResult OK(int workerId) { + SimulationWorkerResult res = new SimulationWorkerResult(); + res.workerId = workerId; + return res; + } + + /** + * Constructs an error result. + */ + static SimulationWorkerResult Error(int workerId, SimulationWorkerError err) { + SimulationWorkerResult res = new SimulationWorkerResult(); + res.error = Optional.of(err); + res.workerId = workerId; + return res; + } + + /** + * Returns whether this result is an error. + */ + public boolean isError() { + return error.isPresent(); + } + + /** + * Returns the error for this result. Only valid to call if an error is present. + */ + public SimulationWorkerError error() { + return error.get(); + } + + public int workerId() { + return workerId; + } + + private int workerId; // The worker that generated this result. + private Optional<SimulationWorkerError> error = Optional.empty(); + + } + + + public SimulationWorker(int id, ITool tool, StateVec initStates, BlockingQueue<SimulationWorkerResult> resultQueue, + long seed, long maxTraceDepth, long maxTraceNum, boolean checkDeadlock, String traceFile, + ILiveCheck liveCheck, LongAdder numOfGenStates, LongAdder numOfGenTraces) { + this.id = id; + this.localRng = new RandomGenerator(seed); + this.tool = tool; + this.maxTraceDepth = maxTraceDepth; + this.maxTraceNum = maxTraceNum; + this.resultQueue = resultQueue; + this.initStates = initStates; + this.checkDeadlock = checkDeadlock; + this.traceFile = traceFile; + this.liveCheck = liveCheck; + this.numOfGenStates = numOfGenStates; + this.numOfGenTraces = numOfGenTraces; + } + + /** + * The main worker loop. Continually generates random traces until the trace count limit + * is reached or until the worker is interrupted. + * + * We use the standard Java notion of thread "interruption" as a mechanism for + * halting/cancelling the execution of a worker thread. There's nothing particularly + * special about this. The Thread.interrupt() just sets a boolean flag that the + * running thread then periodically checks via calls to Thread.interrupted(). We could + * implement this manually but it's simpler to use the built-in mechanism. + */ + public final void run() { + while(true) { + try { + // The trace simulation method should do appropriately frequent interruption + // checks. + final Optional<SimulationWorkerError> res = simulateRandomTrace(); + traceCnt++; + this.numOfGenTraces.increment(); + + // If we have an error result, place it on the output queue. + if (res.isPresent()) { + final SimulationWorkerError err = res.get(); + resultQueue.put(SimulationWorkerResult.Error(this.id, err)); + } + + // Abide by the maximum trace generation count. + if (traceCnt >= maxTraceNum) { + resultQueue.put(SimulationWorkerResult.OK(this.id)); + return; + } + } catch (final InterruptedException e) { + // Gracefully terminate if we were interrupted. + resultQueue.offer(SimulationWorkerResult.OK(this.id)); + return; + } catch (final Exception e) { + final SimulationWorkerError err = new SimulationWorkerError(0, null, this.curState, this.stateTrace, e); + resultQueue.offer(SimulationWorkerResult.Error(this.id, err)); + return; + } + } + } + + /** + * Check to see if the worker thread has been interrupted. + */ + private void checkForInterrupt() throws InterruptedException { + if (Thread.interrupted()) { + throw new InterruptedException(); + } + } + + /** + * This method returns the set of next states generated by a randomly chosen + * action. It returns null if there is no possible next state. + */ + public final StateVec randomNextStates(RandomGenerator rng, TLCState state) { + final Action[] actions = this.tool.getActions(); + final int len = actions.length; + int index = (int) Math.floor(rng.nextDouble() * len); + final int p = rng.nextPrime(); + for (int i = 0; i < len; i++) { + final StateVec pstates = this.tool.getNextStates(actions[index], state); + if (!pstates.empty()) { + return pstates; + } + index = (index + p) % len; + } + return null; + } + + /** + * This method returns a state that is randomly chosen from the set of states. + * It returns null if the set of states is empty. + */ + private final TLCState randomState(RandomGenerator rng, StateVec states) throws EvalException { + final int len = states.size(); + if (len > 0) { + final int index = (int) Math.floor(rng.nextDouble() * len); + return states.elementAt(index); + } + return null; + } + + /** + * Generates a single random trace. + * + * The core steps of this process are as follows: + * + * a) Pick one of the initial states. + * b) Randomly pick an action to generate the successor states (more than 1) to the current initial state. + * c) Check all of the generated successors for their validity. + * d) Randomly pick a generated successor and make it the new current state. + * + * Returns an Optional error representing the outcome of the trace generation. If the trace generation produced no error, + * returns Optional.empty(). + * + */ + private Optional<SimulationWorkerError> simulateRandomTrace() throws Exception { + this.curState = null; + this.stateTrace = new StateVec((int) maxTraceDepth); + stateTrace.clear(); + + // a) Randomly select a state from the set of init states. + curState = randomState(this.localRng, initStates); + + boolean inConstraints = tool.isInModel(curState); + + // Simulate a trace up to the maximum specified length. + for (int traceIdx = 0; traceIdx < maxTraceDepth; traceIdx++) { + // We don't want this thread to run for too long without checking for + // interruption, so we do so on every iteration of the main trace generation + // loop. + checkForInterrupt(); + + // Add the curState to the trace regardless of its inModel property. + stateTrace.addElement(curState); + + // Make sure this state satisfies the model constraints. + if (!inConstraints) { + break; + } + + // b) Get the current state's successor states. + final StateVec nextStates = randomNextStates(this.localRng, curState); + if (nextStates == null) { + if (checkDeadlock) { + // We get here because of deadlock. + return Optional.of(new SimulationWorkerError(EC.TLC_DEADLOCK_REACHED, null, curState, stateTrace, null)); + } + break; + } + + // c) Check all generated next states before all but one are discarded. + for (int i = 0; i < nextStates.size(); i++) { + numOfGenStates.increment(); + final TLCState state = nextStates.elementAt(i); + + if (!tool.isGoodState(state)) { + return Optional.of(new SimulationWorkerError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, null, state, + stateTrace, null)); + } + + // Check invariants. + int idx = 0; + try { + for (idx = 0; idx < this.tool.getInvariants().length; idx++) { + if (!tool.isValid(this.tool.getInvariants()[idx], state)) { + // We get here because of an invariant violation. + return Optional.of(new SimulationWorkerError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, + new String[] { tool.getInvNames()[idx] }, state, stateTrace, null)); + } + } + } catch (final Exception e) { + return Optional.of(new SimulationWorkerError(EC.TLC_INVARIANT_EVALUATION_FAILED, + new String[] { tool.getInvNames()[idx], e.getMessage() }, state, stateTrace, null)); + } + + // Check action properties. + try { + for (idx = 0; idx < this.tool.getImpliedActions().length; idx++) { + if (!tool.isValid(this.tool.getImpliedActions()[idx], curState, state)) { + // We get here because of implied-action violation. + return Optional.of(new SimulationWorkerError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, + new String[] { tool.getImpliedActNames()[idx] }, state, stateTrace, null)); + } + } + } catch (final Exception e) { + return Optional.of(new SimulationWorkerError(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, + new String[] { tool.getImpliedActNames()[idx], e.getMessage() }, state, stateTrace, null)); + } + + } + + // At this point all generated successor states have been checked for + // their respective validity (isGood/isValid/impliedActions/...). + + // d) Randomly select one of them and make it the current state for the next + // iteration of the loop. + final TLCState s1 = randomState(localRng, nextStates); + inConstraints = (tool.isInModel(s1) && tool.isInActions(curState, s1)); + curState = s1; + } + + // Check for interruption once more before entering liveness checking. + checkForInterrupt(); + + // Check if the current trace satisfies liveness properties. + liveCheck.checkTrace(tool, stateTrace); + + + // Write the trace out if desired. The trace is printed in the + // format of TLA module, so that it can be read by TLC again. + if (traceFile != null) { + // Make sure each worker outputs to its own set of trace files. + final String fileName = traceFile + "_" + String.valueOf(this.id) + "_" + this.traceCnt; + // TODO is it ok here? + final PrintWriter pw = new PrintWriter(FileUtil.newBFOS(fileName)); + pw.println("---------------- MODULE " + fileName + " -----------------"); + for (int idx = 0; idx < stateTrace.size(); idx++) { + pw.println("STATE_" + (idx + 1) + " == "); + pw.println(stateTrace.elementAt(idx) + "\n"); + } + pw.println("================================================="); + pw.close(); + } + + // Finished trace generation without any errors. + return Optional.empty(); + } +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/Simulator.java b/tlatools/src/tlc2/tool/Simulator.java index 905896c416d8ada68e0bd77250660e73a5572e7c..e149a48520657302dcf5076c91c0c1677d25911a 100644 --- a/tlatools/src/tlc2/tool/Simulator.java +++ b/tlatools/src/tlc2/tool/Simulator.java @@ -6,50 +6,46 @@ package tlc2.tool; import java.io.IOException; -import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TimerTask; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.LongAdder; -import tla2sany.modanalyzer.SpecObj; -import tla2sany.semantic.SemanticNode; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import tlc2.output.StatePrinter; +import tlc2.tool.SimulationWorker.SimulationWorkerError; +import tlc2.tool.SimulationWorker.SimulationWorkerResult; +import tlc2.tool.coverage.CostModelCreator; +import tlc2.tool.impl.Tool; import tlc2.tool.liveness.ILiveCheck; import tlc2.tool.liveness.LiveCheck; import tlc2.tool.liveness.LiveCheck1; import tlc2.tool.liveness.LiveException; import tlc2.tool.liveness.NoOpLiveCheck; -import tlc2.util.ObjLongTable; import tlc2.util.RandomGenerator; import tlc2.util.statistics.DummyBucketStatistics; -import tlc2.value.Value; +import tlc2.value.IValue; +import util.Assert.TLCRuntimeException; import util.FileUtil; import util.FilenameToStream; -public class Simulator implements Cancelable { +public class Simulator { - public static boolean EXPERIMENTAL_LIVENESS_SIMULATION = Boolean.getBoolean(Simulator.class.getName() + ".experimentalLiveness"); - + public static boolean EXPERIMENTAL_LIVENESS_SIMULATION = Boolean + .getBoolean(Simulator.class.getName() + ".experimentalLiveness"); /* Constructors */ - /** - * SZ Feb 20, 2009: added the possibility to pass the SpecObject, this is - * compatibility constructor - * @throws IOException - * - * @deprecated use - * {@link Simulator#Simulator(String, String, String, boolean, int, long, RandomGenerator, long, boolean, FilenameToStream, SpecObj)} - * instead and pass the <code>null</code> as SpecObj - */ - public Simulator(String specFile, String configFile, String traceFile, boolean deadlock, int traceDepth, - long traceNum, RandomGenerator rng, long seed, boolean preprocess, FilenameToStream resolver) throws IOException { - this(specFile, configFile, traceFile, deadlock, traceDepth, traceNum, rng, seed, preprocess, resolver, null); - } // SZ Feb 20, 2009: added the possibility to pass the SpecObject public Simulator(String specFile, String configFile, String traceFile, boolean deadlock, int traceDepth, - long traceNum, RandomGenerator rng, long seed, boolean preprocess, FilenameToStream resolver, - SpecObj specObj) throws IOException { + long traceNum, RandomGenerator rng, long seed, FilenameToStream resolver, + int numWorkers) throws IOException { int lastSep = specFile.lastIndexOf(FileUtil.separatorChar); String specDir = (lastSep == -1) ? "" : specFile.substring(0, lastSep + 1); specFile = specFile.substring(lastSep + 1); @@ -60,14 +56,9 @@ public class Simulator implements Cancelable { this.tool = new Tool(specDir, specFile, configFile, resolver); - this.tool.init(preprocess, specObj); // parse and process the spec - this.checkDeadlock = deadlock; this.checkLiveness = !this.tool.livenessIsTrue(); - this.actions = this.tool.getActions(); this.invariants = this.tool.getInvariants(); - this.impliedActions = this.tool.getImpliedActions(); - this.numOfGenStates = 0; if (traceDepth != -1) { // this.actionTrace = new Action[traceDepth]; // SZ: never read // locally @@ -81,241 +72,284 @@ public class Simulator implements Cancelable { this.rng = rng; this.seed = seed; this.aril = 0; - this.astCounts = new ObjLongTable(10); + this.numWorkers = numWorkers; + this.workers = new ArrayList<>(numWorkers); // Initialization for liveness checking if (this.checkLiveness) { if (EXPERIMENTAL_LIVENESS_SIMULATION) { final String tmpDir = System.getProperty("java.io.tmpdir"); - liveCheck = new LiveCheck(this.tool, new Action[0], tmpDir, new DummyBucketStatistics()); + liveCheck = new LiveCheck(this.tool, tmpDir, new DummyBucketStatistics()); } else { liveCheck = new LiveCheck1(this.tool); } } else { liveCheck = new NoOpLiveCheck(tool, specDir); } + + if (TLCGlobals.isCoverageEnabled()) { + CostModelCreator.create(this.tool); + } + + //TODO Eventually derive Simulator from AbstractChecker. + AbstractChecker.scheduleTermination(new TimerTask() { + @Override + public void run() { + Simulator.this.stop(); + } + }); } /* Fields */ private final ILiveCheck liveCheck; - private final Tool tool; - private final Action[] actions; // the sub actions + private final ITool tool; private final Action[] invariants; // the invariants to be checked - private final Action[] impliedActions; // the implied-actions to be checked private final boolean checkDeadlock; // check deadlock? private final boolean checkLiveness; // check liveness? - private long numOfGenStates; + + // The total number of states/traces generated by all workers. May be written to + // concurrently, so we use a LongAdder to reduce potential contention. + private final LongAdder numOfGenStates = new LongAdder(); + private final LongAdder numOfGenTraces = new LongAdder(); + // private Action[] actionTrace; // SZ: never read locally private final String traceFile; + + // The maximum length of a simulated trace. private final long traceDepth; + + // The maximum number of total traces to generate. private final long traceNum; + + // The number of worker threads to use for simulation. + private int numWorkers = 1; + private final RandomGenerator rng; private final long seed; private long aril; - private final ObjLongTable astCounts; - private boolean isCancelled; // SZ Feb 24, 2009: cancellation added - private Value[] localValues = new Value[4]; + private IValue[] localValues = new IValue[4]; + + // The set of all initial states for the given spec. This should be only be + // computed once and re-used whenever a new random trace is generated. This + // variable should not be written to concurrently, but is allowed to be read + // concurrently. + private StateVec initStates = new StateVec(0); + + // Each simulation worker pushes their results onto this shared queue. + private BlockingQueue<SimulationWorkerResult> workerResultQueue = new LinkedBlockingQueue<>(); + + /** + * Timestamp of when simulation started. + */ + private final long startTime = System.currentTimeMillis(); + + private final List<SimulationWorker> workers; + + /** + * Returns whether a given error code is considered "continuable". That is, if + * any worker returns this error, should we consider continuing to run the + * simulator. These errors are considered "fatal" since they most likely + * indicate an error in the way the spec is written. + */ + private boolean isNonContinuableError(int ec) { + return ec == EC.TLC_INVARIANT_EVALUATION_FAILED || + ec == EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED || + ec == EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT; + } + + /** + * Shut down all of the given workers and make sure they have stopped. + */ + private void shutdownAndJoinWorkers(final List<SimulationWorker> workers) throws InterruptedException { + for (SimulationWorker worker : workers) { + worker.interrupt(); + worker.join(); + } + } /* - * This method does simulation on a TLA+ spec. Its argument specifies the - * main module of the TLA+ spec. + * This method does random simulation on a TLA+ spec. + * + * It runs until en error is encountered or we have generated the maximum number of traces. + * + * @return an error code, or <code>EC.NO_ERROR</code> on success */ - public void simulate() throws Exception { - StateVec theInitStates = null; + public int simulate() throws Exception { TLCState curState = null; - if (isCancelled) { - return; - } - // Compute the initial states: + // + // Compute the initial states. + // try { + // The init states are calculated only ever once and never change // in the loops below. Ideally the variable would be final. - theInitStates = this.tool.getInitStates(); - this.numOfGenStates = theInitStates.size(); - for (int i = 0; i < theInitStates.size(); i++) { - curState = theInitStates.elementAt(i); + this.initStates = this.tool.getInitStates(); + + // This counter should always be initialized at zero. + assert (this.numOfGenStates.longValue() == 0); + this.numOfGenStates.add(this.initStates.size()); + + MP.printMessage(EC.TLC_COMPUTING_INIT_PROGRESS, this.numOfGenStates.toString()); + + // Check all initial states for validity. + for (int i = 0; i < this.initStates.size(); i++) { + curState = this.initStates.elementAt(i); if (this.tool.isGoodState(curState)) { for (int j = 0; j < this.invariants.length; j++) { if (!this.tool.isValid(this.invariants[j], curState)) { - // We get here because of invariant violation: - MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, + // We get here because of invariant violation. + return MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { this.tool.getInvNames()[j], curState.toString() }); - return; } } } else { - MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL, curState.toString()); - return; + return MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL, curState.toString()); } } } catch (Exception e) { - // Assert.printStack(e); + final int errorCode; if (curState != null) { - MP.printError(EC.TLC_INITIAL_STATE, + errorCode = MP.printError(EC.TLC_INITIAL_STATE, new String[] { (e.getMessage() == null) ? e.toString() : e.getMessage(), curState.toString() }); } else { - MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 + errorCode = MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 } this.printSummary(); - return; + return errorCode; } - if (this.numOfGenStates == 0) { - MP.printError(EC.TLC_NO_STATES_SATISFYING_INIT); - return; + + if (this.numOfGenStates.longValue() == 0) { + return MP.printError(EC.TLC_NO_STATES_SATISFYING_INIT); } + // It appears deepNormalize brings the states into a canonical form to // speed up equality checks. - theInitStates.deepNormalize(); + this.initStates.deepNormalize(); - // Start progress report thread: + // + // Start progress report thread. + // final ProgressReport report = new ProgressReport(); report.start(); - // Start simulating: - final StateVec stateTrace = new StateVec((int) traceDepth); - int idx = 0; - try { - // The two loops essentially do: - // a) Pick one of the initial states for as long as the bahavior's length is less than traceCnt - // b) Randomly pick an action to generate the successor states (more than 1) to the current initial state - // c) Check all of the generated successors for their validity - // d) Randomly pick a generated successor and make it curState - for (int traceCnt = 1; traceCnt <= this.traceNum; traceCnt++) { - this.aril = rng.getAril(); - stateTrace.clear(); - - // a) Randomly select a state from the set of init states. - curState = this.randomState(theInitStates); - boolean inConstraints = this.tool.isInModel(curState); - - for (int traceIdx = 0; traceIdx < this.traceDepth; traceIdx++) { - // Add the curState to the trace regardless of its inModel - // property. - stateTrace.addElement(curState); - - if (!inConstraints) { - break; - } - - // b) Get the curState's successor states - StateVec nextStates = this.randomNextStates(curState); - if (nextStates == null) { - if (this.checkDeadlock) { - // We get here because of deadlock: - this.printBehavior(EC.TLC_DEADLOCK_REACHED, null, curState, stateTrace); - if (!TLCGlobals.continuation) { - return; - } - } - break; - } - - // c) Check all generated next states before all but one are - // discarded - for (int i = 0; i < nextStates.size(); i++) { - this.numOfGenStates++; - TLCState state = nextStates.elementAt(i); + // + // Start simulating. + // + this.aril = rng.getAril(); + + // Start up multiple simulation worker threads, each with their own unique seed. + final Set<Integer> runningWorkers = new HashSet<>(); + for (int i = 0; i < this.numWorkers; i++) { + final SimulationWorker worker = new SimulationWorker(i, this.tool, initStates, this.workerResultQueue, + this.rng.nextLong(), this.traceDepth, this.traceNum, this.checkDeadlock, this.traceFile, + this.liveCheck, this.numOfGenStates, this.numOfGenTraces); + + worker.start(); + workers.add(worker); + runningWorkers.add(i); + } - if (TLCGlobals.coverageInterval >= 0) { - ((TLCStateMutSource) state).addCounts(this.astCounts); - } + int errorCode = EC.NO_ERROR; + + // Continuously consume results from all worker threads. + while (true) { + final SimulationWorkerResult result = workerResultQueue.take(); - if (!this.tool.isGoodState(state)) { - this.printBehavior(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, null, state, stateTrace); - return; - } else { - try { - for (idx = 0; idx < this.invariants.length; idx++) { - if (!this.tool.isValid(this.invariants[idx], state)) { - // We get here because of invariant - // violation: - this.printBehavior(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, - new String[] { this.tool.getInvNames()[idx] }, state, stateTrace); - if (!TLCGlobals.continuation) { - return; - } - } - } - } catch (Exception e) { - // Assert.printStack(e); - this.printBehavior(EC.TLC_INVARIANT_EVALUATION_FAILED, - new String[] { this.tool.getInvNames()[idx], e.getMessage() }, state, stateTrace); - return; - } - - try { - for (idx = 0; idx < this.impliedActions.length; idx++) { - if (!this.tool.isValid(this.impliedActions[idx], curState, state)) { - // We get here because of implied-action - // violation: - - this.printBehavior(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, - new String[] { this.tool.getImpliedActNames()[idx] }, state, stateTrace); - if (!TLCGlobals.continuation) { - return; - } - } - } - } catch (Exception e) { - // Assert.printStack(e); - this.printBehavior(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, - new String[] { this.tool.getImpliedActNames()[idx], e.getMessage() }, state, - stateTrace); - return; - } - } + // If the result is an error, print it. + if (result.isError()) { + SimulationWorkerError error = result.error(); + + // We assume that if a worker threw an unexpected exception, there is a bug + // somewhere, so we print out the exception and terminate. In the case of a + // liveness error, which is reported as an exception, we also terminate. + if (error.exception != null) { + if (error.exception instanceof LiveException) { + // In case of a liveness error, there is no need to print out + // the behavior since the liveness checker should take care of that itself. + this.printSummary(); + errorCode = ((LiveException)error.exception).errorCode; + } else if (error.exception instanceof TLCRuntimeException) { + final TLCRuntimeException exception = (TLCRuntimeException)error.exception; + printBehavior(exception, error.state, error.stateTrace); + errorCode = exception.errorCode; + } else { + printBehavior(EC.GENERAL, new String[] { MP.ECGeneralMsg("", error.exception) }, error.state, + error.stateTrace); + errorCode = EC.GENERAL; } - // At this point all generated successor states have been checked for - // their respective validity (isGood/isValid/impliedActions/...). - // d) Then randomly select one of them and make it curState - // for the next iteration of the loop. - TLCState s1 = this.randomState(nextStates); - inConstraints = (this.tool.isInModel(s1) && this.tool.isInActions(curState, s1)); - curState = s1; + break; } - // Check if the current trace satisfies liveness properties. - liveCheck.checkTrace(stateTrace); - - // Write the trace out if desired. The trace is printed in the - // format of TLA module, so that it can be read by TLC again. - if (this.traceFile != null) { - String fileName = this.traceFile + traceCnt; - // TODO is it ok here? - PrintWriter pw = new PrintWriter(FileUtil.newBFOS(fileName)); - pw.println("---------------- MODULE " + fileName + " -----------------"); - for (idx = 0; idx < stateTrace.size(); idx++) { - pw.println("STATE_" + (idx + 1) + " == "); - pw.println(stateTrace.elementAt(idx) + "\n"); - } - pw.println("================================================="); - pw.close(); + // Print the trace for all other errors. + printBehavior(error); + + // For certain, "fatal" errors, we shut down all workers and terminate, + // regardless of the "continue" parameter, since these errors likely indicate a bug in the spec. + if (isNonContinuableError(error.errorCode)) { + errorCode = error.errorCode; + break; + } + + // If the 'continue' option is false, then we always terminate on the + // first error, shutting down all workers. Otherwise, we continue receiving + // results from the worker threads. + if (!TLCGlobals.continuation) { + errorCode = error.errorCode; + break; + } + + if (errorCode == EC.NO_ERROR) + { + errorCode = EC.GENERAL; } } - } catch (Throwable e) { - // Assert.printStack(e); - if (e instanceof LiveException) { - this.printSummary(); - } else { - // LL modified error message on 7 April 2012 - this.printBehavior(EC.GENERAL, new String[] { MP.ECGeneralMsg("", e) }, curState, stateTrace); - } - } finally { - report.isRunning = false; - synchronized (report) { - report.notify(); + // If the result is OK, this indicates that the worker has terminated, so we + // make note of this. If all of the workers have terminated, there is no need to + // continue waiting for results, so we should terminate. + else { + runningWorkers.remove(result.workerId()); + if(runningWorkers.isEmpty()) { + break; + } } } + + // Shut down all workers. + this.shutdownAndJoinWorkers(workers); + + // Do a final progress report. + report.isRunning = false; + synchronized (report) { + report.notify(); + } + // Wait for the progress reporter thread to finish. + report.join(); + + return errorCode; + } + + + public final void printBehavior(final TLCRuntimeException exception, final TLCState state, final StateVec stateTrace) { + MP.printTLCRuntimeException(exception); + printBehavior(state, stateTrace); + } + + public final void printBehavior(SimulationWorkerError error) { + printBehavior(error.errorCode, error.parameters, error.state, error.stateTrace); } /** * Prints out the simulation behavior, in case of an error. (unless we're at * maximum depth, in which case don't!) */ - public final void printBehavior(int errorCode, String[] parameters, TLCState state, final StateVec stateTrace) { - + public final void printBehavior(final int errorCode, final String[] parameters, final TLCState state, final StateVec stateTrace) { MP.printError(errorCode, parameters); + printBehavior(state, stateTrace); + this.printSummary(); + } + + public final void printBehavior(final TLCState state, final StateVec stateTrace) { if (this.traceDepth == Long.MAX_VALUE) { MP.printMessage(EC.TLC_ERROR_STATE); StatePrinter.printState(state); @@ -328,58 +362,18 @@ public class Simulator implements Cancelable { } StatePrinter.printState(state, null, stateTrace.size() + 1); } - this.printSummary(); } - /** - * This method returns a state that is randomly chosen from the set of - * states. It returns null if the set of states is empty. - */ - public final TLCState randomState(StateVec states) throws EvalException { - int len = states.size(); - if (len > 0) { - int index = (int) Math.floor(this.rng.nextDouble() * len); - return states.elementAt(index); - } - return null; - } - - /* - * (non-Javadoc) - * @see tlc2.tool.Cancelable#setCancelFlag(boolean) - */ - public void setCancelFlag(boolean flag) { - this.isCancelled = flag; - } - - /** - * This method returns the set of next states generated by a randomly chosen - * action. It returns null if there is no possible next state. - */ - public final StateVec randomNextStates(TLCState state) { - int len = this.actions.length; - int index = (int) Math.floor(this.rng.nextDouble() * len); - int p = this.rng.nextPrime(); - for (int i = 0; i < len; i++) { - StateVec pstates = this.tool.getNextStates(this.actions[index], state); - if (!pstates.empty()) { - return pstates; - } - index = (index + p) % len; - } - return null; - } - - public Value getLocalValue(int idx) { + public IValue getLocalValue(int idx) { if (idx < this.localValues.length) { return this.localValues[idx]; } return null; } - public void setLocalValue(int idx, Value val) { + public void setLocalValue(int idx, IValue val) { if (idx >= this.localValues.length) { - Value[] vals = new Value[idx + 1]; + IValue[] vals = new IValue[idx + 1]; System.arraycopy(this.localValues, 0, vals, 0, this.localValues.length); this.localValues = vals; } @@ -394,14 +388,13 @@ public class Simulator implements Cancelable { /* * This allows the toolbox to easily display the last set of state space - * statistics by putting them in the same form as all other progress - * statistics. + * statistics by putting them in the same form as all other progress statistics. */ if (TLCGlobals.tool) { - MP.printMessage(EC.TLC_PROGRESS_SIMU, String.valueOf(this.numOfGenStates)); + MP.printMessage(EC.TLC_PROGRESS_SIMU, String.valueOf(numOfGenStates.longValue())); } - MP.printMessage(EC.TLC_STATS_SIMU, new String[] { String.valueOf(this.numOfGenStates), + MP.printMessage(EC.TLC_STATS_SIMU, new String[] { String.valueOf(numOfGenStates.longValue()), String.valueOf(this.seed), String.valueOf(this.aril) }); } @@ -409,21 +402,8 @@ public class Simulator implements Cancelable { * Reports coverage */ public final void reportCoverage() { - if (TLCGlobals.coverageInterval >= 0) { - MP.printMessage(EC.TLC_COVERAGE_START); - ObjLongTable counts = this.tool.getPrimedLocs(); - ObjLongTable.Enumerator keys = this.astCounts.keys(); - Object key; - while ((key = keys.nextElement()) != null) { - String loc = ((SemanticNode) key).getLocation().toString(); - counts.add(loc, astCounts.get(key)); - } - Object[] skeys = counts.sortStringKeys(); - for (int i = 0; i < skeys.length; i++) { - long val = counts.get(skeys[i]); - MP.printMessage(EC.TLC_COVERAGE_VALUE, new String[] { skeys[i].toString(), String.valueOf(val) }); - } - MP.printMessage(EC.TLC_COVERAGE_END); + if (TLCGlobals.isCoverageEnabled()) { + CostModelCreator.report(this.tool, this.startTime ); } } @@ -431,9 +411,9 @@ public class Simulator implements Cancelable { * Reports progress information */ final class ProgressReport extends Thread { - + volatile boolean isRunning = true; - + public void run() { int count = TLCGlobals.coverageInterval / TLCGlobals.progressInterval; try { @@ -441,8 +421,7 @@ public class Simulator implements Cancelable { synchronized (this) { this.wait(TLCGlobals.progressInterval); } - MP.printMessage(EC.TLC_PROGRESS_SIMU, String.valueOf(numOfGenStates)); - + MP.printMessage(EC.TLC_PROGRESS_SIMU, String.valueOf(numOfGenStates.longValue())); if (count > 1) { count--; } else { @@ -456,4 +435,10 @@ public class Simulator implements Cancelable { } } } + + public void stop() { + for (SimulationWorker worker : workers) { + worker.interrupt(); + } + } } diff --git a/tlatools/src/tlc2/tool/Specs.java b/tlatools/src/tlc2/tool/Specs.java new file mode 100644 index 0000000000000000000000000000000000000000..4ff9e63c91c4bebaae73a8ca12a5f5bc86a357de --- /dev/null +++ b/tlatools/src/tlc2/tool/Specs.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import java.util.HashSet; +import java.util.Iterator; + +import tla2sany.semantic.ExprNode; +import tla2sany.semantic.LevelNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SubstInNode; +import tla2sany.semantic.SymbolNode; +import tlc2.util.Context; +import tlc2.util.List; +import tlc2.value.impl.LazyValue; + +public abstract class Specs { + + /** + * The level of the expression according to level checking. + * static method, does not change instance state + */ + public static int getLevel(LevelNode expr, Context c) + { + HashSet<SymbolNode> lpSet = expr.getLevelParams(); + if (lpSet.isEmpty()) + return expr.getLevel(); + + int level = expr.getLevel(); + Iterator<SymbolNode> iter = lpSet.iterator(); + while (iter.hasNext()) + { + SymbolNode param = (SymbolNode) iter.next(); + Object res = c.lookup(param, true); + if (res != null) + { + if (res instanceof LazyValue) + { + LazyValue lv = (LazyValue) res; + int plevel = getLevel((LevelNode) lv.expr, lv.con); + level = (plevel > level) ? plevel : level; + } else if (res instanceof OpDefNode) + { + int plevel = getLevel((LevelNode) res, c); + level = (plevel > level) ? plevel : level; + } + } + } + return level; + } + + /** + * Static method, does not change instance state + * @param expr + * @param subs + * @return + */ + public static final ExprNode addSubsts(ExprNode expr, List subs) + { + ExprNode res = expr; + + while (!subs.isEmpty()) + { + SubstInNode sn = (SubstInNode) subs.car(); + res = new SubstInNode(sn.stn, sn.getSubsts(), res, sn.getInstantiatingModule(), sn.getInstantiatedModule()); + subs = subs.cdr(); + } + return res; + } +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/StateVec.java b/tlatools/src/tlc2/tool/StateVec.java index 82465eb6477090e0a08ab1a0bc8a56d933e2c7be..617136b5dac4e114131f2e6fa7a857d0b92f2a51 100644 --- a/tlatools/src/tlc2/tool/StateVec.java +++ b/tlatools/src/tlc2/tool/StateVec.java @@ -5,12 +5,9 @@ package tlc2.tool; -import tla2sany.semantic.SemanticNode; import tlc2.TLCGlobals; import tlc2.output.EC; -import tlc2.value.Value; import util.Assert; -import util.UniqueString; /* * This class represents a TLA+ state vector. @@ -68,22 +65,6 @@ public final class StateVec implements IStateFunctor { this.size = 0; } - // Add the binding to all the variables - public final StateVec bind(UniqueString var, Value val, SemanticNode ast) { - for (int i = 0; i < this.size; i++) { - TLCState s = this.v[i]; - if (s.containsKey(var)) return null; - v[i] = s.bind(var, val, ast); - } - return this; - } - - // Bind a value in one of the states. - public final StateVec bindAt(int i, UniqueString var, Value val, SemanticNode ast) { - v[i] = v[i].bind(var, val, ast); - return this; - } - /* (non-Javadoc) * @see tlc2.tool.IStateFunction#addElement(tlc2.tool.TLCState) */ @@ -122,6 +103,14 @@ public final class StateVec implements IStateFunctor { this.size--; } + public void removeAt(final int index) { + replaceAt(index, null); + } + + public void replaceAt(final int index, final TLCState state) { + this.v[index] = state; + } + public final StateVec copy() { TLCState[] res = new TLCState[this.size]; for (int i = 0; i < this.size; i++) { diff --git a/tlatools/src/tlc2/tool/TLCState.java b/tlatools/src/tlc2/tool/TLCState.java index 4203c5bd274280329fec852456b0d3adad78596c..cd1f86de4700ec9c402b54943269146f53f9e616 100644 --- a/tlatools/src/tlc2/tool/TLCState.java +++ b/tlatools/src/tlc2/tool/TLCState.java @@ -12,52 +12,57 @@ import java.util.Map; import java.util.Set; import tla2sany.semantic.OpDeclNode; -import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; -import tlc2.value.Value; -import tlc2.value.ValueInputStream; -import tlc2.value.ValueOutputStream; +import tlc2.output.EC; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import util.Assert; import util.UniqueString; public abstract class TLCState implements Cloneable, Serializable { + public short workerId = Short.MAX_VALUE; // Must be set to a non-negative number. Valid worker ids \in [0,Short.MAX_VALUE] and start at 0. public long uid = -1; // Must be set to a non-negative number - public short level = 0; + private int level = 1; // Set by subclasses. Cannot set until we know what the variables are. public static TLCState Empty = null; // The state variables. public static OpDeclNode[] vars = null; - - public static void setVariables(OpDeclNode[] variables) - { - vars = variables; - // SZ 10.04.2009: since this method is called exactly one from Spec#processSpec - // moved the call of UniqueString#setVariables to that place - - // UniqueString[] varNames = new UniqueString[variables.length]; - // for (int i = 0; i < varNames.length; i++) - // { - // varNames[i] = variables[i].getName(); - //} - //UniqueString.setVariables(varNames); - } - public void read(ValueInputStream vis) throws IOException { - this.uid = vis.readLongNat(); + public void read(IValueInputStream vis) throws IOException { + this.workerId = vis.readShortNat(); + this.uid = vis.readLongNat(); this.level = vis.readShortNat(); assert this.level >= 0; // Should never overflow. } - public void write(ValueOutputStream vos) throws IOException { - vos.writeLongNat(this.uid); - vos.writeShortNat(this.level); - } + public void write(IValueOutputStream vos) throws IOException { + if (this.level > Short.MAX_VALUE) { + // The on-disk representation of TLCState limits the diameter/level to + // Short.MAX_VALUE whereas the in-memory rep supports int. The underlying + // assumption being that state spaces with a diameter beyond 32767 AND which + // require TLC to swap the state queue to disk are infeasible to check anyway. + // However, one can easily come up with a spec that corresponds to few, very long + // behaviors which can be kept in memory. + Assert.fail(EC.TLC_TRACE_TOO_LONG, this.toString()); + } + vos.writeShortNat(this.workerId); + vos.writeLongNat(this.uid); + vos.writeShortNat((short) this.level); + } - public abstract TLCState bind(UniqueString name, Value value, SemanticNode expr); - public abstract TLCState bind(SymbolNode id, Value value, SemanticNode expr); + public abstract TLCState bind(UniqueString name, IValue value); + public abstract TLCState bind(SymbolNode id, IValue value); public abstract TLCState unbind(UniqueString name); - public abstract Value lookup(UniqueString var); + /** + * Convenience method when performance doesn't matter. + */ + public IValue lookup(String var) { + return lookup(UniqueString.uniqueStringOf(var)); + } + public abstract IValue lookup(UniqueString var); public abstract boolean containsKey(UniqueString var); public abstract TLCState copy(); public abstract TLCState deepCopy(); @@ -71,18 +76,29 @@ public abstract class TLCState implements Cloneable, Serializable { /** * Returns a mapping of variable names to their assigned values in this state. */ - public Map<UniqueString, Value> getVals() { - final Map<UniqueString, Value> valMap = new HashMap<UniqueString, Value>(); + public final Map<UniqueString, IValue> getVals() { + final Map<UniqueString, IValue> valMap = new HashMap<UniqueString, IValue>(); for(int i = 0; i < vars.length; i++) { UniqueString key = vars[i].getName(); - Value val = this.lookup(key); + IValue val = this.lookup(key); valMap.put(key, val); } return valMap; } - public boolean isInitial() { - return this.level == 0; + public final void setPredecessor(final TLCState predecessor) { + if (predecessor.getLevel() == Integer.MAX_VALUE) { + Assert.fail(EC.TLC_TRACE_TOO_LONG, this.toString()); + } + this.level = predecessor.getLevel() + 1; + } + + public final int getLevel() { + return this.level; + } + + public final boolean isInitial() { + return this.level == 1; } /* Returns a string representation of this state. */ diff --git a/tlatools/src/tlc2/tool/TLCStateFun.java b/tlatools/src/tlc2/tool/TLCStateFun.java index 8f5470a40fdac8d16bbe607062c0c2aee375028b..389ae6e07d45124130b674ca632c46d7974455da 100644 --- a/tlatools/src/tlc2/tool/TLCStateFun.java +++ b/tlatools/src/tlc2/tool/TLCStateFun.java @@ -10,12 +10,12 @@ import java.util.HashSet; import java.util.Set; import tla2sany.semantic.OpDeclNode; -import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.util.Context; -import tlc2.value.Value; -import tlc2.value.ValueInputStream; -import tlc2.value.ValueOutputStream; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.impl.Value; import util.UniqueString; import util.WrongInvocationException; @@ -27,12 +27,12 @@ import util.WrongInvocationException; */ public final class TLCStateFun extends TLCState { private SymbolNode name; - private Value value; + private IValue value; private TLCStateFun next; public final static TLCState Empty = new TLCStateFun(null, null, null); - private TLCStateFun(SymbolNode name, Value value, TLCStateFun state) { + private TLCStateFun(SymbolNode name, IValue value, TLCStateFun state) { this.name = name; this.value = value; this.next = state; @@ -40,11 +40,11 @@ public final class TLCStateFun extends TLCState { public final TLCState createEmpty() { return Empty; } - public final TLCState bind(UniqueString name, Value value, SemanticNode expr) { + public final TLCState bind(UniqueString name, IValue value) { throw new WrongInvocationException("TLCStateFun.bind: This is a TLC bug."); } - public final TLCState bind(SymbolNode id, Value value, SemanticNode expr) { + public final TLCState bind(SymbolNode id, IValue value) { return new TLCStateFun(id, value, this); } @@ -52,7 +52,7 @@ public final class TLCStateFun extends TLCState { throw new WrongInvocationException("TLCStateFun.unbind: This is a TLC bug."); } - public final Value lookup(UniqueString var) { + public final IValue lookup(UniqueString var) { for (TLCStateFun cur = this; cur != Empty; cur = cur.next) { if (var == cur.name.getName()) return cur.value; } @@ -98,11 +98,11 @@ public final class TLCStateFun extends TLCState { return states.addElement(this); } - public final void read(ValueInputStream vis) throws IOException { + public final void read(IValueInputStream vis) throws IOException { throw new WrongInvocationException("TLCStateFun.read: This is a TLC bug."); } - public final void write(ValueOutputStream vos) throws IOException { + public final void write(IValueOutputStream vos) throws IOException { throw new WrongInvocationException("TLCStateFun.write: This is a TLC bug."); } diff --git a/tlatools/src/tlc2/tool/TLCStateMut.java b/tlatools/src/tlc2/tool/TLCStateMut.java index 883fef603431cda120a84949a0064888df4959e8..acf1645bf6f4767bb7b4877ba892f2f93a389cb0 100644 --- a/tlatools/src/tlc2/tool/TLCStateMut.java +++ b/tlatools/src/tlc2/tool/TLCStateMut.java @@ -17,10 +17,11 @@ import tla2sany.semantic.SymbolNode; import tlc2.TLCGlobals; import tlc2.util.Context; import tlc2.util.FP64; -import tlc2.value.MVPerm; -import tlc2.value.Value; -import tlc2.value.ValueInputStream; -import tlc2.value.ValueOutputStream; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.UniqueString; import util.WrongInvocationException; @@ -33,8 +34,8 @@ import util.WrongInvocationException; * The viewMap was added by Rajeev Joshi. */ public final class TLCStateMut extends TLCState implements Cloneable, Serializable { - private Value values[]; - private static Tool mytool = null; + private IValue values[]; + private static ITool mytool = null; /** * If non-null, viewMap denotes the function to be applied to @@ -46,20 +47,35 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab * If non-null, perms denotes the set of permutations under the * symmetry assumption. */ - private static MVPerm[] perms = null; + private static IMVPerm[] perms = null; - private TLCStateMut(Value[] vals) { this.values = vals; } + private TLCStateMut(IValue[] vals) { this.values = vals; } + + public static void setVariables(OpDeclNode[] variables) + { + vars = variables; + IValue[] vals = new IValue[vars.length]; + Empty = new TLCStateMut(vals); + + // SZ 10.04.2009: since this method is called exactly one from Spec#processSpec + // moved the call of UniqueString#setVariables to that place + + // UniqueString[] varNames = new UniqueString[variables.length]; + // for (int i = 0; i < varNames.length; i++) + // { + // varNames[i] = variables[i].getName(); + //} + //UniqueString.setVariables(varNames); + } - public static void init(Tool tool) { + public static void setTool(ITool tool) { mytool = tool; - Value[] vals = new Value[vars.length]; - Empty = new TLCStateMut(vals); viewMap = tool.getViewSpec(); perms = tool.getSymmetryPerms(); } public final TLCState createEmpty() { - Value[] vals = new Value[vars.length]; + IValue[] vals = new IValue[vars.length]; return new TLCStateMut(vals); } @@ -81,14 +97,14 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab return false; } - public final TLCState bind(UniqueString name, Value value, SemanticNode expr) { + public final TLCState bind(UniqueString name, IValue value) { // Note, tla2sany.semantic.OpApplNode.toString(Value) relies on this ordering. int loc = name.getVarLoc(); this.values[loc] = value; return this; } - public final TLCState bind(SymbolNode id, Value value, SemanticNode expr) { + public final TLCState bind(SymbolNode id, IValue value) { throw new WrongInvocationException("TLCStateMut.bind: This is a TLC bug."); } @@ -98,7 +114,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab return this; } - public final Value lookup(UniqueString var) { + public final IValue lookup(UniqueString var) { int loc = var.getVarLoc(); if (loc < 0) return null; return this.values[loc]; @@ -110,7 +126,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab public final TLCState copy() { int len = this.values.length; - Value[] vals = new Value[len]; + IValue[] vals = new IValue[len]; for (int i = 0; i < len; i++) { vals[i] = this.values[i]; } @@ -119,9 +135,9 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab public final TLCState deepCopy() { int len = this.values.length; - Value[] vals = new Value[len]; + IValue[] vals = new IValue[len]; for (int i = 0; i < len; i++) { - Value val = this.values[i]; + IValue val = this.values[i]; if (val != null) { vals[i] = val.deepCopy(); } @@ -135,7 +151,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab public final void deepNormalize() { for (int i = 0; i < this.values.length; i++) { - Value val = this.values[i]; + IValue val = this.values[i]; if (val != null) { val.deepNormalize(); } @@ -184,9 +200,9 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab // If this state is not the lexicographically smallest state ss, its current // minVals will be replaced temporarily with the values of ss for the // calculation of the fingerprint. - Value[] minVals = this.values; + IValue[] minVals = this.values; if (perms != null) { - Value[] vals = new Value[sz]; + IValue[] vals = new IValue[sz]; // The following for loop converges to the smallest state ss under symmetry by // looping over all permutations applying each. If the outcome turns out to be // lexicographically smaller than the currently smallest, it replaces the @@ -220,9 +236,9 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab if (cmp < 0) { if (minVals == this.values) { minVals = vals; - vals = new Value[sz]; + vals = new IValue[sz]; } else { - Value[] temp = minVals; + IValue[] temp = minVals; minVals = vals; vals = temp; } @@ -248,7 +264,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab if (minVals != this.values) { state = new TLCStateMut(minVals); } - Value val = mytool.eval(viewMap, Context.Empty, state); + IValue val = mytool.eval(viewMap, Context.Empty, state); fp = val.fingerPrint(fp); } return fp; @@ -279,7 +295,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab return unassignedVars; } - public final void read(ValueInputStream vis) throws IOException { + public final void read(IValueInputStream vis) throws IOException { super.read(vis); int len = this.values.length; for (int i = 0; i < len; i++) { @@ -287,38 +303,38 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab } } - public final void write(ValueOutputStream vos) throws IOException { + public final void write(IValueOutputStream vos) throws IOException { super.write(vos); int len = this.values.length; for (int i = 0; i < len; i++) { - vos.write(this.values[i]); + this.values[i].write(vos); } } /* Returns a string representation of this state. */ public final String toString() { if (TLCGlobals.useView && viewMap != null) { - Value val = mytool.eval(viewMap, Context.Empty, this); + IValue val = mytool.eval(viewMap, Context.Empty, this); return viewMap.toString(val); } StringBuffer result = new StringBuffer(); int vlen = vars.length; if (vlen == 1) { UniqueString key = vars[0].getName(); - Value val = this.lookup(key); + IValue val = this.lookup(key); result.append(key.toString()); result.append(" = "); - result.append(Value.ppr(val)); + result.append(Values.ppr(val)); result.append("\n"); } else { for (int i = 0; i < vlen; i++) { UniqueString key = vars[i].getName(); - Value val = this.lookup(key); + IValue val = this.lookup(key); result.append("/\\ "); result.append(key.toString()); result.append(" = "); - result.append(Value.ppr(val)); + result.append(Values.ppr(val)); result.append("\n"); } } @@ -333,22 +349,22 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab int vlen = vars.length; if (vlen == 1) { UniqueString key = vars[0].getName(); - Value val = this.lookup(key); - Value lstateVal = lstate.lookup(key); + IValue val = this.lookup(key); + IValue lstateVal = lstate.lookup(key); if (!lstateVal.equals(val)) { result.append(key.toString()); - result.append(" = " + Value.ppr(val) + "\n"); + result.append(" = " + Values.ppr(val) + "\n"); } } else { for (int i = 0; i < vlen; i++) { UniqueString key = vars[i].getName(); - Value val = this.lookup(key); - Value lstateVal = lstate.lookup(key); + IValue val = this.lookup(key); + IValue lstateVal = lstate.lookup(key); if (!lstateVal.equals(val)) { result.append("/\\ "); result.append(key.toString()); - result.append(" = " + Value.ppr(val) + "\n"); + result.append(" = " + Values.ppr(val) + "\n"); } } } diff --git a/tlatools/src/tlc2/tool/TLCStateMutSource.java b/tlatools/src/tlc2/tool/TLCStateMutSource.java index 2df3b9249ea4619364efe97ab06210eeacefccb4..8f9a2a18496afbccad7d89e7618bdf59d9a48a6e 100644 --- a/tlatools/src/tlc2/tool/TLCStateMutSource.java +++ b/tlatools/src/tlc2/tool/TLCStateMutSource.java @@ -1,343 +1,344 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Mon 30 Apr 2007 at 15:30:02 PST by lamport -// modified on Fri Aug 24 15:08:38 PDT 2001 by yuanyu - -package tlc2.tool; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Comparator; -import java.util.Set; -import java.util.TreeSet; - -import tla2sany.semantic.OpDeclNode; -import tla2sany.semantic.SemanticNode; -import tla2sany.semantic.SymbolNode; -import tlc2.TLCGlobals; -import tlc2.util.Context; -import tlc2.util.FP64; -import tlc2.util.ObjLongTable; -import tlc2.value.MVPerm; -import tlc2.value.Value; -import tlc2.value.ValueInputStream; -import tlc2.value.ValueOutputStream; -import util.UniqueString; -import util.WrongInvocationException; - -/** - * This class represents a TLA+ state, which simply is an assignment - * of explicit values to all the global variables. This is the - * mutable version, which means that in-place updates are used for - * improved performance and reduced allocation. - * - * The viewMap was added by Rajeev Joshi. - */ -public final class TLCStateMutSource extends TLCState -implements Cloneable, Serializable { - private Value[] values; - private SemanticNode[] asts; - private static Tool mytool = null; - - /** - * If non-null, viewMap denotes the function to be applied to - * a state before its fingerprint is computed. - */ - private static SemanticNode viewMap = null; - - /** - * If non-null, perms denotes the set of permutations under - * the symmetry assumption. - */ - private static MVPerm[] perms = null; - - private TLCStateMutSource(Value[] vals, SemanticNode[] asts) { - this.values = vals; - this.asts = asts; - } - - public static void init(Tool tool) { - mytool = tool; - Value[] vals = new Value[vars.length]; - SemanticNode[] snodes = new SemanticNode[vars.length]; - Empty = new TLCStateMutSource(vals, snodes); - viewMap = tool.getViewSpec(); - perms = tool.getSymmetryPerms(); - } - - public final TLCState createEmpty() { - int sz = vars.length; - return new TLCStateMutSource(new Value[sz], new SemanticNode[sz]); - } - - public final boolean equals(Object obj) { - if (obj instanceof TLCStateMutSource) { - TLCStateMutSource state = (TLCStateMutSource)obj; - for (int i = 0; i < this.values.length; i++) { - if (this.values[i] == null) { - if (state.values[i] != null) return false; - } - else if (state.values[i] == null || - !this.values[i].equals(state.values[i])) { - return false; - } - } - return true; - } - return false; - } - - public final TLCState bind(UniqueString name, Value value, SemanticNode ast) { - int loc = name.getVarLoc(); - this.values[loc] = value; - if (this.asts != null) { - this.asts[loc] = ast; - } - return this; - } - - public final TLCState bind(SymbolNode id, Value value, SemanticNode expr) { - throw new WrongInvocationException("TLCStateMutSource.bind: This is a TLC bug."); - } - - public final TLCState unbind(UniqueString name) { - int loc = name.getVarLoc(); - this.values[loc] = null; - this.asts[loc] = null; - return this; - } - - public final Value lookup(UniqueString var) { - int loc = var.getVarLoc(); - if (loc < 0) return null; - return this.values[loc]; - } - - public final boolean containsKey(UniqueString var) { - return (this.lookup(var) != null); - } - - public final TLCState copy() { - int len = this.values.length; - Value[] vals = new Value[len]; - SemanticNode[] astClone = new SemanticNode[len]; - for (int i = 0; i < len; i++) { - vals[i] = this.values[i]; - astClone[i] = this.asts[i]; - } - return new TLCStateMutSource(vals, astClone); - } - - public final TLCState deepCopy() { - int len = this.values.length; - Value[] vals = new Value[len]; - SemanticNode[] astClone = new SemanticNode[len]; - for (int i = 0; i < len; i++) { - Value val = this.values[i]; - if (val != null) { - vals[i] = val.deepCopy(); - astClone[i] = this.asts[i]; - } - } - return new TLCStateMutSource(vals, astClone); - } - - public final StateVec addToVec(StateVec states) { - return states.addElement(this.copy()); - } - - public final void deepNormalize() { - for (int i = 0; i < this.values.length; i++) { - Value val = this.values[i]; - if (val != null) { - val.deepNormalize(); - } - } - } - - private final void readObject(ObjectInputStream ois) - throws IOException, ClassNotFoundException { - this.values = (Value[])ois.readObject(); - this.asts = null; - } - - private final void writeObject(ObjectOutputStream oos) throws IOException { - oos.writeObject(this.values); - } - - /** - * This method returns the fingerprint of this state. We fingerprint - * the values in the state according to the order given by vars. - * This guarantees the same state has the same fingerprint. - * - * Since the values in this state can be shared by multiple threads - * via the state queue. They have to be normalized before adding to - * the state queue. We do that here. - * - * @see TLCStateMut#fingerPrint() for a commented version of this - * implementation. - */ - public final long fingerPrint() { - int sz = this.values.length; - - Value[] minVals = this.values; - if (perms != null) { - Value[] vals = new Value[sz]; - // Find the "smallest" state under the symmetry permutations: - for (int i = 0; i < perms.length; i++) { - int cmp = 0; - for (int j = 0; j < sz; j++) { - vals[j] = this.values[j].permute(perms[i]); - if (cmp == 0) { - cmp = vals[j].compareTo(minVals[j]); - } - } - if (cmp < 0) { - if (minVals == this.values) { - minVals = vals; - vals = new Value[sz]; - } - else { - Value[] temp = minVals; - minVals = vals; - vals = temp; - } - } - } - } - // Fingerprint the state: - long fp = FP64.New(); - if (viewMap == null) { - for (int i = 0; i < sz; i++) { - fp = minVals[i].fingerPrint(fp); - } - if (this.values != minVals) { - for (int i = 0; i < sz; i++) { - this.values[i].deepNormalize(); - } - } - } - else { - for (int i = 0; i < sz; i++) { - this.values[i].deepNormalize(); - } - TLCStateMutSource state = this; - if (minVals != this.values) { - state = new TLCStateMutSource(minVals, this.asts); - } - Value val = mytool.eval(viewMap, Context.Empty, state); - fp = val.fingerPrint(fp); - } - return fp; - } - - public final void addCounts(ObjLongTable counts) { - for (int i = 0; i < this.asts.length; i++) { - counts.add(this.asts[i], 1); - } - } - - public final boolean allAssigned() { - int len = this.values.length; - for (int i = 0; i < len; i++) { - if (values[i] == null) return false; - } - return true; - } - - public final Set<OpDeclNode> getUnassigned() { - // Return sorted set (lexicographical). - final Set<OpDeclNode> unassignedVars = new TreeSet<OpDeclNode>(new Comparator<OpDeclNode>() { - @Override - public int compare(OpDeclNode o1, OpDeclNode o2) { - return o1.getName().toString().compareTo(o2.getName().toString()); - } - }); - int len = this.values.length; - for (int i = 0; i < len; i++) { - if (values[i] == null) { - unassignedVars.add(vars[i]); - } - } - return unassignedVars; - } - - public final void read(ValueInputStream vis) throws IOException { - super.read(vis); - int len = this.values.length; - for (int i = 0; i < len; i++) { - this.values[i] = vis.read(); - } - } - - public final void write(ValueOutputStream vos) throws IOException { - super.write(vos); - int len = this.values.length; - for (int i = 0; i < len; i++) { - vos.write(this.values[i]); - } - } - - /* Returns a string representation of this state. */ - public final String toString() { - if (TLCGlobals.useView && viewMap != null) { - Value val = mytool.eval(viewMap, Context.Empty, this); - return viewMap.toString(val); - } - StringBuffer result = new StringBuffer(); - int vlen = vars.length; - if (vlen == 1) { - UniqueString key = vars[0].getName(); - Value val = lookup(key); - result.append(key.toString()); - result.append(" = "); - result.append(Value.ppr(val)); - result.append("\n"); - } - else { - for (int i = 0; i < vlen; i++) { - UniqueString key = vars[i].getName(); - Value val = lookup(key); - result.append("/\\ "); - result.append(key.toString()); - result.append(" = "); - result.append(Value.ppr(val)); - result.append("\n"); - } - } - return result.toString(); - } - - /* Returns a string representation of this state. */ - public final String toString(TLCState lastState) { - StringBuffer result = new StringBuffer(); - TLCStateMutSource lstate = (TLCStateMutSource)lastState; - - int vlen = vars.length; - if (vlen == 1) { - UniqueString key = vars[0].getName(); - Value val = this.lookup(key); - Value lstateVal = lstate.lookup(key); - if (val == null || !val.equals(lstateVal)) { - result.append(key.toString()); - result.append(" = " + Value.ppr(val) + "\n"); - } - } - else { - for (int i = 0; i < vlen; i++) { - UniqueString key = vars[i].getName(); - Value val = this.lookup(key); - Value lstateVal = lstate.lookup(key); - if (val == null || !val.equals(lstateVal)) { - result.append("/\\ "); - result.append(key.toString()); - result.append(" = " + Value.ppr(val) + "\n"); - } - } - } - return result.toString(); - } - -} +//// Copyright (c) 2003 Compaq Corporation. All rights reserved. +//// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +//// Last modified on Mon 30 Apr 2007 at 15:30:02 PST by lamport +//// modified on Fri Aug 24 15:08:38 PDT 2001 by yuanyu +// +//package tlc2.tool; +// +//import java.io.IOException; +//import java.io.ObjectInputStream; +//import java.io.ObjectOutputStream; +//import java.io.Serializable; +//import java.util.Comparator; +//import java.util.Set; +//import java.util.TreeSet; +// +//import tla2sany.semantic.OpDeclNode; +//import tla2sany.semantic.SemanticNode; +//import tla2sany.semantic.SymbolNode; +//import tlc2.TLCGlobals; +//import tlc2.tool.coverage.CostModel; +//import tlc2.util.Context; +//import tlc2.util.FP64; +//import tlc2.util.ObjLongTable; +//import tlc2.value.MVPerm; +//import tlc2.value.Value; +//import tlc2.value.ValueInputStream; +//import tlc2.value.ValueOutputStream; +//import util.UniqueString; +//import util.WrongInvocationException; +// +///** +// * This class represents a TLA+ state, which simply is an assignment +// * of explicit values to all the global variables. This is the +// * mutable version, which means that in-place updates are used for +// * improved performance and reduced allocation. +// * +// * The viewMap was added by Rajeev Joshi. +// */ +//public final class TLCStateMutSource extends TLCState +//implements Cloneable, Serializable { +// private Value[] values; +// private SemanticNode[] asts; +// private static Tool mytool = null; +// +// /** +// * If non-null, viewMap denotes the function to be applied to +// * a state before its fingerprint is computed. +// */ +// private static SemanticNode viewMap = null; +// +// /** +// * If non-null, perms denotes the set of permutations under +// * the symmetry assumption. +// */ +// private static MVPerm[] perms = null; +// +// private TLCStateMutSource(Value[] vals, SemanticNode[] asts) { +// this.values = vals; +// this.asts = asts; +// } +// +// public static void init(Tool tool) { +// mytool = tool; +// Value[] vals = new Value[vars.length]; +// SemanticNode[] snodes = new SemanticNode[vars.length]; +// Empty = new TLCStateMutSource(vals, snodes); +// viewMap = tool.getViewSpec(); +// perms = tool.getSymmetryPerms(); +// } +// +// public final TLCState createEmpty() { +// int sz = vars.length; +// return new TLCStateMutSource(new Value[sz], new SemanticNode[sz]); +// } +// +// public final boolean equals(Object obj) { +// if (obj instanceof TLCStateMutSource) { +// TLCStateMutSource state = (TLCStateMutSource)obj; +// for (int i = 0; i < this.values.length; i++) { +// if (this.values[i] == null) { +// if (state.values[i] != null) return false; +// } +// else if (state.values[i] == null || +// !this.values[i].equals(state.values[i])) { +// return false; +// } +// } +// return true; +// } +// return false; +// } +// +// public final TLCState bind(UniqueString name, Value value, SemanticNode ast, CostModel cm) { +// int loc = name.getVarLoc(); +// this.values[loc] = value; +// if (this.asts != null) { +// this.asts[loc] = ast; +// } +// return this; +// } +// +// public final TLCState bind(SymbolNode id, Value value, SemanticNode expr, CostModel cm) { +// throw new WrongInvocationException("TLCStateMutSource.bind: This is a TLC bug."); +// } +// +// public final TLCState unbind(UniqueString name) { +// int loc = name.getVarLoc(); +// this.values[loc] = null; +// this.asts[loc] = null; +// return this; +// } +// +// public final Value lookup(UniqueString var) { +// int loc = var.getVarLoc(); +// if (loc < 0) return null; +// return this.values[loc]; +// } +// +// public final boolean containsKey(UniqueString var) { +// return (this.lookup(var) != null); +// } +// +// public final TLCState copy() { +// int len = this.values.length; +// Value[] vals = new Value[len]; +// SemanticNode[] astClone = new SemanticNode[len]; +// for (int i = 0; i < len; i++) { +// vals[i] = this.values[i]; +// astClone[i] = this.asts[i]; +// } +// return new TLCStateMutSource(vals, astClone); +// } +// +// public final TLCState deepCopy() { +// int len = this.values.length; +// Value[] vals = new Value[len]; +// SemanticNode[] astClone = new SemanticNode[len]; +// for (int i = 0; i < len; i++) { +// Value val = this.values[i]; +// if (val != null) { +// vals[i] = val.deepCopy(); +// astClone[i] = this.asts[i]; +// } +// } +// return new TLCStateMutSource(vals, astClone); +// } +// +// public final StateVec addToVec(StateVec states) { +// return states.addElement(this.copy()); +// } +// +// public final void deepNormalize() { +// for (int i = 0; i < this.values.length; i++) { +// Value val = this.values[i]; +// if (val != null) { +// val.deepNormalize(); +// } +// } +// } +// +// private final void readObject(ObjectInputStream ois) +// throws IOException, ClassNotFoundException { +// this.values = (Value[])ois.readObject(); +// this.asts = null; +// } +// +// private final void writeObject(ObjectOutputStream oos) throws IOException { +// oos.writeObject(this.values); +// } +// +// /** +// * This method returns the fingerprint of this state. We fingerprint +// * the values in the state according to the order given by vars. +// * This guarantees the same state has the same fingerprint. +// * +// * Since the values in this state can be shared by multiple threads +// * via the state queue. They have to be normalized before adding to +// * the state queue. We do that here. +// * +// * @see TLCStateMut#fingerPrint() for a commented version of this +// * implementation. +// */ +// public final long fingerPrint() { +// int sz = this.values.length; +// +// Value[] minVals = this.values; +// if (perms != null) { +// Value[] vals = new Value[sz]; +// // Find the "smallest" state under the symmetry permutations: +// for (int i = 0; i < perms.length; i++) { +// int cmp = 0; +// for (int j = 0; j < sz; j++) { +// vals[j] = this.values[j].permute(perms[i]); +// if (cmp == 0) { +// cmp = vals[j].compareTo(minVals[j]); +// } +// } +// if (cmp < 0) { +// if (minVals == this.values) { +// minVals = vals; +// vals = new Value[sz]; +// } +// else { +// Value[] temp = minVals; +// minVals = vals; +// vals = temp; +// } +// } +// } +// } +// // Fingerprint the state: +// long fp = FP64.New(); +// if (viewMap == null) { +// for (int i = 0; i < sz; i++) { +// fp = minVals[i].fingerPrint(fp); +// } +// if (this.values != minVals) { +// for (int i = 0; i < sz; i++) { +// this.values[i].deepNormalize(); +// } +// } +// } +// else { +// for (int i = 0; i < sz; i++) { +// this.values[i].deepNormalize(); +// } +// TLCStateMutSource state = this; +// if (minVals != this.values) { +// state = new TLCStateMutSource(minVals, this.asts); +// } +// Value val = mytool.eval(viewMap, Context.Empty, state); +// fp = val.fingerPrint(fp); +// } +// return fp; +// } +// +// public final void addCounts(final ObjLongTable<SemanticNode> counts) { +// for (int i = 0; i < this.asts.length; i++) { +// counts.add(this.asts[i], 1); +// } +// } +// +// public final boolean allAssigned() { +// int len = this.values.length; +// for (int i = 0; i < len; i++) { +// if (values[i] == null) return false; +// } +// return true; +// } +// +// public final Set<OpDeclNode> getUnassigned() { +// // Return sorted set (lexicographical). +// final Set<OpDeclNode> unassignedVars = new TreeSet<OpDeclNode>(new Comparator<OpDeclNode>() { +// @Override +// public int compare(OpDeclNode o1, OpDeclNode o2) { +// return o1.getName().toString().compareTo(o2.getName().toString()); +// } +// }); +// int len = this.values.length; +// for (int i = 0; i < len; i++) { +// if (values[i] == null) { +// unassignedVars.add(vars[i]); +// } +// } +// return unassignedVars; +// } +// +// public final void read(ValueInputStream vis) throws IOException { +// super.read(vis); +// int len = this.values.length; +// for (int i = 0; i < len; i++) { +// this.values[i] = vis.read(); +// } +// } +// +// public final void write(ValueOutputStream vos) throws IOException { +// super.write(vos); +// int len = this.values.length; +// for (int i = 0; i < len; i++) { +// vos.write(this.values[i]); +// } +// } +// +// /* Returns a string representation of this state. */ +// public final String toString() { +// if (TLCGlobals.useView && viewMap != null) { +// Value val = mytool.eval(viewMap, Context.Empty, this); +// return viewMap.toString(val); +// } +// StringBuffer result = new StringBuffer(); +// int vlen = vars.length; +// if (vlen == 1) { +// UniqueString key = vars[0].getName(); +// Value val = lookup(key); +// result.append(key.toString()); +// result.append(" = "); +// result.append(Value.ppr(val)); +// result.append("\n"); +// } +// else { +// for (int i = 0; i < vlen; i++) { +// UniqueString key = vars[i].getName(); +// Value val = lookup(key); +// result.append("/\\ "); +// result.append(key.toString()); +// result.append(" = "); +// result.append(Value.ppr(val)); +// result.append("\n"); +// } +// } +// return result.toString(); +// } +// +// /* Returns a string representation of this state. */ +// public final String toString(TLCState lastState) { +// StringBuffer result = new StringBuffer(); +// TLCStateMutSource lstate = (TLCStateMutSource)lastState; +// +// int vlen = vars.length; +// if (vlen == 1) { +// UniqueString key = vars[0].getName(); +// Value val = this.lookup(key); +// Value lstateVal = lstate.lookup(key); +// if (val == null || !val.equals(lstateVal)) { +// result.append(key.toString()); +// result.append(" = " + Value.ppr(val) + "\n"); +// } +// } +// else { +// for (int i = 0; i < vlen; i++) { +// UniqueString key = vars[i].getName(); +// Value val = this.lookup(key); +// Value lstateVal = lstate.lookup(key); +// if (val == null || !val.equals(lstateVal)) { +// result.append("/\\ "); +// result.append(key.toString()); +// result.append(" = " + Value.ppr(val) + "\n"); +// } +// } +// } +// return result.toString(); +// } +// +//} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/TLCTrace.java b/tlatools/src/tlc2/tool/TLCTrace.java index ce69ae367d3105eaeef4d5aeb2ed9f0f2a1cf676..691bd258e07504440a225ba66f061d495f794a4b 100644 --- a/tlatools/src/tlc2/tool/TLCTrace.java +++ b/tlatools/src/tlc2/tool/TLCTrace.java @@ -15,80 +15,68 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import tlc2.output.OutputCollector; import tlc2.output.StatePrinter; import tlc2.util.BufferedRandomAccessFile; import tlc2.util.LongVec; -import tlc2.value.EnumerableValue; +import tlc2.value.RandomEnumerableValues; import util.FileUtil; public class TLCTrace { + static final String EXT = ".st"; private static String filename; - private BufferedRandomAccessFile raf; + private final BufferedRandomAccessFile raf; private long lastPtr; - // TODO This arrays causes coherence. This problem is easily removed by - // storing each ptr in lastPtrs in the corresponding worker. That's a little - // bit ugly though in terms of separation of concerns. The current solution - // confines all related aspects to TLCTrace. - private final long[] lastPtrs = new long[TLCGlobals.getNumWorkers()]; private TraceApp tool; - public TLCTrace(String metadir, String specFile, TraceApp tool) - throws IOException { - filename = metadir + FileUtil.separator + specFile + ".st"; + public TLCTrace(String metadir, String specFile, TraceApp tool) throws IOException { + filename = metadir + FileUtil.separator + specFile + EXT; this.raf = new BufferedRandomAccessFile(filename, "rw"); this.lastPtr = 1L; this.tool = tool; } /** - * @param fp A finger print of a state without a predecessor (init state) + * @param fp + * A finger print of a state without a predecessor (init state) * @return The new location (pointer) for the given finger print (state) * @throws IOException */ - public final synchronized long writeState(final long aFingerprint) - throws IOException { + public final synchronized long writeState(final long aFingerprint) throws IOException { return writeState(1, aFingerprint); } /** - * @param predecessor The predecessor state - * @param fp A finger print + * @param predecessor + * The predecessor state + * @param fp + * A finger print * @return The new location (pointer) for the given finger print (state) * @throws IOException */ - public final synchronized long writeState(final TLCState predecessor, final long aFingerprint) - throws IOException { + public final synchronized long writeState(final TLCState predecessor, final long aFingerprint) throws IOException { return writeState(predecessor.uid, aFingerprint); } - public final synchronized long writeState(final TLCState predecessor, final long aFingerprint, final IWorker worker) - throws IOException { - final long lastPtr = writeState(predecessor.uid, aFingerprint); - this.lastPtrs[worker.myGetId()] = lastPtr; - return lastPtr; - } - /** - * @param predecessorLoc The location of the state predecessor - * @param fp A finger print + * @param predecessorLoc + * The location of the state predecessor + * @param fp + * A finger print * @return The new location (pointer) for the given finger print (state) * @throws IOException */ - private final synchronized long writeState(long predecessorLoc, long fp) - throws IOException { - // TODO Remove synchronization as all threads content for this lock + private final synchronized long writeState(long predecessorLoc, long fp) throws IOException { this.lastPtr = this.raf.getFilePointer(); this.raf.writeLongNat(predecessorLoc); this.raf.writeLong(fp); return this.lastPtr; } - public final void close() throws IOException { + public void close() throws IOException { this.raf.close(); } @@ -103,33 +91,6 @@ public class TLCTrace { return this.raf.readLong(); } - /** - * The level is the length of the longest path in the execution trees - * (forest) (his forest is stored in the trace file). - * <p> - * With multiple workers, the level is an approximation. With multiple - * workers, the forest has an unknown number of leafs and we do not know the - * position of leafs in the trace file. - * <p> - * We know however the vertices, that the set of workers last added to the - * forest. Thus, we calculate the lengths of each path or path fragment - * from those vertices. The maximum length is then our approximation of the - * longest path. It's not elegant but good enough for now. - * - * @see TLCTrace#getLevel() - */ - public final synchronized int getLevelForFinalReporting() throws IOException { - // TODO We generally assume the length and the number of workers to be - // relatively small to not warrant parallelization. The current - // getLevel(lastPtr) cannot be called concurrently, because it uses a - // single BufferedRandomAccessFile. - int max = 0; - for (long lastPtr : lastPtrs) { - max = Math.max(max, lastPtr > 0 ? getLevel(lastPtr) : 0); - } - return max; - } - /** * Returns the level (monotonically increasing)! * @@ -150,7 +111,7 @@ public class TLCTrace { * * @see TLCTrace#getLevel() */ - public final synchronized int getLevelForReporting() throws IOException { + public synchronized int getLevelForReporting() throws IOException { final int calculatedLevel = getLevel(this.lastPtr); if (calculatedLevel > previousLevel) { previousLevel = calculatedLevel; @@ -167,7 +128,7 @@ public class TLCTrace { * @see TLCTrace#getLevel(long) * @return 1 to the length of the longest behavior found so far. */ - public final int getLevel() throws IOException { + public int getLevel() throws IOException { // This assumption (lastPtr) only holds for the TLC in non-parallel mode. // Generally the last line (logically a state) is not necessarily // on the highest level of the state tree, which is only true if @@ -275,14 +236,16 @@ public class TLCTrace { } /** - * @param loc The start location (pointer) from where the trace should be computed - * @param included true if the start location state should be included + * @param loc + * The start location (pointer) from where the trace should be + * computed + * @param included + * true if the start location state should be included * @return An array of predecessor states * @throws IOException */ - public final TLCStateInfo[] getTrace(long loc, boolean included) - throws IOException { - LongVec fps = new LongVec(); + protected TLCStateInfo[] getTrace(long loc, boolean included) throws IOException { + LongVec fps = new LongVec(); // Starting at the given start fingerprint (which is the end of the // trace from the point of the initial states), the chain of @@ -296,7 +259,18 @@ public class TLCTrace { } this.raf.seek(curLoc); } + + return getTrace(fps); + } + protected final TLCStateInfo[] getTrace(LongVec fps) { + // Re-Initialize the rng with the seed value recorded and used during the model + // checking phase. Otherwise, we won't be able to reconstruct the error trace + // because the set of initial states is likely to be different. + // This is only necessary though, if TLCGlobals.enumFraction was < 1 during + // the generation of inits. + RandomEnumerableValues.reset(); + // The vector of fingerprints is now being followed forward from the // initial state (which is the last state in the long vector), to the // end state. @@ -314,10 +288,9 @@ public class TLCTrace { // Recover initial state from its fingerprint. long fp = fps.elementAt(len - 1); TLCStateInfo sinfo = this.tool.getState(fp); - if (sinfo == null) - { + if (sinfo == null) { MP.printError(EC.TLC_FAILED_TO_RECOVER_INIT); - MP.printError(EC.TLC_BUG, "1"); + MP.printError(EC.TLC_BUG, "1 " + Long.toString(fp)); System.exit(1); } // Recover successor states from its predecessor and its fingerprint. @@ -327,12 +300,12 @@ public class TLCTrace { sinfo = this.tool.getState(fp, sinfo.state); if (sinfo == null) { /* - * The following error message is misleading, because it's triggered - * when TLC can't find a non-initial state from its fingerprint - * when it's generating an error trace. LL 7 Mar 2012 + * The following error message is misleading, because it's triggered when TLC + * can't find a non-initial state from its fingerprint when it's generating an + * error trace. LL 7 Mar 2012 */ MP.printError(EC.TLC_FAILED_TO_RECOVER_INIT); - MP.printError(EC.TLC_BUG, "2"); + MP.printError(EC.TLC_BUG, "2 " + Long.toString(fp)); System.exit(1); } res[stateNum++] = sinfo; @@ -342,26 +315,24 @@ public class TLCTrace { } /** - * Write out a sequence of states that reaches s2 from an initial - * state, according to the spec. s2 is a next state of s1. + * Write out a sequence of states that reaches s2 from an initial state, + * according to the spec. s2 is a next state of s1. * - * @param s1 may not be null. - * @param s2 may be null. + * @param s1 + * may not be null. + * @param s2 + * may be null. * @throws IOException * @throws WorkerException */ - public synchronized final void printTrace(final TLCState s1, final TLCState s2) - throws IOException, WorkerException - { - // Re-Initialize the rng with the seed value recorded and used during the model - // checking phase. Otherwise, we won't be able to reconstruct the error trace - // because the set of initial states is likely to be different. - // This is only necessary though, if TLCGlobals.enumFraction was < 1 during - // the generation of inits. - EnumerableValue.resetRandom(); - + public void printTrace(final TLCState s1, final TLCState s2) throws IOException, WorkerException { + printTrace(s1, s2, getTrace(s1.uid, false)); + } + + protected synchronized final void printTrace(final TLCState s1, final TLCState s2, final TLCStateInfo[] prefix) + throws IOException, WorkerException { ArrayList<TLCStateInfo> trace = new ArrayList<TLCStateInfo>(); // collecting the whole error trace - + if (s1.isInitial()) { // Do not recreate the potentially expensive error trace - e.g. when the set of // initial states is huge such as during inductive invariant checking. Instead @@ -382,12 +353,9 @@ public class TLCTrace { MP.printError(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT); // Print the prefix leading to s1: - long loc1 = s1.uid; TLCState lastState = null; - TLCStateInfo[] prefix = this.getTrace(loc1, false); int idx = 0; - while (idx < prefix.length) - { + while (idx < prefix.length) { StatePrinter.printState(prefix[idx], lastState, idx + 1); lastState = prefix[idx].state; trace.add(prefix[idx]); @@ -401,27 +369,22 @@ public class TLCTrace { // to s1. if (prefix.length == 0) { sinfo = this.tool.getState(s1.fingerPrint()); - if (sinfo == null) - { + if (sinfo == null) { MP.printError(EC.TLC_FAILED_TO_RECOVER_INIT); MP.printError(EC.TLC_BUG, "3"); System.exit(1); } - } - else - { + } else { TLCState s0 = prefix[prefix.length - 1].state; sinfo = this.tool.getState(s1.fingerPrint(), s0); - if (sinfo == null) - { + if (sinfo == null) { MP.printError(EC.TLC_FAILED_TO_RECOVER_INIT); MP.printError(EC.TLC_BUG, "4"); StatePrinter.printState(s1); System.exit(1); } } - if (s2 == null) - { + if (s2 == null) { lastState = null; } StatePrinter.printState(sinfo, lastState, ++idx); @@ -432,8 +395,7 @@ public class TLCTrace { // The predecessor to s2 is s1. if (s2 != null) { sinfo = this.tool.getState(s2, s1); - if (sinfo == null) - { + if (sinfo == null) { MP.printError(EC.TLC_FAILED_TO_RECOVER_INIT); MP.printError(EC.TLC_BUG, "5"); StatePrinter.printState(s2); @@ -446,8 +408,8 @@ public class TLCTrace { } /** - * Returns a sequence of states that reaches, but excludes the - * state with fingerprint fp. + * Returns a sequence of states that reaches, but excludes the state with + * fingerprint fp. */ @SuppressWarnings("unused") private final TLCStateInfo[] printPrefix(long fp) throws IOException { @@ -472,7 +434,7 @@ public class TLCTrace { } /* Checkpoint. */ - public synchronized final void beginChkpt() throws IOException { + public synchronized void beginChkpt() throws IOException { this.raf.flush(); // SZ Feb 24, 2009: FileUtil introduced DataOutputStream dos = FileUtil.newDFOS(filename + ".tmp"); @@ -481,16 +443,15 @@ public class TLCTrace { dos.close(); } - public final void commitChkpt() throws IOException { + public void commitChkpt() throws IOException { File oldChkpt = new File(filename + ".chkpt"); File newChkpt = new File(filename + ".tmp"); - if ((oldChkpt.exists() && !oldChkpt.delete()) || - !newChkpt.renameTo(oldChkpt)) { + if ((oldChkpt.exists() && !oldChkpt.delete()) || !newChkpt.renameTo(oldChkpt)) { throw new IOException("Trace.commitChkpt: cannot delete " + oldChkpt); } } - public final void recover() throws IOException { + public void recover() throws IOException { // SZ Feb 24, 2009: FileUtil introduced DataInputStream dis = FileUtil.newDFIS(filename + ".chkpt"); long filePos = dis.readLong(); @@ -499,16 +460,6 @@ public class TLCTrace { this.raf.seek(filePos); } - public static String getFilename() { return filename; } - - public static long getRecoverPtr() throws IOException { - // SZ Feb 24, 2009: FileUtil introduced - DataInputStream dis = FileUtil.newDFIS(filename + ".chkpt"); - long res = dis.readLong(); - dis.close(); - return res; - } - @SuppressWarnings("unused") private long[] addBlock(long fp[], long prev[]) throws IOException { // Reuse prev. @@ -518,20 +469,27 @@ public class TLCTrace { return prev; } - public synchronized final Enumerator elements() throws IOException { - return new Enumerator(); + public synchronized Enumerator elements() throws IOException { + return new TLCTraceEnumerator(); } - final class Enumerator { + public interface Enumerator { + long nextPos(); + long nextFP() throws IOException; + void close() throws IOException; + void reset(long i) throws IOException; + } + + public class TLCTraceEnumerator implements Enumerator { long len; BufferedRandomAccessFile enumRaf; - Enumerator() throws IOException { + TLCTraceEnumerator() throws IOException { this.len = raf.length(); this.enumRaf = new BufferedRandomAccessFile(filename, "r"); } - final void reset(long pos) throws IOException { + public final void reset(long pos) throws IOException { this.len = raf.length(); if (pos == -1) { pos = this.enumRaf.getFilePointer(); @@ -540,16 +498,22 @@ public class TLCTrace { this.enumRaf.seek(pos); } - final long nextPos() { + public final long nextPos() { long fpos = this.enumRaf.getFilePointer(); - if (fpos < this.len) { return fpos; } - return -1; + if (fpos < this.len) { + return fpos; + } + return -1L; } - final long nextFP() throws IOException { + public final long nextFP() throws IOException { this.enumRaf.readLongNat(); /* drop */ return this.enumRaf.readLong(); } + + public final void close() throws IOException { + this.enumRaf.close(); + } } } diff --git a/tlatools/src/tlc2/tool/ToolGlobals.java b/tlatools/src/tlc2/tool/ToolGlobals.java index 90fe0a8a45eb9ed741168dff078dfb23a3fc1388..2d6fa5ed720ffe8903351a1677360bb0d3e080ba 100644 --- a/tlatools/src/tlc2/tool/ToolGlobals.java +++ b/tlatools/src/tlc2/tool/ToolGlobals.java @@ -7,7 +7,6 @@ package tlc2.tool; import tla2sany.semantic.ASTConstants; import tla2sany.semantic.OpDefNode; -import tlc2.value.Value; import util.UniqueString; public interface ToolGlobals extends ASTConstants { @@ -15,8 +14,6 @@ public interface ToolGlobals extends ASTConstants { * This interface provides useful globals for the implementation * of the tools. */ - - public static final Value[] EmptyArgs = new Value[0]; // SZ 11.04.2009: changed the method to the equivalent public static final OpDefNode EXCEPT_AT = new OpDefNode(UniqueString.uniqueStringOf("@")); diff --git a/tlatools/src/tlc2/tool/Worker.java b/tlatools/src/tlc2/tool/Worker.java index be2d92a47baf05a2216149383cc58e194c60b89c..1bd32d89b7e7f823814c7a233872a072f7647948 100644 --- a/tlatools/src/tlc2/tool/Worker.java +++ b/tlatools/src/tlc2/tool/Worker.java @@ -5,15 +5,25 @@ package tlc2.tool; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; + import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.queue.IStateQueue; +import tlc2.util.BufferedRandomAccessFile; +import tlc2.util.IStateWriter; import tlc2.util.IdThread; -import tlc2.util.ObjLongTable; +import tlc2.util.SetOfStates; import tlc2.util.statistics.FixedSizedBucketStatistics; import tlc2.util.statistics.IBucketStatistics; +import util.FileUtil; + +public final class Worker extends IdThread implements IWorker { -public class Worker extends IdThread implements IWorker { + private static final int INITIAL_CAPACITY = 16; /** * Multi-threading helps only when running on multiprocessors. TLC can @@ -22,35 +32,40 @@ public class Worker extends IdThread implements IWorker { */ private final ModelChecker tlc; private final IStateQueue squeue; - private final ObjLongTable astCounts; private final IBucketStatistics outDegree; + private final String filename; + private final BufferedRandomAccessFile raf; + + private long lastPtr; private long statesGenerated; - + private int unseenSuccessorStates = 0; + private volatile int maxLevel = 0; // SZ Feb 20, 2009: changed due to super type introduction - public Worker(int id, AbstractChecker tlc) { + public Worker(int id, AbstractChecker tlc, String metadir, String specFile) throws IOException { super(id); // SZ 12.04.2009: added thread name this.setName("TLC Worker " + id); this.tlc = (ModelChecker) tlc; this.squeue = this.tlc.theStateQueue; - this.astCounts = new ObjLongTable(10); this.outDegree = new FixedSizedBucketStatistics(this.getName(), 32); // maximum outdegree of 32 appears sufficient for now. this.setName("TLCWorkerThread-" + String.format("%03d", id)); - } - public final ObjLongTable getCounts() { return this.astCounts; } + this.filename = metadir + FileUtil.separator + specFile + "-" + myGetId(); + this.raf = new BufferedRandomAccessFile(filename + TLCTrace.EXT, "rw"); + } /** * This method gets a state from the queue, generates all the * possible next states of the state, checks the invariants, and * updates the state set and state queue. */ - public final void run() { + public void run() { + final boolean checkLiveness = this.tlc.checkLiveness; TLCState curState = null; try { while (true) { - curState = (TLCState) this.squeue.sDequeue(); + curState = this.squeue.sDequeue(); if (curState == null) { synchronized (this.tlc) { this.tlc.setDone(); @@ -60,18 +75,32 @@ public class Worker extends IdThread implements IWorker { return; } setCurrentState(curState); - if (this.tlc.doNext(curState, this.astCounts, this)) { + + SetOfStates setOfStates = null; + if (checkLiveness) { + setOfStates = createSetOfStates(); + } + + if (this.tlc.doNext(curState, setOfStates, this)) { return; } + + // Finally, add curState into the behavior graph for liveness checking: + if (checkLiveness) + { + doNextCheckLiveness(curState, setOfStates); + } + + this.outDegree.addSample(unseenSuccessorStates); + unseenSuccessorStates = 0; } } catch (Throwable e) { // Something bad happened. Quit ... // Assert.printStack(e); resetCurrentState(); synchronized (this.tlc) { - if (this.tlc.setErrState(curState, null, true)) { - MP.printError(EC.GENERAL, e); // LL changed call 7 April - // 2012 + if (this.tlc.setErrState(curState, null, true, EC.GENERAL)) { + MP.printError(EC.GENERAL, e); // LL changed call 7 April 2012 } this.squeue.finishAll(); this.tlc.notify(); @@ -79,20 +108,177 @@ public class Worker extends IdThread implements IWorker { return; } } + + /* Liveness */ + + private int multiplier = 1; + + private final void doNextCheckLiveness(TLCState curState, SetOfStates liveNextStates) throws IOException { + final long curStateFP = curState.fingerPrint(); + + // Add the stuttering step: + liveNextStates.put(curStateFP, curState); + this.tlc.allStateWriter.writeState(curState, curState, true, IStateWriter.Visualization.STUTTERING); - void incrementStatesGenerated(long l) { + this.tlc.liveCheck.addNextState(tlc.tool, curState, curStateFP, liveNextStates); + + if (liveNextStates.capacity() > (multiplier * INITIAL_CAPACITY)) { + // Increase initial size for as long as the set has to grow + multiplier++; + } + } + + private final SetOfStates createSetOfStates() { + return new SetOfStates(multiplier * INITIAL_CAPACITY); + } + + /* Statistics */ + + final void incrementStatesGenerated(long l) { this.statesGenerated += l; } - long getStatesGenerated() { + final long getStatesGenerated() { return this.statesGenerated; } - void setOutDegree(final int numOfSuccessors) { - this.outDegree.addSample(numOfSuccessors); + public final IBucketStatistics getOutDegree() { + return this.outDegree; + } + + public final int getMaxLevel() { + return maxLevel; } - public IBucketStatistics getOutDegree() { - return this.outDegree; + final void setLevel(int level) { + maxLevel = level; + } + + /* Maintain trace file (to reconstruct error-trace) */ + + /* + * Synchronize reads and writes to read a consistent union of all trace file + * fragments when one worker W wants to create the counter-example. Otherwise, we + * might not be able to correctly trace the path from state to an initial state. + * The W thread holds ModelChecker.this. The other workers might either: a) Wait + * on IStateQueue#sDequeue (waiting for a new state to be read from disk or + * added to the queue) b) Wait on ModelChecker.this (because they also found + * another counter-example but are blocked until we are done printing it) c) + * Wait on ModelChecker.this in Worker#run because the state queue is empty and + * they which to terminate. d) Run state space exploration The on-disk file of + * each worker's trace fragment is potentially inconsistent because the worker's + * cache in BufferedRandomAccessFile hasn't been flushed out. + */ + + public final synchronized void writeState(final TLCState initialState, final long fp) throws IOException { + // Write initial state to trace file. + this.lastPtr = this.raf.getFilePointer(); + this.raf.writeLongNat(1L); + this.raf.writeShortNat(myGetId()); + this.raf.writeLong(fp); + + // Add predecessor pointer to success state. + initialState.workerId = (short) myGetId(); + initialState.uid = this.lastPtr; + } + + public final synchronized void writeState(final TLCState curState, final long sucStateFp, final TLCState sucState) throws IOException { + // Keep track of maximum diameter. + maxLevel = Math.max(curState.getLevel() + 1, maxLevel); + + // Write to trace file. + this.lastPtr = this.raf.getFilePointer(); + this.raf.writeLongNat(curState.uid); + this.raf.writeShortNat(curState.workerId); + this.raf.writeLong(sucStateFp); + + // Add predecessor pointer to success state. + sucState.workerId = (short) myGetId(); + sucState.uid = this.lastPtr; + + sucState.setPredecessor(curState); + + unseenSuccessorStates++; + +// System.err.println(String.format("<<%s, %s>>: pred=<<%s, %s>>, %s -> %s", myGetId(), this.lastPtr, +// curState.uid, curState.workerId, +// curState.fingerPrint(), sucStateFp)); + } + + // Read from previously written (see writeState) trace file. + public final synchronized ConcurrentTLCTrace.Record readStateRecord(final long ptr) throws IOException { + this.raf.seek(ptr); + + final long prev = this.raf.readLongNat(); + assert 0 <= ptr; + + final int worker = this.raf.readShortNat(); + assert 0 <= worker && worker < tlc.workers.length; + + final long fp = this.raf.readLong(); + assert tlc.theFPSet.contains(fp); + + return new ConcurrentTLCTrace.Record(prev, worker, fp); + } + + /* Checkpointing */ + + public final synchronized void beginChkpt() throws IOException { + this.raf.flush(); + final DataOutputStream dos = FileUtil.newDFOS(filename + ".tmp"); + dos.writeLong(this.raf.getFilePointer()); + dos.writeLong(this.lastPtr); + dos.close(); + } + + public final synchronized void commitChkpt() throws IOException { + final File oldChkpt = new File(filename + ".chkpt"); + final File newChkpt = new File(filename + ".tmp"); + if ((oldChkpt.exists() && !oldChkpt.delete()) || !newChkpt.renameTo(oldChkpt)) { + throw new IOException("Trace.commitChkpt: cannot delete " + oldChkpt); + } + } + + public final void recover() throws IOException { + final DataInputStream dis = FileUtil.newDFIS(filename + ".chkpt"); + final long filePos = dis.readLong(); + this.lastPtr = dis.readLong(); + dis.close(); + this.raf.seek(filePos); + } + + /* Enumerator */ + + public final Enumerator elements() throws IOException { + return new Enumerator(); + } + + public class Enumerator { + + private final long len; + private final BufferedRandomAccessFile enumRaf; + + Enumerator() throws IOException { + this.len = raf.getFilePointer(); + this.enumRaf = new BufferedRandomAccessFile(filename + TLCTrace.EXT, "r"); + } + + public boolean hasMoreFP() { + final long fpos = this.enumRaf.getFilePointer(); + if (fpos < this.len) { + return true; + } + return false; + } + + public long nextFP() throws IOException { + this.enumRaf.readLongNat(); /* drop */ + this.enumRaf.readShortNat(); /* drop */ + return this.enumRaf.readLong(); + } + + public void close() throws IOException { + this.enumRaf.close(); + } } } diff --git a/tlatools/src/tlc2/tool/coverage/ActionWrapper.java b/tlatools/src/tlc2/tool/coverage/ActionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4ffe571fd28cc7b9967d3b577992c4ff04153de0 --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/ActionWrapper.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.SubstInNode; +import tla2sany.st.Location; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.tool.Action; + +public final class ActionWrapper extends CostModelNode { + + public enum Relation { + INIT, NEXT, PROP; + } + + private final Action action; + private final Relation relation; + + public ActionWrapper(final Action action, Relation rel) { + this.action = action; + this.relation = rel; + } + + /* (non-Javadoc) + * @see tlc2.tool.coverage.CostModelNode#getLocation() + */ + @Override + protected Location getLocation() { + if (this.action.isDeclared()) { + return this.action.getDeclaration(); + } + return this.action.pred.getLocation(); + } + + private String printLocation() { + if (!this.action.isDeclared()) { + // Safeguard for legacy cases if any. + return this.action.toString(); + } + // Determine if the mapping from the action's name/identifier/declaration to the + // action's definition is 1:1 or 1:N. + // + // Act == /\ x = 23 + // /\ x' = 42 + // vs + // Act == \/ /\ x = 23 + // /\ x' = 42 + // \/ /\ x = 123 + // /\ x' = 4711 + // or + // Act == (x = 23 /\ x' = 42) \/ (x = 123 /\ x' = 4711) + // + // For a 1:1 mapping this prints just the location of Act. For a 1:N mapping it + // prints the location of Act _and_ the location (in shortened form) of the actual + // disjunct. + final Location declaration = this.action.getDeclaration(); + final Location definition = this.action.getOpDef().getBody().getLocation(); + final Location actual = this.action.pred.getLocation(); + if (definition.equals(actual)) { + // 1:1 + return String.format("<%s %s>", this.action.getName(), declaration); + } else { + // 1:N + return String.format("<%s %s (%s %s %s %s)>", this.action.getName(), declaration, actual.beginLine(), + actual.beginColumn(), actual.endLine(), actual.endColumn()); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.coverage.CostModelNode#getRoot() + */ + @Override + public CostModelNode getRoot() { + return this; + } + + /* (non-Javadoc) + * @see tlc2.tool.CostModel#get(tla2sany.semantic.SemanticNode) + */ + @Override + public final CostModel get(final SemanticNode eon) { + if (eon instanceof SubstInNode) { + final SubstInNode sin = (SubstInNode) eon; + return this.children.get(sin.getBody()); + } + return this.children.get(eon); + } + + /* (non-Javadoc) + * @see tlc2.tool.coverage.CostModelNode#getNode() + */ + @Override + SemanticNode getNode() { + return action.pred; + } + + /* (non-Javadoc) + * @see tlc2.tool.coverage.CostModelNode#isRoot() + */ + @Override + boolean isRoot() { + return true; + } + + /* (non-Javadoc) + * @see tlc2.tool.coverage.CostModel#report() + */ + public CostModel report() { + // Report count for action itself. + if (relation == Relation.PROP) { + assert getEvalCount() == 0L && this.secondary.getCount() == 0L; + MP.printMessage(EC.TLC_COVERAGE_PROPERTY, new String[] { printLocation() }); + } else if (relation == Relation.INIT) { + // TODO Eventually coverage for init and next should consistently report states + // found and distinct states into the same counters. + MP.printMessage(EC.TLC_COVERAGE_INIT, new String[] { printLocation(), String.valueOf(getEvalCount()), + String.valueOf(getEvalCount() + this.secondary.getCount()) }); + } else { + MP.printMessage(EC.TLC_COVERAGE_NEXT, new String[] { printLocation(), + String.valueOf(this.secondary.getCount()), String.valueOf(getEvalCount()) }); + } + + // An action has single child which is the OpApplNodeWrapper with the OpApplNode + // for this OpDefNode unless the action's pred is a substitution. + assert !(this.action.pred instanceof SubstInNode) ? this.children.size() == 1 : !this.children.isEmpty(); + // Let children report. + // Could disable here if decided to implement action-only coverage at the TLC + // level (see org.lamport.tla.toolbox.tool.tlc.model.Model.Coverage). + this.children.values().forEach(c -> c.report()); + return this; + } + + public boolean is(Relation r) { + return r == this.relation; + } +} diff --git a/tlatools/src/tlc2/tool/coverage/CostModel.java b/tlatools/src/tlc2/tool/coverage/CostModel.java new file mode 100644 index 0000000000000000000000000000000000000000..43f66a09c590296e0b19e9564a9b1fc7fdc4b0c6 --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/CostModel.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import tla2sany.semantic.SemanticNode; + +public interface CostModel { + + CostModel DO_NOT_RECORD = new CostModel() { + + @Override + public CostModel report() { + // no-op + return this; + } + + @Override + public CostModel get(final SemanticNode sn) { + return this; + } + + @Override + public CostModel getRoot() { + return this; + } + + @Override + public CostModel incInvocations() { + // no-op + return this; + } + + @Override + public CostModel incInvocations(final long value) { + // no-op + return this; + } + + @Override + public CostModel incSecondary() { + // no-op + return this; + } + + @Override + public CostModel incSecondary(long value) { + // no-op + return null; + } + + @Override + public CostModel getAndIncrement(SemanticNode eon) { + // no-op + return this; + } + }; + + CostModel incInvocations(); + + CostModel incInvocations(final long value); + + CostModel incSecondary(); + + CostModel incSecondary(final long value); + + CostModel report(); + + CostModel get(final SemanticNode sn); + + CostModel getAndIncrement(final SemanticNode eon); + + CostModel getRoot(); +} diff --git a/tlatools/src/tlc2/tool/coverage/CostModelCreator.java b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..ff2c11d4c55efc0a2809deda4be329fb2af5b452 --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java @@ -0,0 +1,379 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import static tlc2.tool.ToolGlobals.OPCODE_unchanged; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import tla2sany.explorer.ExploreNode; +import tla2sany.explorer.ExplorerVisitor; +import tla2sany.semantic.ExprNode; +import tla2sany.semantic.ExprOrOpArgNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.Subst; +import tla2sany.semantic.SubstInNode; +import tla2sany.semantic.SymbolNode; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.output.OutputCollector; +import tlc2.tool.Action; +import tlc2.tool.ITool; +import tlc2.tool.coverage.ActionWrapper.Relation; +import tlc2.util.Context; +import tlc2.util.ObjLongTable; +import tlc2.util.Vect; + +/** + * <h1>Why a CostModel:</h1> Why a CostModelCreator to traverses the semantic + * graph to create a forest of OpApplNode trees (rooted at an action)?<br> + * The semantic graph is no fit to store cost metrics. This is due to the fact + * that the semantic graph has only a single node for each OpDefNode and thus + * OpApplNode even when an OpApplNode is invoked from different actions and thus + * different call trees. If we were to store costs inside the semantic graph, it + * would thus not be possible to show costs per action. Therefore, + * CostModelCreate creates a tree for each action whose subtree is the set of + * OpApplNodes reachable from this particular action. + * <p> + * A CostModel tree of an action gets traversed by Tool in lockstep (except that + * the tree only contains OpApplNodes thus <code>return this</code> in + * OpApplNodeWrapper#get) when Tool traverses the semantic graph to evaluate an + * action. + * <p> + * As part of the work on the CostModel, the ExplorerVisitor received an extension + * to export the semantic graph into dot notation, which can be rendered with + * GraphViz: + * <code>java -cp tla2tools.jartla2sany.SANY -d ATLA+Spec.tla dot</code> It + * optionally includes line numbers if the system property + * <code>tla2sany.explorer.DotExplorerVisitor.includeLineNumbers=true</code> + * is set. + * <p> + * ----------------------------------------------------------------------------- + * <h2>Note on performance:</h2> Spec/Tool and Value turn isCoverageEnabled into + * constants. This should help the runtime to optimize away most calls to + * CostModel unless coverage is enabled. + * <p> + * Macro-benchmarks on a real-world PlusCal [1] model show a 2% performance drop + * in terms of throughput due to the addition of the "if (coverage) {...}" calls + * when coverage is turned off (it is in the range of %40 when turned on). In + * other words, the CostModel data collector has a non-zero overhead. The + * reasons are unknown and further investigations have been abandoned. Instead, + * the problem has been side-stepped by refactorings in ModelChecker and Tool. + * [1] + * https://bitbucket.org/parvmor/tarjanconcurrentscc/src/unionfind/specifications/MCBloemenSCC.tla + * altered to terminate TLC after five minutes with TLCSet("exit",...) + * <p> + * The refactorings essentially decomposed large methods into smaller ones (see + * git history for commits). This allows the runtime to emit more efficient code + * s.t. hot methods can be inlined to reduce invocations. The net gain is in the + * range of 5%; enough to make up for the 2% drop introduced by the CostModel + * collector.<br> + * Methods were identified by: + * <code>java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining + * -jar tla2tools.jar -workers 1 | grep "hot method too big"</code> + * <p> + * A far more elegant implementation and zero-overhead solution of the CostModel + * collector uses aspect-programming (based on e.g. AspectJ used in other places + * of TLC). This approach has been prototyped in CostModelAspect.java. The + * aspects in CostModelAspect are woven into TLC by AspectJ at the defined + * pointcuts when needed.<br> + * Weaving can either be done at compile-time (CTW) or launch-time (LTW) where + * LTW is preferable in our case to only load the CostModel code when a user + * enables it. Unfortunately, benchmarks revealed a huge performance drops in + * the order of a magnitude with LTW. Inspections of the generated bytecode with + * JitWatch did not reveal the root cause for this major performance drop. As a + * side-effect, LTW would require TLC to include the AspectJ runtime - and even + * bigger in size - the ASM bytecode instrumentation. Users would also have to + * pass the -javaagent parameter to TLC. In other words, using coverage wouldn't + * be as transparent to the user as it is today. + * <p> + * Experiments with CTW - compared to LTW - resulted in much better performance + * with coverage enabled. Still, the overhead of CTW with coverage disabled was + * non-negligible. We therefore went as far as hacking the class-loading in + * TLC.java to load vanilla TLC with coverage off and instrumented code with + * coverage on. However, we considered this approach to be too hack-ish and + * abandoned it in favor of the aforementioned refactorings (it also broke the + * model.ModelInJarfeature). It additionally increased the size of tla2tools.jar + * two-fold.<br> + * Generally it appears as if the code generation in AspectJ is not optimized to + * emit the most efficient code. Most pointcuts result in superfluous object + * allocations inside the generated bytecode - to pass along method parameters - + * for *every* method invocation. Future versions of AspectJ might produce more + * efficient code though. + * <p> + * ----------------------------------------------------------------------------- + * Changing tla2sany.semantic.Generator to generate a forest of call trees - + * s.t. there is one OpDefNode & OpApplNode instance per call tree instead of + * one global graph - appears to be the implementation with minimal overhead. We + * did not follow up on this idea however, because of the inherent risk of + * introducing subtle side-effect into the semantics of TLA+ expression + * evaluation. An optimization - to only generate a forest when coverage is + * enabled - that uses dynamic proxies (JDK dynamic proxies, CGLib, ASM) proved + * impossible unless the complete class hierarchy of SemanticNode gets + * refactored into a hierarchy with interfaces (proxies can practically only be + * generated for interfaces) + */ +public class CostModelCreator extends ExplorerVisitor { + + private final Deque<CostModelNode> stack = new ArrayDeque<>(); + private final Map<ExprOrOpArgNode, Subst> substs = new HashMap<>(); + private final Map<OpApplNode, OpApplNodeWrapper> node2Wrapper = new HashMap<>(); + private final Set<OpDefNode> opDefNodes = new HashSet<>(); + // OpAppNode does not implement equals/hashCode which causes problem when added + // to sets or maps. E.g. for a test, an OpApplNode instance belonging to + // Sequences.tla showed up in coverage output. + private final Set<OpApplNodeWrapper> nodes = new HashSet<>(); + private final ITool tool; + + private ActionWrapper root; + private Context ctx = Context.Empty; + + private CostModelCreator(final SemanticNode root, final ITool tool) { + this.tool = tool; + this.stack.push(new RecursiveOpApplNodeWrapper()); + root.walkGraph(new CoverageHashTable(opDefNodes), this); + } + + // root cannot be type OpApplNode but has to be SemanticNode (see Test216). + private CostModelCreator(final ITool tool) { + this.tool = tool; + // MAK 10/08/2018: Annotate OApplNodes in the semantic tree that correspond to + // primed vars. It is unclear why OpApplNodes do not get marked as primed when + // instantiated. The logic in Tool#getPrimedLocs is too obscure to tell. + final ObjLongTable<SemanticNode>.Enumerator<SemanticNode> keys = tool.getPrimedLocs().keys(); + SemanticNode sn; + while ((sn = keys.nextElement()) != null) { + this.nodes.add(new OpApplNodeWrapper((OpApplNode) sn, null)); + } + } + + private CostModel getCM(final Action act, final ActionWrapper.Relation relation) { + this.substs.clear(); + this.node2Wrapper.clear(); + this.opDefNodes.clear(); + this.stack.clear(); + this.ctx = Context.Empty; + + this.root = new ActionWrapper(act, relation); + this.stack.push(root); + act.pred.walkGraph(new CoverageHashTable(opDefNodes), this); + + assert this.stack.peek().isRoot(); + return this.stack.peek().getRoot(); + } + + @Override + public void preVisit(final ExploreNode exploreNode) { + if (exploreNode instanceof OpApplNode) { + final OpApplNode opApplNode = (OpApplNode) exploreNode; + if (opApplNode.isStandardModule()) { + return; + } + + final OpApplNodeWrapper oan; + if (opApplNode.hasOpcode(OPCODE_unchanged)) { + oan = new UnchangedOpApplNodeWrapper(opApplNode, this.root); + } else { + oan = new OpApplNodeWrapper(opApplNode, this.root); + } + + if (nodes.contains(oan)) { + oan.setPrimed(); + } + + // CONSTANT operators (including definition overrides...) + final SymbolNode operator = opApplNode.getOperator(); + final Object val = tool.lookup(operator); + if (val instanceof OpDefNode && operator != val) { // second conjunct bc lookup returns operator when nothing else found. + final OpDefNode odn = (OpDefNode) val; + final ExprNode body = odn.getBody(); + if (body instanceof OpApplNode) { + final CostModelCreator substitution = new CostModelCreator(body, tool); + oan.addChild((OpApplNodeWrapper) substitution.getModel()); + } + } + + // RECURSIVE + if (operator instanceof OpDefNode) { + final OpDefNode odn = (OpDefNode) operator; + if (odn.getInRecursive()) { + final OpApplNodeWrapper recursive = (OpApplNodeWrapper) stack.stream() + .filter(w -> w.getNode() != null && ((OpApplNode) w.getNode()).getOperator() == odn).findFirst() + .orElse(null); + if (recursive != null) { + oan.setRecursive(recursive); + } + } + } + + // Higher-order operators/Operators as arguments (LAMBDA, ...) + if (tool != null && operator instanceof OpDefNode && opApplNode.hasOpcode(0)) { + // 1) Maintain Context as done by Tool... + final OpDefNode odn = (OpDefNode) operator; + this.ctx = tool.getOpContext(odn, opApplNode.getArgs(), ctx, false); + } + final Object lookup = this.ctx.lookup(opApplNode.getOperator()); + if (lookup instanceof OpDefNode) { + // 2) Context has an entry for the given body. Remember for later. + final ExprNode body = ((OpDefNode) lookup).getBody(); + if (body instanceof OpApplNode) { + this.node2Wrapper.put((OpApplNode) body, oan); + } + } + if (this.node2Wrapper.containsKey(opApplNode)) { + // 3) Now its later. Connect w and oan. + final OpApplNodeWrapper w = this.node2Wrapper.get(opApplNode); + w.addChild(oan); + } + + // Substitutions + if (this.substs.containsKey(exploreNode)) { + final Subst subst = this.substs.get(exploreNode); + assert subst.getExpr() == oan.getNode(); + subst.setCM(oan); + } + + final CostModelNode parent = stack.peek(); + parent.addChild(oan.setLevel(parent.getLevel() + 1)); + stack.push(oan); + } else if (exploreNode instanceof SubstInNode) { + final SubstInNode sin = (SubstInNode) exploreNode; + final Subst[] substs = sin.getSubsts(); + for (Subst subst : substs) { + this.substs.put(subst.getExpr(), subst); + } + } else if (exploreNode instanceof OpDefNode) { + //TODO Might suffice to just keep RECURSIVE ones. + opDefNodes.add((OpDefNode) exploreNode); + } + } + + @Override + public void postVisit(final ExploreNode exploreNode) { + if (exploreNode instanceof OpApplNode) { + if (((OpApplNode) exploreNode).isStandardModule()) { + return; + } + final CostModelNode pop = stack.pop(); + assert pop.getNode() == exploreNode; + } else if (exploreNode instanceof OpDefNode) { + final boolean removed = opDefNodes.remove((OpDefNode) exploreNode); + assert removed; + } + } + + private CostModel getModel() { + assert this.stack.peek().isRoot(); + return this.stack.peek().getRoot(); + } + + public static final void create(final ITool tool) { + final CostModelCreator collector = new CostModelCreator(tool); + + // TODO Start from the ModuleNode similar to how the Explorer works. It is + // unclear how to lookup the corresponding subtree in the global CM graph + // in getNextState and getInitStates of the model checker. + final Vect<Action> init = tool.getInitStateSpec(); + for (int i = 0; i < init.size(); i++) { + final Action initAction = init.elementAt(i); + initAction.cm = collector.getCM(initAction, Relation.INIT); + } + + final Map<SemanticNode, CostModel> cms = new HashMap<>(); + for (Action nextAction : tool.getActions()) { + if (cms.containsKey(nextAction.pred)) { + nextAction.cm = cms.get(nextAction.pred); + } else { + nextAction.cm = collector.getCM(nextAction, Relation.NEXT); + cms.put(nextAction.pred, nextAction.cm); + } + } + + for (Action invariant : tool.getInvariants()) { + invariant.cm = collector.getCM(invariant, Relation.PROP); + } + } + + public static void report(final ITool tool, final long startTime) { + MP.printMessage(EC.TLC_COVERAGE_START); + OutputCollector.setModuleNode(tool.getRootModule()); + final Vect<Action> init = tool.getInitStateSpec(); + for (int i = 0; i < init.size(); i++) { + final Action initAction = init.elementAt(i); + initAction.cm.report(); + } + + // Order next-state actions based on location to print in order of location. + // Note that Action[] actions may contain action instances with identical + // location which is the case for actions that are evaluated in the scope of a + // Context, i.e. \E s \in ProcSet: action(s) \/ ... + // However, actions with identical location share the ActionWrapper instance + // which is why we can non-deterministically choose to report one of it without + // producing bogus results (see CostModelCreator.preVisit(ExploreNode) above). + final Action[] actions = tool.getActions(); + final Set<CostModel> reported = new HashSet<>(); + final Set<Action> sortedActions = new TreeSet<>(new Comparator<Action>() { + @Override + public int compare(Action o1, Action o2) { + return o1.pred.getLocation().compareTo(o2.pred.getLocation()); + } + }); + sortedActions.addAll(Arrays.asList(actions)); + for (Action action : sortedActions) { + if (!reported.contains(action.cm)) { + action.cm.report(); + reported.add(action.cm); + } + } + + for (Action invariant : tool.getInvariants()) { + //TODO May need to be ordered similar to next-state actions above. + invariant.cm.report(); + } + + // Notify users about the performance overhead related to coverage collection + // after N minutes of model checking. The assumption is that a user has little + // interest in coverage for a large (long-running) model anyway. In the future + // it is hopefully possible to switch from profiling to sampling to relax the + // performance overhead of coverage and cost statistics. + final long l = System.currentTimeMillis() - startTime; + if (l > (5L * 60L * 1000L)) { + MP.printMessage(EC.TLC_COVERAGE_END_OVERHEAD); + } else { + MP.printMessage(EC.TLC_COVERAGE_END); + } + } +} diff --git a/tlatools/src/tlc2/tool/coverage/CostModelNode.java b/tlatools/src/tlc2/tool/coverage/CostModelNode.java new file mode 100644 index 0000000000000000000000000000000000000000..7b4700eb5bfc9b2482b11bca912e39c7965f349f --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/CostModelNode.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import java.util.LinkedHashMap; +import java.util.Map; + +import tla2sany.semantic.SemanticNode; +import tla2sany.st.Location; +import tlc2.TLCGlobals; +import tlc2.util.statistics.CounterStatistic; + +public abstract class CostModelNode implements CostModel { + + // children has to preserve order to later traverse tree in the module location + // order when reporting coverage. Thus, use LinkedHashMap here. + protected final Map<SemanticNode, CostModelNode> children = new LinkedHashMap<>(); + + protected final CounterStatistic stats = CounterStatistic.getInstance(() -> TLCGlobals.isCoverageEnabled()); + protected final CounterStatistic secondary = CounterStatistic.getInstance(() -> TLCGlobals.isCoverageEnabled()); + + // ---------------- Statistics ---------------- // + + protected long getEvalCount() { + return this.stats.getCount(); + } + + protected long getSecondary() { + return this.secondary.getCount(); + } + + protected abstract Location getLocation(); + + // -- --// + + void addChild(final CostModelNode child) { + final boolean newlyInserted = this.children.put(child.getNode(), child) == null; + assert newlyInserted; + } + + abstract SemanticNode getNode(); + + @Override + public abstract CostModelNode getRoot(); + + boolean isRoot() { + return false; + } + + int getLevel() { + return 0; + } + + // -- -- // + + @Override + public final CostModel getAndIncrement(final SemanticNode eon) { + return get(eon).incInvocations(); + } + + @Override + public final CostModel incInvocations(long size) { + this.stats.add(size); + return this; + } + + @Override + public final CostModel incInvocations() { + this.stats.increment(); + return this; + } + + public final CostModel incSecondary() { + this.secondary.increment(); + return this; + } + + @Override + public final CostModel incSecondary(final long value) { + this.secondary.add(value); + return this; + } +} diff --git a/tlatools/src/tlc2/tool/coverage/CoverageHashTable.java b/tlatools/src/tlc2/tool/coverage/CoverageHashTable.java new file mode 100644 index 0000000000000000000000000000000000000000..c4b3fede60cd40bd3a2f452e564d9eaa6f8cabdf --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/CoverageHashTable.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import java.util.Set; + +import tla2sany.explorer.ExploreNode; +import tla2sany.semantic.OpDefNode; + +@SuppressWarnings("serial") +class CoverageHashTable extends java.util.Hashtable<Integer, ExploreNode> { + private final Set<OpDefNode> nodes; + + public CoverageHashTable(final Set<OpDefNode> nodes) { + this.nodes = nodes; + } + + @Override + public ExploreNode get(Object key) { + // Return null here to visit an OpDefNode D multiple times if D is "called" from + // multiple OpApplNodes. However, stop endless recursion if D is a RECURSIVE + // operator. + final ExploreNode v = super.get(key); + if (v instanceof OpDefNode) { + final OpDefNode odn = (OpDefNode) v; + if (odn.getInRecursive()) { + if (nodes.contains(odn)) { + // RECURSIVE operators + return v; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java b/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..f2c0e0ee8511713b175ff4149250642583e2593f --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java @@ -0,0 +1,331 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import java.util.HashSet; +import java.util.Set; + +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.st.Location; +import tlc2.TLCGlobals; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.output.OutputCollector; + +public class OpApplNodeWrapper extends CostModelNode implements Comparable<OpApplNodeWrapper>, CostModel { + + private final Set<Long> childCounts = new HashSet<>(); + private final CostModelNode root; + private final OpApplNode node; + // Periodic coverage reporting executes concurrently with the evaluation of the + // init and next-state relation. Traversing the CostModel trees to collect the + // individual eval counts creates thus an inconsistent snapshot. To reduce the + // inconsistency, freeze the eval count for all tree nodes on the first tree + // traversal while the child counts are calculated. The snapshot is still + // inconsistent from the perspective of the evaluation, but at least the + // reporting in print (eval counts reported to parent - childCounts - and eval + // counts printed is consistent. Alternatively, evaluation of init and next + // could be suspended for the duration of the snapshot, but that seems overkill. + private long snapshotEvalCount = 0; + private boolean primed = false; + private int level; + private OpApplNodeWrapper recursive; + + OpApplNodeWrapper(OpApplNode node, CostModelNode root) { + super(); + this.node = node; + this.root = root; + this.level = 0; + } + + // For unit testing only. + OpApplNodeWrapper() { + this(null, null); + } + + // For unit testing only. + OpApplNodeWrapper(OpApplNode node, long samples) { + this(node, null); + this.incInvocations(samples); + } + + // ---------------- Identity... ---------------- // + + @Override + public int compareTo(OpApplNodeWrapper arg0) { + return this.getLocation().compareTo(arg0.getLocation()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((node.getLocation() == null) ? 0 : node.getLocation().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + OpApplNodeWrapper other = (OpApplNodeWrapper) obj; + if (node.getLocation() == null) { + if (other.node.getLocation() != null) + return false; + } else if (!node.getLocation().equals(other.node.getLocation())) { + return false; + } + return true; + + } + + @Override + public String toString() { + if (this.node == null) { + return "root"; + } + return node.toString(); + } + + // ---------------- ---------------- // + + @Override + protected Location getLocation() { + return this.node != null ? this.node.getLocation() : Location.nullLoc; + } + + public OpApplNode getNode() { + return this.node; + } + + public boolean isRoot() { + return this.node == null; + } + + // ---------------- Parent <> Child ---------------- // + + public OpApplNodeWrapper setRecursive(OpApplNodeWrapper recursive) { + assert this.recursive == null; + this.recursive = recursive; + return this; + } + + @Override + public CostModelNode getRoot() { + assert this.root instanceof ActionWrapper; + return this.root; + } + + private final Set<Integer> seen = new HashSet<>(); + + @Override + public final CostModelNode get(final SemanticNode eon) { + if (eon == this.node || !(eon instanceof OpApplNode)) { + return this; + } + + CostModelNode child = children.get(eon); + if (child != null) { + return child; + } + + if (recursive != null) { + child = recursive.children.get(eon); + if (child != null) { + return child; + } + } + + // TODO Not all places in Tool lookup the correct CM yet. This should only be an + // engineering effort though. + if (seen.add(eon.myUID)) { + //...only report it once to not spam the Toolbox console. + MP.printMessage(EC.TLC_COVERAGE_MISMATCH, new String[] { eon.toString(), this.toString() }); + } + return this; + } + + // ---------------- Level ---------------- // + + public int getLevel() { + return this.level; + } + + public OpApplNodeWrapper setLevel(int level) { + this.level = level; + return this; + } + + // ---------------- Primed ---------------- // + + public OpApplNodeWrapper setPrimed() { + assert !isPrimed(); + this.primed = true; + return this; + } + + protected boolean isPrimed() { + return this.primed; + } + + // ---------------- Print ---------------- // + + protected long getEvalCount(Calculate fresh) { + if (fresh == Calculate.FRESH) { + return super.getEvalCount(); + } else { + return snapshotEvalCount; + } + } + + public CostModel report() { + print(0, Calculate.FRESH); + return this; + } + + protected void print(int level, final Calculate fresh) { + final Set<Long> collectedEvalCounts = new HashSet<>(); + this.collectChildren(collectedEvalCounts, fresh); + if (collectedEvalCounts.isEmpty()) { + // Subtree has nothing to report. + if (getEvalCount(fresh) == 0l && !isPrimed()) { + // ..this node neither. + return; + } else { + printSelf(level++); + return; // Do not invoke printSelf(...) again below. + } + } + + if (collectedEvalCounts.size() == 1) { + final long count = getCount(collectedEvalCounts); + + if (count < getEvalCount(fresh)) { + // Cannot collapse subtree because inconsistent with this node. + printSelf(level++); + printChildren(level); + return; + } + if (!isPrimed() && getEvalCount(fresh) == 0l && count != 0l) { + // Collapse consistent subtree into this node unless this node is primed. + printSelf(level++, count); + return; + } + if (getEvalCount(fresh) == count && count == 0l) { + if (isPrimed()) { + printSelf(level++); + } + // Have a primed in subtree. + printChildren(level); + return; + } + if (getEvalCount(fresh) == count) { + // Have a primed in subtree. + printSelf(level++); + return; + } + } + + // Subtree is inconsistent and needs to report itself. + if (getEvalCount(fresh) > 0 || isPrimed()) { + printSelf(level++); + } + printChildren(level); + } + + private long getCount(Set<Long> collectWeights) { + assert collectWeights.size() == 1; + for (Long l : collectWeights) { + return l; + } + return -1l; // make compiler happy + } + + protected void printChildren(final int level) { + for (CostModelNode cmn : children.values()) { + ((OpApplNodeWrapper) cmn).print(level, Calculate.CACHED); + } + } + + protected void printSelf(final int level, final long count) { + MP.printMessage(EC.TLC_COVERAGE_VALUE, new String[] { + indentBegin(level, TLCGlobals.coverageIndent, getLocation().toString()), String.valueOf(count) }); + OutputCollector.putLineCount(getLocation(), count); + } + + protected void printSelf(final int level, final long count, final long cost) { + MP.printMessage(EC.TLC_COVERAGE_VALUE_COST, + new String[] { indentBegin(level, TLCGlobals.coverageIndent, getLocation().toString()), + String.valueOf(count), String.valueOf(cost) }); + OutputCollector.putLineCount(getLocation(), count); + } + + protected void printSelf(final int level) { + if (getSecondary() > 0) { + printSelf(level, getEvalCount(), getSecondary()); + } else { + printSelf(level, getEvalCount()); + } + } + + protected static String indentBegin(final int n, final char c, final String str) { + assert n >= 0; + final String whitespaces = new String(new char[n]).replace('\0', c); + return whitespaces + str; + } + + // ---------------- Child counts ---------------- // + + protected enum Calculate { + FRESH, CACHED; + } + + protected void collectChildren(final Set<Long> result, Calculate c) { + for (CostModelNode cmn : children.values()) { + ((OpApplNodeWrapper) cmn).collectAndFreezeEvalCounts(result, c); + } + } + + protected void collectAndFreezeEvalCounts(final Set<Long> result, final Calculate c) { + if (c == Calculate.FRESH) { + snapshotEvalCount = this.getEvalCount(c); + childCounts.clear(); + if (snapshotEvalCount > 0 || this.isPrimed()) { + childCounts.add(snapshotEvalCount); + } + collectChildren(childCounts, c); + } + result.addAll(childCounts); + } +} \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/coverage/RecursiveOpApplNodeWrapper.java b/tlatools/src/tlc2/tool/coverage/RecursiveOpApplNodeWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..98ab4bcfa7c5d5adad94e569b4b2989e4b54cc79 --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/RecursiveOpApplNodeWrapper.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) Nov 20, 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +public final class RecursiveOpApplNodeWrapper extends OpApplNodeWrapper { + + RecursiveOpApplNodeWrapper() { + super(null, null); + } + + @Override + public boolean isRoot() { + assert this.getNode() == null; + return true; + } + + @Override + public CostModelNode getRoot() { + assert this.children.size() == 1; + return this.children.values().iterator().next(); + } +} diff --git a/tlatools/src/tlc2/tool/coverage/UnchangedOpApplNodeWrapper.java b/tlatools/src/tlc2/tool/coverage/UnchangedOpApplNodeWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..58a02229e49c932a39d6148c85fc2bf0af0bff46 --- /dev/null +++ b/tlatools/src/tlc2/tool/coverage/UnchangedOpApplNodeWrapper.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import java.util.HashSet; +import java.util.Set; + +import tla2sany.semantic.OpApplNode; + +public class UnchangedOpApplNodeWrapper extends OpApplNodeWrapper { + + public UnchangedOpApplNodeWrapper(OpApplNode opApplNode, ActionWrapper root) { + super(opApplNode, root); + } + + @Override + protected boolean isPrimed() { + return true; + } + + @Override + protected void print(int level, final Calculate fresh) { + final Set<Long> collectedEvalCounts = new HashSet<>(); + this.collectChildren(collectedEvalCounts, fresh); + collectedEvalCounts.remove(0L); + if (collectedEvalCounts.isEmpty()) { + printSelf(level++); + return; + } else { + printSelf(level, Math.max(getEvalCount(), collectedEvalCounts.iterator().next())); + } + } +} diff --git a/tlatools/src/tlc2/tool/distributed/TLCApp.java b/tlatools/src/tlc2/tool/distributed/TLCApp.java index 696b53305179ca4169a3062c818a441dccd7366a..f880583ce064312d6189d6a19ab8f3bf65a12edb 100644 --- a/tlatools/src/tlc2/tool/distributed/TLCApp.java +++ b/tlatools/src/tlc2/tool/distributed/TLCApp.java @@ -6,26 +6,22 @@ package tlc2.tool.distributed; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; import java.util.List; import model.InJarFilenameToStream; import model.ModelInJar; -import tla2sany.modanalyzer.ParseUnit; -import tla2sany.modanalyzer.SpecObj; import tlc2.TLCGlobals; import tlc2.tool.Action; import tlc2.tool.IStateFunctor; +import tlc2.tool.ITool; import tlc2.tool.StateVec; import tlc2.tool.TLCState; import tlc2.tool.TLCStateInfo; -import tlc2.tool.Tool; import tlc2.tool.WorkerException; import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; +import tlc2.tool.impl.Tool; import tlc2.util.FP64; -import tlc2.value.Value; import util.FileUtil; import util.FilenameToStream; import util.ToolIO; @@ -34,30 +30,29 @@ import util.UniqueString; public class TLCApp extends DistApp { private String config; - private final SpecObj specObj; /* Constructors */ public TLCApp(String specFile, String configFile, boolean deadlock, String fromChkpt, FPSetConfiguration fpSetConfig) throws IOException { - this(specFile, configFile, deadlock, true, null); + this(specFile, configFile, deadlock, null); this.fromChkpt = fromChkpt; - this.metadir = FileUtil.makeMetaDir(this.tool.specDir, fromChkpt); + this.metadir = FileUtil.makeMetaDir(this.tool.getSpecDir(), fromChkpt); this.fpSetConfig = fpSetConfig; } public TLCApp(String specFile, String configFile, boolean deadlock, String fromChkpt, FPSetConfiguration fpSetConfig, FilenameToStream fts) throws IOException { - this(specFile, configFile, deadlock, true, fts); + this(specFile, configFile, deadlock, fts); this.fromChkpt = fromChkpt; - this.metadir = FileUtil.makeMetaDir(this.tool.specDir, fromChkpt); + this.metadir = FileUtil.makeMetaDir(this.tool.getSpecDir(), fromChkpt); this.fpSetConfig = fpSetConfig; } // TODO too many constructors redefinitions, replace with this(..) calls public TLCApp(String specFile, String configFile, - Boolean deadlock, Boolean preprocess, FilenameToStream fts) throws IOException { + Boolean deadlock, FilenameToStream fts) throws IOException { // get the spec dir from the spec file int lastSep = specFile.lastIndexOf(File.separatorChar); @@ -67,20 +62,11 @@ public class TLCApp extends DistApp { this.config = configFile; - // TODO NameResolver + + this.checkDeadlock = deadlock.booleanValue(); + this.preprocess = true; this.tool = new Tool(specDir, specFile, configFile, fts); - // SZ Feb 24, 2009: setup the user directory - if (ToolIO.getUserDir() == null) { - // First one to set specDir wins. This should only ever be the case - // With DistributedTLCTestCase which runs TLCServer and TLCWorker in - // a single VM. - ToolIO.setUserDir(specDir); - } - this.checkDeadlock = deadlock.booleanValue(); - this.preprocess = preprocess.booleanValue(); - // SZ Feb 20, 2009: added null reference to SpecObj - specObj = this.tool.init(this.preprocess, null); this.impliedInits = this.tool.getImpliedInits(); this.invariants = this.tool.getInvariants(); this.impliedActions = this.tool.getImpliedActions(); @@ -88,13 +74,13 @@ public class TLCApp extends DistApp { } /* Fields */ - public Tool tool; + public ITool tool; public Action[] invariants; // the invariants to be checked public Action[] impliedInits; // the implied-inits to be checked public Action[] impliedActions; // the implied-actions to be checked public Action[] actions; // the subactions private boolean checkDeadlock; // check deadlock? - private boolean preprocess; // preprocess? + private final boolean preprocess; // preprocess? private String fromChkpt = null; // recover from this checkpoint private String metadir = null; // the directory pathname for metadata private FPSetConfiguration fpSetConfig; @@ -117,14 +103,14 @@ public class TLCApp extends DistApp { * @see tlc2.tool.distributed.DistApp#getFileName() */ public final String getFileName() { - return this.tool.rootFile; + return this.tool.getRootFile(); } /* (non-Javadoc) * @see tlc2.tool.distributed.DistApp#getSpecDir() */ public String getSpecDir() { - return this.tool.specDir; + return this.tool.getSpecDir(); } /* (non-Javadoc) @@ -149,16 +135,7 @@ public class TLCApp extends DistApp { } public List<File> getModuleFiles() { - final List<File> result = new ArrayList<File>(); - - final Enumeration<ParseUnit> parseUnitContext = this.specObj.parseUnitContext.elements(); - final FilenameToStream resolver = new InJarFilenameToStream(ModelInJar.PATH); - while (parseUnitContext.hasMoreElements()) { - ParseUnit pu = (ParseUnit) parseUnitContext.nextElement(); - File resolve = resolver.resolve(pu.getFileName(), false); - result.add(resolve); - } - return result; + return this.tool.getModuleFiles(new InJarFilenameToStream(ModelInJar.PATH)); } /* (non-Javadoc) @@ -378,7 +355,7 @@ public class TLCApp extends DistApp { } } else if (args[index].equals("-terse")) { index++; - Value.expand = false; + TLCGlobals.expand = false; } else if (args[index].equals("-nowarning")) { index++; TLCGlobals.warn = false; diff --git a/tlatools/src/tlc2/tool/distributed/TLCServer.java b/tlatools/src/tlc2/tool/distributed/TLCServer.java index 8c6070978fc97bca8d23e9c52592139a879fa336..e6b199d3bd03d0b0622f0c00aedef9ef5d41252a 100644 --- a/tlatools/src/tlc2/tool/distributed/TLCServer.java +++ b/tlatools/src/tlc2/tool/distributed/TLCServer.java @@ -54,6 +54,7 @@ import tlc2.tool.queue.DiskStateQueue; import tlc2.tool.queue.IStateQueue; import tlc2.util.FP64; import util.Assert; +import util.Assert.TLCRuntimeException; import util.FileUtil; import util.MailSender; import util.UniqueString; @@ -201,7 +202,7 @@ public class TLCServer extends UnicastRemoteObject implements TLCServerRMI, final FPSet fpSet = FPSetFactory.getFPSet(work.getFPSetConfiguration()); fpSet.init(1, metadir, work.getFileName()); return new NonDistributedFPSetManager(fpSet, InetAddress.getLocalHost() - .getCanonicalHostName()); + .getCanonicalHostName(), trace); } /* (non-Javadoc) @@ -451,9 +452,10 @@ public class TLCServer extends UnicastRemoteObject implements TLCServerRMI, // would require synchronization among all (distributed) // workers. In distributed mode, it is of limited use anyway. if (e instanceof EvalException - && ((EvalException) e).getErrorCode() == EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE - && (((EvalException) e).getMessage().contains("tlc2.module.TLC.TLCSet") - || ((EvalException) e).getMessage().contains("tlc2.module.TLC.TLCGet"))) { + && ((EvalException) e).getErrorCode() == EC.TLC_MODULE_TLCGET_UNDEFINED + && (((EvalException) e).getMessage().contains("TLCSet") + || ((EvalException) e).getMessage().contains("TLCGet")) + || (e instanceof TLCRuntimeException && ((TLCRuntimeException) e).errorCode == EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE)) { MP.printError(EC.TLC_FEATURE_UNSUPPORTED, "TLCSet & TLCGet operators not supported by distributed TLC."); } else { @@ -528,9 +530,13 @@ public class TLCServer extends UnicastRemoteObject implements TLCServerRMI, distinctStatesPerMinute = (long) ((fpSetSize - oldFPSetSize) / factor); // print to system.out - MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { String.valueOf(trace.getLevelForReporting()), - String.valueOf(numOfGenStates), String.valueOf(fpSetSize), - String.valueOf(getNewStates()), String.valueOf(statesPerMinute), String.valueOf(distinctStatesPerMinute) }); + MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { + String.valueOf(trace.getLevelForReporting()), + MP.format(numOfGenStates), + MP.format(fpSetSize), + MP.format(getNewStates()), + MP.format(statesPerMinute), + MP.format(distinctStatesPerMinute) }); // Make the TLCServer main thread sleep for one report interval wait(REPORT_INTERVAL); @@ -602,9 +608,9 @@ public class TLCServer extends UnicastRemoteObject implements TLCServerRMI, // Postprocessing: if (hasNoErrors()) { // We get here because the checking has succeeded. - final double actualProb = fpSetManager.checkFPs(); + final long actualDistance = fpSetManager.checkFPs(); final long statesSeen = fpSetManager.getStatesSeen(); - ModelChecker.reportSuccess(finalNumberOfDistinctStates, actualProb, statesSeen); + ModelChecker.reportSuccess(finalNumberOfDistinctStates, actualDistance, statesSeen); } else if (keepCallStack) { // We redo the work on the error state, recording the call stack. work.setCallStack(); @@ -677,9 +683,12 @@ public class TLCServer extends UnicastRemoteObject implements TLCServerRMI, public static final void printSummary(int level, long statesGenerated, long statesLeftInQueue, long distinctStates, boolean success) throws IOException { if (TLCGlobals.tool) { - MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { String.valueOf(level), - String.valueOf(statesGenerated), String.valueOf(distinctStates), - String.valueOf(statesLeftInQueue), "0", "0" }); + MP.printMessage(EC.TLC_PROGRESS_STATS, new String[] { + String.valueOf(level), + MP.format(statesGenerated), + MP.format(distinctStates), + MP.format(statesLeftInQueue), + "0", "0" }); } MP.printMessage(EC.TLC_STATS, new String[] { String.valueOf(statesGenerated), diff --git a/tlatools/src/tlc2/tool/distributed/TLCWorker.java b/tlatools/src/tlc2/tool/distributed/TLCWorker.java index 43c17683c2a2e662c2d54ac93d9189c33d455578..b4cbeca16890a016137f0ce7bf0aab8f446fc9f6 100644 --- a/tlatools/src/tlc2/tool/distributed/TLCWorker.java +++ b/tlatools/src/tlc2/tool/distributed/TLCWorker.java @@ -372,8 +372,7 @@ public class TLCWorker extends UnicastRemoteObject implements TLCWorkerRMI { fts.setTLCServer(server); DistApp work = new TLCApp(server.getSpecFileName(), - server.getConfigFileName(), server.getCheckDeadlock(), - server.getPreprocess(), fts); + server.getConfigFileName(), server.getCheckDeadlock(), fts); final IFPSetManager fpSetManager = server.getFPSetManager(); diff --git a/tlatools/src/tlc2/tool/distributed/fp/FPSetManager.java b/tlatools/src/tlc2/tool/distributed/fp/FPSetManager.java index aef350cd022e840fd7728225a8017035e9d0d154..582ff06b056529c0c7ceace497ec4e7eaa80bf83 100644 --- a/tlatools/src/tlc2/tool/distributed/fp/FPSetManager.java +++ b/tlatools/src/tlc2/tool/distributed/fp/FPSetManager.java @@ -421,19 +421,19 @@ public abstract class FPSetManager implements IFPSetManager { /* (non-Javadoc) * @see tlc2.tool.distributed.IFPSetManager#checkFPs() */ - public double checkFPs() { + public long checkFPs() { final int len = this.fpSets.size(); // Instantiation of a thread pool here is fine, as long as checkFPs is only called seldomly. final ExecutorService executorService = Executors.newFixedThreadPool(len); try { // Start checkFP on all FPSets concurrently // (checkFPs scans the full set sequentially!) - final CompletionService<Double> ecs = new ExecutorCompletionService<Double>(executorService); + final CompletionService<Long> ecs = new ExecutorCompletionService<Long>(executorService); for (int i = 0; i < len; i++) { ecs.submit(new CheckFPsCallable(fpSets.get(i).getFpset())); } // Return minimum value - double res = Double.MAX_VALUE; + long res = Long.MAX_VALUE; for (int i = 0; i < len; i++) { try { res = Math.min(res, ecs.take().get()); diff --git a/tlatools/src/tlc2/tool/distributed/fp/FPSetRMI.java b/tlatools/src/tlc2/tool/distributed/fp/FPSetRMI.java index 4d74ad1a38f4fa63e28c24d0a8f0a6f8bdd707d7..b44d0e5200af17117ef6a26ccde5b5081e38590a 100644 --- a/tlatools/src/tlc2/tool/distributed/fp/FPSetRMI.java +++ b/tlatools/src/tlc2/tool/distributed/fp/FPSetRMI.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.rmi.Remote; import java.rmi.RemoteException; +import tlc2.tool.TLCTrace; import tlc2.tool.fp.FPSet; import tlc2.util.BitVector; import tlc2.util.LongVec; @@ -32,7 +33,7 @@ public interface FPSetRMI extends Remote { * This distance reflects the probability of a fingerprint * collision. */ - double checkFPs() throws IOException; + long checkFPs() throws IOException; /** * @see FPSet#checkInvariant() @@ -102,7 +103,7 @@ public interface FPSetRMI extends Remote { */ BitVector putBlock(LongVec fpv) throws IOException; - void recover() throws IOException; + void recover(TLCTrace trace) throws IOException; void recover(String filename) throws IOException; diff --git a/tlatools/src/tlc2/tool/distributed/fp/IFPSetManager.java b/tlatools/src/tlc2/tool/distributed/fp/IFPSetManager.java index c179b1d54eeb67a4d07f74f9676f2596ddc9a84c..11299ec9f16a4d0d838f8d3a0b6d40adba4f7fd6 100644 --- a/tlatools/src/tlc2/tool/distributed/fp/IFPSetManager.java +++ b/tlatools/src/tlc2/tool/distributed/fp/IFPSetManager.java @@ -20,7 +20,7 @@ public interface IFPSetManager extends Serializable { /** * @see FPSetRMI#checkFPs() */ - double checkFPs(); + long checkFPs(); /** * @see FPSetRMI#checkInvariant() diff --git a/tlatools/src/tlc2/tool/distributed/fp/NonDistributedFPSetManager.java b/tlatools/src/tlc2/tool/distributed/fp/NonDistributedFPSetManager.java index 87ea734a4f081ad5b07766b39a80d4844e0f910f..659b064cac2da203497b82283244245adcc7e630 100644 --- a/tlatools/src/tlc2/tool/distributed/fp/NonDistributedFPSetManager.java +++ b/tlatools/src/tlc2/tool/distributed/fp/NonDistributedFPSetManager.java @@ -6,6 +6,7 @@ import java.util.concurrent.ExecutorService; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.TLCTrace; import tlc2.util.BitVector; import tlc2.util.LongVec; @@ -14,11 +15,13 @@ public class NonDistributedFPSetManager implements IFPSetManager { private final FPSetRMI fpSet; private final String hostname; + private final transient TLCTrace trace; // Do not serialize trace and send it over the wire. Recovery executes on the master, not on the workers. public NonDistributedFPSetManager(final FPSetRMI fpSet, - final String hostname) throws IOException { + final String hostname, TLCTrace trace) throws IOException { this.fpSet = fpSet; this.hostname = hostname; + this.trace = trace; } /* (non-Javadoc) @@ -137,7 +140,7 @@ public class NonDistributedFPSetManager implements IFPSetManager { /* (non-Javadoc) * @see tlc2.tool.distributed.fp.FPSetManager#checkFPs() */ - public double checkFPs() { + public long checkFPs() { try { return this.fpSet.checkFPs(); } catch (IOException e) { @@ -211,7 +214,7 @@ public class NonDistributedFPSetManager implements IFPSetManager { * @see tlc2.tool.distributed.fp.FPSetManager#recover(java.lang.String) */ public void recover(String fname) throws InterruptedException, IOException { - this.fpSet.recover(); + this.fpSet.recover(trace); } /* (non-Javadoc) diff --git a/tlatools/src/tlc2/tool/distributed/fp/callable/CheckFPsCallable.java b/tlatools/src/tlc2/tool/distributed/fp/callable/CheckFPsCallable.java index 3b9871414e63dc67b1dc8026ca97e2522180c045..c07e2be4aaf8a02c6fd916f2fdf7a1eabf87f2d1 100644 --- a/tlatools/src/tlc2/tool/distributed/fp/callable/CheckFPsCallable.java +++ b/tlatools/src/tlc2/tool/distributed/fp/callable/CheckFPsCallable.java @@ -8,7 +8,7 @@ import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.distributed.fp.FPSetRMI; -public class CheckFPsCallable implements Callable<Double> { +public class CheckFPsCallable implements Callable<Long> { private final FPSetRMI fpSetRMI; public CheckFPsCallable(FPSetRMI fpSetRMI) { @@ -18,7 +18,7 @@ public class CheckFPsCallable implements Callable<Double> { /* (non-Javadoc) * @see java.util.concurrent.Callable#call() */ - public Double call() throws Exception { + public Long call() throws Exception { try { return fpSetRMI.checkFPs(); } catch (IOException e) { @@ -26,7 +26,7 @@ public class CheckFPsCallable implements Callable<Double> { MP.printError(EC.GENERAL, e); // return max value to indicate to caller that the result is // incorrect. - return Double.MAX_VALUE; + return Long.MAX_VALUE; } } } \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/distributed/management/TLCServerMXWrapper.java b/tlatools/src/tlc2/tool/distributed/management/TLCServerMXWrapper.java index 2a9e52c6826fc75eea3735d2f3a5a140c025959e..420999af8669c2202f1ba4adea3cd0469c5573ac 100644 --- a/tlatools/src/tlc2/tool/distributed/management/TLCServerMXWrapper.java +++ b/tlatools/src/tlc2/tool/distributed/management/TLCServerMXWrapper.java @@ -161,4 +161,35 @@ public class TLCServerMXWrapper extends TLCStandardMBean implements TLCStatistic } return "N/A"; } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#stop() + */ + public void stop() { + synchronized (tlcServer) { + tlcServer.setDone(); + tlcServer.stateQueue.finishAll(); + tlcServer.notifyAll(); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#suspend() + */ + @Override + public void suspend() { + synchronized (tlcServer) { + tlcServer.stateQueue.suspendAll(); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#resume() + */ + @Override + public void resume() { + synchronized (tlcServer) { + tlcServer.stateQueue.resumeAll(); + } + } } diff --git a/tlatools/src/tlc2/tool/distributed/management/TLCStatisticsMXBean.java b/tlatools/src/tlc2/tool/distributed/management/TLCStatisticsMXBean.java index 4fa25190e1ba21d9fa96eb69fd990372ed93afcf..d49f008b71d90a5a857464dd626225a689def856 100644 --- a/tlatools/src/tlc2/tool/distributed/management/TLCStatisticsMXBean.java +++ b/tlatools/src/tlc2/tool/distributed/management/TLCStatisticsMXBean.java @@ -92,4 +92,20 @@ public interface TLCStatisticsMXBean { * @return The name of the model curreclty being checked by TLC. */ String getModelName(); + + /** + * Force TLC to stop model checking. + */ + void stop(); + + /** + * Suspend model checking until resume is called. + */ + void suspend(); + + /** + * Resumes model checking after a suspend. Do not resume an running model checker. + * It could interfere with model checking. + */ + void resume(); } diff --git a/tlatools/src/tlc2/tool/fp/DiskFPSet.java b/tlatools/src/tlc2/tool/fp/DiskFPSet.java index b7fdb65ff37cebc3817d4932d7c9b67e5afc5cdb..f032773b46e25ddf4f5794a4fba8313fd9503d80 100644 --- a/tlatools/src/tlc2/tool/fp/DiskFPSet.java +++ b/tlatools/src/tlc2/tool/fp/DiskFPSet.java @@ -19,6 +19,7 @@ import javax.management.NotCompliantMBeanException; import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.TLCTrace; +import tlc2.tool.TLCTrace.Enumerator; import tlc2.tool.fp.management.DiskFPSetMXWrapper; import tlc2.tool.management.TLCStandardMBean; import tlc2.util.BufferedRandomAccessFile; @@ -210,7 +211,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#init(int, java.lang.String, java.lang.String) */ - public void init(int numThreads, String aMetadir, String filename) + public FPSet init(int numThreads, String aMetadir, String filename) throws IOException { // Make it possible to pass in alternative location for the .fp and @@ -265,6 +266,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { new String[] { this.fpFilename, e.getMessage() }); throw new IOException(message); } + return this; } /* (non-Javadoc) @@ -368,8 +370,9 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { * @return true iff fp is on disk */ final boolean diskLookup(long fp) throws IOException { - if (this.index == null) + if (this.index == null) { return false; + } // Increment disk lookup counter this.diskLookupCnt.increment(); @@ -382,11 +385,13 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { long hiVal = this.index[hiPage]; // Test boundary cases (if not inside interval) - if (fp < loVal || fp > hiVal) + if (fp < loVal || fp > hiVal) { return false; - if (fp == hiVal) // why not check loVal? memLookup would have found it already! + } + if (fp == hiVal) {// why not check loVal? memLookup would have found it already! return true; - double dfp = (double) fp; + } + final double dfp = (double) fp; // a) find disk page that would potentially contain the fp. this.index contains // the first fp of each disk page @@ -398,10 +403,10 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { * * loVal <= fp < hiVal exists x: loPage < x < hiPage */ - double dhi = (double) hiPage; - double dlo = (double) loPage; - double dhiVal = (double) hiVal; - double dloVal = (double) loVal; + final double dhi = (double) hiPage; + final double dlo = (double) loPage; + final double dhiVal = (double) hiVal; + final double dloVal = (double) loVal; int midPage = (loPage + 1) + (int) ((dhi - dlo - 1.0) * (dfp - dloVal) / (dhiVal - dloVal)); @@ -410,7 +415,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { Assert.check(loPage < midPage && midPage < hiPage, EC.SYSTEM_INDEX_ERROR); - long v = this.index[midPage]; + final long v = this.index[midPage]; if (fp < v) { hiPage = midPage; hiVal = v; @@ -422,6 +427,11 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { return true; } } + return diskLookupBinarySearch(fp, indexLength, loPage, hiPage, loVal, hiVal, dfp); + } + + private final boolean diskLookupBinarySearch(final long fp, final int indexLength, final int loPage, final int hiPage, long loVal, long hiVal, + final double dfp) throws IOException { // no page is in between loPage and hiPage at this point Assert.check(hiPage == loPage + 1, EC.SYSTEM_INDEX_ERROR); @@ -435,18 +445,11 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { try { // b0) open file for reading that is associated with current thread BufferedRandomAccessFile raf; - int id = IdThread.GetId(this.braf.length); + final int id = IdThread.GetId(this.braf.length); if (id < this.braf.length) { raf = this.braf[id]; } else { - synchronized (this.brafPool) { - if (this.poolIndex < this.brafPool.length) { - raf = this.brafPool[this.poolIndex++]; - } else { - raf = new BufferedRandomAccessFile( - this.fpFilename, "r"); - } - } + raf = poolOpen(); } // b1) do interpolated binary search on disk page determined by a) @@ -468,7 +471,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { } else { diskSeekCache.increment(); } - long v = raf.readLong(); + final long v = raf.readLong(); if (fp < v) { hiEntry = midEntry; @@ -483,15 +486,9 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { } // b2) done doing disk search -> close file (finally candidate? => not really because if we exit with error, TLC exits) if (id >= this.braf.length) { - synchronized (this.brafPool) { - if (this.poolIndex > 0) { - this.brafPool[--this.poolIndex] = raf; - } else { - raf.close(); - } - } + poolClose(raf); } - } catch (IOException e) { + } catch (final IOException e) { if(midEntry * LongSize < 0) { // LL modified error message on 7 April 2012 MP.printError(EC.GENERAL, new String[]{"looking up a fingerprint, and" + @@ -504,6 +501,27 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { return diskHit; } + private final BufferedRandomAccessFile poolOpen() throws IOException { + synchronized (this.brafPool) { + if (this.poolIndex < this.brafPool.length) { + return this.brafPool[this.poolIndex++]; + } else { + return new BufferedRandomAccessFile( + this.fpFilename, "r"); + } + } + } + + private final void poolClose(final BufferedRandomAccessFile raf) throws IOException { + synchronized (this.brafPool) { + if (this.poolIndex > 0) { + this.brafPool[--this.poolIndex] = raf; + } else { + raf.close(); + } + } + } + /** * Calculates a mid entry where to divide the interval * @@ -601,7 +619,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#checkFPs() */ - public double checkFPs() throws IOException { + public long checkFPs() throws IOException { // It seems pointless to acquire the locks when checkFPs is only // executed after model checking has finished. Lock the disk // fingerprint sets though. Acquiring the locks is cheap. @@ -625,7 +643,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { } } braf.close(); - return (1.0 / dis); + return dis; } /* (non-Javadoc) @@ -763,19 +781,13 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#recover() */ - public final void recover() throws IOException { - long recoverPtr = TLCTrace.getRecoverPtr(); - final RandomAccessFile braf = new BufferedRandomAccessFile( - TLCTrace.getFilename(), "r"); - while (braf.getFilePointer() < recoverPtr) { - // drop readLongNat - if (braf.readInt() < 0) - braf.readInt(); - - long fp = braf.readLong(); + public final void recover(TLCTrace trace) throws IOException { + final Enumerator elements = trace.elements(); + while (elements.nextPos() != -1) { + long fp = elements.nextFP(); this.recoverFP(fp); } - braf.close(); + elements.close(); } private String getChkptName(String fname, String name) { diff --git a/tlatools/src/tlc2/tool/fp/FPSet.java b/tlatools/src/tlc2/tool/fp/FPSet.java index 316abdb58b19f412aafd2ab49dc35c09868ea5e1..8bf0987e10c8b2aa16fb5e5b356f9b7d409f1329 100644 --- a/tlatools/src/tlc2/tool/fp/FPSet.java +++ b/tlatools/src/tlc2/tool/fp/FPSet.java @@ -10,6 +10,7 @@ import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; +import tlc2.tool.TLCTrace; import tlc2.tool.distributed.fp.DistributedFPSet; import tlc2.tool.distributed.fp.FPSetRMI; import tlc2.util.BitVector; @@ -47,7 +48,7 @@ public abstract class FPSet extends UnicastRemoteObject implements FPSetRMI * override this method as necessary. This method must be called * after the constructor but before any of the other methods below. */ - public abstract void init(int numThreads, String metadir, String filename) throws IOException; + public abstract FPSet init(int numThreads, String metadir, String filename) throws IOException; public void incWorkers(int num) { // subclasses may override @@ -100,7 +101,7 @@ public abstract class FPSet extends UnicastRemoteObject implements FPSetRMI /* (non-Javadoc) * @see tlc2.tool.distributed.fp.FPSetRMI#checkFPs() */ - public abstract double checkFPs() throws IOException; + public abstract long checkFPs() throws IOException; /* (non-Javadoc) * @see tlc2.tool.distributed.fp.FPSetRMI#beginChkpt() @@ -115,7 +116,7 @@ public abstract class FPSet extends UnicastRemoteObject implements FPSetRMI /* (non-Javadoc) * @see tlc2.tool.distributed.fp.FPSetRMI#recover() */ - public abstract void recover() throws IOException; + public abstract void recover(TLCTrace trace) throws IOException; public abstract void recoverFP(long fp) throws IOException; diff --git a/tlatools/src/tlc2/tool/fp/FPSetFactory.java b/tlatools/src/tlc2/tool/fp/FPSetFactory.java index 0843520d451097fcba31c1b9a74bfdfc989b514b..6dd235f42e29487d6776f818819bd79093c12131 100644 --- a/tlatools/src/tlc2/tool/fp/FPSetFactory.java +++ b/tlatools/src/tlc2/tool/fp/FPSetFactory.java @@ -6,7 +6,12 @@ import java.lang.reflect.InvocationTargetException; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import util.TLCRuntime; @@ -116,6 +121,27 @@ public abstract class FPSetFactory { return new MSBDiskFPSet(fpSetConfig); } } + + + /** + * Create and *initialize* the set. + */ + public static Future<FPSet> getFPSetInitialized(final FPSetConfiguration fpSetConfiguration, final String metadir, + final String mainFile) { + final ExecutorService es = Executors.newSingleThreadExecutor(); + return es.submit(new Callable<FPSet>() { + @Override + public FPSet call() throws Exception { + try { + final FPSet fpSet = FPSetFactory.getFPSet(fpSetConfiguration); + fpSet.init(TLCGlobals.getNumWorkers(), metadir, mainFile); + return fpSet; + } finally { + es.shutdown(); + } + } + }); + } /** * @return A list of classes implementing {@link FPSet}. Eventually this diff --git a/tlatools/src/tlc2/tool/fp/LongArray.java b/tlatools/src/tlc2/tool/fp/LongArray.java index ee29c7ec352cb40ab0777d8219475be36794302a..82afa7971064cadd96f791558478ada45899c1d3 100644 --- a/tlatools/src/tlc2/tool/fp/LongArray.java +++ b/tlatools/src/tlc2/tool/fp/LongArray.java @@ -12,7 +12,25 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import sun.misc.Unsafe; +/* + * On Java 11 (probably starting with 9) sun.misc.Unsafe is implemented on top + * of jdk.internal.misc.Unsafe which provides a similar though not quiet + * identical API. While sun.misc.Unsafe remains available to client code such + * as LongArray in Java 11, parts of its API have already been dissolved + * (see e.g. https://bugs.openjdk.java.net/browse/JDK-8202999). This does not + * affect LongArray yet, but will probably affect LongArray in the future. + * Refactoring LongArray to replace sun.misc.Unsafe with jdk.internal.misc.Unsafe + * requires the following changes: + * - Replace sun.misc.Unsafe with jdk.internal.misc.Unsafe + * - Change Unsafe#compareAndSwapLong with Unsafe#compareAndSetLong in LongArray#trySet + * - Run LongArray on Java 11 with "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" + * to configure Java's module system (Jigsaw) to expose jdk.internal.misc.Unsafe + * to LongArray. + * The last requirement is visible to TLA+ users who run tla2tools.jar on the + * command-line. As we do not want to expose JVM parameters to them, we keep + * sun.misc.Unsafe for now. + */ +import sun.misc.Unsafe; // jdk.internal.misc.Unsafe; import tlc2.output.EC; import util.Assert; import util.TLCRuntime; @@ -107,6 +125,17 @@ public final class LongArray { e); } } + + /** + * Initializes the memory by overriding each byte with zero starting at + * <code>baseAddress</code> and ending when all positions have been written. + * + * @throws IOException + */ + public final void zeroMemory() + throws IOException { + this.unsafe.setMemory(baseAddress, length * 8L, (byte) 0); // times 8L because it only writes a single byte. + } /** * Initializes the memory by overriding each byte with zero starting at @@ -225,6 +254,17 @@ public final class LongArray { set(position2, tmp); } + /* + * Variant of swap that uses copyMemory. This implementation - suprisingly - is + * *not* faster compared to swap above (see LongArrayBenchmark). + */ + void swapCopy(final long position1, final long position2) { + final long tmp = unsafe.getAddress(log2phy(position1)); + unsafe.copyMemory(log2phy(position2), log2phy(position1), 8L); + unsafe.putAddress(log2phy(position2), tmp); + } + + /** * Returns the number of elements in this array. * @@ -262,4 +302,11 @@ public final class LongArray { b.append(", "); } } + + public static void main(final String[] args) throws IOException { + final long elements = 1L << Integer.valueOf(args[0]); + System.out.format("Allocating LongArray with %,d elements.\n", elements); + final LongArray longArray = new LongArray(elements); + longArray.zeroMemory(); + } } diff --git a/tlatools/src/tlc2/tool/fp/MemFPSet.java b/tlatools/src/tlc2/tool/fp/MemFPSet.java index d3772a9eb10c38ed46962929d7c5386b66f3f75c..366e2ae5f3db79e77566ac4cd78352a686ebf5cb 100644 --- a/tlatools/src/tlc2/tool/fp/MemFPSet.java +++ b/tlatools/src/tlc2/tool/fp/MemFPSet.java @@ -10,6 +10,7 @@ import java.rmi.RemoteException; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.TLCTrace; import util.Assert; import util.BufferedDataInputStream; import util.BufferedDataOutputStream; @@ -63,9 +64,10 @@ public class MemFPSet extends FPSet { this.mask = initialCapacity - 1; } - public final void init(int numThreads, String metadir, String filename) { + public final FPSet init(int numThreads, String metadir, String filename) { this.metadir = metadir; this.filename = filename; + return this; } /** @@ -213,7 +215,7 @@ public class MemFPSet extends FPSet { System.exit(0); } - public final double checkFPs() { + public final long checkFPs() { long dis = Long.MAX_VALUE; for (int i = 0; i < this.table.length; i++) { long[] bucket = this.table[i]; @@ -238,7 +240,7 @@ public class MemFPSet extends FPSet { } } } - return (1.0/dis); + return dis; } // Checkpoint. @@ -287,7 +289,7 @@ public class MemFPSet extends FPSet { this.commitChkpt(this.filename); } - final public void recover() throws IOException { + final public void recover(TLCTrace trace) throws IOException { this.recover(this.filename); } diff --git a/tlatools/src/tlc2/tool/fp/MemFPSet1.java b/tlatools/src/tlc2/tool/fp/MemFPSet1.java index f434cf4773410dac5595542a1ae5a553e0350aca..dd6c5386aba1e5d0637c62f6f4966a63e4a384f3 100644 --- a/tlatools/src/tlc2/tool/fp/MemFPSet1.java +++ b/tlatools/src/tlc2/tool/fp/MemFPSet1.java @@ -14,6 +14,7 @@ import java.rmi.RemoteException; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.TLCTrace; import tlc2.util.SetOfLong; import util.Assert; import util.FileUtil; @@ -33,9 +34,10 @@ public final class MemFPSet1 extends FPSet { this.set = new SetOfLong(10001, 0.75f); } - public final void init(int numThreads, String metadir, String filename) { + public final FPSet init(int numThreads, String metadir, String filename) { this.metadir = metadir; this.filename = filename; + return this; } public final long size() { return this.set.size(); } @@ -62,7 +64,7 @@ public final class MemFPSet1 extends FPSet { System.exit(0); } - public final double checkFPs() { return this.set.checkFPs(); } + public final long checkFPs() { return this.set.checkFPs(); } /* Checkpoint. */ public final void beginChkpt(String fname) throws IOException { @@ -96,7 +98,7 @@ public final class MemFPSet1 extends FPSet { this.commitChkpt(this.filename); } - public final void recover() throws IOException { + public final void recover(TLCTrace trace) throws IOException { this.recover(this.filename); } diff --git a/tlatools/src/tlc2/tool/fp/MemFPSet2.java b/tlatools/src/tlc2/tool/fp/MemFPSet2.java index e9bd74a8cdcb8ec9c89076138a0d94afb8c2ed1b..413bd337c69593eb1318d1ec133cab255b6fb11a 100644 --- a/tlatools/src/tlc2/tool/fp/MemFPSet2.java +++ b/tlatools/src/tlc2/tool/fp/MemFPSet2.java @@ -10,6 +10,7 @@ import java.rmi.RemoteException; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.TLCTrace; import util.Assert; import util.BufferedDataInputStream; import util.BufferedDataOutputStream; @@ -72,9 +73,10 @@ public final class MemFPSet2 extends FPSet { this.mask = spineSize - 1; } - public void init(int numThreads, String metadir, String fname) { + public FPSet init(int numThreads, String metadir, String fname) { this.metadir = metadir; this.filename = metadir + FileUtil.separator + fname; + return this; } public synchronized final long size() { return this.count; } @@ -140,7 +142,7 @@ public final class MemFPSet2 extends FPSet { System.exit(0); } - public final double checkFPs() { + public final long checkFPs() { long dis = Long.MAX_VALUE; for (int i = 0; i < this.table.length; i++) { long low = i & 0xffffffL; @@ -189,7 +191,7 @@ public final class MemFPSet2 extends FPSet { } } } - return (1.0/dis); + return dis; } public final void beginChkpt(String fname) throws IOException { @@ -247,7 +249,7 @@ public final class MemFPSet2 extends FPSet { this.commitChkpt(this.filename); } - public final void recover() throws IOException { + public final void recover(TLCTrace trace) throws IOException { this.recover(this.filename); } diff --git a/tlatools/src/tlc2/tool/fp/MultiFPSet.java b/tlatools/src/tlc2/tool/fp/MultiFPSet.java index 68425c98007aea4239d9b836c37b534a42fac6a1..61a379c43011e1702051cf554bda1dc8ea41bf16 100644 --- a/tlatools/src/tlc2/tool/fp/MultiFPSet.java +++ b/tlatools/src/tlc2/tool/fp/MultiFPSet.java @@ -8,10 +8,13 @@ import java.io.IOException; import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; import tlc2.output.EC; import tlc2.tool.TLCTrace; -import tlc2.util.BufferedRandomAccessFile; +import tlc2.tool.TLCTrace.Enumerator; import util.Assert; /** @@ -31,7 +34,7 @@ public class MultiFPSet extends FPSet { /** * Contains all nested {@link FPSet}s */ - protected FPSet[] sets; + protected final List<FPSet> sets; /** * Amount of leftmost bits used to determine nested {@link FPSet} @@ -59,11 +62,10 @@ public class MultiFPSet extends FPSet { this.fpbits = 64 - bits; } - protected FPSet[] getNestedFPSets(final FPSetConfiguration fpSetConfiguration) throws RemoteException { - int len = fpSetConfiguration.getMultiFPSetCnt(); - final FPSet[] s = new FPSet[len]; - for (int i = 0; i < len; i++) { - s[i] = FPSetFactory.getFPSet(new MultiFPSetConfiguration(fpSetConfiguration)); + protected List<FPSet> getNestedFPSets(final FPSetConfiguration fpSetConfiguration) throws RemoteException { + final List<FPSet> s = new ArrayList<>(fpSetConfiguration.getMultiFPSetCnt()); + for (int i = 0; i < fpSetConfiguration.getMultiFPSetCnt(); i++) { + s.add(FPSetFactory.getFPSet(new MultiFPSetConfiguration(fpSetConfiguration))); } return s; } @@ -71,18 +73,21 @@ public class MultiFPSet extends FPSet { /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#init(int, java.lang.String, java.lang.String) */ - public final void init(int numThreads, String metadir, String filename) throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].init(numThreads, metadir, filename + "_" + i); - } + public final FPSet init(final int numThreads, final String metadir, final String filename) throws IOException { + IntStream.range(0, this.sets.size()).parallel().forEach(i -> { + try { + sets.get(i).init(numThreads, metadir, filename + "_" + i); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + return this; } @Override - public void incWorkers(int num) { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].incWorkers(num); - } + public void incWorkers(final int num) { + sets.stream().forEach(s -> s.incWorkers(num) ); } /* (non-Javadoc) @@ -90,11 +95,7 @@ public class MultiFPSet extends FPSet { */ public final long size() { /* Returns the number of fingerprints in this set. */ - long sum = 0; - for (int i = 0; i < this.sets.length; i++) { - sum += this.sets[i].size(); - } - return sum; + return sets.parallelStream().mapToLong(FPSet::size).sum(); } /** @@ -106,7 +107,7 @@ public class MultiFPSet extends FPSet { // shifts a zero into the leftmost (msb) position of the first operand for right operand times // and cast it to int loosing the leftmost 32 bit final int idx = (int) (fp >>> this.fpbits); - return this.sets[idx]; + return this.sets.get(idx); } /** @@ -134,8 +135,8 @@ public class MultiFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#close() */ public final void close() { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].close(); + for (FPSet fpSet : sets) { + fpSet.close(); } } @@ -143,8 +144,8 @@ public class MultiFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#unexportObject(boolean) */ public void unexportObject(boolean force) throws NoSuchObjectException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].unexportObject(force); + for (FPSet fpSet : sets) { + fpSet.unexportObject(force); } UnicastRemoteObject.unexportObject(this, force); } @@ -152,25 +153,27 @@ public class MultiFPSet extends FPSet { /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#checkFPs() */ - public final double checkFPs() throws IOException { - /* This is not quite correct. */ - double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < this.sets.length; i++) { - res = Math.max(res, this.sets[i].checkFPs()); - } - return res; + public final long checkFPs() throws IOException { + return sets.parallelStream().mapToLong(s -> { + try { + return s.checkFPs(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).min().orElse(Long.MAX_VALUE); } /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#checkInvariant() */ public boolean checkInvariant() throws IOException { - for (int i = 0; i < this.sets.length; i++) { - if (!this.sets[i].checkInvariant()) { - return false; + return sets.parallelStream().allMatch(s -> { + try { + return s.checkInvariant(); + } catch (IOException e) { + throw new RuntimeException(e); } - } - return true; + }); } /* (non-Javadoc) @@ -178,8 +181,8 @@ public class MultiFPSet extends FPSet { */ public final void exit(boolean cleanup) throws IOException { super.exit(cleanup); - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].exit(cleanup); + for (FPSet fpSet : sets) { + fpSet.exit(cleanup); } } @@ -187,8 +190,8 @@ public class MultiFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#beginChkpt() */ public final void beginChkpt() throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].beginChkpt(); + for (FPSet fpSet : sets) { + fpSet.beginChkpt(); } } @@ -196,23 +199,21 @@ public class MultiFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#commitChkpt() */ public final void commitChkpt() throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].commitChkpt(); + for (FPSet fpSet : sets) { + fpSet.commitChkpt(); } } /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#recover() */ - public final void recover() throws IOException { - long recoverPtr = TLCTrace.getRecoverPtr(); - BufferedRandomAccessFile braf = new BufferedRandomAccessFile(TLCTrace.getFilename(), "r"); - while (braf.getFilePointer() < recoverPtr) { - braf.readLongNat(); /* drop */ - long fp = braf.readLong(); + public final void recover(TLCTrace trace) throws IOException { + final Enumerator elements = trace.elements(); + while (elements.nextPos() != -1) { + long fp = elements.nextFP(); getFPSet(fp).recoverFP(fp); } - braf.close(); + elements.close(); } /* (non-Javadoc) @@ -226,30 +227,42 @@ public class MultiFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#beginChkpt(java.lang.String) */ public final void beginChkpt(String filename) throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].beginChkpt(filename + "_" + i); - } + IntStream.range(0, this.sets.size()).parallel().forEach(i -> { + try { + sets.get(i).beginChkpt(filename + "_" + i); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#commitChkpt(java.lang.String) */ public final void commitChkpt(String filename) throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].commitChkpt(filename + "_" + i); - } + IntStream.range(0, this.sets.size()).parallel().forEach(i -> { + try { + sets.get(i).commitChkpt(filename + "_" + i); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } /* (non-Javadoc) * @see tlc2.tool.fp.FPSet#recover(java.lang.String) */ public final void recover(String filename) throws IOException { - for (int i = 0; i < this.sets.length; i++) { - this.sets[i].recover(filename + "_" + i); - } + IntStream.range(0, this.sets.size()).parallel().forEach(i -> { + try { + sets.get(i).recover(filename + "_" + i); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } public FPSet[] getFPSets() { - return sets; + return sets.toArray(new FPSet[sets.size()]); } } diff --git a/tlatools/src/tlc2/tool/fp/NoopFPSet.java b/tlatools/src/tlc2/tool/fp/NoopFPSet.java index b03633fe64944111ed49b2dec69b5b15abc87693..d35e1e00005c0726f273ee20ccd48d285eea44cc 100644 --- a/tlatools/src/tlc2/tool/fp/NoopFPSet.java +++ b/tlatools/src/tlc2/tool/fp/NoopFPSet.java @@ -28,6 +28,8 @@ package tlc2.tool.fp; import java.io.IOException; import java.rmi.RemoteException; +import tlc2.tool.TLCTrace; + /** * An FPSet whose methods are all no-ops. */ @@ -42,7 +44,8 @@ public class NoopFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#init(int, java.lang.String, java.lang.String) */ @Override - public void init(int numThreads, String metadir, String filename) throws IOException { + public FPSet init(int numThreads, String metadir, String filename) throws IOException { + return this; } /* (non-Javadoc) @@ -73,7 +76,7 @@ public class NoopFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#checkFPs() */ @Override - public double checkFPs() throws IOException { + public long checkFPs() throws IOException { return 0; } @@ -95,7 +98,7 @@ public class NoopFPSet extends FPSet { * @see tlc2.tool.fp.FPSet#recover() */ @Override - public void recover() throws IOException { + public void recover(TLCTrace trace) throws IOException { } /* (non-Javadoc) diff --git a/tlatools/src/tlc2/tool/fp/OffHeapDiskFPSet.java b/tlatools/src/tlc2/tool/fp/OffHeapDiskFPSet.java index 12b8424d312438c06f715e964654f9992ff71359..954b7f72a6d2b1831f1235bafbfc92420e8deba1 100644 --- a/tlatools/src/tlc2/tool/fp/OffHeapDiskFPSet.java +++ b/tlatools/src/tlc2/tool/fp/OffHeapDiskFPSet.java @@ -163,12 +163,13 @@ public final class OffHeapDiskFPSet extends NonCheckpointableDiskFPSet implement * @see tlc2.tool.fp.DiskFPSet#init(int, java.lang.String, java.lang.String) */ @Override - public void init(final int numThreads, String aMetadir, String filename) + public FPSet init(final int numThreads, String aMetadir, String filename) throws IOException { super.init(numThreads, aMetadir, filename); this.numThreads = numThreads; array.zeroMemory(numThreads); + return this; } /* (non-Javadoc) @@ -453,12 +454,12 @@ public final class OffHeapDiskFPSet extends NonCheckpointableDiskFPSet implement * @see tlc2.tool.fp.DiskFPSet#checkFPs() */ @Override - public double checkFPs() throws IOException { + public long checkFPs() throws IOException { if (getTblCnt() <= 0) { - return Double.MAX_VALUE; + return Long.MAX_VALUE; } // The superclass implementation provides insufficient performance and - // scalability. These problems get more pronounced with a large array. + // scalability. These problems get more pronounced with large arrays. // In order to provide a faster solution to the closest pair problem in // one-dimensional space, we cheat and determine the minimum distance // between fingerprints only on a subset of fingerprints. The subset are @@ -471,6 +472,20 @@ public final class OffHeapDiskFPSet extends NonCheckpointableDiskFPSet implement // Scalability is achieved by partitioning the array for 1) and 2), // which is possible due to the bounded disorder in array. + // One can think of two shortcuts to approximate of the closest pair: + // a) Track the minimum distance during the 1) step in prepareTable. A possible + // implementation can pass something similar to a BinaryOpeartor to the + // LongComparator. Due to the bounded disorder, this generally works except for + // the corner case where the closest pair are two fingerprints in two + // non-adjacent partitions, i.e. [,,,fp23],[],...,[],[,,fp42,,,]. This is + // frequently the case for very sparsely populated arrays. + // b) For low load factors (thus low collision rates) simply skip step 1) and do + // not sort the array at all. A zero collision rate implies that the array + // is sorted (except for first PROBE_LIMIT slots) if fingerprints wrapped around. + // c) Select just 1..N partitions out of the set of all array partitions + // for which the closest pair gets calculated. This is a more extreme variant + // of the current approximation which skips fingerprints on disk. + // 1) Sort all fingerprints, either with a sequential or concurrent // flusher depending on the size of the array. final int numThreads = TLCGlobals.getNumWorkers(); @@ -540,7 +555,7 @@ public final class OffHeapDiskFPSet extends NonCheckpointableDiskFPSet implement } } }).get().get(); - return 1.0 / distance; + return distance; } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new OffHeapRuntimeException(ie); @@ -549,6 +564,31 @@ public final class OffHeapDiskFPSet extends NonCheckpointableDiskFPSet implement } finally { executorService.shutdown(); } + + + // Dynamic variant to maintain closest pair: + // The dynamic (during insertions and not on static data) variant of the closest + // pair problem also provides an approximation of the actual closest pair. It + // can be maintained with little overhead in runtime and space and returned in + // constant time O(1). Contrary to the current implementation, it does not skip + // fingerprints on disk but observes all fingerprints. + // For that, we observe the minimum distance OD of the fingerprint to be inserted + // and all fingerprints it collides with in the method memInsert0. Before + // returning from memInsert0, the global minimum distance GD gets updated to the + // observed distance OD iff OD < GD (for scalability reasons we want to use a + // java.util.concurrent.atomic.LongAccumulator). + // This provides a sufficient approximation iff the collision rate is + // sufficiently high. Under a low collision rate, the number of comparisons in + // memInsert0 will be low. But even under a high collision rate, the + // approximation GD does not necessarily converge with the real minimum distance: + // Let f1 differs from f2 in just the lowest significant bit (LSB) and let f1 < + // f2. Depending on the size of the array, it is possible that f1 and f2 are + // indexed to two adjacent positions. If both positions for f1 and f2 are empty + // by the time f1 and f2 get inserted, no distance for f1 and f2 will be + // calculated. + // For low hash table/array collision rates (small load factors), we could + // simply report "insufficient data". Users will still have the optimistic FP64 + // collision probability, which will also be very small. } //**************************** Indexer ****************************// diff --git a/tlatools/src/tlc2/tool/fp/dfid/FPIntSet.java b/tlatools/src/tlc2/tool/fp/dfid/FPIntSet.java index d7e2663497f429db2332d720d3c27b4f988382c3..3a4edd2305a0b0919ec1804656d758c07281081d 100644 --- a/tlatools/src/tlc2/tool/fp/dfid/FPIntSet.java +++ b/tlatools/src/tlc2/tool/fp/dfid/FPIntSet.java @@ -115,7 +115,7 @@ public abstract class FPIntSet public abstract void exit(boolean cleanup) throws IOException; - public abstract double checkFPs() throws IOException; + public abstract long checkFPs() throws IOException; public abstract void beginChkpt() throws IOException; public abstract void commitChkpt() throws IOException; diff --git a/tlatools/src/tlc2/tool/fp/dfid/MemFPIntSet.java b/tlatools/src/tlc2/tool/fp/dfid/MemFPIntSet.java index 20e07455f5d212827f5bb80756e308084e53c2d2..b54df811813cb3e6742274df171f502833c1a3e3 100644 --- a/tlatools/src/tlc2/tool/fp/dfid/MemFPIntSet.java +++ b/tlatools/src/tlc2/tool/fp/dfid/MemFPIntSet.java @@ -262,7 +262,7 @@ public class MemFPIntSet extends FPIntSet { System.exit(0); } - public final double checkFPs() { + public final long checkFPs() { long dis = Long.MAX_VALUE; for (int i = 0; i < this.table.length; i++) { int[] bucket = this.table[i]; @@ -289,7 +289,7 @@ public class MemFPIntSet extends FPIntSet { } } } - return (1.0/dis); + return dis; } // Checkpoint. diff --git a/tlatools/src/tlc2/tool/fp/dfid/MultiFPIntSet.java b/tlatools/src/tlc2/tool/fp/dfid/MultiFPIntSet.java index 32c5dfc47eeb3b0838d39b1949dd91dff58d16e0..533c3d545fd67557f8a6557dac238211d9ef295f 100644 --- a/tlatools/src/tlc2/tool/fp/dfid/MultiFPIntSet.java +++ b/tlatools/src/tlc2/tool/fp/dfid/MultiFPIntSet.java @@ -73,8 +73,8 @@ public class MultiFPIntSet extends FPIntSet { } /* This is not quite correct. */ - public final double checkFPs() throws IOException { - double res = Double.NEGATIVE_INFINITY; + public final long checkFPs() throws IOException { + long res = Long.MIN_VALUE; for (int i = 0; i < this.sets.length; i++) { res = Math.max(res, this.sets[i].checkFPs()); } diff --git a/tlatools/src/tlc2/tool/ActionItemList.java b/tlatools/src/tlc2/tool/impl/ActionItemList.java similarity index 66% rename from tlatools/src/tlc2/tool/ActionItemList.java rename to tlatools/src/tlc2/tool/impl/ActionItemList.java index 236a9dea92ebd138bfec2585e7dc95cb60524126..904f172f8f13b5a8bc91654d30ce29fc8d553716 100644 --- a/tlatools/src/tlc2/tool/ActionItemList.java +++ b/tlatools/src/tlc2/tool/impl/ActionItemList.java @@ -1,47 +1,36 @@ // Copyright (c) 2003 Compaq Corporation. All rights reserved. // Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -package tlc2.tool; +package tlc2.tool.impl; import tla2sany.semantic.SemanticNode; +import tlc2.TLCGlobals; +import tlc2.tool.IActionItemList; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; -public class ActionItemList { +class ActionItemList implements IActionItemList { + private static final boolean coverage = TLCGlobals.isCoverageEnabled(); /** - * predicate of a conjunction - */ - public static final int CONJUNCT = 0; - /** - * predicate - */ - public static final int PRED = -1; - /** - * UNCHANGED predicate - */ - public static final int UNCHANGED = -2; - /** - * pred' # pred - */ - public static final int CHANGED = -3; - - /** * We assume that this.pred is null iff the list is empty. */ public final SemanticNode pred; // Expression of the action public final Context con; // Context of the action private final int kind; public final ActionItemList next; + public final CostModel cm; public final static ActionItemList - Empty = new ActionItemList(null, null, 0, null); + Empty = new ActionItemList(null, null, 0, null, null); /* Constructors */ private ActionItemList(SemanticNode pred, Context con, - int kind, ActionItemList next) { + int kind, ActionItemList next, CostModel cm) { this.pred = pred; this.con = con; this.kind = kind; this.next = next; + this.cm = cm; } public final SemanticNode carPred() { return this.pred; } @@ -59,9 +48,9 @@ public class ActionItemList { public final ActionItemList cdr() { return this.next; } - public final ActionItemList cons(SemanticNode pred, - Context con, int kind) { - return new ActionItemList(pred, con, kind, this); + public final IActionItemList cons(SemanticNode pred, + Context con, CostModel cm, int kind) { + return new ActionItemList(pred, con, kind, this, coverage ? cm.get(pred) : cm); } public final boolean isEmpty() { return this == Empty; } diff --git a/tlatools/src/tlc2/tool/ContextEnumerator.java b/tlatools/src/tlc2/tool/impl/ContextEnumerator.java similarity index 90% rename from tlatools/src/tlc2/tool/ContextEnumerator.java rename to tlatools/src/tlc2/tool/impl/ContextEnumerator.java index 2ed8032915a7840b39006f6d7d36d7b93be4ef22..516282c030f4ec4f1aefb776f182c5d1b9b6192f 100644 --- a/tlatools/src/tlc2/tool/ContextEnumerator.java +++ b/tlatools/src/tlc2/tool/impl/ContextEnumerator.java @@ -3,17 +3,18 @@ // Last modified on Mon 30 Apr 2007 at 15:29:55 PST by lamport // modified on Tue Nov 9 11:06:41 PST 1999 by yuanyu -package tlc2.tool; +package tlc2.tool.impl; import tla2sany.semantic.SymbolNode; import tlc2.output.EC; +import tlc2.tool.IContextEnumerator; import tlc2.util.Context; -import tlc2.value.TupleValue; -import tlc2.value.Value; -import tlc2.value.ValueEnumeration; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueEnumeration; import util.Assert; -public final class ContextEnumerator { +public final class ContextEnumerator implements IContextEnumerator { private Context con; private Object[] vars; private ValueEnumeration[] enums; @@ -35,6 +36,7 @@ public final class ContextEnumerator { } } + @Override public final Context nextElement() { Context con1 = this.con; if (this.isDone) return null; diff --git a/tlatools/src/tlc2/tool/ModelConfig.java b/tlatools/src/tlc2/tool/impl/ModelConfig.java similarity index 96% rename from tlatools/src/tlc2/tool/ModelConfig.java rename to tlatools/src/tlc2/tool/impl/ModelConfig.java index a106dea9ef888c9c385898cd04724f032ffe8f47..af920417521a86ae40899fb2b9c52bcab47f9e65 100644 --- a/tlatools/src/tlc2/tool/ModelConfig.java +++ b/tlatools/src/tlc2/tool/impl/ModelConfig.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 15:29:56 PST by lamport // modified on Thu Aug 23 17:46:39 PDT 2001 by yuanyu -package tlc2.tool; +package tlc2.tool.impl; import java.io.FileInputStream; import java.io.IOException; @@ -16,14 +16,17 @@ import tla2sany.parser.TLAplusParserTokenManager; import tla2sany.parser.Token; import tla2sany.parser.TokenMgrError; import tlc2.output.EC; +import tlc2.tool.ConfigFileException; import tlc2.util.Vect; -import tlc2.value.IntValue; -import tlc2.value.ModelValue; -import tlc2.value.SetEnumValue; -import tlc2.value.StringValue; -import tlc2.value.Value; +import tlc2.value.IValue; import tlc2.value.ValueConstants; -import tlc2.value.ValueVec; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueVec; import util.FileUtil; import util.FilenameToStream; import util.SimpleFilenameToStream; @@ -31,7 +34,6 @@ import util.SimpleFilenameToStream; /** * Stores information from user's model configuration file. * @author Yuan Yu, Leslie Lamport - * @version $Id$ */ public class ModelConfig implements ValueConstants, Serializable { @@ -89,17 +91,17 @@ public class ModelConfig implements ValueConstants, Serializable ModelValue.init(); this.configFileName = configFileName; - this.configTbl = new Hashtable(); - Vect temp = new Vect(); + this.configTbl = new Hashtable<>(); + Vect temp = new Vect<>(); this.configTbl.put(Constant, temp); this.configTbl.put(Constants, temp); - temp = new Vect(); + temp = new Vect<>(); this.configTbl.put(Constraint, temp); this.configTbl.put(Constraints, temp); - temp = new Vect(); + temp = new Vect<>(); this.configTbl.put(ActionConstraint, temp); this.configTbl.put(ActionConstraints, temp); - temp = new Vect(); + temp = new Vect<>(); this.configTbl.put(Invariant, temp); this.configTbl.put(Invariants, temp); this.configTbl.put(Init, ""); @@ -107,15 +109,15 @@ public class ModelConfig implements ValueConstants, Serializable this.configTbl.put(View, ""); this.configTbl.put(Symmetry, ""); this.configTbl.put(Spec, ""); - temp = new Vect(); + temp = new Vect<>(); this.configTbl.put(Prop, temp); this.configTbl.put(Props, temp); this.configTbl.put(Type, ""); this.configTbl.put(TypeConstraint, ""); - this.modConstants = new Hashtable(); - this.modOverrides = new Hashtable(); - this.overrides = new Hashtable(); + this.modConstants = new Hashtable<>(); + this.modOverrides = new Hashtable<>(); + this.overrides = new Hashtable<>(); } /** @@ -315,7 +317,7 @@ public class ModelConfig implements ValueConstants, Serializable while (true) { tt = getNextToken(tmgr); - Value arg = this.parseValue(tt, scs, tmgr); + IValue arg = this.parseValue(tt, scs, tmgr); line.addElement(arg); tt = getNextToken(tmgr); if (!tt.image.equals(",")) @@ -426,10 +428,10 @@ public class ModelConfig implements ValueConstants, Serializable return new StringValue(tval.substring(1, tval.length() - 1)); } else if (tt.image.equals("TRUE")) { - return ValTrue; + return BoolValue.ValTrue; } else if (tt.image.equals("FALSE")) { - return ValFalse; + return BoolValue.ValFalse; } else if (tt.image.equals("{")) { ValueVec elems = new ValueVec(); @@ -438,7 +440,7 @@ public class ModelConfig implements ValueConstants, Serializable { while (true) { - Value elem = this.parseValue(tt, scs, tmgr); + Value elem = this.parseValue(tt, scs, tmgr); elems.addElement(elem); tt = getNextToken(tmgr); if (!tt.image.equals(",")) diff --git a/tlatools/src/tlc2/tool/impl/Spec.java b/tlatools/src/tlc2/tool/impl/Spec.java new file mode 100644 index 0000000000000000000000000000000000000000..dd9d7c60f80f9c6bcd442e64aaaaf7730160dbe6 --- /dev/null +++ b/tlatools/src/tlc2/tool/impl/Spec.java @@ -0,0 +1,939 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 19 May 2008 at 1:13:48 PST by lamport +// modified on Fri Aug 24 14:43:24 PDT 2001 by yuanyu + +package tlc2.tool.impl; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import tla2sany.modanalyzer.ParseUnit; +import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.APSubstInNode; +import tla2sany.semantic.ExprNode; +import tla2sany.semantic.ExprOrOpArgNode; +import tla2sany.semantic.ExternalModuleTable; +import tla2sany.semantic.FormalParamNode; +import tla2sany.semantic.FrontEnd; +import tla2sany.semantic.LabelNode; +import tla2sany.semantic.LetInNode; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpArgNode; +import tla2sany.semantic.OpDeclNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.Subst; +import tla2sany.semantic.SubstInNode; +import tla2sany.semantic.SymbolNode; +import tla2sany.semantic.ThmOrAssumpDefNode; +import tlc2.TLCGlobals; +import tlc2.output.EC; +import tlc2.tool.Action; +import tlc2.tool.BuiltInOPs; +import tlc2.tool.Defns; +import tlc2.tool.TLCState; +import tlc2.tool.ToolGlobals; +import tlc2.tool.coverage.CostModel; +import tlc2.util.Context; +import tlc2.util.ObjLongTable; +import tlc2.util.Vect; +import tlc2.value.IValue; +import tlc2.value.ValueConstants; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.LazyValue; +import tlc2.value.impl.ModelValue; +import util.Assert; +import util.FilenameToStream; +import util.UniqueString; + +abstract class Spec implements ValueConstants, ToolGlobals, Serializable +{ + /** + * @see See note on performance in CostModelCreator. + */ + protected static final boolean coverage = TLCGlobals.isCoverageEnabled(); + + protected static final int toolId = FrontEnd.getToolId(); + + protected final String specDir; // The spec directory. + protected final String rootFile; // The root file of this spec. + protected final String configFile; // The model config file. + protected final ModelConfig config; // The model configuration. + protected final ExternalModuleTable moduleTbl; // The external modules reachable from root + protected final ModuleNode rootModule; // The root module. + protected final Set<OpDefNode> processedDefs ; + protected final SpecObj specObj; + // The set of OpDefNodes on which processSpec has been called. + // Added by LL & YY on 25 June 2014 to eliminate infinite + // loop when a recursively defined operator is used as an + // operator argument in its own definition. + protected final Defns defns; // Global definitions reachable from root + protected final Defns unprocessedDefns; + // SZ 10.04.2009: changed the name of the variable to reflect its nature + protected final OpDeclNode[] variablesNodes; // The state variables. + protected final TLAClass tlaClass; // TLA built-in classes. + protected final Vect<Action> initPredVec; // The initial state predicate. + protected final Action nextPred; // The next state predicate. + protected final Action[] temporals; // Fairness specifications... + protected final String[] temporalNames; // ... and their names + protected final Action[] impliedTemporals; // Liveness conds to check... + protected final String[] impliedTemporalNames; // ... and their names + protected final Action[] invariants; // Invariants to be checked... + protected final String[] invNames; // ... and their names + protected final Action[] impliedInits; // Implied-inits to be checked... + protected final String[] impliedInitNames; // ... and their names + protected final Action[] impliedActions; // Implied-actions to be checked... + protected final String[] impliedActNames; // ... and their names + protected final ExprNode[] modelConstraints; // Model constraints + protected final ExprNode[] actionConstraints; // Action constraints + protected final ExprNode[] assumptions; // Assumpt ions + protected final boolean[] assumptionIsAxiom; // assumptionIsAxiom[i] is true iff assumptions[i] + // is an AXIOM. Added 26 May 2010 by LL + private final FilenameToStream resolver; // takes care of path to stream resolution + + // SZ Feb 20, 2009: added support to name resolver, to be able to run outside of the tool + public Spec(String specDir, String specFile, String configFile, FilenameToStream resolver) + { + this.specDir = specDir; + this.rootFile = specFile; + this.defns = new Defns(); + this.tlaClass = new TLAClass("tlc2.module", resolver); + this.processedDefs = new HashSet<OpDefNode>(); + this.resolver = resolver; + + // SZ Mar 9, 2009: added initialization of the modelValue class + ModelValue.init(); + this.configFile = configFile; + this.config = new ModelConfig(configFile + ".cfg", resolver); + this.config.parse(); + ModelValue.setValues(); // called after seeing all model values + + // SpecProcessor has be factored out to be able to assign the variables below as + // final. SpecProcessor duplicates most of the variables here but I don't have + // time to clean it up. + final SpecProcessor processor = new SpecProcessor(rootFile, resolver, toolId, defns, config, this, tlaClass); + this.rootModule = processor.getRootModule(); + this.moduleTbl = processor.getModuleTbl(); + this.variablesNodes = processor.getVariablesNodes(); + this.initPredVec = processor.getInitPred(); + this.nextPred = processor.getNextPred(); + this.temporals = processor.getTemporal(); + this.temporalNames = processor.getTemporalNames(); + this.impliedTemporals = processor.getImpliedTemporals(); + this.impliedTemporalNames = processor.getImpliedTemporalNames(); + this.invariants = processor.getInvariants(); + this.invNames = processor.getInvariantsNames(); + this.impliedInits = processor.getImpliedInits(); + this.impliedInitNames = processor.getImpliedInitNames(); + this.impliedActions = processor.getImpliedActions(); + this.impliedActNames = processor.getImpliedActionNames(); + this.modelConstraints = processor.getModelConstraints(); + this.actionConstraints = processor.getActionConstraints(); + this.assumptions = processor.getAssumptions(); + this.assumptionIsAxiom = processor.getAssumptionIsAxiom(); + this.specObj = processor.getSpecObj(); + + this.unprocessedDefns = processor.getUnprocessedDefns(); + } + + protected Spec(Spec other) { + this.specDir = other.specDir; + this.rootFile = other.rootFile; + this.configFile = other.configFile; + this.config = other.config; + this.moduleTbl = other.moduleTbl; + this.rootModule = other.rootModule; + this.processedDefs = other.processedDefs; + this.defns = other.defns; + this.variablesNodes = other.variablesNodes; + this.tlaClass = other.tlaClass; + this.initPredVec = other.initPredVec; + this.nextPred = other.nextPred; + this.temporals = other.temporals; + this.temporalNames = other.temporalNames; + this.impliedTemporals = other.impliedTemporals; + this.impliedTemporalNames = other.impliedTemporalNames; + this.invariants = other.invariants; + this.invNames = other.invNames; + this.impliedInits = other.impliedInits; + this.impliedInitNames = other.impliedInitNames; + this.impliedActions = other.impliedActions; + this.impliedActNames = other.impliedActNames; + this.modelConstraints = other.modelConstraints; + this.actionConstraints = other.actionConstraints; + this.assumptions = other.assumptions; + this.assumptionIsAxiom = other.assumptionIsAxiom; + this.resolver = other.resolver; + this.specObj = other.specObj; + this.unprocessedDefns = other.unprocessedDefns; + } + + /* Return the variable if expr is a state variable. Otherwise, null. */ + public final SymbolNode getVar(SemanticNode expr, Context c, boolean cutoff) + { + if (expr instanceof OpApplNode) + { + SymbolNode opNode = ((OpApplNode) expr).getOperator(); + + if (opNode.getArity() == 0) + { + boolean isVarDecl = (opNode.getKind() == VariableDeclKind); + Object val = this.lookup(opNode, c, cutoff && isVarDecl); + + if (val instanceof LazyValue) + { + LazyValue lval = (LazyValue) val; + return this.getVar(lval.expr, lval.con, cutoff); + } + if (val instanceof OpDefNode) + { + return this.getVar(((OpDefNode) val).getBody(), c, cutoff); + } + if (isVarDecl) + { + return opNode; + } + } + } + return null; + } + + /* Return the variable if expr is a primed state variable. Otherwise, null. */ + public final SymbolNode getPrimedVar(SemanticNode expr, Context c, boolean cutoff) + { + if (expr instanceof OpApplNode) + { + OpApplNode expr1 = (OpApplNode) expr; + SymbolNode opNode = expr1.getOperator(); + + if (BuiltInOPs.getOpCode(opNode.getName()) == OPCODE_prime) + { + return this.getVar(expr1.getArgs()[0], c, cutoff); + } + + if (opNode.getArity() == 0) + { + boolean isVarDecl = (opNode.getKind() == VariableDeclKind); + Object val = this.lookup(opNode, c, cutoff && isVarDecl); + + if (val instanceof LazyValue) + { + LazyValue lval = (LazyValue) val; + return this.getPrimedVar(lval.expr, lval.con, cutoff); + } + if (val instanceof OpDefNode) + { + return this.getPrimedVar(((OpDefNode) val).getBody(), c, cutoff); + } + } + } + return null; + } + + /** + * Get model constraints. + */ + public final ExprNode[] getModelConstraints() + { + return this.modelConstraints; + } + + /** + * Get action constraints. + */ + public final ExprNode[] getActionConstraints() + { + return this.actionConstraints; + } + + /* Get the initial state predicate of the specification. */ + public final Vect<Action> getInitStateSpec() + { + return this.initPredVec; + } + + /* Get the action (next state) predicate of the specification. */ + public final Action getNextStateSpec() + { + return this.nextPred; + } + + /** + * Get the view mapping for the specification. + */ + public final SemanticNode getViewSpec() + { + String name = this.config.getView(); + if (name.length() == 0) + return null; + + Object view = this.defns.get(name); + if (view == null) + { + Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "view function", name }); + } + if (!(view instanceof OpDefNode)) + { + Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "view function", name }); + } + OpDefNode def = (OpDefNode) view; + if (def.getArity() != 0) + { + Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "view function", name }); + } + return def.getBody(); + } + + /* Get the type declaration for the state variables. */ + public final SemanticNode getTypeSpec() + { + String name = this.config.getType(); + if (name.length() == 0) + { + Assert.fail(EC.TLC_CONFIG_NO_STATE_TYPE); + } + + Object type = this.defns.get(name); + if (type == null) + { + Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "type", name }); + } + if (!(type instanceof OpDefNode)) + { + Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "type", name }); + } + OpDefNode def = (OpDefNode) type; + if (def.getArity() != 0) + { + Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "type", name }); + } + return def.getBody(); + } + + /* Get the type declaration for the state variables. */ + public final SemanticNode getTypeConstraintSpec() + { + String name = this.config.getTypeConstraint(); + if (name.length() == 0) + { + return null; + } + + Object type = this.defns.get(name); + if (type == null) + { + Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "type constraint", name }); + } + if (!(type instanceof OpDefNode)) + { + Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "type constraint", name }); + } + OpDefNode def = (OpDefNode) type; + if (def.getArity() != 0) + { + Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "type constraint", name }); + + } + return def.getBody(); + } + + public final boolean livenessIsTrue() + { + return this.impliedTemporals.length == 0; + } + + /* Get the fairness condition of the specification. */ + public final Action[] getTemporals() + { + return this.temporals; + } + + public final String[] getTemporalNames() + { + return this.temporalNames; + } + + /* Get the liveness checks of the specification. */ + public final Action[] getImpliedTemporals() + { + return this.impliedTemporals; + } + + public final String[] getImpliedTemporalNames() + { + return this.impliedTemporalNames; + } + + /* Get the invariants of the specification. */ + public final Action[] getInvariants() + { + return this.invariants; + } + + public final String[] getInvNames() + { + return this.invNames; + } + + /* Get the implied-inits of the specification. */ + public final Action[] getImpliedInits() + { + return this.impliedInits; + } + + public final String[] getImpliedInitNames() + { + return this.impliedInitNames; + } + + /* Get the implied-actions of the specification. */ + public final Action[] getImpliedActions() + { + return this.impliedActions; + } + + public final String[] getImpliedActNames() + { + return this.impliedActNames; + } + + /* Get the assumptions of the specification. */ + public final ExprNode[] getAssumptions() + { + return this.assumptions; + } + + /* Get the assumptionIsAxiom field */ + public final boolean[] getAssumptionIsAxiom() { + return this.assumptionIsAxiom; + } + /** + * This method gets the value of a symbol from the environment. We + * look up in the context c, its tool object, and the state s. + * + * It and the lookup method that follows it were modified by LL + * on 10 April 2011 to fix the following bug. When a constant definition + * Foo == ... + * is overridden to substitute Bar for Foo, the TLC tool object for + * the body of Foo's OpDef node is set to the OpDefNode for Bar. + * When evaluating a use of Foo, the lookup method is apparently + * supposed to return the OpDefNode for Bar. (I don't understand + * how the callers make use of the returned value.) That's what it + * does for uses of Foo in the module in which Foo is defined. + * However, if Foo is imported by instantiation with renaming as + * X!Foo, then it appears that looking up X!Foo should also return + * the OpDefNode for Bar. If the instantiated module had no + * parameters, then that's what happened because the body of the + * OpDefNode for X!Foo is the same (contains a pointer to the + * same object) as the body of Foo's OpDefNode. However, that + * wasn't the case if the instantiated module had parameters, + * because then X!Foo's OpDefNode consists of a sequence of + * nested SubstInNode objects, the last of which points to + * the body of Foo's OpDefNode. So, LL modified the lookup + * methods so they follow the sequence of SubstInNode bodies + * down to the body of Foo's OpDefNode when looking up the result. + * (If a SubstInNode has a non-null TLC tool object for a + * SubstInNode, then it returns that object. I don't think this + * should ever be the case, and if it is, I have no idea what the + * lookup method should do.) + * + */ + public final Object lookup(SymbolNode opNode, Context c, TLCState s, boolean cutoff) + { + Object result = lookup(opNode, c, cutoff); + if (result != opNode) { + return result; + } + result = s.lookup(opNode.getName()); + if (result != null) { + return result; + } + return opNode; + } + + public final Object lookup(SymbolNode opNode, Context c, boolean cutoff) + { + boolean isVarDecl = (opNode.getKind() == VariableDeclKind); + Object result = c.lookup(opNode, cutoff && isVarDecl); + if (result != null) { + return result; + } + + result = opNode.getToolObject(toolId); + if (result != null) { + return result; + } + + if (opNode.getKind() == UserDefinedOpKind) + { + // Changed by LL on 10 Apr 2011 from + // + // result = ((OpDefNode) opNode).getBody().getToolObject(toolId); + // + // to the following + ExprNode body = ((OpDefNode) opNode).getBody(); + result = body.getToolObject(toolId); + while ((result == null) && (body.getKind() == SubstInKind)) { + body = ((SubstInNode) body).getBody(); + result = body.getToolObject(toolId); + } + // end change + + if (result != null) { + return result; + } + } + return opNode; + } + public final Object lookup(final SymbolNode opNode) { + return lookup(opNode, Context.Empty, false); + } + public final Object getVal(ExprOrOpArgNode expr, Context c, final boolean cachable) + { + return getVal(expr, c, cachable, CostModel.DO_NOT_RECORD); + } + + public final Object getVal(ExprOrOpArgNode expr, Context c, final boolean cachable, CostModel cm) + { + if (expr instanceof ExprNode) + { + return new LazyValue(expr, c, cachable, cm); + } + SymbolNode opNode = ((OpArgNode) expr).getOp(); + return this.lookup(opNode, c, false); + } + public final Context getOpContext(OpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable) + { + return getOpContext(opDef, args, c, cachable, CostModel.DO_NOT_RECORD); + } + + public final Context getOpContext(OpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable, final CostModel cm) + { + FormalParamNode[] formals = opDef.getParams(); + int alen = args.length; + Context c1 = c; + for (int i = 0; i < alen; i++) + { + Object aval = this.getVal(args[i], c, cachable, cm); + c1 = c1.cons(formals[i], aval); + } + return c1; + } + + /** + * The following added by LL on 23 October 2012 to fix bug in evaluation of names of theorems and + * assumptions imported by parameterized instantiation. + * + * @param opDef + * @param args + * @param c + * @param cachable + * @return + */ + public final Context getOpContext(ThmOrAssumpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable) + { + FormalParamNode[] formals = opDef.getParams(); + int alen = args.length; + Context c1 = c; + for (int i = 0; i < alen; i++) + { + Object aval = this.getVal(args[i], c, cachable); + c1 = c1.cons(formals[i], aval); + } + return c1; + } + /** + * Return a table containing the locations of subexpression in the + * spec of forms x' = e and x' \in e. Warning: Current implementation + * may not be able to find all such locations. + */ + public final ObjLongTable<SemanticNode> getPrimedLocs() + { + final ObjLongTable<SemanticNode> tbl = new ObjLongTable<SemanticNode>(10); + final Action act = this.getNextStateSpec(); + if (act == null) { + // MAK 10/17/2018: If spec defines no next-state action (see e.g. + // tlc2.tool.ASTest) and this method is called before ModelChecker checks + // actions (search for tlc2.output.EC.TLC_STATES_AND_NO_NEXT_ACTION) this will + // NPE. + return tbl; + } + this.collectPrimedLocs(act.pred, act.con, tbl); + return tbl; + } + + public final void collectPrimedLocs(SemanticNode pred, Context c, ObjLongTable<SemanticNode> tbl) + { + switch (pred.getKind()) { + case OpApplKind: { + OpApplNode pred1 = (OpApplNode) pred; + this.collectPrimedLocsAppl(pred1, c, tbl); + return; + } + case LetInKind: { + LetInNode pred1 = (LetInNode) pred; + this.collectPrimedLocs(pred1.getBody(), c, tbl); + return; + } + case SubstInKind: { + SubstInNode pred1 = (SubstInNode) pred; + Subst[] subs = pred1.getSubsts(); + Context c1 = c; + for (int i = 0; i < subs.length; i++) + { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + } + this.collectPrimedLocs(pred1.getBody(), c, tbl); + return; + } + + // Added by LL on 13 Nov 2009 to handle theorem and assumption names. + case APSubstInKind: { + APSubstInNode pred1 = (APSubstInNode) pred; + Subst[] subs = pred1.getSubsts(); + Context c1 = c; + for (int i = 0; i < subs.length; i++) + { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + } + this.collectPrimedLocs(pred1.getBody(), c, tbl); + return; + } + + + /*********************************************************************** + * LabelKind case added by LL on 13 Jun 2007. * + ***********************************************************************/ + case LabelKind: { + LabelNode pred1 = (LabelNode) pred; + this.collectPrimedLocs(pred1.getBody(), c, tbl); + return; + } + } + } + + private final void collectPrimedLocsAppl(OpApplNode pred, Context c, ObjLongTable<SemanticNode> tbl) + { + ExprOrOpArgNode[] args = pred.getArgs(); + SymbolNode opNode = pred.getOperator(); + int opcode = BuiltInOPs.getOpCode(opNode.getName()); + + switch (opcode) { + case OPCODE_fa: // FcnApply + { + this.collectPrimedLocs(args[0], c, tbl); + break; + } + case OPCODE_ite: // IfThenElse + { + this.collectPrimedLocs(args[1], c, tbl); + this.collectPrimedLocs(args[2], c, tbl); + break; + } + case OPCODE_case: // Case + { + for (int i = 0; i < args.length; i++) + { + OpApplNode pair = (OpApplNode) args[i]; + this.collectPrimedLocs(pair.getArgs()[1], c, tbl); + } + break; + } + case OPCODE_eq: // x' = 42 + case OPCODE_in: { // x' \in S (eq case "falls through") + SymbolNode var = this.getPrimedVar(args[0], c, false); + if (var != null && var.getName().getVarLoc() != -1) + { + tbl.put(pred, 0); + } + break; + } + case OPCODE_cl: // ConjList + case OPCODE_dl: // DisjList + case OPCODE_be: // BoundedExists + case OPCODE_bf: // BoundedForall + case OPCODE_land: + case OPCODE_lor: + case OPCODE_implies: + case OPCODE_nop: // This case added 13 Nov 2009 by LL to handle subexpression names. + { + for (int i = 0; i < args.length; i++) + { + this.collectPrimedLocs(args[i], c, tbl); + } + break; + } + case OPCODE_unchanged: { + this.collectUnchangedLocs(args[0], c, tbl); + break; + } + case OPCODE_aa: // AngleAct <A>_e + { + this.collectPrimedLocs(args[0], c, tbl); + break; + } + case OPCODE_sa: // [A]_e + { + this.collectPrimedLocs(args[0], c, tbl); + tbl.put(args[1], 0); + break; + } + default: { + if (opcode == 0) + { + Object val = this.lookup(opNode, c, false); + + if (val instanceof OpDefNode) + { + OpDefNode opDef = (OpDefNode) val; + // Following added by LL on 10 Apr 2010 to avoid infinite + // recursion for recursive operator definitions + if (opDef.getInRecursive()) { + return ; + } + Context c1 = this.getOpContext(opDef, args, c, true); + this.collectPrimedLocs(opDef.getBody(), c1, tbl); + } else if (val instanceof LazyValue) + { + LazyValue lv = (LazyValue) val; + this.collectPrimedLocs(lv.expr, lv.con, tbl); + } + } + } + } + } + + private final void collectUnchangedLocs(final SemanticNode expr, final Context c, + final ObjLongTable<SemanticNode> tbl) { + if (expr instanceof OpApplNode) + { + OpApplNode expr1 = (OpApplNode) expr; + SymbolNode opNode = expr1.getOperator(); + UniqueString opName = opNode.getName(); + int opcode = BuiltInOPs.getOpCode(opName); + + if (opName.getVarLoc() >= 0) + { + // a state variable: + tbl.put(expr, 0); + return; + } + + ExprOrOpArgNode[] args = expr1.getArgs(); + if (opcode == OPCODE_tup) + { + // a tuple, might be: + // UNCHANGED <<x,y,z>> + // or: + // vars == <<x,y,z>> + // ... + // UNCHANGED vars + // For the latter, we don't want vars == <<x,y,z>> to show up, but the vars in + // UNCHANGED vars (see CoverageStatisticsTest). + for (int i = 0; i < args.length; i++) + { + this.collectUnchangedLocs(args[i], c, tbl); + } + return; + } + + if (opcode == 0 && args.length == 0) + { + // a 0-arity operator: + Object val = this.lookup(opNode, c, false); + if (val instanceof OpDefNode) + { + this.collectUnchangedLocs(((OpDefNode) val).getBody(), c, tbl); + return; + } + } + } + return; + } + + /** + * This method only returns an approximation of the level of the + * expression. The "real" level is at most the return value. Adding + * <name, ValOne> to the context means that there is no need to + * compute level for name. + * + * Note that this method does not work if called on a part of an + * EXCEPT expression. + */ + public final int getLevelBound(SemanticNode expr, Context c) + { + switch (expr.getKind()) { + case OpApplKind: { + OpApplNode expr1 = (OpApplNode) expr; + return this.getLevelBoundAppl(expr1, c); + } + case LetInKind: { + LetInNode expr1 = (LetInNode) expr; + OpDefNode[] letDefs = expr1.getLets(); + int letLen = letDefs.length; + Context c1 = c; + int level = 0; + for (int i = 0; i < letLen; i++) + { + OpDefNode opDef = letDefs[i]; + level = Math.max(level, this.getLevelBound(opDef.getBody(), c1)); + c1 = c1.cons(opDef, IntValue.ValOne); + } + return Math.max(level, this.getLevelBound(expr1.getBody(), c1)); + } + case SubstInKind: { + SubstInNode expr1 = (SubstInNode) expr; + Subst[] subs = expr1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) + { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + } + return this.getLevelBound(expr1.getBody(), c1); + } + + // Added by LL on 13 Nov 2009 to handle theorem and assumption names. + case APSubstInKind: { + APSubstInNode expr1 = (APSubstInNode) expr; + Subst[] subs = expr1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) + { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + } + return this.getLevelBound(expr1.getBody(), c1); + } + + + /*********************************************************************** + * LabelKind case added by LL on 13 Jun 2007. * + ***********************************************************************/ + case LabelKind: { + LabelNode expr1 = (LabelNode) expr; + return this.getLevelBound(expr1.getBody(), c); + } + default: { + return 0; + } + } + } + + private final int getLevelBoundAppl(OpApplNode expr, Context c) + { + SymbolNode opNode = expr.getOperator(); + UniqueString opName = opNode.getName(); + int opcode = BuiltInOPs.getOpCode(opName); + + if (BuiltInOPs.isTemporal(opcode)) + { + return 3; // Conservative estimate + } + + if (BuiltInOPs.isAction(opcode)) + { + return 2; // Conservative estimate + } + + if (opcode == OPCODE_enabled) + { + return 1; // Conservative estimate + } + + int level = 0; + ExprNode[] bnds = expr.getBdedQuantBounds(); + for (int i = 0; i < bnds.length; i++) + { + level = Math.max(level, this.getLevelBound(bnds[i], c)); + } + + if (opcode == OPCODE_rfs) + { + // For recursive function, don't compute level of the function body + // again in the recursive call. + SymbolNode fname = expr.getUnbdedQuantSymbols()[0]; + c = c.cons(fname, IntValue.ValOne); + } + + ExprOrOpArgNode[] args = expr.getArgs(); + int alen = args.length; + for (int i = 0; i < alen; i++) + { + if (args[i] != null) + { + level = Math.max(level, this.getLevelBound(args[i], c)); + } + } + + if (opcode == 0) + { + // This operator is a user-defined operator. + if (opName.getVarLoc() >= 0) + return 1; + + Object val = this.lookup(opNode, c, false); + if (val instanceof OpDefNode) + { + OpDefNode opDef = (OpDefNode) val; + c = c.cons(opNode, IntValue.ValOne); + level = Math.max(level, this.getLevelBound(opDef.getBody(), c)); + } else if (val instanceof LazyValue) + { + LazyValue lv = (LazyValue) val; + level = Math.max(level, this.getLevelBound(lv.expr, lv.con)); + } + } + return level; + } + + public FilenameToStream getResolver() + { + return resolver; + } + + public String getRootFile() { + return this.rootFile; + } + + public ModuleNode getRootModule() { + return this.rootModule; + } + + public String getConfigFile() { + return this.configFile; + } + + public String getSpecDir() { + return this.specDir; + } + + public int getId() { + return toolId; + } + + abstract IValue eval(SemanticNode body, Context empty, TLCState empty2, CostModel doNotRecord); + + public List<File> getModuleFiles(final FilenameToStream resolver) { + final List<File> result = new ArrayList<File>(); + + final Enumeration<ParseUnit> parseUnitContext = this.specObj.parseUnitContext.elements(); + while (parseUnitContext.hasMoreElements()) { + ParseUnit pu = (ParseUnit) parseUnitContext.nextElement(); + File resolve = resolver.resolve(pu.getFileName(), false); + result.add(resolve); + } + return result; + } +} diff --git a/tlatools/src/tlc2/tool/Spec.java b/tlatools/src/tlc2/tool/impl/SpecProcessor.java similarity index 53% rename from tlatools/src/tlc2/tool/Spec.java rename to tlatools/src/tlc2/tool/impl/SpecProcessor.java index 8fb1fce24bd37e877414af490fbc88b6352d0429..4c135a163046fa83fd9bfd260a8ec09f8e613a45 100644 --- a/tlatools/src/tlc2/tool/Spec.java +++ b/tlatools/src/tlc2/tool/impl/SpecProcessor.java @@ -1,18 +1,40 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Mon 19 May 2008 at 1:13:48 PST by lamport -// modified on Fri Aug 24 14:43:24 PDT 2001 by yuanyu - -package tlc2.tool; +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.impl; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; +import java.util.Arrays; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; +import java.util.Map; import java.util.Set; import tla2sany.drivers.FrontEndException; @@ -24,10 +46,8 @@ import tla2sany.semantic.DecimalNode; import tla2sany.semantic.ExprNode; import tla2sany.semantic.ExprOrOpArgNode; import tla2sany.semantic.ExternalModuleTable; -import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.LabelNode; import tla2sany.semantic.LetInNode; -import tla2sany.semantic.LevelNode; import tla2sany.semantic.ModuleNode; import tla2sany.semantic.NumeralNode; import tla2sany.semantic.OpApplNode; @@ -40,163 +60,285 @@ import tla2sany.semantic.Subst; import tla2sany.semantic.SubstInNode; import tla2sany.semantic.SymbolNode; import tla2sany.semantic.TheoremNode; -import tla2sany.semantic.ThmOrAssumpDefNode; import tlc2.TLCGlobals; import tlc2.module.BuiltInModuleHelper; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.Action; +import tlc2.tool.BuiltInOPs; +import tlc2.tool.Defns; +import tlc2.tool.EvalControl; +import tlc2.tool.EvalException; +import tlc2.tool.Specs; +import tlc2.tool.TLCState; +import tlc2.tool.TLCStateMut; +import tlc2.tool.ToolGlobals; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; import tlc2.util.List; -import tlc2.util.ObjLongTable; import tlc2.util.Vect; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.LazyValue; -import tlc2.value.MethodValue; -import tlc2.value.ModelValue; -import tlc2.value.OpRcdValue; -import tlc2.value.SetEnumValue; -import tlc2.value.StringValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; +import tlc2.value.IValue; import tlc2.value.ValueConstants; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.LazyValue; +import tlc2.value.impl.MethodValue; +import tlc2.value.impl.OpRcdValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.Value; import util.Assert; import util.FilenameToStream; import util.ToolIO; import util.UniqueString; -public class Spec implements ValueConstants, ToolGlobals, Serializable -{ - - public String specDir; // The spec directory. - public String rootFile; // The root file of this spec. - protected String configFile; // The model config file. - protected ModelConfig config; // The model configuration. - protected ExternalModuleTable moduleTbl; // The external modules reachable from root - protected ModuleNode rootModule; // The root module. - protected Set<OpDefNode> processedDefs ; - // The set of OpDefNodes on which processSpec has been called. - // Added by LL & YY on 25 June 2014 to eliminate infinite - // loop when a recursively defined operator is used as an - // operator argument in its own definition. - protected Defns defns; // Global definitions reachable from root - // SZ 10.04.2009: changed the name of the variable to reflect its nature - public OpDeclNode[] variablesNodes; // The state variables. - protected TLAClass tlaClass; // TLA built-in classes. - protected Vect initPredVec; // The initial state predicate. - protected Action nextPred; // The next state predicate. - protected Action[] temporals; // Fairness specifications... - protected String[] temporalNames; // ... and their names - protected Action[] impliedTemporals; // Liveness conds to check... - protected String[] impliedTemporalNames; // ... and their names - protected Action[] invariants; // Invariants to be checked... - protected String[] invNames; // ... and their names - protected Action[] impliedInits; // Implied-inits to be checked... - protected String[] impliedInitNames; // ... and their names - protected Action[] impliedActions; // Implied-actions to be checked... - protected String[] impliedActNames; // ... and their names - protected ExprNode[] modelConstraints; // Model constraints - protected ExprNode[] actionConstraints; // Action constraints - protected ExprNode[] assumptions; // Assumpt ions - protected boolean[] assumptionIsAxiom; // assumptionIsAxiom[i] is true iff assumptions[i] - // is an AXIOM. Added 26 May 2010 by LL +public class SpecProcessor implements ValueConstants, ToolGlobals { + + private final String rootFile; // The root file of this spec. private final FilenameToStream resolver; // takes care of path to stream resolution + private final int toolId; + private final Defns defns; // Global definitions reachable from root + private final ModelConfig config; // The model configuration. + private final Spec spec; + private final TLAClass tlaClass; + + private OpDeclNode[] variablesNodes; // The state variables. + private ExternalModuleTable moduleTbl; // The external modules reachable from root + private ModuleNode rootModule; // The root module. + private Set<OpDefNode> processedDefs; + private SpecObj specObj; + private Defns snapshot; + + private Vect<Action> initPredVec; // The initial state predicate. + private Action nextPred; // The next state predicate. + private Action[] temporals; // Fairness specifications... + private String[] temporalNames; // ... and their names + private Action[] impliedTemporals; // Liveness conds to check... + private String[] impliedTemporalNames; // ... and their names + private Action[] invariants; // Invariants to be checked... + private String[] invNames; // ... and their names + private Action[] impliedInits; // Implied-inits to be checked... + private String[] impliedInitNames; // ... and their names + private Action[] impliedActions; // Implied-actions to be checked... + private String[] impliedActNames; // ... and their names + private ExprNode[] modelConstraints; // Model constraints + private ExprNode[] actionConstraints; // Action constraints + private ExprNode[] assumptions; // Assumpt ions + private boolean[] assumptionIsAxiom; // assumptionIsAxiom[i] is true iff assumptions[i] + // is an AXIOM. Added 26 May 2010 by LL + + private Vect<Action> invVec = new Vect<>(); + private Vect<String> invNameVec = new Vect<>(); + private Vect<Action> impliedInitVec = new Vect<>(); + private Vect<String> impliedInitNameVec = new Vect<>(); + private Vect<Action> impliedActionVec = new Vect<>(); + private Vect<String> impliedActNameVec = new Vect<>(); + private Vect<Action> temporalVec = new Vect<>(); + private Vect<String> temporalNameVec = new Vect<>(); + private Vect<Action> impliedTemporalVec = new Vect<>(); + private Vect<String> impliedTemporalNameVec = new Vect<>(); + + SpecProcessor(String rootFile, FilenameToStream resolver, int toolId, Defns defns, ModelConfig config, + Spec spec, TLAClass tlaClass) { + super(); + this.rootFile = rootFile; + this.resolver = resolver; + this.toolId = toolId; + this.defns = defns; + this.config = config; + this.spec = spec; + this.tlaClass = tlaClass; + this.processedDefs = new HashSet<OpDefNode>(); + this.initPredVec = new Vect<>(5); + + // Parse and process this spec. + // It takes care of all overrides. + processSpec(); + + snapshot = defns.snapshot(); + + // Pre-evaluate all the definitions in the spec that are constants. + processConstantDefns(); + + // Finally, process the config file. + processConfig(); + } - public Spec(String specDir, String file, FilenameToStream resolver) - { - this.processedDefs = new HashSet<OpDefNode>(); - this.specDir = specDir; - this.rootFile = file; - this.rootModule = null; - this.config = null; - this.moduleTbl = null; - this.variablesNodes = null; - this.defns = new Defns(); - this.tlaClass = new TLAClass("tlc2.module", resolver); - this.initPredVec = new Vect(5); - this.nextPred = null; - this.temporals = null; - this.temporalNames = null; - this.impliedTemporals = null; - this.impliedTemporalNames = null; - this.invariants = null; - this.invNames = null; - this.impliedInits = null; - this.impliedInitNames = null; - this.impliedActions = null; - this.impliedActNames = null; - this.modelConstraints = null; - this.actionConstraints = null; - this.assumptions = null; - this.assumptionIsAxiom = null; // added 26 May 2010 by LL - this.resolver = resolver; + /** + * This method converts every definition that is constant into TLC + * value. By doing this, TLC avoids evaluating the same expression + * multiple times. + * + * The method runs for every module in the module tables. + * + * Modified by LL on 23 July 2013 so it is not run for modules that are + * instantiated and have parameters (CONSTANT or VARIABLE declarations) + */ + private void processConstantDefns() { + ModuleNode[] mods = this.moduleTbl.getModuleNodes(); + for (int i = 0; i < mods.length; i++) { + if ( (! mods[i].isInstantiated()) + || ( (mods[i].getConstantDecls().length == 0) + && (mods[i].getVariableDecls().length == 0) ) ) { + this.processConstantDefns(mods[i]); + } + } } - // SZ Feb 20, 2009: added support to name resolver, to be able to run outside of the tool - public Spec(String specDir, String specFile, String configFile, FilenameToStream resolver) - { - this(specDir, specFile, resolver); - // SZ Mar 9, 2009: added initialization of the modelValue class - ModelValue.init(); - this.configFile = configFile; - this.config = new ModelConfig(configFile + ".cfg", resolver); - this.config.parse(); - ModelValue.setValues(); // called after seeing all model values + /** + * Converts the constant definitions in the corresponding value for the + * module -- that is, it "converts" (which seems to mean calling deepNormalize) + * the values substituted for the declared constants. On 17 Mar 2012 it was + * modified by LL to evaluate the OpDefNode when a defined operator is substituted + * for an ordinary declared constant (not a declared operator constant). Without this + * evaluation, the definition gets re-evaluated every time TLC evaluates the declared + * constant. LL also added a check that an operator substituted for the declared + * constant also has the correct arity. + * + * @param mod the module to run on + */ + private void processConstantDefns(ModuleNode mod) { + + // run for constant definitions + OpDeclNode[] consts = mod.getConstantDecls(); + for (int i = 0; i < consts.length; i++) { + Object val = consts[i].getToolObject(toolId); + if (val != null && val instanceof IValue) { + ((IValue)val).deepNormalize(); + // System.err.println(consts[i].getName() + ": " + val); + } // The following else clause was added by LL on 17 March 2012. + else if (val != null && val instanceof OpDefNode) { + OpDefNode opDef = (OpDefNode) val; + // The following check logically belongs in Spec.processSpec, but it's not there. + // So, LL just added it here. This error cannot occur when running TLC from + // the Toolbox. + Assert.check(opDef.getArity() == consts[i].getArity(), + EC.TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS, + new String[] {consts[i].getName().toString(), opDef.getName().toString()}); + + if (opDef.getArity() == 0) { + try { + IValue defVal = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD); + defVal.deepNormalize(); + consts[i].setToolObject(toolId, defVal); + } catch (Assert.TLCRuntimeException | EvalException e) { + Assert.fail(EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT, + new String[] { consts[i].getName().toString(), opDef.getName().toString() }); + } + } + } + } + + // run for constant operator definitions + OpDefNode[] opDefs = mod.getOpDefs(); + DEFS: for (int i = 0; i < opDefs.length; i++) { + OpDefNode opDef = opDefs[i]; + + // The following variable evaluate and its value added by LL on 24 July 2013 + // to prevent pre-evaluation of a definition from an EXTENDS of a module that + // is also instantiated. + ModuleNode moduleNode = opDef.getOriginallyDefinedInModuleNode() ; + boolean evaluate = (moduleNode == null) + || (! moduleNode.isInstantiated()) + || ( (moduleNode.getConstantDecls().length == 0) + && (moduleNode.getVariableDecls().length == 0) ) ; + + if (evaluate && opDef.getArity() == 0) { + Object realDef = spec.lookup(opDef, Context.Empty, false); + if (realDef instanceof OpDefNode) { + opDef = (OpDefNode)realDef; + if (spec.getLevelBound(opDef.getBody(), Context.Empty) == 0) { + try { + UniqueString opName = opDef.getName(); + if (isVetoed(opName)) { + continue DEFS; + } + // System.err.println(opName); + IValue val = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD); + val.deepNormalize(); + // System.err.println(opName + ": " + val); + opDef.setToolObject(toolId, val); + Object def = this.defns.get(opName); + if (def == opDef) { + this.defns.put(opName, val); + } + } + catch (Throwable e) { + // Assert.printStack(e); + } + } + } + } + } + + // run for all inner modules + ModuleNode[] imods = mod.getInnerModules(); + for (int i = 0; i < imods.length; i++) { + this.processConstantDefns(imods[i]); + } } + public static final String LAZY_CONSTANT_OPERATORS = SpecProcessor.class.getName() + ".vetoed"; + + private static final Set<String> vetos = new HashSet<String>( + Arrays.asList(System.getProperty(LAZY_CONSTANT_OPERATORS, ""))); + + private boolean isVetoed(final UniqueString us) { + return vetos.contains(us.toString()); + } + /** * Processes the specification and collects information to be used * by tools. The processing tries to use any customized module (Java * class) to override the corresponding TLA+ module. */ // SZ Feb 20, 2009: added support for existing specObj - protected final SpecObj processSpec(SpecObj spec) + private final void processSpec() { - if (spec == null) - { - // construct new specification object, if the - // passed one was null - spec = new SpecObj(this.rootFile, resolver); + // construct new specification object, if the + // passed one was null + specObj = new SpecObj(this.rootFile, resolver); - // We first call the SANY front-end to parse and semantic-analyze - // the complete TLA+ spec starting with the main module rootFile. - if (TLCGlobals.tool) - { - MP.printMessage(EC.TLC_SANY_START); - } - try - { - // SZ Feb 20, 2009: - // call SANY to parse the module - // this method will not throw any exceptions on - // checked errors (init, parse, semantic). - // Only if something unexpected happens the - // exception is thrown - SANY.frontEndMain(spec, this.rootFile, ToolIO.out); - } catch (FrontEndException e) - { - Assert.fail(EC.TLC_PARSING_FAILED2, e); - } + // We first call the SANY front-end to parse and semantic-analyze + // the complete TLA+ spec starting with the main module rootFile. + if (TLCGlobals.tool) + { + MP.printMessage(EC.TLC_SANY_START); + } + try + { + // SZ Feb 20, 2009: + // call SANY to parse the module + // this method will not throw any exceptions on + // checked errors (init, parse, semantic). + // Only if something unexpected happens the + // exception is thrown + SANY.frontEndMain(specObj, this.rootFile, ToolIO.out); + } catch (FrontEndException e) + { + Assert.fail(EC.TLC_PARSING_FAILED2, e); + } - if (TLCGlobals.tool) - { - MP.printMessage(EC.TLC_SANY_END); - } - // The following statement moved here by LL on 11 March 2011 - MP.printMessage(EC.TLC_STARTING); + if (TLCGlobals.tool) + { + MP.printMessage(EC.TLC_SANY_END); } + // The following statement moved here by LL on 11 March 2011 + MP.printMessage(EC.TLC_STARTING); // SZ Feb 20, 2009: // since failed parsing is not marked by an exception, // check the status of the spec // check if the specification has been successfully created - if (!spec.initErrors.isSuccess() || !spec.parseErrors.isSuccess() || !spec.semanticErrors.isSuccess()) + if (!specObj.initErrors.isSuccess() || !specObj.parseErrors.isSuccess() || !specObj.semanticErrors.isSuccess()) { Assert.fail(EC.TLC_PARSING_FAILED); } // Set the rootModule: - this.moduleTbl = spec.getExternalModuleTable(); + this.moduleTbl = specObj.getExternalModuleTable(); UniqueString rootName = UniqueString.uniqueStringOf(this.rootFile); this.rootModule = this.moduleTbl.getModuleNode(rootName); @@ -214,7 +356,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } // set variables to the static filed in the state - TLCState.setVariables(this.variablesNodes); + TLCStateMut.setVariables(this.variablesNodes); // SZ 11.04.2009: set the number of variables UniqueString.setVariableCount(varDecls.length); @@ -228,11 +370,11 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable this.defns.setDefnCount(varDecls.length); // Add predefined (Boolean and String) in defns. - this.defns.put("TRUE", ValTrue); - this.defns.put("FALSE", ValFalse); + this.defns.put("TRUE", BoolValue.ValTrue); + this.defns.put("FALSE", BoolValue.ValFalse); Value[] elems = new Value[2]; - elems[0] = ValFalse; - elems[1] = ValTrue; + elems[0] = BoolValue.ValFalse; + elems[1] = BoolValue.ValTrue; this.defns.put("BOOLEAN", new SetEnumValue(elems, true)); Class stringModule = this.tlaClass.loadClass("Strings"); @@ -255,9 +397,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable // should not be accessed by application code. Thus, exclude // synthetic members from being processed. if (!ms[i].isSynthetic()) { - MethodValue mv = new MethodValue(ms[i]); - Value val = (acnt == 0) ? mv.apply(EmptyArgs, EvalControl.Clear) : mv; - this.defns.put(name, val); + this.defns.put(name, MethodValue.get(ms[i])); } } } @@ -266,11 +406,11 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable // here since we use defns. Things added into defns later will make it // wrong to use it in the method processConstants. ModuleNode[] mods = this.moduleTbl.getModuleNodes(); - Set<String> modSet = new HashSet<String>(); + final Map<String, ModuleNode> modSet = new HashMap<String, ModuleNode>(); for (int i = 0; i < mods.length; i++) { this.processConstants(mods[i]); - modSet.add(mods[i].getName().toString()); + modSet.put(mods[i].getName().toString(), mods[i]); } // Collect all the assumptions. @@ -298,7 +438,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable { Assert.fail(EC.TLC_CONFIG_VALUE_NOT_ASSIGNED_TO_CONSTANT_PARAM, name.toString()); } - rootConsts[i].setToolObject(TLCGlobals.ToolId, val); + rootConsts[i].setToolObject(toolId, val); this.defns.put(name, val); } @@ -313,18 +453,18 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable this.defns.put(name, rootOpDefs[i]); } else { - rootOpDefs[i].setToolObject(TLCGlobals.ToolId, val); + rootOpDefs[i].setToolObject(toolId, val); this.defns.put(name, val); } } // Apply config file module specific constants to operator defns. // We do not allow this kind of replacement for constant decls. - Hashtable modConstants = this.initializeModConstants(); + Hashtable<String, Hashtable> modConstants = this.initializeModConstants(); for (int i = 0; i < mods.length; i++) { UniqueString modName = mods[i].getName(); - Hashtable mConsts = (Hashtable) modConstants.get(modName.toString()); + Hashtable mConsts = modConstants.get(modName.toString()); if (mConsts != null) { OpDefNode[] opDefs = mods[i].getOpDefs(); @@ -334,7 +474,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Object val = mConsts.get(name.toString()); if (val != null) { - opDefs[j].getBody().setToolObject(TLCGlobals.ToolId, val); + opDefs[j].getBody().setToolObject(toolId, val); } } } @@ -343,30 +483,50 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable // Apply module overrides: for (int i = 0; i < mods.length; i++) { - UniqueString modName = mods[i].getName(); - Class userModule = this.tlaClass.loadClass(modName.toString()); + + final UniqueString modName = mods[i].getName(); + final Class userModule = this.tlaClass.loadClass(modName.toString()); if (userModule != null) { + final Map<UniqueString, Integer> opname2arity = new HashMap<>(); + if (!BuiltInModuleHelper.isBuiltInModule(userModule)) { + // Remember arity for non built-in overrides to later match with java override + // when loading. + for (OpDefNode opDefNode : rootOpDefs) { + if (opDefNode.getOriginallyDefinedInModuleNode().getName().equals(modName)) { + opname2arity.put(opDefNode.getName(), opDefNode.getArity()); + } + } + } // Override with a user defined Java class for the TLA+ module. // Collects new definitions: - Hashtable<UniqueString, Value> javaDefs = new Hashtable<UniqueString, Value>(); - Method[] mds = userModule.getDeclaredMethods(); + final Hashtable<UniqueString, IValue> javaDefs = new Hashtable<UniqueString, IValue>(); + final Method[] mds = userModule.getDeclaredMethods(); for (int j = 0; j < mds.length; j++) { - int mdf = mds[j].getModifiers(); + final Method method = mds[j]; + int mdf = method.getModifiers(); if (Modifier.isPublic(mdf) && Modifier.isStatic(mdf)) { - String name = TLARegistry.mapName(mds[j].getName()); + String name = TLARegistry.mapName(method.getName()); UniqueString uname = UniqueString.uniqueStringOf(name); - int acnt = mds[j].getParameterTypes().length; - MethodValue mv = new MethodValue(mds[j]); - boolean isConstant = (acnt == 0) && Modifier.isFinal(mdf); - Value val = isConstant ? mv.apply(EmptyArgs, EvalControl.Clear) : mv; - javaDefs.put(uname, val); + final int acnt = method.getParameterCount(); + final MethodValue val = MethodValue.get(method); if (!BuiltInModuleHelper.isBuiltInModule(userModule)) { - final URL resource = userModule.getResource(userModule.getSimpleName() + ".class"); - MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED, new String[] {uname.toString(), resource.toExternalForm(), mv.toString()}); + final URL resource = userModule.getResource(userModule.getSimpleName() + ".class"); + // Print success or failure of loading the module override (arity mismatch). + final Integer arity = opname2arity.get(uname); + if (arity == null || arity != acnt) { + MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH, + new String[] { uname.toString(), resource.toExternalForm(), val.toString() }); + } else { + javaDefs.put(uname, val); + MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED, + new String[] { uname.toString(), resource.toExternalForm(), val.toString() }); + } + } else { + javaDefs.put(uname, val); } } } @@ -378,7 +538,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Object val = javaDefs.get(uname); if (val != null) { - opDefs[j].getBody().setToolObject(TLCGlobals.ToolId, val); + opDefs[j].getBody().setToolObject(toolId, val); this.defns.put(uname, val); } } @@ -402,7 +562,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable { Assert.fail(EC.TLC_CONFIG_WRONG_SUBSTITUTION, new String[] { lhs.toString(), rhs }); } - rootConsts[i].setToolObject(TLCGlobals.ToolId, myVal); + rootConsts[i].setToolObject(toolId, myVal); this.defns.put(lhs, myVal); overriden.add(lhs.toString()); } @@ -429,7 +589,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable { Assert.fail(EC.TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS, new String[] { lhs.toString(), rhs }); } - rootOpDefs[i].setToolObject(TLCGlobals.ToolId, myVal); + rootOpDefs[i].setToolObject(toolId, myVal); this.defns.put(lhs, myVal); overriden.add(lhs.toString()); } @@ -447,12 +607,12 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable // Apply config file module specific overrides to operator defns. // We do not allow this kind of replacement for constant decls. - Hashtable modOverrides = this.config.getModOverrides(); + Hashtable<String, Hashtable> modOverrides = this.config.getModOverrides(); for (int i = 0; i < mods.length; i++) { UniqueString modName = mods[i].getName(); - Hashtable mDefs = (Hashtable) modOverrides.get(modName.toString()); - HashSet modOverriden = new HashSet(); + Hashtable mDefs = modOverrides.get(modName.toString()); + HashSet<String> modOverriden = new HashSet<>(); if (mDefs != null) { // the operator definitions: @@ -479,7 +639,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Assert.fail(EC.TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS, new String[] { lhs.toString(), rhs }); } - opDefs[j].getBody().setToolObject(TLCGlobals.ToolId, myVal); + opDefs[j].getBody().setToolObject(toolId, myVal); modOverriden.add(lhs.toString()); } } @@ -501,264 +661,17 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable while (modKeys.hasMoreElements()) { Object modName = modKeys.nextElement(); - if (!modSet.contains(modName)) + if (!modSet.keySet().contains(modName)) { Assert.fail(EC.TLC_NO_MODULES, modName.toString()); } } - - return spec; - } - - /************************************************************************* - * The following method goes through all the nodes to set their * - * tool-specific fields. It was modified on 1 May 2007 so it would find * - * the nodes in the body of a Lambda expression. Obviously, if new * - * semantic node types are added, this method will have to be modified. * - * Less obviously, if a tool wants to call TLC on a specification that * - * was not all created inside a module, then this method may need to be * - * modified so TLC finds those nodes not part of the module. * - * * - * Yuan claims that this is the only method in TLC that has to find all * - * the nodes in such a way. * - *************************************************************************/ - private final void processConstants(SemanticNode expr) - { - switch (expr.getKind()) { - case ModuleKind: { - ModuleNode expr1 = (ModuleNode) expr; - // Process operator definitions: - OpDefNode[] opDefs = expr1.getOpDefs(); - for (int i = 0; i < opDefs.length; i++) - { - Object def = opDefs[i].getToolObject(TLCGlobals.ToolId); - if (def instanceof OpDefNode) - { - this.processedDefs.add((OpDefNode) def); - this.processConstants(((OpDefNode) def).getBody()); - } - this.processConstants(opDefs[i].getBody()); - } - // Process all the inner modules: - ModuleNode[] imods = expr1.getInnerModules(); - for (int i = 0; i < imods.length; i++) - { - this.processConstants(imods[i]); - } - // Process all the assumptions: - AssumeNode[] assumps = expr1.getAssumptions(); - for (int i = 0; i < assumps.length; i++) - { - this.processConstants(assumps[i]); - } - // On 13 Nov 2009, Yuan Yu added the following - // processing of all TheoremNodes, which was needed to - // allow Theorem and Assumption names to be used as expressions. - // - // Process all the theorems: - TheoremNode[] thms = expr1.getTheorems(); - for (int i = 0; i < thms.length; i++) { - this.processConstants(thms[i]); - } - - return; - } - case OpApplKind: { - OpApplNode expr1 = (OpApplNode) expr; - SymbolNode opNode = expr1.getOperator(); - Object val = this.defns.get(opNode.getName()); - if (val != null) - { - opNode.setToolObject(TLCGlobals.ToolId, val); - } else - { - SemanticNode[] args = expr1.getArgs(); - for (int i = 0; i < args.length; i++) - { - if (args[i] != null) - { - this.processConstants(args[i]); - } - } - ExprNode[] bnds = expr1.getBdedQuantBounds(); - for (int i = 0; i < bnds.length; i++) - { - this.processConstants(bnds[i]); - } - } - return; - } - case LetInKind: { - LetInNode expr1 = (LetInNode) expr; - OpDefNode[] letDefs = expr1.getLets(); - for (int i = 0; i < letDefs.length; i++) - { - this.processConstants(letDefs[i].getBody()); - } - this.processConstants(expr1.getBody()); - return; - } - case SubstInKind: { - SubstInNode expr1 = (SubstInNode) expr; - Subst[] subs = expr1.getSubsts(); - for (int i = 0; i < subs.length; i++) - { - this.processConstants(subs[i].getExpr()); - } - this.processConstants(expr1.getBody()); - return; - } - - // Added by LL on 13 Nov 2009 to handle theorem and assumption names. - case APSubstInKind: { - APSubstInNode expr1 = (APSubstInNode) expr; - Subst[] subs = expr1.getSubsts(); - for (int i = 0; i < subs.length; i++) - { - this.processConstants(subs[i].getExpr()); - } - this.processConstants(expr1.getBody()); - return; - } - - - case NumeralKind: { - NumeralNode expr1 = (NumeralNode) expr; - IntValue val = IntValue.gen(expr1.val()); - // LL added this test on 20 Jul 2011; otherwise - // TLC treats a number bigger than MAX_VALUE - // (2^31-1 or 2,147,483,647) as if it equals 0. - if (expr1.bigVal() != null) { - Assert.fail(EC.TLC_INTEGER_TOO_BIG, expr1.toString()); - return; - } - expr1.setToolObject(TLCGlobals.ToolId, val); - return; - } - case DecimalKind: { - DecimalNode expr1 = (DecimalNode) expr; // SZ: using typed variable - Assert.fail(EC.TLC_CANT_HANDLE_REAL_NUMBERS, expr1.toString()); - return; - } - case StringKind: { - StringNode expr1 = (StringNode) expr; - StringValue val = new StringValue(expr1.getRep()); - expr1.setToolObject(TLCGlobals.ToolId, val); - return; - } - case AssumeKind: { - AssumeNode expr1 = (AssumeNode) expr; - this.processConstants(expr1.getAssume()); - return; - } - // On 13 Nov 2009, Yuan Yu added the following case, which was - // needed to allow Theorem and Assumption names to be used as - // expressions. - // - case TheoremKind: - { - TheoremNode expr1 = (TheoremNode)expr; - this.processConstants(expr1.getTheorem()); - return; - } - case OpArgKind: { - SymbolNode opArgNode = ((OpArgNode) expr).getOp(); - if (opArgNode.getKind() == UserDefinedOpKind) - { OpDefNode opdef = (OpDefNode) opArgNode ; - if (! processedDefs.contains(opdef)) { - processedDefs.add(opdef) ; - this.processConstants(opdef.getBody()); - } - } - return; - } - /*********************************************************************** - * LabelKind case added by LL on 13 Jun 2007. * - ***********************************************************************/ - case LabelKind: { - LabelNode expr1 = (LabelNode) expr; - this.processConstants(expr1.getBody()); - } - } - } - - /* Return the variable if expr is a state variable. Otherwise, null. */ - public final SymbolNode getVar(SemanticNode expr, Context c, boolean cutoff) - { - if (expr instanceof OpApplNode) - { - SymbolNode opNode = ((OpApplNode) expr).getOperator(); - - if (opNode.getArity() == 0) - { - boolean isVarDecl = (opNode.getKind() == VariableDeclKind); - Object val = this.lookup(opNode, c, cutoff && isVarDecl); - - if (val instanceof LazyValue) - { - LazyValue lval = (LazyValue) val; - return this.getVar(lval.expr, lval.con, cutoff); - } - if (val instanceof OpDefNode) - { - return this.getVar(((OpDefNode) val).getBody(), c, cutoff); - } - if (isVarDecl) - { - return opNode; - } - } - } - return null; - } - - /* Return the variable if expr is a primed state variable. Otherwise, null. */ - public final SymbolNode getPrimedVar(SemanticNode expr, Context c, boolean cutoff) - { - if (expr instanceof OpApplNode) - { - OpApplNode expr1 = (OpApplNode) expr; - SymbolNode opNode = expr1.getOperator(); - - if (BuiltInOPs.getOpCode(opNode.getName()) == OPCODE_prime) - { - return this.getVar(expr1.getArgs()[0], c, cutoff); - } - - if (opNode.getArity() == 0) - { - boolean isVarDecl = (opNode.getKind() == VariableDeclKind); - Object val = this.lookup(opNode, c, cutoff && isVarDecl); - - if (val instanceof LazyValue) - { - LazyValue lval = (LazyValue) val; - return this.getPrimedVar(lval.expr, lval.con, cutoff); - } - if (val instanceof OpDefNode) - { - return this.getPrimedVar(((OpDefNode) val).getBody(), c, cutoff); - } - } - } - return null; } - private Vect invVec = new Vect(); - private Vect invNameVec = new Vect(); - private Vect impliedInitVec = new Vect(); - private Vect impliedInitNameVec = new Vect(); - private Vect impliedActionVec = new Vect(); - private Vect impliedActNameVec = new Vect(); - private Vect temporalVec = new Vect(); - private Vect temporalNameVec = new Vect(); - private Vect impliedTemporalVec = new Vect(); - private Vect impliedTemporalNameVec = new Vect(); - /** * Process the configuration file. */ - public final void processConfig() + private final void processConfig() { // Process the invariants: this.processConfigInvariants(); @@ -793,7 +706,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } // Process the properties: - Vect propNames = this.config.getProperties(); + Vect<String> propNames = this.config.getProperties(); for (int i = 0; i < propNames.size(); i++) { String propName = (String) propNames.elementAt(i); @@ -809,7 +722,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } else if (prop == null) { Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "property", propName }); - } else if (!(prop instanceof BoolValue) || !(((BoolValue) prop).val)) + } else if (!(prop instanceof IBoolValue) || !(((BoolValue) prop).val)) { Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, new String[] { "property", propName, prop.toString() }); } @@ -910,7 +823,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable { Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "initial predicate", name }); } - this.initPredVec.addElement(new Action(def.getBody(), Context.Empty)); + this.initPredVec.addElement(new Action(def.getBody(), Context.Empty, def)); } name = this.config.getNext(); @@ -930,7 +843,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable { Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "next state action", name }); } - this.nextPred = new Action(def.getBody(), Context.Empty); + this.nextPred = new Action(def.getBody(), Context.Empty, def); } } @@ -966,11 +879,11 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Assert.fail(EC.TLC_INVARIANT_VIOLATED_LEVEL, def.getName().toString()); } this.invNameVec.addElement(name); - this.invVec.addElement(new Action(def.getBody(), Context.Empty)); + this.invVec.addElement(new Action(def.getBody(), Context.Empty, def)); } else if (inv == null) { Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "invariant", name }); - } else if (!(inv instanceof BoolValue) || !(((BoolValue) inv).val)) + } else if (!(inv instanceof IBoolValue) || !(((BoolValue) inv).val)) { Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, new String[] { "invariant", name, inv.toString() }); } @@ -995,7 +908,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable if (args.length == 0) { SymbolNode opNode = pred1.getOperator(); - Object val = this.lookup(opNode, c, false); + Object val = spec.lookup(opNode, c, false); if (val instanceof OpDefNode) { if (((OpDefNode) val).getArity() != 0) @@ -1003,9 +916,9 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Assert.fail(EC.TLC_CONFIG_OP_NO_ARGS, new String[] { opNode.getName().toString() }); } ExprNode body = ((OpDefNode) val).getBody(); - if (this.getLevelBound(body, c) == 1) + if (spec.getLevelBound(body, c) == 1) { - this.initPredVec.addElement(new Action(Spec.addSubsts(body, subs), c)); + this.initPredVec.addElement(new Action(Specs.addSubsts(body, subs), c, ((OpDefNode) val))); } else { this.processConfigSpec(body, c, subs); @@ -1013,7 +926,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } else if (val == null) { Assert.fail(EC.TLC_CONFIG_OP_NOT_IN_SPEC, new String[] { opNode.getName().toString() }); - } else if (val instanceof BoolValue) + } else if (val instanceof IBoolValue) { if (!((BoolValue) val).val) { @@ -1062,17 +975,17 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable * of this specification object -- otherwise TLC's * analysis is incorrect. **/ - Vect components; + Vect<SymbolNode> components; SubscriptCollector() { - this.components = new Vect(); + this.components = new Vect<>(); } void enter(ExprNode subscript, Context c) { // if it's a variable, add it to the vector and return - SymbolNode var = getVar(subscript, c, false); + SymbolNode var = spec.getVar(subscript, c, false); if (var != null) { components.addElement(var); @@ -1100,11 +1013,11 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable return; } // user-defined operator: look up its definition - Object opDef = lookup(opNode, c, false); + Object opDef = spec.lookup(opNode, c, false); if (opDef instanceof OpDefNode) { OpDefNode opDef1 = (OpDefNode) opDef; - this.enter(opDef1.getBody(), getOpContext(opDef1, args, c, false)); + this.enter(opDef1.getBody(), spec.getOpContext(opDef1, args, c, false)); return; } if (opDef instanceof LazyValue) @@ -1122,7 +1035,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Context c1 = c; for (int i = 0; i < subs.length; i++) { - c1 = c1.cons(subs[i].getOp(), getVal(subs[i].getExpr(), c, false)); + c1 = c1.cons(subs[i].getOp(), spec.getVal(subs[i].getExpr(), c, false)); } this.enter(subscript1.getBody(), c1); return; @@ -1152,7 +1065,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } } - Vect getComponents() + Vect<SymbolNode> getComponents() { return components; } @@ -1167,7 +1080,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable Subst[] snsubs = sn.getSubsts(); for (int i = 0; i < snsubs.length; i++) { - c1 = c1.cons(snsubs[i].getOp(), getVal(snsubs[i].getExpr(), c, false)); + c1 = c1.cons(snsubs[i].getOp(), spec.getVal(snsubs[i].getExpr(), c, false)); } subs1 = subs1.cdr(); } @@ -1195,7 +1108,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } if (this.nextPred == null) { - this.nextPred = new Action(Spec.addSubsts(arg, subs), c); + this.nextPred = new Action(Specs.addSubsts(arg, subs), c); } else { Assert.fail(EC.TLC_CANT_HANDLE_TOO_MANY_NEXT_STATE_RELS); @@ -1203,7 +1116,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable // ---sm 09/06/04 >>> } else { - this.temporalVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.temporalVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); this.temporalNameVec.addElement(pred.toString()); } return; @@ -1216,13 +1129,13 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } } - int level = this.getLevelBound(pred, c); + int level = spec.getLevelBound(pred, c); if (level <= 1) { - this.initPredVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.initPredVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); } else if (level == 3) { - this.temporalVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.temporalVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); this.temporalNameVec.addElement(pred.toString()); } else { @@ -1246,7 +1159,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable if (args.length == 0) { SymbolNode opNode = pred1.getOperator(); - Object val = this.lookup(opNode, c, false); + Object val = spec.lookup(opNode, c, false); if (val instanceof OpDefNode) { if (((OpDefNode) val).getArity() != 0) @@ -1257,7 +1170,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } else if (val == null) { Assert.fail(EC.TLC_CONFIG_OP_NOT_IN_SPEC, opNode.getName().toString()); - } else if (val instanceof BoolValue) + } else if (val instanceof IBoolValue) { if (!((BoolValue) val).val) { @@ -1293,10 +1206,10 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable name = boxArg1.getOperator().getName().toString(); } this.impliedActNameVec.addElement(name); - this.impliedActionVec.addElement(new Action(Spec.addSubsts(boxArg, subs), c)); - } else if (this.getLevelBound(boxArg, c) < 2) + this.impliedActionVec.addElement(new Action(Specs.addSubsts(boxArg, subs), c)); + } else if (spec.getLevelBound(boxArg, c) < 2) { - this.invVec.addElement(new Action(Spec.addSubsts(boxArg, subs), c)); + this.invVec.addElement(new Action(Specs.addSubsts(boxArg, subs), c)); if ((boxArg instanceof OpApplNode) && (((OpApplNode) boxArg).getArgs().length == 0)) { name = ((OpApplNode) boxArg).getOperator().getName().toString(); @@ -1304,7 +1217,7 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable this.invNameVec.addElement(name); } else { - this.impliedTemporalVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.impliedTemporalVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); this.impliedTemporalNameVec.addElement(name); } return; @@ -1316,870 +1229,414 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable return; } } - int level = this.getLevelBound(pred, c); + int level = spec.getLevelBound(pred, c); if (level <= 1) { - this.impliedInitVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.impliedInitVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); this.impliedInitNameVec.addElement(name); } else if (level == 3) { - this.impliedTemporalVec.addElement(new Action(Spec.addSubsts(pred, subs), c)); + this.impliedTemporalVec.addElement(new Action(Specs.addSubsts(pred, subs), c)); this.impliedTemporalNameVec.addElement(name); } else { Assert.fail(EC.TLC_CONFIG_PROPERTY_NOT_CORRECTLY_DEFINED, name); } } - - private final Hashtable makeConstantTable(Vect consts) - { - Hashtable constTbl = new Hashtable(); - for (int i = 0; i < consts.size(); i++) - { - Vect line = (Vect) consts.elementAt(i); - int len = line.size(); - String name = (String) line.elementAt(0); - if (len <= 2) - { - constTbl.put(name, line.elementAt(1)); - } else - { - Object val = constTbl.get(name); - if (val == null) - { - OpRcdValue opVal = new OpRcdValue(); - opVal.addLine(line); - constTbl.put(name, opVal); - } else - { - OpRcdValue opVal = (OpRcdValue) val; - int arity = ((Value[]) opVal.domain.elementAt(0)).length; - if (len != arity + 2) - { - Assert.fail(EC.TLC_CONFIG_OP_ARITY_INCONSISTENT, name); - } - opVal.addLine(line); - } - } - } - return constTbl; - } - - /** - * Initialize the spec constants using the config file. - */ - public final Hashtable initializeConstants() - { - Vect consts = this.config.getConstants(); - if (consts == null) - { - return new Hashtable(); - } - return this.makeConstantTable(consts); - } - - public final Hashtable initializeModConstants() - { - Hashtable modConstants = this.config.getModConstants(); - Hashtable constants = new Hashtable(); - Enumeration mods = modConstants.keys(); - while (mods.hasMoreElements()) - { - String modName = (String) mods.nextElement(); - constants.put(modName, this.makeConstantTable((Vect) modConstants.get(modName))); - } - return constants; - } - - /** - * Get model constraints. - */ - public final ExprNode[] getModelConstraints() - { - return this.modelConstraints; - } - - private final void processModelConstraints() { - Vect names = this.config.getConstraints(); - this.modelConstraints = new ExprNode[names.size()]; - int idx = 0; - for (int i = 0; i < names.size(); i++) - { - String name = (String) names.elementAt(i); - Object constr = this.defns.get(name); - if (constr instanceof OpDefNode) - { - OpDefNode def = (OpDefNode) constr; - if (def.getArity() != 0) - { - Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "constraint", name }); - } - this.modelConstraints[idx++] = def.getBody(); - } else if (constr != null) - { - if (!(constr instanceof BoolValue) || !((BoolValue) constr).val) - { - Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, new String[] { "constraint", name, constr.toString() }); - } - } else - { - Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "constraint", name }); - } - } + + private void processActionConstraints() { + Vect names = this.config.getActionConstraints(); + this.actionConstraints = new ExprNode[names.size()]; + int idx = 0; + for (int i = 0; i < names.size(); i++) + { + String name = (String) names.elementAt(i); + Object constr = this.defns.get(name); + if (constr instanceof OpDefNode) + { + OpDefNode def = (OpDefNode) constr; + if (def.getArity() != 0) + { + Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "action constraint", name }); + } + this.actionConstraints[idx++] = def.getBody(); + } else if (constr != null) + { + if (!(constr instanceof IBoolValue) || !((BoolValue) constr).val) + { + Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, + new String[] { "action constraint", name, constr.toString() }); + } + } else + { + Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "action constraint", name }); + } + } + // Shrink in case array has been overallocated + if (idx < this.actionConstraints.length) + { + ExprNode[] constrs = new ExprNode[idx]; + for (int i = 0; i < idx; i++) + { + constrs[i] = this.actionConstraints[i]; + } + this.actionConstraints = constrs; + } + } + + private final void processModelConstraints() { + Vect names = this.config.getConstraints(); + this.modelConstraints = new ExprNode[names.size()]; + int idx = 0; + for (int i = 0; i < names.size(); i++) + { + String name = (String) names.elementAt(i); + Object constr = this.defns.get(name); + if (constr instanceof OpDefNode) + { + OpDefNode def = (OpDefNode) constr; + if (def.getArity() != 0) + { + Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "constraint", name }); + } + this.modelConstraints[idx++] = def.getBody(); + } else if (constr != null) + { + if (!(constr instanceof IBoolValue) || !((BoolValue) constr).val) + { + Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, new String[] { "constraint", name, constr.toString() }); + } + } else + { + Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "constraint", name }); + } + } // Shrink modelContraints in case we allocated a too large array. See // nested if block above for why some constraints don't get instantiated. - if (idx < this.modelConstraints.length) - { - ExprNode[] constrs = new ExprNode[idx]; - for (int i = 0; i < idx; i++) - { - constrs[i] = this.modelConstraints[i]; - } - this.modelConstraints = constrs; - } - } - - /** - * Get action constraints. - */ - public final ExprNode[] getActionConstraints() + if (idx < this.modelConstraints.length) + { + ExprNode[] constrs = new ExprNode[idx]; + for (int i = 0; i < idx; i++) + { + constrs[i] = this.modelConstraints[i]; + } + this.modelConstraints = constrs; + } + } + + /************************************************************************* + * The following method goes through all the nodes to set their * + * tool-specific fields. It was modified on 1 May 2007 so it would find * + * the nodes in the body of a Lambda expression. Obviously, if new * + * semantic node types are added, this method will have to be modified. * + * Less obviously, if a tool wants to call TLC on a specification that * + * was not all created inside a module, then this method may need to be * + * modified so TLC finds those nodes not part of the module. * + * * + * Yuan claims that this is the only method in TLC that has to find all * + * the nodes in such a way. * + *************************************************************************/ + private final void processConstants(SemanticNode expr) { - return this.actionConstraints; - } - - private void processActionConstraints() { - Vect names = this.config.getActionConstraints(); - this.actionConstraints = new ExprNode[names.size()]; - int idx = 0; - for (int i = 0; i < names.size(); i++) - { - String name = (String) names.elementAt(i); - Object constr = this.defns.get(name); - if (constr instanceof OpDefNode) - { - OpDefNode def = (OpDefNode) constr; - if (def.getArity() != 0) - { - Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "action constraint", name }); - } - this.actionConstraints[idx++] = def.getBody(); - } else if (constr != null) + switch (expr.getKind()) { + case ModuleKind: { + ModuleNode expr1 = (ModuleNode) expr; + // Process operator definitions: + OpDefNode[] opDefs = expr1.getOpDefs(); + for (int i = 0; i < opDefs.length; i++) { - if (!(constr instanceof BoolValue) || !((BoolValue) constr).val) + Object def = opDefs[i].getToolObject(toolId); + if (def instanceof OpDefNode) { - Assert.fail(EC.TLC_CONFIG_ID_HAS_VALUE, - new String[] { "action constraint", name, constr.toString() }); + this.processedDefs.add((OpDefNode) def); + this.processConstants(((OpDefNode) def).getBody()); } - } else - { - Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "action constraint", name }); + this.processConstants(opDefs[i].getBody()); } - } - // Shrink in case array has been overallocated - if (idx < this.actionConstraints.length) - { - ExprNode[] constrs = new ExprNode[idx]; - for (int i = 0; i < idx; i++) + // Process all the inner modules: + ModuleNode[] imods = expr1.getInnerModules(); + for (int i = 0; i < imods.length; i++) { - constrs[i] = this.actionConstraints[i]; - } - this.actionConstraints = constrs; - } - } - - /* Get the initial state predicate of the specification. */ - public final Vect getInitStateSpec() - { - return this.initPredVec; - } - - /* Get the action (next state) predicate of the specification. */ - public final Action getNextStateSpec() - { - return this.nextPred; - } - - /** - * Get the view mapping for the specification. - */ - public final SemanticNode getViewSpec() - { - String name = this.config.getView(); - if (name.length() == 0) - return null; - - Object view = this.defns.get(name); - if (view == null) - { - Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "view function", name }); - } - if (!(view instanceof OpDefNode)) - { - Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "view function", name }); - } - OpDefNode def = (OpDefNode) view; - if (def.getArity() != 0) - { - Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "view function", name }); - } - return def.getBody(); - } - - /* Get the type declaration for the state variables. */ - public final SemanticNode getTypeSpec() - { - String name = this.config.getType(); - if (name.length() == 0) - { - Assert.fail(EC.TLC_CONFIG_NO_STATE_TYPE); - } - - Object type = this.defns.get(name); - if (type == null) - { - Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "type", name }); - } - if (!(type instanceof OpDefNode)) - { - Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "type", name }); - } - OpDefNode def = (OpDefNode) type; - if (def.getArity() != 0) - { - Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "type", name }); - } - return def.getBody(); - } - - /* Get the type declaration for the state variables. */ - public final SemanticNode getTypeConstraintSpec() - { - String name = this.config.getTypeConstraint(); - if (name.length() == 0) - { - return null; - } - - Object type = this.defns.get(name); - if (type == null) - { - Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "type constraint", name }); - } - if (!(type instanceof OpDefNode)) - { - Assert.fail(EC.TLC_CONFIG_ID_MUST_NOT_BE_CONSTANT, new String[] { "type constraint", name }); - } - OpDefNode def = (OpDefNode) type; - if (def.getArity() != 0) - { - Assert.fail(EC.TLC_CONFIG_ID_REQUIRES_NO_ARG, new String[] { "type constraint", name }); - - } - return def.getBody(); - } - - public final boolean livenessIsTrue() - { - return this.impliedTemporals.length == 0; - } - - /* Get the fairness condition of the specification. */ - public final Action[] getTemporals() - { - return this.temporals; - } - - public final String[] getTemporalNames() - { - return this.temporalNames; - } - - /* Get the liveness checks of the specification. */ - public final Action[] getImpliedTemporals() - { - return this.impliedTemporals; - } - - public final String[] getImpliedTemporalNames() - { - return this.impliedTemporalNames; - } - - /* Get the invariants of the specification. */ - public final Action[] getInvariants() - { - return this.invariants; - } - - public final String[] getInvNames() - { - return this.invNames; - } - - /* Get the implied-inits of the specification. */ - public final Action[] getImpliedInits() - { - return this.impliedInits; - } - - public final String[] getImpliedInitNames() - { - return this.impliedInitNames; - } - - /* Get the implied-actions of the specification. */ - public final Action[] getImpliedActions() - { - return this.impliedActions; - } - - public final String[] getImpliedActNames() - { - return this.impliedActNames; - } - - /* Get the assumptions of the specification. */ - public final ExprNode[] getAssumptions() - { - return this.assumptions; - } - - /* Get the assumptionIsAxiom field */ - public final boolean[] getAssumptionIsAxiom() { - return this.assumptionIsAxiom; - } - /** - * This method gets the value of a symbol from the enviroment. We - * look up in the context c, its tool object, and the state s. - * - * It and the lookup method that follows it were modified by LL - * on 10 April 2011 to fix the following bug. When a constant definition - * Foo == ... - * is overridden to substitute Bar for Foo, the TLC tool object for - * the body of Foo's OpDef node is set to the OpDefNode for Bar. - * When evaluating a use of Foo, the lookup method is apparently - * supposed to return the OpDefNode for Bar. (I don't understand - * how the callers make use of the returned value.) That's what it - * does for uses of Foo in the module in which Foo is defined. - * However, if Foo is imported by instantiation with renaming as - * X!Foo, then it appears that looking up X!Foo should also return - * the OpDefNode for Bar. If the instantiated module had no - * parameters, then that's what happened because the body of the - * OpDefNode for X!Foo is the same (contains a pointer to the - * same object) as the body of Foo's OpDefNode. However, that - * wasn't the case if the instantiated module had parameters, - * because then X!Foo's OpDefNode consists of a sequence of - * nested SubstInNode objects, the last of which points to - * the body of Foo's OpDefNode. So, LL modified the lookup - * methods so they follow the sequence of SubstInNode bodies - * down to the body of Foo's OpDefNode when looking up the result. - * (If a SubstInNode has a non-null TLC tool object for a - * SubstInNode, then it returns that object. I don't think this - * should ever be the case, and if it is, I have no idea what the - * lookup method should do.) - * - */ - public final Object lookup(SymbolNode opNode, Context c, TLCState s, boolean cutoff) - { - boolean isVarDecl = (opNode.getKind() == VariableDeclKind); - Object result = c.lookup(opNode, cutoff && isVarDecl); - if (result != null) - return result; - - result = opNode.getToolObject(TLCGlobals.ToolId); - if (result != null) - return result; - - if (opNode.getKind() == UserDefinedOpKind) - { - // Changed by LL on 10 Apr 2011 from - // - // result = ((OpDefNode) opNode).getBody().getToolObject(TLCGlobals.ToolId); - // - // to the following - ExprNode body = ((OpDefNode) opNode).getBody(); - result = body.getToolObject(TLCGlobals.ToolId); - while ((result == null) && (body.getKind() == SubstInKind)) { - body = ((SubstInNode) body).getBody(); - result = body.getToolObject(TLCGlobals.ToolId); - } - // end change - - if (result != null) - return result; - } - - result = s.lookup(opNode.getName()); - if (result != null) - return result; - return opNode; - } - - public final Object lookup(SymbolNode opNode, Context c, boolean cutoff) - { - boolean isVarDecl = (opNode.getKind() == VariableDeclKind); - Object result = c.lookup(opNode, cutoff && isVarDecl); - if (result != null) - return result; - - result = opNode.getToolObject(TLCGlobals.ToolId); - if (result != null) - return result; - - if (opNode.getKind() == UserDefinedOpKind) - { - // Changed by LL on 10 Apr 2011 from - // - // result = ((OpDefNode) opNode).getBody().getToolObject(TLCGlobals.ToolId); - // - // to the following - ExprNode body = ((OpDefNode) opNode).getBody(); - result = body.getToolObject(TLCGlobals.ToolId); - while ((result == null) && (body.getKind() == SubstInKind)) { - body = ((SubstInNode) body).getBody(); - result = body.getToolObject(TLCGlobals.ToolId); + this.processConstants(imods[i]); } - // end change - if (result != null) - return result; - } - return opNode; - } - - public final Object getVal(ExprOrOpArgNode expr, Context c, final boolean cachable) - { - if (expr instanceof ExprNode) - { - return new LazyValue(expr, c, cachable); - } - SymbolNode opNode = ((OpArgNode) expr).getOp(); - return this.lookup(opNode, c, false); - } - - public final Context getOpContext(OpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable) - { - FormalParamNode[] formals = opDef.getParams(); - int alen = args.length; - Context c1 = c; - for (int i = 0; i < alen; i++) - { - Object aval = this.getVal(args[i], c, cachable); - c1 = c1.cons(formals[i], aval); - } - return c1; - } - - /** - * The following added by LL on 23 October 2012 to fix bug in evaluation of names of theorems and - * assumptions imported by parameterized instantiation. - * - * @param opDef - * @param args - * @param c - * @param cachable - * @return - */ - public final Context getOpContext(ThmOrAssumpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable) - { - FormalParamNode[] formals = opDef.getParams(); - int alen = args.length; - Context c1 = c; - for (int i = 0; i < alen; i++) - { - Object aval = this.getVal(args[i], c, cachable); - c1 = c1.cons(formals[i], aval); - } - return c1; - } - /** - * Return a table containing the locations of subexpression in the - * spec of forms x' = e and x' \in e. Warning: Current implementation - * may not be able to find all such locations. - */ - public final ObjLongTable getPrimedLocs() - { - ObjLongTable tbl = new ObjLongTable(10); - Action act = this.getNextStateSpec(); - this.collectPrimedLocs(act.pred, act.con, tbl); - return tbl; - } - - public final void collectPrimedLocs(SemanticNode pred, Context c, ObjLongTable tbl) - { - switch (pred.getKind()) { - case OpApplKind: { - OpApplNode pred1 = (OpApplNode) pred; - this.collectPrimedLocsAppl(pred1, c, tbl); - return; - } - case LetInKind: { - LetInNode pred1 = (LetInNode) pred; - this.collectPrimedLocs(pred1.getBody(), c, tbl); - return; - } - case SubstInKind: { - SubstInNode pred1 = (SubstInNode) pred; - Subst[] subs = pred1.getSubsts(); - Context c1 = c; - for (int i = 0; i < subs.length; i++) + // Process all the assumptions: + AssumeNode[] assumps = expr1.getAssumptions(); + for (int i = 0; i < assumps.length; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + this.processConstants(assumps[i]); } - this.collectPrimedLocs(pred1.getBody(), c, tbl); - return; - } - - // Added by LL on 13 Nov 2009 to handle theorem and assumption names. - case APSubstInKind: { - APSubstInNode pred1 = (APSubstInNode) pred; - Subst[] subs = pred1.getSubsts(); - Context c1 = c; - for (int i = 0; i < subs.length; i++) - { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + // On 13 Nov 2009, Yuan Yu added the following + // processing of all TheoremNodes, which was needed to + // allow Theorem and Assumption names to be used as expressions. + // + // Process all the theorems: + TheoremNode[] thms = expr1.getTheorems(); + for (int i = 0; i < thms.length; i++) { + this.processConstants(thms[i]); } - this.collectPrimedLocs(pred1.getBody(), c, tbl); - return; - } - - /*********************************************************************** - * LabelKind case added by LL on 13 Jun 2007. * - ***********************************************************************/ - case LabelKind: { - LabelNode pred1 = (LabelNode) pred; - this.collectPrimedLocs(pred1.getBody(), c, tbl); return; } - } - } - - private final void collectPrimedLocsAppl(OpApplNode pred, Context c, ObjLongTable tbl) - { - ExprOrOpArgNode[] args = pred.getArgs(); - SymbolNode opNode = pred.getOperator(); - int opcode = BuiltInOPs.getOpCode(opNode.getName()); - - switch (opcode) { - case OPCODE_fa: // FcnApply - { - this.collectPrimedLocs(args[0], c, tbl); - break; - } - case OPCODE_ite: // IfThenElse - { - this.collectPrimedLocs(args[1], c, tbl); - this.collectPrimedLocs(args[2], c, tbl); - break; - } - case OPCODE_case: // Case - { - for (int i = 0; i < args.length; i++) - { - OpApplNode pair = (OpApplNode) args[i]; - this.collectPrimedLocs(pair.getArgs()[1], c, tbl); - } - break; - } - case OPCODE_eq: - case OPCODE_in: { - SymbolNode var = this.getPrimedVar(args[0], c, false); - if (var != null && var.getName().getVarLoc() != -1) - { - tbl.put(pred.toString(), 0); - } - break; - } - case OPCODE_cl: // ConjList - case OPCODE_dl: // DisjList - case OPCODE_be: // BoundedExists - case OPCODE_bf: // BoundedForall - case OPCODE_land: - case OPCODE_lor: - case OPCODE_implies: - case OPCODE_nop: // This case added 13 Nov 2009 by LL to handle subexpression names. - { - for (int i = 0; i < args.length; i++) - { - this.collectPrimedLocs(args[i], c, tbl); - } - break; - } - case OPCODE_unchanged: { - this.collectUnchangedLocs(args[0], c, tbl); - break; - } - case OPCODE_aa: // AngleAct <A>_e - { - this.collectPrimedLocs(args[0], c, tbl); - break; - } - case OPCODE_sa: // [A]_e - { - this.collectPrimedLocs(args[0], c, tbl); - tbl.put(args[1].toString(), 0); - break; - } - default: { - if (opcode == 0) - { - Object val = this.lookup(opNode, c, false); - - if (val instanceof OpDefNode) - { - OpDefNode opDef = (OpDefNode) val; - // Following added by LL on 10 Apr 2010 to avoid infinite - // recursion for recursive operator definitions - if (opDef.getInRecursive()) { - return ; - } - Context c1 = this.getOpContext(opDef, args, c, true); - this.collectPrimedLocs(opDef.getBody(), c1, tbl); - } else if (val instanceof LazyValue) - { - LazyValue lv = (LazyValue) val; - this.collectPrimedLocs(lv.expr, lv.con, tbl); - } - } - } - } - } - - private final void collectUnchangedLocs(SemanticNode expr, Context c, ObjLongTable tbl) - { - if (expr instanceof OpApplNode) - { + case OpApplKind: { OpApplNode expr1 = (OpApplNode) expr; SymbolNode opNode = expr1.getOperator(); - UniqueString opName = opNode.getName(); - int opcode = BuiltInOPs.getOpCode(opName); - - if (opName.getVarLoc() >= 0) + Object val = this.defns.get(opNode.getName()); + if (val != null) { - // a state variable: - tbl.put(expr.toString(), 0); - return; - } - - ExprOrOpArgNode[] args = expr1.getArgs(); - if (opcode == OPCODE_tup) + opNode.setToolObject(toolId, val); + } else { - // a tuple: + SemanticNode[] args = expr1.getArgs(); for (int i = 0; i < args.length; i++) { - this.collectUnchangedLocs(args[i], c, tbl); + if (args[i] != null) + { + this.processConstants(args[i]); + } } - return; - } - - if (opcode == 0 && args.length == 0) - { - // a 0-arity operator: - Object val = this.lookup(opNode, c, false); - if (val instanceof OpDefNode) + ExprNode[] bnds = expr1.getBdedQuantBounds(); + for (int i = 0; i < bnds.length; i++) { - this.collectUnchangedLocs(((OpDefNode) val).getBody(), c, tbl); - return; + this.processConstants(bnds[i]); } } - } - return; - } - - /** - * This method only returns an approximation of the level of the - * expression. The "real" level is at most the return value. Adding - * <name, ValOne> to the context means that there is no need to - * compute level for name. - * - * Note that this method does not work if called on a part of an - * EXCEPT expression. - */ - public final int getLevelBound(SemanticNode expr, Context c) - { - switch (expr.getKind()) { - case OpApplKind: { - OpApplNode expr1 = (OpApplNode) expr; - return this.getLevelBoundAppl(expr1, c); + return; } case LetInKind: { LetInNode expr1 = (LetInNode) expr; OpDefNode[] letDefs = expr1.getLets(); - int letLen = letDefs.length; - Context c1 = c; - int level = 0; - for (int i = 0; i < letLen; i++) + for (int i = 0; i < letDefs.length; i++) { - OpDefNode opDef = letDefs[i]; - level = Math.max(level, this.getLevelBound(opDef.getBody(), c1)); - c1 = c1.cons(opDef, ValOne); + this.processConstants(letDefs[i].getBody()); } - return Math.max(level, this.getLevelBound(expr1.getBody(), c1)); + this.processConstants(expr1.getBody()); + return; } case SubstInKind: { SubstInNode expr1 = (SubstInNode) expr; Subst[] subs = expr1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) + for (int i = 0; i < subs.length; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + this.processConstants(subs[i].getExpr()); } - return this.getLevelBound(expr1.getBody(), c1); + this.processConstants(expr1.getBody()); + return; } // Added by LL on 13 Nov 2009 to handle theorem and assumption names. case APSubstInKind: { APSubstInNode expr1 = (APSubstInNode) expr; Subst[] subs = expr1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) + for (int i = 0; i < subs.length; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); + this.processConstants(subs[i].getExpr()); } - return this.getLevelBound(expr1.getBody(), c1); + this.processConstants(expr1.getBody()); + return; } - /*********************************************************************** - * LabelKind case added by LL on 13 Jun 2007. * - ***********************************************************************/ - case LabelKind: { - LabelNode expr1 = (LabelNode) expr; - return this.getLevelBound(expr1.getBody(), c); - } - default: { - return 0; - } + case NumeralKind: { + NumeralNode expr1 = (NumeralNode) expr; + IntValue val = IntValue.gen(expr1.val()); + // LL added this test on 20 Jul 2011; otherwise + // TLC treats a number bigger than MAX_VALUE + // (2^31-1 or 2,147,483,647) as if it equals 0. + if (expr1.bigVal() != null) { + Assert.fail(EC.TLC_INTEGER_TOO_BIG, expr1.toString()); + return; + } + expr1.setToolObject(toolId, val); + return; } - } - - private final int getLevelBoundAppl(OpApplNode expr, Context c) - { - SymbolNode opNode = expr.getOperator(); - UniqueString opName = opNode.getName(); - int opcode = BuiltInOPs.getOpCode(opName); - - if (BuiltInOPs.isTemporal(opcode)) - { - return 3; // Conservative estimate + case DecimalKind: { + DecimalNode expr1 = (DecimalNode) expr; // SZ: using typed variable + Assert.fail(EC.TLC_CANT_HANDLE_REAL_NUMBERS, expr1.toString()); + return; } - - if (BuiltInOPs.isAction(opcode)) - { - return 2; // Conservative estimate + case StringKind: { + StringNode expr1 = (StringNode) expr; + StringValue val = new StringValue(expr1.getRep()); + expr1.setToolObject(toolId, val); + return; } - - if (opcode == OPCODE_enabled) - { - return 1; // Conservative estimate + case AssumeKind: { + AssumeNode expr1 = (AssumeNode) expr; + this.processConstants(expr1.getAssume()); + return; } - - int level = 0; - ExprNode[] bnds = expr.getBdedQuantBounds(); - for (int i = 0; i < bnds.length; i++) - { - level = Math.max(level, this.getLevelBound(bnds[i], c)); + // On 13 Nov 2009, Yuan Yu added the following case, which was + // needed to allow Theorem and Assumption names to be used as + // expressions. + // + case TheoremKind: + { + TheoremNode expr1 = (TheoremNode)expr; + this.processConstants(expr1.getTheorem()); + return; + } + case OpArgKind: { + SymbolNode opArgNode = ((OpArgNode) expr).getOp(); + if (opArgNode.getKind() == UserDefinedOpKind) + { OpDefNode opdef = (OpDefNode) opArgNode ; + if (! processedDefs.contains(opdef)) { + processedDefs.add(opdef) ; + this.processConstants(opdef.getBody()); + } + } + return; } - - if (opcode == OPCODE_rfs) - { - // For recursive function, don't compute level of the function body - // again in the recursive call. - SymbolNode fname = expr.getUnbdedQuantSymbols()[0]; - c = c.cons(fname, ValOne); + /*********************************************************************** + * LabelKind case added by LL on 13 Jun 2007. * + ***********************************************************************/ + case LabelKind: { + LabelNode expr1 = (LabelNode) expr; + this.processConstants(expr1.getBody()); } - - ExprOrOpArgNode[] args = expr.getArgs(); - int alen = args.length; - for (int i = 0; i < alen; i++) - { - if (args[i] != null) - { - level = Math.max(level, this.getLevelBound(args[i], c)); - } } + } - if (opcode == 0) + private final Hashtable<String, Serializable> makeConstantTable(Vect<Vect<String>> consts) + { + Hashtable<String, Serializable> constTbl = new Hashtable<>(); + for (int i = 0; i < consts.size(); i++) { - // This operator is a user-defined operator. - if (opName.getVarLoc() >= 0) - return 1; - - Object val = this.lookup(opNode, c, false); - if (val instanceof OpDefNode) + Vect<String> line = (Vect<String>) consts.elementAt(i); + int len = line.size(); + String name = (String) line.elementAt(0); + if (len <= 2) { - OpDefNode opDef = (OpDefNode) val; - c = c.cons(opNode, ValOne); - level = Math.max(level, this.getLevelBound(opDef.getBody(), c)); - } else if (val instanceof LazyValue) + constTbl.put(name, line.elementAt(1)); + } else { - LazyValue lv = (LazyValue) val; - level = Math.max(level, this.getLevelBound(lv.expr, lv.con)); + Object val = constTbl.get(name); + if (val == null) + { + OpRcdValue opVal = new OpRcdValue(); + opVal.addLine(line); + constTbl.put(name, opVal); + } else + { + OpRcdValue opVal = (OpRcdValue) val; + int arity = ((IValue[]) opVal.domain.elementAt(0)).length; + if (len != arity + 2) + { + Assert.fail(EC.TLC_CONFIG_OP_ARITY_INCONSISTENT, name); + } + opVal.addLine(line); + } } } - return level; - } - - public FilenameToStream getResolver() - { - return resolver; + return constTbl; } /** - * The level of the expression according to level checking. - * static method, does not change instance state + * Initialize the spec constants using the config file. */ - public static int getLevel(LevelNode expr, Context c) + private final Hashtable initializeConstants() { - HashSet lpSet = expr.getLevelParams(); - if (lpSet.isEmpty()) - return expr.getLevel(); - - int level = expr.getLevel(); - Iterator iter = lpSet.iterator(); - while (iter.hasNext()) + Vect<Vect<String>> consts = this.config.getConstants(); + if (consts == null) { - SymbolNode param = (SymbolNode) iter.next(); - Object res = c.lookup(param, true); - if (res != null) - { - if (res instanceof LazyValue) - { - LazyValue lv = (LazyValue) res; - int plevel = getLevel((LevelNode) lv.expr, lv.con); - level = (plevel > level) ? plevel : level; - } else if (res instanceof OpDefNode) - { - int plevel = getLevel((LevelNode) res, c); - level = (plevel > level) ? plevel : level; - } - } + return new Hashtable<>(); } - return level; + return this.makeConstantTable(consts); } - /** - * Static method, does not change instance state - * @param expr - * @param subs - * @return - */ - private static final ExprNode addSubsts(ExprNode expr, List subs) + private final Hashtable<String, Hashtable> initializeModConstants() { - ExprNode res = expr; - - while (!subs.isEmpty()) + Hashtable<String, ?> modConstants = this.config.getModConstants(); + Hashtable<String, Hashtable> constants = new Hashtable<>(); + Enumeration<String> mods = modConstants.keys(); + while (mods.hasMoreElements()) { - SubstInNode sn = (SubstInNode) subs.car(); - res = new SubstInNode(sn.stn, sn.getSubsts(), res, sn.getInstantiatingModule(), sn.getInstantiatedModule()); - subs = subs.cdr(); + String modName = mods.nextElement(); + constants.put(modName, this.makeConstantTable((Vect<Vect<String>>) modConstants.get(modName))); } - return res; + return constants; } + + public ModuleNode getRootModule() { + return rootModule; + } + + public ExternalModuleTable getModuleTbl() { + return moduleTbl; + } + + public OpDeclNode[] getVariablesNodes() { + return variablesNodes; + } + + public Vect<Action> getInitPred() { + return initPredVec; + } + + public Action getNextPred() { + return nextPred; + } + + public Action[] getTemporal() { + return temporals; + } + + public String[] getTemporalNames() { + return temporalNames; + } + + public Action[] getImpliedTemporals() { + return impliedTemporals; + } + + public String[] getImpliedTemporalNames() { + return impliedTemporalNames; + } + + public Action[] getInvariants() { + return invariants; + } + + public String[] getInvariantsNames() { + return invNames; + } + + public Action[] getImpliedInits() { + return impliedInits; + } + + public String[] getImpliedInitNames() { + return impliedInitNames; + } + + public Action[] getImpliedActions() { + return impliedActions; + } + + public String[] getImpliedActionNames() { + return impliedActNames; + } + + public ExprNode[] getModelConstraints() { + return modelConstraints; + } + + public ExprNode[] getActionConstraints() { + return actionConstraints; + } + + public ExprNode[] getAssumptions() { + return assumptions; + } + + public boolean[] getAssumptionIsAxiom() { + return assumptionIsAxiom; + } + + public SpecObj getSpecObj() { + return specObj; + } + + public Defns getUnprocessedDefns() { + return snapshot; + } } diff --git a/tlatools/src/tlc2/tool/TLAClass.java b/tlatools/src/tlc2/tool/impl/TLAClass.java similarity index 88% rename from tlatools/src/tlc2/tool/TLAClass.java rename to tlatools/src/tlc2/tool/impl/TLAClass.java index a5b2403d0654ec8ac3690126223dc7517c3b29c7..e6a0de3ab32d948284306792ab5613539afe2c39 100644 --- a/tlatools/src/tlc2/tool/TLAClass.java +++ b/tlatools/src/tlc2/tool/impl/TLAClass.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:18:28 PST by lamport // modified on Mon Jan 29 16:21:11 PST 2001 by yuanyu -package tlc2.tool; +package tlc2.tool.impl; import java.io.File; import java.net.URL; @@ -60,11 +60,13 @@ public class TLAClass try { try { - final File module = resolver.resolve(name + ".class", false); - if (module != null && module.getAbsoluteFile() != null) { - final URL url = module.getAbsoluteFile().getParentFile().toURI().toURL(); - cl = new URLClassLoader(new URL[] {url}).loadClass(name); - } + if (resolver != null) { + final File module = resolver.resolve(name + ".class", false); + if (module != null && module.getAbsoluteFile() != null) { + final URL url = module.getAbsoluteFile().getParentFile().toURI().toURL(); + cl = new URLClassLoader(new URL[] {url}).loadClass(name); + } + } } catch (Exception ignored1) { /*SKIP*/ } finally { diff --git a/tlatools/src/tlc2/tool/TLARegistry.java b/tlatools/src/tlc2/tool/impl/TLARegistry.java similarity index 98% rename from tlatools/src/tlc2/tool/TLARegistry.java rename to tlatools/src/tlc2/tool/impl/TLARegistry.java index 286752857afbbcf768b3c2cffe1a907bc806eccf..30b9c1d3ed2e0adc649f9469a77ccefa16320ad9 100644 --- a/tlatools/src/tlc2/tool/TLARegistry.java +++ b/tlatools/src/tlc2/tool/impl/TLARegistry.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:18:28 PST by lamport // modified on Fri Sep 15 11:06:03 PDT 2000 by yuanyu -package tlc2.tool; +package tlc2.tool.impl; import java.util.Enumeration; import java.util.Hashtable; diff --git a/tlatools/src/tlc2/tool/Tool.java b/tlatools/src/tlc2/tool/impl/Tool.java similarity index 70% rename from tlatools/src/tlc2/tool/Tool.java rename to tlatools/src/tlc2/tool/impl/Tool.java index b88cd660c99a1506187105d252d84f929e7866e2..bb0f30e7af9f073520c5d46b072a3eaff4274acf 100644 --- a/tlatools/src/tlc2/tool/Tool.java +++ b/tlatools/src/tlc2/tool/impl/Tool.java @@ -4,9 +4,10 @@ // modified on Thu 2 Aug 2007 at 10:25:48 PST by lamport // modified on Fri Jan 4 22:46:57 PST 2002 by yuanyu -package tlc2.tool; +package tlc2.tool.impl; + +import java.io.File; -import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.APSubstInNode; import tla2sany.semantic.ExprNode; import tla2sany.semantic.ExprOrOpArgNode; @@ -15,52 +16,69 @@ import tla2sany.semantic.LabelNode; import tla2sany.semantic.LetInNode; import tla2sany.semantic.LevelConstants; import tla2sany.semantic.LevelNode; -import tla2sany.semantic.ModuleNode; import tla2sany.semantic.OpApplNode; import tla2sany.semantic.OpArgNode; -import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.OpDefNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.Subst; import tla2sany.semantic.SubstInNode; import tla2sany.semantic.SymbolNode; import tla2sany.semantic.ThmOrAssumpDefNode; -import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.Action; +import tlc2.tool.BuiltInOPs; +import tlc2.tool.CallStack; +import tlc2.tool.EvalControl; +import tlc2.tool.EvalException; +import tlc2.tool.IActionItemList; +import tlc2.tool.IContextEnumerator; +import tlc2.tool.IStateFunctor; +import tlc2.tool.ITool; +import tlc2.tool.StateVec; +import tlc2.tool.TLCState; +import tlc2.tool.TLCStateFun; +import tlc2.tool.TLCStateInfo; +import tlc2.tool.TLCStateMut; +import tlc2.tool.ToolGlobals; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; import tlc2.util.IdThread; import tlc2.util.Vect; -import tlc2.value.Applicable; -import tlc2.value.BoolValue; -import tlc2.value.Enumerable; -import tlc2.value.FcnLambdaValue; -import tlc2.value.FcnParams; -import tlc2.value.FcnRcdValue; -import tlc2.value.LazyValue; -import tlc2.value.MVPerm; -import tlc2.value.MethodValue; -import tlc2.value.OpLambdaValue; -import tlc2.value.OpValue; -import tlc2.value.RecordValue; -import tlc2.value.Reducible; -import tlc2.value.SetCapValue; -import tlc2.value.SetCupValue; -import tlc2.value.SetDiffValue; -import tlc2.value.SetEnumValue; -import tlc2.value.SetOfFcnsValue; -import tlc2.value.SetOfRcdsValue; -import tlc2.value.SetOfTuplesValue; -import tlc2.value.SetPredValue; -import tlc2.value.StringValue; -import tlc2.value.SubsetValue; -import tlc2.value.TupleValue; -import tlc2.value.UnionValue; -import tlc2.value.Value; +import tlc2.value.IFcnLambdaValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; import tlc2.value.ValueConstants; -import tlc2.value.ValueEnumeration; -import tlc2.value.ValueExcept; -import tlc2.value.ValueVec; +import tlc2.value.Values; +import tlc2.value.impl.Applicable; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.FcnLambdaValue; +import tlc2.value.impl.FcnParams; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.LazyValue; +import tlc2.value.impl.MVPerms; +import tlc2.value.impl.MethodValue; +import tlc2.value.impl.OpLambdaValue; +import tlc2.value.impl.OpValue; +import tlc2.value.impl.RecordValue; +import tlc2.value.impl.Reducible; +import tlc2.value.impl.SetCapValue; +import tlc2.value.impl.SetCupValue; +import tlc2.value.impl.SetDiffValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.SetOfFcnsValue; +import tlc2.value.impl.SetOfRcdsValue; +import tlc2.value.impl.SetOfTuplesValue; +import tlc2.value.impl.SetPredValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.SubsetValue; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.UnionValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueEnumeration; +import tlc2.value.impl.ValueExcept; +import tlc2.value.impl.ValueVec; import util.Assert; import util.Assert.TLCRuntimeException; import util.FilenameToStream; @@ -76,63 +94,68 @@ import util.UniqueString; */ public class Tool extends Spec - implements ValueConstants, ToolGlobals, TraceApp + implements ValueConstants, ToolGlobals, ITool { - protected Action[] actions; // the list of TLA actions. + + public static final Value[] EmptyArgs = new Value[0]; + + + protected final Action[] actions; // the list of TLA actions. private CallStack callStack; // the call stack. - private Vect actionVec = new Vect(10); + private Vect<Action> actionVec = new Vect<>(10); /** * Creates a new tool handle - * @param specDir - * @param specFile - * @param configFile */ + public Tool(String specFile, String configFile) { + this(new File(specFile), specFile, configFile, null); + } + + public Tool(String specFile, String configFile, FilenameToStream resolver) { + this(new File(specFile), specFile, configFile, resolver); + } + + private Tool(File specDir, String specFile, String configFile, FilenameToStream resolver) + { + this(specDir.isAbsolute() ? specDir.getParent() : "", specFile, configFile, resolver); + } + public Tool(String specDir, String specFile, String configFile, FilenameToStream resolver) { super(specDir, specFile, configFile, resolver); - this.actions = null; this.callStack = null; - } - - /** - * Initialization. Any Tool object must call it before doing anything. - * @param spec - <code>null</code> or a filled spec object from previous SANY run - */ - public final SpecObj init(boolean preprocess, SpecObj spec) - { - - // Parse and process this spec. - // It takes care of all overrides. - // SZ Feb 20, 2009: added spec reference, - // if not null it is just used instead of re-parsing - SpecObj processSpec = super.processSpec(spec); // Initialize state. - if (TLCGlobals.coverageInterval >= 0) { - TLCStateMutSource.init(this); - } - else { - TLCStateMut.init(this); - } - - // Pre-evaluate all the definitions in the spec that are constants. - if (preprocess) { - this.processConstantDefns(); - } - - // Finally, process the config file. - super.processConfig(); + TLCStateMut.setTool(this); + + Action next = this.getNextStateSpec(); + if (next == null) { + this.actions = new Action[0]; + } else { + this.getActions(next); + int sz = this.actionVec.size(); + this.actions = new Action[sz]; + for (int i = 0; i < sz; i++) { + this.actions[i] = (Action) this.actionVec.elementAt(i); + } + } + } - return processSpec; + Tool(Tool other) { + super(other); + this.actions = other.actions; + this.callStack = other.callStack; + this.actionVec = other.actionVec; } + @Override public final void setCallStack() { this.callStack = new CallStack(); } + @Override public final CallStack getCallStack() { return this.callStack; @@ -146,40 +169,27 @@ public class Tool * splitting it into a set of actions for the maximum prefix * of disjunction and existential quantification. */ + @Override public final Action[] getActions() { - if (this.actions == null) { - Action next = this.getNextStateSpec(); - if (next == null) { - this.actions = new Action[0]; - } - else { - this.getActions(next.pred, next.con); - int sz = this.actionVec.size(); - this.actions = new Action[sz]; - for (int i = 0; i < sz; i++) { - this.actions[i] = (Action)this.actionVec.elementAt(i); - } - } - } return this.actions; } - private final void getActions(SemanticNode next, Context con) { - this.getActions(next, con, Action.UNNAMED_ACTION); - } + private final void getActions(final Action next) { + this.getActions(next.pred, next.con, next.getOpDef(), next.cm); + } - private final void getActions(SemanticNode next, Context con, final UniqueString actionName) { + private final void getActions(SemanticNode next, Context con, final OpDefNode opDefNode, CostModel cm) { switch (next.getKind()) { case OpApplKind: { OpApplNode next1 = (OpApplNode)next; - this.getActionsAppl(next1, con, actionName); + this.getActionsAppl(next1, con, opDefNode, cm); return; } case LetInKind: { LetInNode next1 = (LetInNode)next; - this.getActions(next1.getBody(), con, actionName); + this.getActions(next1.getBody(), con, opDefNode, cm); return; } case SubstInKind: @@ -187,10 +197,10 @@ public class Tool SubstInNode next1 = (SubstInNode)next; Subst[] substs = next1.getSubsts(); if (substs.length == 0) { - this.getActions(next1.getBody(), con, actionName); + this.getActions(next1.getBody(), con, opDefNode, cm); } else { - Action action = new Action(next1, con, actionName); + Action action = new Action(next1, con, opDefNode); this.actionVec.addElement(action); } return; @@ -202,10 +212,10 @@ public class Tool APSubstInNode next1 = (APSubstInNode)next; Subst[] substs = next1.getSubsts(); if (substs.length == 0) { - this.getActions(next1.getBody(), con, actionName); + this.getActions(next1.getBody(), con, opDefNode, cm); } else { - Action action = new Action(next1, con, actionName); + Action action = new Action(next1, con, opDefNode); this.actionVec.addElement(action); } return; @@ -217,7 +227,7 @@ public class Tool case LabelKind: { LabelNode next1 = (LabelNode)next; - this.getActions(next1.getBody(), con, actionName); + this.getActions(next1.getBody(), con, opDefNode, cm); return; } default: @@ -227,7 +237,7 @@ public class Tool } } - private final void getActionsAppl(OpApplNode next, Context con, final UniqueString actionName) { + private final void getActionsAppl(OpApplNode next, Context con, final OpDefNode actionName, CostModel cm) { ExprOrOpArgNode[] args = next.getArgs(); SymbolNode opNode = next.getOperator(); int opcode = BuiltInOPs.getOpCode(opNode.getName()); @@ -250,10 +260,10 @@ public class Tool if (argLevel == 0) { Context con1 = con; for (int i = 0; i < alen; i++) { - Value aval = this.eval(args[i], con, TLCState.Empty); + IValue aval = this.eval(args[i], con, TLCState.Empty, cm); con1 = con1.cons(formals[i], aval); } - this.getActions(opDef.getBody(), con1, opDef.getName()); + this.getActions(opDef.getBody(), con1, opDef, cm); return; } } @@ -261,7 +271,7 @@ public class Tool } } if (opcode == 0) { - Action action = new Action(next, con, opNode.getName()); + Action action = new Action(next, con, (OpDefNode) opNode); this.actionVec.addElement(action); return; } @@ -273,10 +283,10 @@ public class Tool int cnt = this.actionVec.size(); try { ContextEnumerator Enum = - this.contexts(next, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); + this.contexts(next, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear, cm); Context econ; while ((econ = Enum.nextElement()) != null) { - this.getActions(args[0], econ, actionName); + this.getActions(args[0], econ, actionName, cm); } } catch (Throwable e) { @@ -290,7 +300,7 @@ public class Tool case OPCODE_lor: { for (int i = 0; i < args.length; i++) { - this.getActions(args[i], con, actionName); + this.getActions(args[i], con, actionName, cm); } return; } @@ -310,32 +320,39 @@ public class Tool * can be under-specified. Too many possible initial states will * probably make tools like TLC useless. */ + @Override public final StateVec getInitStates() { final StateVec initStates = new StateVec(0); getInitStates(initStates); return initStates; } + @Override public final void getInitStates(IStateFunctor functor) { - Vect init = this.getInitStateSpec(); + Vect<Action> init = this.getInitStateSpec(); ActionItemList acts = ActionItemList.Empty; - for (int i = 1; i < init.size(); i++) { + // MAK 09/11/2018: Tail to head iteration order cause the first elem added with + // acts.cons to be acts tail. This fixes the bug/funny behavior that the init + // predicate Init == A /\ B /\ C /\ D was evaluated in the order A, D, C, B (A + // doesn't get added to acts at all). + for (int i = (init.size() - 1); i > 0; i--) { Action elem = (Action)init.elementAt(i); - acts = acts.cons(elem.pred, elem.con, ActionItemList.PRED); + acts = (ActionItemList) acts.cons(elem.pred, elem.con, elem.cm, IActionItemList.PRED); } if (init.size() != 0) { Action elem = (Action)init.elementAt(0); TLCState ps = TLCState.Empty.createEmpty(); - this.getInitStates(elem.pred, acts, elem.con, ps, functor); + this.getInitStates(elem.pred, acts, elem.con, ps, functor, elem.cm); } } /* Create the state specified by pred. */ + @Override public final TLCState makeState(SemanticNode pred) { ActionItemList acts = ActionItemList.Empty; TLCState ps = TLCState.Empty.createEmpty(); StateVec states = new StateVec(0); - this.getInitStates(pred, acts, Context.Empty, ps, states); + this.getInitStates(pred, acts, Context.Empty, ps, states, acts.cm); if (states.size() != 1) { Assert.fail("The predicate does not specify a unique state." + pred); } @@ -347,20 +364,20 @@ public class Tool } private final void getInitStates(SemanticNode init, ActionItemList acts, - Context c, TLCState ps, IStateFunctor states) { + Context c, TLCState ps, IStateFunctor states, CostModel cm) { if (this.callStack != null) this.callStack.push(init); try { switch (init.getKind()) { case OpApplKind: { OpApplNode init1 = (OpApplNode)init; - this.getInitStatesAppl(init1, acts, c, ps, states); + this.getInitStatesAppl(init1, acts, c, ps, states, cm); return; } case LetInKind: { LetInNode init1 = (LetInNode)init; - this.getInitStates(init1.getBody(), acts, c, ps, states); + this.getInitStates(init1.getBody(), acts, c, ps, states, cm); return; } case SubstInKind: @@ -370,9 +387,9 @@ public class Tool Context c1 = c; for (int i = 0; i < subs.length; i++) { Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm)); } - this.getInitStates(init1.getBody(), acts, c1, ps, states); + this.getInitStates(init1.getBody(), acts, c1, ps, states, cm); return; } // Added by LL on 13 Nov 2009 to handle theorem and assumption names. @@ -383,16 +400,16 @@ public class Tool Context c1 = c; for (int i = 0; i < subs.length; i++) { Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm)); } - this.getInitStates(init1.getBody(), acts, c1, ps, states); + this.getInitStates(init1.getBody(), acts, c1, ps, states, cm); return; } // LabelKind class added by LL on 13 Jun 2007 case LabelKind: { LabelNode init1 = (LabelNode)init; - this.getInitStates(init1.getBody(), acts, c, ps, states); + this.getInitStates(init1.getBody(), acts, c, ps, states, cm); return; } default: @@ -413,8 +430,12 @@ public class Tool } } - private final void getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states) { + private final void getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states, CostModel cm) { if (acts.isEmpty()) { + if (coverage) { + cm.incInvocations(); + cm.getRoot().incInvocations(); + } states.addElement(ps.copy()); return; } else if (ps.allAssigned()) { @@ -425,29 +446,38 @@ public class Tool // This optimization is especially useful to check inductive invariants which // require TLC to generate a very large set of initial states. while (!acts.isEmpty()) { - final Value bval = this.eval(acts.carPred(), acts.carContext(), ps, TLCState.Empty, EvalControl.Init); + final Value bval = this.eval(acts.carPred(), acts.carContext(), ps, TLCState.Empty, EvalControl.Init, acts.cm); if (!(bval instanceof BoolValue)) { //TODO Choose more fitting error message. Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "initial states", "boolean", bval.toString(), acts.pred.toString() }); } if (!((BoolValue) bval).val) { + if (coverage) { + // Increase "states found". + cm.getRoot().incSecondary(); + } return; } // Move on to the next action in the ActionItemList. acts = acts.cdr(); } + if (coverage) { + cm.incInvocations(); + cm.getRoot().incInvocations(); + } states.addElement(ps.copy()); return; } // Assert.check(act.kind > 0 || act.kind == -1); ActionItemList acts1 = acts.cdr(); - this.getInitStates(acts.carPred(), acts1, acts.carContext(), ps, states); + this.getInitStates(acts.carPred(), acts1, acts.carContext(), ps, states, acts.cm); } private final void getInitStatesAppl(OpApplNode init, ActionItemList acts, - Context c, TLCState ps, IStateFunctor states) { + Context c, TLCState ps, IStateFunctor states, CostModel cm) { if (this.callStack != null) this.callStack.push(init); + if (coverage) {cm = cm.get(init);} try { ExprOrOpArgNode[] args = init.getArgs(); int alen = args.length; @@ -465,8 +495,8 @@ public class Tool opcode = BuiltInOPs.getOpCode(opDef.getName()); if (opcode == 0) { // Context c1 = this.getOpContext(opDef, args, c, false); - Context c1 = this.getOpContext(opDef, args, c, true); - this.getInitStates(opDef.getBody(), acts, c1, ps, states); + Context c1 = this.getOpContext(opDef, args, c, true, cm); + this.getInitStates(opDef.getBody(), acts, c1, ps, states, cm); return; } } @@ -479,14 +509,14 @@ public class Tool ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode)val; opcode = BuiltInOPs.getOpCode(opDef.getName()); Context c1 = this.getOpContext(opDef, args, c, true); - this.getInitStates(opDef.getBody(), acts, c1, ps, states); + this.getInitStates(opDef.getBody(), acts, c1, ps, states, cm); return; } if (val instanceof LazyValue) { LazyValue lv = (LazyValue)val; if (lv.getValue() == null || lv.isUncachable()) { - this.getInitStates(lv.expr, acts, lv.con, ps, states); + this.getInitStates(lv.expr, acts, lv.con, ps, states, cm); return; } val = lv.getValue(); @@ -500,14 +530,7 @@ public class Tool } else { if (val instanceof OpValue) { - Applicable opVal = (Applicable)val; - Value[] argVals = new Value[alen]; - // evaluate the actuals: - for (int i = 0; i < alen; i++) { - argVals[i] = this.eval(args[i], c, ps, TLCState.Empty, EvalControl.Init); - } - // apply the operator: - bval = opVal.apply(argVals, EvalControl.Init); + bval = ((OpValue) val).eval(this, args, c, ps, TLCState.Empty, EvalControl.Init, cm); } } @@ -520,7 +543,7 @@ public class Tool } if (((BoolValue) bval).val) { - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); } return; } @@ -531,7 +554,7 @@ public class Tool case OPCODE_lor: { for (int i = 0; i < alen; i++) { - this.getInitStates(args[i], acts, c, ps, states); + this.getInitStates(args[i], acts, c, ps, states, cm); } return; } @@ -539,49 +562,49 @@ public class Tool case OPCODE_land: { for (int i = alen-1; i > 0; i--) { - acts = acts.cons(args[i], c, i); + acts = (ActionItemList) acts.cons(args[i], c, cm, i); } - this.getInitStates(args[0], acts, c, ps, states); + this.getInitStates(args[0], acts, c, ps, states, cm); return; } case OPCODE_be: // BoundedExists { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(init, c, ps, TLCState.Empty, EvalControl.Init); + ContextEnumerator Enum = this.contexts(init, c, ps, TLCState.Empty, EvalControl.Init, cm); Context c1; while ((c1 = Enum.nextElement()) != null) { - this.getInitStates(body, acts, c1, ps, states); + this.getInitStates(body, acts, c1, ps, states, cm); } return; } case OPCODE_bf: // BoundedForall { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(init, c, ps, TLCState.Empty, EvalControl.Init); + ContextEnumerator Enum = this.contexts(init, c, ps, TLCState.Empty, EvalControl.Init, cm); Context c1 = Enum.nextElement(); if (c1 == null) { - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); } else { ActionItemList acts1 = acts; Context c2; while ((c2 = Enum.nextElement()) != null) { - acts1 = acts1.cons(body, c2, ActionItemList.PRED); + acts1 = (ActionItemList) acts1.cons(body, c2, cm, IActionItemList.PRED); } - this.getInitStates(body, acts1, c1, ps, states); + this.getInitStates(body, acts1, c1, ps, states, cm); } return; } case OPCODE_ite: // IfThenElse { - Value guard = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init); + Value guard = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init, cm); if (!(guard instanceof BoolValue)) { Assert.fail("In computing initial states, a non-boolean expression (" + guard.getKindString() + ") was used as the condition " + "of an IF.\n" + init); } int idx = (((BoolValue)guard).val) ? 1 : 2; - this.getInitStates(args[idx], acts, c, ps, states); + this.getInitStates(args[idx], acts, c, ps, states, cm); return; } case OPCODE_case: // Case @@ -594,14 +617,14 @@ public class Tool other = pairArgs[1]; } else { - Value bval = this.eval(pairArgs[0], c, ps, TLCState.Empty, EvalControl.Init); + Value bval = this.eval(pairArgs[0], c, ps, TLCState.Empty, EvalControl.Init, cm); if (!(bval instanceof BoolValue)) { Assert.fail("In computing initial states, a non-boolean expression (" + bval.getKindString() + ") was used as a guard condition" + " of a CASE.\n" + pairArgs[1]); } if (((BoolValue)bval).val) { - this.getInitStates(pairArgs[1], acts, c, ps, states); + this.getInitStates(pairArgs[1], acts, c, ps, states, cm); return; } } @@ -610,17 +633,17 @@ public class Tool Assert.fail("In computing initial states, TLC encountered a CASE with no" + " conditions true.\n" + init); } - this.getInitStates(other, acts, c, ps, states); + this.getInitStates(other, acts, c, ps, states, cm); return; } case OPCODE_fa: // FcnApply { - Value fval = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init); + Value fval = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init, cm); if (fval instanceof FcnLambdaValue) { FcnLambdaValue fcn = (FcnLambdaValue)fval; if (fcn.fcnRcd == null) { - Context c1 = this.getFcnContext(fcn, args, c, ps, TLCState.Empty, EvalControl.Init); - this.getInitStates(fcn.body, acts, c1, ps, states); + Context c1 = this.getFcnContext(fcn, args, c, ps, TLCState.Empty, EvalControl.Init, cm); + this.getInitStates(fcn.body, acts, c1, ps, states, cm); return; } fval = fcn.fcnRcd; @@ -630,7 +653,7 @@ public class Tool fval.getKindString() + ") was applied as a function.\n" + init); } Applicable fcn = (Applicable) fval; - Value argVal = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init); + Value argVal = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init, cm); Value bval = fcn.apply(argVal, EvalControl.Init); if (!(bval instanceof BoolValue)) { @@ -638,7 +661,7 @@ public class Tool init.toString() }); } if (((BoolValue)bval).val) { - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); } return; } @@ -646,18 +669,18 @@ public class Tool { SymbolNode var = this.getVar(args[0], c, false); if (var == null || var.getName().getVarLoc() < 0) { - Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init); + Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init, cm); if (!((BoolValue)bval).val) { return; } } else { UniqueString varName = var.getName(); - Value lval = ps.lookup(varName); - Value rval = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init); + IValue lval = ps.lookup(varName); + Value rval = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init, cm); if (lval == null) { - ps = ps.bind(varName, rval, init); - this.getInitStates(acts, ps, states); + ps = ps.bind(varName, rval); + this.getInitStates(acts, ps, states, cm); ps.unbind(varName); return; } @@ -667,22 +690,22 @@ public class Tool } } } - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); return; } case OPCODE_in: { SymbolNode var = this.getVar(args[0], c, false); if (var == null || var.getName().getVarLoc() < 0) { - Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init); + Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init, cm); if (!((BoolValue)bval).val) { return; } } else { UniqueString varName = var.getName(); - Value lval = ps.lookup(varName); - Value rval = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init); + Value lval = (Value) ps.lookup(varName); + Value rval = this.eval(args[1], c, ps, TLCState.Empty, EvalControl.Init, cm); if (lval == null) { if (!(rval instanceof Enumerable)) { Assert.fail("In computing initial states, the right side of \\IN" + @@ -691,8 +714,8 @@ public class Tool ValueEnumeration Enum = ((Enumerable)rval).elements(); Value elem; while ((elem = Enum.nextElement()) != null) { - ps.bind(varName, elem, init); - this.getInitStates(acts, ps, states); + ps.bind(varName, elem); + this.getInitStates(acts, ps, states, cm); ps.unbind(varName); } return; @@ -703,41 +726,41 @@ public class Tool } } } - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); return; } case OPCODE_implies: { - Value lval = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init); + Value lval = this.eval(args[0], c, ps, TLCState.Empty, EvalControl.Init, cm); if (!(lval instanceof BoolValue)) { Assert.fail("In computing initial states of a predicate of form" + " P => Q, P was " + lval.getKindString() + "\n." + init); } if (((BoolValue)lval).val) { - this.getInitStates(args[1], acts, c, ps, states); + this.getInitStates(args[1], acts, c, ps, states, cm); } else { - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); } return; } // The following case added by LL on 13 Nov 2009 to handle subexpression names. case OPCODE_nop: { - this.getInitStates(args[0], acts, c, ps, states); + this.getInitStates(args[0], acts, c, ps, states, cm); return; } default: { // For all the other builtin operators, simply evaluate: - Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init); + Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init, cm); if (!(bval instanceof BoolValue)) { Assert.fail("In computing initial states, TLC expected a boolean expression," + "\nbut instead found " + bval + ".\n" + init); } if (((BoolValue)bval).val) { - this.getInitStates(acts, ps, states); + this.getInitStates(acts, ps, states, cm); } return; } @@ -755,59 +778,67 @@ public class Tool * This method returns the set of next states when taking the action * in the given state. */ - public /*final*/ StateVec getNextStates(Action action, TLCState state) { + @Override +public final StateVec getNextStates(Action action, TLCState state) { ActionItemList acts = ActionItemList.Empty; TLCState s1 = TLCState.Empty.createEmpty(); StateVec nss = new StateVec(0); - this.getNextStates(action.pred, acts, action.con, state, s1, nss); + this.getNextStates(action.pred, acts, action.con, state, s1, nss, action.cm); + if (coverage) { action.cm.incInvocations(nss.size()); } return nss; } private final TLCState getNextStates(SemanticNode pred, ActionItemList acts, Context c, - TLCState s0, TLCState s1, StateVec nss) { - if (this.callStack != null) this.callStack.push(pred); - try { + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { + if (this.callStack != null) { + return getNextStatesWithCallStack(pred, acts, c, s0, s1, nss, cm); + } else { + return getNextStatesImpl(pred, acts, c, s0, s1, nss, cm); + } + } + + private final TLCState getNextStatesWithCallStack(SemanticNode pred, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, final CostModel cm) { + this.callStack.push(pred); + try { + return getNextStatesImpl(pred, acts, c, s0, s1, nss, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final TLCState getNextStatesImpl(SemanticNode pred, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { switch (pred.getKind()) { case OpApplKind: { OpApplNode pred1 = (OpApplNode)pred; - return this.getNextStatesAppl(pred1, acts, c, s0, s1, nss); + if (coverage) {cm = cm.get(pred);} + return this.getNextStatesAppl(pred1, acts, c, s0, s1, nss, cm); } case LetInKind: { LetInNode pred1 = (LetInNode)pred; - return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss); + return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss, cm); } case SubstInKind: { - SubstInNode pred1 = (SubstInNode)pred; - Subst[] subs = pred1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); - } - return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss); + return getNextStatesImplSubstInKind((SubstInNode) pred, acts, c, s0, s1, nss, cm); } // Added by LL on 13 Nov 2009 to handle theorem and assumption names. case APSubstInKind: { - APSubstInNode pred1 = (APSubstInNode)pred; - Subst[] subs = pred1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); - } - return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss); + return getNextStatesImplApSubstInKind((APSubstInNode) pred, acts, c, s0, s1, nss, cm); } // LabelKind class added by LL on 13 Jun 2007 case LabelKind: { LabelNode pred1 = (LabelNode)pred; - return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss); + return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss, cm); } default: { @@ -815,81 +846,141 @@ public class Tool } } return s1; - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } + private final TLCState getNextStatesImplSubstInKind(SubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, final CostModel cm) { + Subst[] subs = pred1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm)); + } + return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss, cm); + } + + private final TLCState getNextStatesImplApSubstInKind(APSubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, final CostModel cm) { + Subst[] subs = pred1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm)); + } + return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss, cm); + } + private final TLCState getNextStates(ActionItemList acts, final TLCState s0, final TLCState s1, - final StateVec nss) { - int kind = acts.carKind(); + final StateVec nss, CostModel cm) { + final TLCState copy = getNextStates0(acts, s0, s1, nss, cm); + if (coverage && copy != s1) { + cm.incInvocations(); + } + return copy; + } + + private final TLCState getNextStates0(ActionItemList acts, final TLCState s0, final TLCState s1, + final StateVec nss, CostModel cm) { if (acts.isEmpty()) { nss.addElement(s1); return s1.copy(); } else if (s1.allAssigned()) { - SemanticNode pred = acts.carPred(); - Context c = acts.carContext(); - while (!acts.isEmpty()) { - if (kind > 0 || kind == -1) { - final Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear); - if (!(bval instanceof BoolValue)) { - // TODO Choose more fitting error message. - Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, - new String[] { "next states", "boolean", bval.toString(), acts.pred.toString() }); - } - if (!((BoolValue) bval).val) { - return s1; - } - } else if (kind == -2) { - // Identical to default handling below (line 876). Ignored during this optimization. - return this.processUnchanged(pred, acts.cdr(), c, s0, s1, nss); - } else { - final Value v1 = this.eval(pred, c, s0); - final Value v2 = this.eval(pred, c, s1); - if (v1.equals(v2)) { - return s1; - } - } - // Move on to the next action in the ActionItemList. - acts = acts.cdr(); - pred = acts.carPred(); - c = acts.carContext(); - kind = acts.carKind(); - } - nss.addElement(s1); - return s1.copy(); + return getNextStatesAllAssigned(acts, s0, s1, nss, cm); } + final int kind = acts.carKind(); SemanticNode pred = acts.carPred(); Context c = acts.carContext(); ActionItemList acts1 = acts.cdr(); + cm = acts.cm; if (kind > 0) { - return this.getNextStates(pred, acts1, c, s0, s1, nss); + return this.getNextStates(pred, acts1, c, s0, s1, nss, cm); } else if (kind == -1) { - return this.getNextStates(pred, acts1, c, s0, s1, nss); + return this.getNextStates(pred, acts1, c, s0, s1, nss, cm); } else if (kind == -2) { - return this.processUnchanged(pred, acts1, c, s0, s1, nss); + return this.processUnchanged(pred, acts1, c, s0, s1, nss, cm); } else { - Value v1 = this.eval(pred, c, s0); - Value v2 = this.eval(pred, c, s1); + IValue v1 = this.eval(pred, c, s0, cm); + IValue v2 = this.eval(pred, c, s1, cm); if (!v1.equals(v2)) { - return this.getNextStates(acts1, s0, s1, nss); + if (coverage) { + return this.getNextStates(acts1, s0, s1, nss, cm); + } else { + return this.getNextStates0(acts1, s0, s1, nss, cm); + } } } return s1; } + + private final TLCState getNextStatesAllAssigned(ActionItemList acts, final TLCState s0, final TLCState s1, + final StateVec nss, final CostModel cm) { + int kind = acts.carKind(); + SemanticNode pred = acts.carPred(); + Context c = acts.carContext(); + CostModel cm2 = acts.cm; + while (!acts.isEmpty()) { + if (kind > 0 || kind == -1) { + final Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm2); + if (!(bval instanceof BoolValue)) { + // TODO Choose more fitting error message. + Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, + new String[] { "next states", "boolean", bval.toString(), acts.pred.toString() }); + } + if (!((BoolValue) bval).val) { + return s1; + } + } else if (kind == -2) { + // Identical to default handling below (line 876). Ignored during this optimization. + return this.processUnchanged(pred, acts.cdr(), c, s0, s1, nss, cm2); + } else { + final IValue v1 = this.eval(pred, c, s0, cm2); + final IValue v2 = this.eval(pred, c, s1, cm2); + if (v1.equals(v2)) { + return s1; + } + } + // Move on to the next action in the ActionItemList. + acts = acts.cdr(); + pred = acts.carPred(); + c = acts.carContext(); + kind = acts.carKind(); + cm2 = acts.cm; + } + nss.addElement(s1); + return s1.copy(); + } + + /* getNextStatesAppl */ private final TLCState getNextStatesAppl(OpApplNode pred, ActionItemList acts, Context c, - TLCState s0, TLCState s1, StateVec nss) { - if (this.callStack != null) this.callStack.push(pred); - try { + TLCState s0, TLCState s1, StateVec nss, final CostModel cm) { + if (this.callStack != null) { + return getNextStatesApplWithCallStack(pred, acts, c, s0, s1, nss, cm); + } else { + return getNextStatesApplImpl(pred, acts, c, s0, s1, nss, cm); + } + } + + private final TLCState getNextStatesApplWithCallStack(OpApplNode pred, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, final CostModel cm) { + this.callStack.push(pred); + try { + return getNextStatesApplImpl(pred, acts, c, s0, s1, nss, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final TLCState getNextStatesApplImpl(OpApplNode pred, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { ExprOrOpArgNode[] args = pred.getArgs(); int alen = args.length; SymbolNode opNode = pred.getOperator(); @@ -906,8 +997,8 @@ public class Tool opcode = BuiltInOPs.getOpCode(opDef.getName()); if (opcode == 0) { // Context c1 = this.getOpContext(opDef, args, c, false); - Context c1 = this.getOpContext(opDef, args, c, true); - return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss); + Context c1 = this.getOpContext(opDef, args, c, true, cm); + return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss, cm); } } @@ -919,13 +1010,13 @@ public class Tool if (val instanceof ThmOrAssumpDefNode) { ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode)val; Context c1 = this.getOpContext(opDef, args, c, true); - return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss); + return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss, cm); } if (val instanceof LazyValue) { LazyValue lv = (LazyValue)val; if (lv.getValue() == null || lv.isUncachable()) { - return this.getNextStates(lv.expr, acts, lv.con, s0, s1, nss); + return this.getNextStates(lv.expr, acts, lv.con, s0, s1, nss, lv.cm); } val = lv.getValue(); } @@ -938,14 +1029,7 @@ public class Tool } else { if (val instanceof OpValue) { - Applicable opVal = (Applicable)val; - Value[] argVals = new Value[alen]; - // evaluate the actuals: - for (int i = 0; i < alen; i++) { - argVals[i] = this.eval(args[i], c, s0, s1, EvalControl.Clear); - } - // apply the operator: - bval = opVal.apply(argVals, EvalControl.Clear); + bval = ((OpValue) val).eval(this, args, c, s0, s1, EvalControl.Clear, cm); } } @@ -958,7 +1042,11 @@ public class Tool } if (((BoolValue) bval).val) { - return this.getNextStates(acts, s0, s1, nss); + if (coverage) { + return this.getNextStates(acts, s0, s1, nss, cm); + } else { + return this.getNextStates0(acts, s0, s1, nss, cm); + } } return s1; } @@ -971,54 +1059,54 @@ public class Tool { ActionItemList acts1 = acts; for (int i = alen - 1; i > 0; i--) { - acts1 = acts1.cons(args[i], c, i); + acts1 = (ActionItemList) acts1.cons(args[i], c, cm, i); } - return this.getNextStates(args[0], acts1, c, s0, s1, nss); + return this.getNextStates(args[0], acts1, c, s0, s1, nss, cm); } case OPCODE_dl: // DisjList case OPCODE_lor: { for (int i = 0; i < alen; i++) { - resState = this.getNextStates(args[i], acts, c, s0, resState, nss); + resState = this.getNextStates(args[i], acts, c, s0, resState, nss, cm); } return resState; } case OPCODE_be: // BoundedExists { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear); + ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm); Context c1; while ((c1 = Enum.nextElement()) != null) { - resState = this.getNextStates(body, acts, c1, s0, resState, nss); + resState = this.getNextStates(body, acts, c1, s0, resState, nss, cm); } return resState; } case OPCODE_bf: // BoundedForall { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear); + ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm); Context c1 = Enum.nextElement(); if (c1 == null) { - resState = this.getNextStates(acts, s0, s1, nss); + resState = this.getNextStates(acts, s0, s1, nss, cm); } else { ActionItemList acts1 = acts; Context c2; while ((c2 = Enum.nextElement()) != null) { - acts1 = acts1.cons(body, c2, ActionItemList.PRED); + acts1 = (ActionItemList) acts1.cons(body, c2, cm, IActionItemList.PRED); } - resState = this.getNextStates(body, acts1, c1, s0, s1, nss); + resState = this.getNextStates(body, acts1, c1, s0, s1, nss, cm); } return resState; } case OPCODE_fa: // FcnApply { - Value fval = this.eval(args[0], c, s0, s1, EvalControl.KeepLazy); + Value fval = this.eval(args[0], c, s0, s1, EvalControl.KeepLazy, cm); if (fval instanceof FcnLambdaValue) { FcnLambdaValue fcn = (FcnLambdaValue)fval; if (fcn.fcnRcd == null) { - Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Clear); - return this.getNextStates(fcn.body, acts, c1, s0, s1, nss); + Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Clear, cm); + return this.getNextStates(fcn.body, acts, c1, s0, s1, nss, cm); } fval = fcn.fcnRcd; } @@ -1027,21 +1115,21 @@ public class Tool fval.getKindString() + ") was applied as a function.\n" + pred); } Applicable fcn = (Applicable)fval; - Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Clear); + Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm); Value bval = fcn.apply(argVal, EvalControl.Clear); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING2, new String[] { "next states", "boolean", pred.toString() }); } if (((BoolValue)bval).val) { - return this.getNextStates(acts, s0, s1, nss); + return this.getNextStates(acts, s0, s1, nss, cm); } return resState; } case OPCODE_aa: // AngleAct <A>_e { - ActionItemList acts1 = acts.cons(args[1], c, ActionItemList.CHANGED); - return this.getNextStates(args[0], acts1, c, s0, s1, nss); + ActionItemList acts1 = (ActionItemList) acts.cons(args[1], c, cm, IActionItemList.CHANGED); + return this.getNextStates(args[0], acts1, c, s0, s1, nss, cm); } case OPCODE_sa: // [A]_e { @@ -1051,22 +1139,22 @@ public class Tool */ // this.getNextStates(args[0], acts, c, s0, s1, nss); // return this.processUnchanged(args[1], acts, c, s0, s1, nss); - resState = this.getNextStates(args[0], acts, c, s0, resState, nss); - return this.processUnchanged(args[1], acts, c, s0, resState, nss); + resState = this.getNextStates(args[0], acts, c, s0, resState, nss, cm); + return this.processUnchanged(args[1], acts, c, s0, resState, nss, cm); } case OPCODE_ite: // IfThenElse { - Value guard = this.eval(args[0], c, s0, s1, EvalControl.Clear); + Value guard = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm); if (!(guard instanceof BoolValue)) { Assert.fail("In computing next states, a non-boolean expression (" + guard.getKindString() + ") was used as the condition of" + " an IF." + pred); } if (((BoolValue)guard).val) { - return this.getNextStates(args[1], acts, c, s0, s1, nss); + return this.getNextStates(args[1], acts, c, s0, s1, nss, cm); } else { - return this.getNextStates(args[2], acts, c, s0, s1, nss); + return this.getNextStates(args[2], acts, c, s0, s1, nss, cm); } } case OPCODE_case: // Case @@ -1079,14 +1167,14 @@ public class Tool other = pairArgs[1]; } else { - Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Clear); + Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Clear, coverage ? cm.get(args[i]) : cm); if (!(bval instanceof BoolValue)) { Assert.fail("In computing next states, a non-boolean expression (" + bval.getKindString() + ") was used as a guard condition" + " of a CASE.\n" + pairArgs[1]); } if (((BoolValue)bval).val) { - return this.getNextStates(pairArgs[1], acts, c, s0, s1, nss); + return this.getNextStates(pairArgs[1], acts, c, s0, s1, nss, coverage ? cm.get(args[i]) : cm); } } } @@ -1094,25 +1182,25 @@ public class Tool Assert.fail("In computing next states, TLC encountered a CASE with no" + " conditions true.\n" + pred); } - return this.getNextStates(other, acts, c, s0, s1, nss); + return this.getNextStates(other, acts, c, s0, s1, nss, coverage ? cm.get(args[alen - 1]) : cm); } case OPCODE_eq: { SymbolNode var = this.getPrimedVar(args[0], c, false); // Assert.check(var.getName().getVarLoc() >= 0); if (var == null) { - Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm); if (!((BoolValue)bval).val) { return resState; } } else { UniqueString varName = var.getName(); - Value lval = s1.lookup(varName); - Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear); + IValue lval = s1.lookup(varName); + Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm); if (lval == null) { - resState.bind(varName, rval, pred); - resState = this.getNextStates(acts, s0, resState, nss); + resState.bind(varName, rval); + resState = this.getNextStates(acts, s0, resState, nss, cm); resState.unbind(varName); return resState; } @@ -1120,22 +1208,22 @@ public class Tool return resState; } } - return this.getNextStates(acts, s0, s1, nss); + return this.getNextStates(acts, s0, s1, nss, cm); } case OPCODE_in: { SymbolNode var = this.getPrimedVar(args[0], c, false); // Assert.check(var.getName().getVarLoc() >= 0); if (var == null) { - Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm); if (!((BoolValue)bval).val) { return resState; } } else { UniqueString varName = var.getName(); - Value lval = s1.lookup(varName); - Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear); + Value lval = (Value) s1.lookup(varName); + Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm); if (lval == null) { if (!(rval instanceof Enumerable)) { Assert.fail("In computing next states, the right side of \\IN" + @@ -1144,8 +1232,8 @@ public class Tool ValueEnumeration Enum = ((Enumerable)rval).elements(); Value elem; while ((elem = Enum.nextElement()) != null) { - resState.bind(varName, elem, pred); - resState = this.getNextStates(acts, s0, resState, nss); + resState.bind(varName, elem); + resState = this.getNextStates(acts, s0, resState, nss, cm); resState.unbind(varName); } return resState; @@ -1154,25 +1242,25 @@ public class Tool return resState; } } - return this.getNextStates(acts, s0, s1, nss); + return this.getNextStates(acts, s0, s1, nss, cm); } case OPCODE_implies: { - Value bval = this.eval(args[0], c, s0, s1, EvalControl.Clear); + Value bval = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm); if (!(bval instanceof BoolValue)) { Assert.fail("In computing next states of a predicate of the form" + " P => Q, P was\n" + bval.getKindString() + ".\n" + pred); } if (((BoolValue)bval).val) { - return this.getNextStates(args[1], acts, c, s0, s1, nss); + return this.getNextStates(args[1], acts, c, s0, s1, nss, cm); } else { - return this.getNextStates(acts, s0, s1, nss); + return this.getNextStates(acts, s0, s1, nss, cm); } } case OPCODE_unchanged: { - return this.processUnchanged(args[0], acts, c, s0, s1, nss); + return this.processUnchanged(args[0], acts, c, s0, s1, nss, cm); } case OPCODE_cdot: { @@ -1192,54 +1280,54 @@ public class Tool // The following case added by LL on 13 Nov 2009 to handle subexpression names. case OPCODE_nop: { - return this.getNextStates(args[0], acts, c, s0, s1, nss); + return this.getNextStates(args[0], acts, c, s0, s1, nss, cm); } default: { // We handle all the other builtin operators here. - Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "next states", "boolean", bval.toString(), pred.toString() }); } if (((BoolValue)bval).val) { - resState = this.getNextStates(acts, s0, s1, nss); + resState = this.getNextStates(acts, s0, s1, nss, cm); } return resState; } } - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } + + /* processUnchanged */ private final TLCState processUnchanged(SemanticNode expr, ActionItemList acts, Context c, - TLCState s0, TLCState s1, StateVec nss) { - if (this.callStack != null) this.callStack.push(expr); - try { + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { + if (this.callStack != null) { + return processUnchangedWithCallStack(expr, acts, c, s0, s1, nss, cm); + } else { + return processUnchangedImpl(expr, acts, c, s0, s1, nss, cm); + } + } + private final TLCState processUnchangedWithCallStack(SemanticNode expr, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { + this.callStack.push(expr); + try { + return processUnchangedImpl(expr, acts, c, s0, s1, nss, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + private final TLCState processUnchangedImpl(SemanticNode expr, ActionItemList acts, Context c, + TLCState s0, TLCState s1, StateVec nss, CostModel cm) { + if (coverage){cm = cm.get(expr);} SymbolNode var = this.getVar(expr, c, false); TLCState resState = s1; if (var != null) { - // expr is a state variable: - UniqueString varName = var.getName(); - Value val0 = s0.lookup(varName); - Value val1 = s1.lookup(varName); - if (val1 == null) { - resState.bind(varName, val0, expr); - resState = this.getNextStates(acts, s0, resState, nss); - resState.unbind(varName); - } - else if (val0.equals(val1)) { - resState = this.getNextStates(acts, s0, s1, nss); - } - else { - MP.printWarning(EC.TLC_UNCHANGED_VARIABLE_CHANGED, new String[]{varName.toString(), expr.toString()}); - } - return resState; + return processUnchangedImplVar(expr, acts, s0, s1, nss, var, cm); } if (expr instanceof OpApplNode) { @@ -1251,64 +1339,130 @@ public class Tool int opcode = BuiltInOPs.getOpCode(opName); if (opcode == OPCODE_tup) { - // a tuple: - if (alen != 0) { - ActionItemList acts1 = acts; - for (int i = alen-1; i > 0; i--) { - acts1 = acts1.cons(args[i], c, ActionItemList.UNCHANGED); - } - return this.processUnchanged(args[0], acts1, c, s0, s1, nss); - } - return this.getNextStates(acts, s0, s1, nss); + return processUnchangedImplTuple(acts, c, s0, s1, nss, args, alen, cm, coverage ? cm.get(expr1) : cm); } if (opcode == 0 && alen == 0) { // a 0-arity operator: - Object val = this.lookup(opNode, c, false); - - if (val instanceof OpDefNode) { - return this.processUnchanged(((OpDefNode)val).getBody(), acts, c, s0, s1, nss); - } - else if (val instanceof LazyValue) { - LazyValue lv = (LazyValue)val; - return this.processUnchanged(lv.expr, acts, lv.con, s0, s1, nss); - } - else { - Assert.fail("In computing next states, TLC found the identifier\n" + - opName + " undefined in an UNCHANGED expression at\n" + expr); - } - return this.getNextStates(acts, s0, s1, nss); + return processUnchangedImpl0Arity(expr, acts, c, s0, s1, nss, cm, opNode, opName); } } - Value v0 = this.eval(expr, c, s0); - Value v1 = this.eval(expr, c, s1, null, EvalControl.Clear); + IValue v0 = this.eval(expr, c, s0, cm); + Value v1 = this.eval(expr, c, s1, null, EvalControl.Clear, cm); if (v0.equals(v1)) { - resState = this.getNextStates(acts, s0, s1, nss); + resState = this.getNextStates(acts, s0, s1, nss, cm); } return resState; - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } - /* Special version of eval for state expressions. */ - public final Value eval(SemanticNode expr, Context c, TLCState s0) { - return this.eval(expr, c, s0, TLCState.Empty, EvalControl.Clear); + private final TLCState processUnchangedImpl0Arity(final SemanticNode expr, final ActionItemList acts, + final Context c, final TLCState s0, final TLCState s1, final StateVec nss, final CostModel cm, + final SymbolNode opNode, final UniqueString opName) { + final Object val = this.lookup(opNode, c, false); + + if (val instanceof OpDefNode) { + return this.processUnchanged(((OpDefNode)val).getBody(), acts, c, s0, s1, nss, cm); + } + else if (val instanceof LazyValue) { + final LazyValue lv = (LazyValue)val; + return this.processUnchanged(lv.expr, acts, lv.con, s0, s1, nss, cm); + } + else { + Assert.fail("In computing next states, TLC found the identifier\n" + + opName + " undefined in an UNCHANGED expression at\n" + expr); + } + return this.getNextStates(acts, s0, s1, nss, cm); + } + + @Override + public final IValue eval(SemanticNode expr, Context c, TLCState s0) { + return this.eval(expr, c, s0, TLCState.Empty, EvalControl.Clear, CostModel.DO_NOT_RECORD); + } + + private final TLCState processUnchangedImplTuple(ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, + ExprOrOpArgNode[] args, int alen, CostModel cm, CostModel cmNested) { + // a tuple: + if (alen != 0) { + ActionItemList acts1 = acts; + for (int i = alen-1; i > 0; i--) { + acts1 = (ActionItemList) acts1.cons(args[i], c, cmNested, IActionItemList.UNCHANGED); + } + return this.processUnchanged(args[0], acts1, c, s0, s1, nss, cmNested); + } + return this.getNextStates(acts, s0, s1, nss, cm); } + + private final TLCState processUnchangedImplVar(SemanticNode expr, ActionItemList acts, TLCState s0, TLCState s1, StateVec nss, + SymbolNode var, final CostModel cm) { + TLCState resState = s1; + // expr is a state variable: + final UniqueString varName = var.getName(); + final IValue val0 = s0.lookup(varName); + final IValue val1 = s1.lookup(varName); + if (val1 == null) { + resState.bind(varName, val0); + if (coverage) { + resState = this.getNextStates(acts, s0, resState, nss, cm); + } else { + resState = this.getNextStates0(acts, s0, resState, nss, cm); + } + resState.unbind(varName); + } + else if (val0.equals(val1)) { + if (coverage) { + resState = this.getNextStates(acts, s0, s1, nss, cm); + } else { + resState = this.getNextStates0(acts, s0, s1, nss, cm); + } + } + else { + MP.printWarning(EC.TLC_UNCHANGED_VARIABLE_CHANGED, new String[]{varName.toString(), expr.toString()}); + } + return resState; + } + + /* eval */ + /* Special version of eval for state expressions. */ + @Override + public final IValue eval(SemanticNode expr, Context c, TLCState s0, CostModel cm) { + return this.eval(expr, c, s0, TLCState.Empty, EvalControl.Clear, cm); + } + + @Override + public final IValue eval(SemanticNode expr, Context c, TLCState s0, + TLCState s1, final int control) { + return eval(expr, c, s0, s1, control, CostModel.DO_NOT_RECORD); + } /* * This method evaluates the expression expr in the given context, * current state, and partial next state. */ public final Value eval(SemanticNode expr, Context c, TLCState s0, - TLCState s1, final int control) { - if (this.callStack != null) this.callStack.push(expr); - try { + TLCState s1, final int control, final CostModel cm) { + if (this.callStack != null) { + return evalWithCallStack(expr, c, s0, s1, control, cm); + } else { + return evalImpl(expr, c, s0, s1, control, cm); + } + } + private final Value evalWithCallStack(SemanticNode expr, Context c, TLCState s0, + TLCState s1, final int control, final CostModel cm) { + this.callStack.push(expr); + try { + return evalImpl(expr, c, s0, s1, control, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final Value evalImpl(final SemanticNode expr, final Context c, final TLCState s0, + final TLCState s1, final int control, CostModel cm) { switch (expr.getKind()) { /*********************************************************************** * LabelKind class added by LL on 13 Jun 2007. * @@ -1316,58 +1470,32 @@ public class Tool case LabelKind: { LabelNode expr1 = (LabelNode) expr; - return this.eval(expr1.getBody(), c, s0, s1, control); + return this.eval(expr1.getBody(), c, s0, s1, control, cm); } case OpApplKind: { OpApplNode expr1 = (OpApplNode)expr; - return this.evalAppl(expr1, c, s0, s1, control); + if (coverage) {cm = cm.get(expr);} + return this.evalAppl(expr1, c, s0, s1, control, cm); } case LetInKind: { - LetInNode expr1 = (LetInNode)expr; - OpDefNode[] letDefs = expr1.getLets(); - int letLen = letDefs.length; - Context c1 = c; - for (int i = 0; i < letLen; i++) { - OpDefNode opDef = letDefs[i]; - if (opDef.getArity() == 0) { - Value rhs = new LazyValue(opDef.getBody(), c1); - c1 = c1.cons(opDef, rhs); - } - } - return this.eval(expr1.getBody(), c1, s0, s1, control); + return evalImplLetInKind((LetInNode) expr, c, s0, s1, control, cm); } case SubstInKind: { - SubstInNode expr1 = (SubstInNode)expr; - Subst[] subs = expr1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); - } - return this.eval(expr1.getBody(), c1, s0, s1, control); + return evalImplSubstInKind((SubstInNode) expr, c, s0, s1, control, cm); } // Added by LL on 13 Nov 2009 to handle theorem and assumption names. case APSubstInKind: { - APSubstInNode expr1 = (APSubstInNode)expr; - Subst[] subs = expr1.getSubsts(); - int slen = subs.length; - Context c1 = c; - for (int i = 0; i < slen; i++) { - Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true)); - } - return this.eval(expr1.getBody(), c1, s0, s1, control); + return evalImplApSubstInKind((APSubstInNode) expr, c, s0, s1, control, cm); } case NumeralKind: case DecimalKind: case StringKind: { - return Value.getValue(expr); + return (Value) expr.getToolObject(toolId); } case AtNodeKind: { @@ -1375,13 +1503,7 @@ public class Tool } case OpArgKind: { - OpArgNode expr1 = (OpArgNode)expr; - SymbolNode opNode = expr1.getOp(); - Object val = this.lookup(opNode, c, false); - if (val instanceof OpDefNode) { - return setSource(expr, new OpLambdaValue((OpDefNode)val, this, c, s0, s1)); - } - return (Value)val; + return evalImplOpArgKind((OpArgNode) expr, c, s0, s1, cm); } default: { @@ -1390,19 +1512,83 @@ public class Tool return null; // make compiler happy } } - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } - private final Value evalAppl(OpApplNode expr, Context c, TLCState s0, - TLCState s1, final int control) { - if (this.callStack != null) this.callStack.push(expr); - try { + private final Value evalImplLetInKind(LetInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) { + OpDefNode[] letDefs = expr1.getLets(); + int letLen = letDefs.length; + Context c1 = c; + for (int i = 0; i < letLen; i++) { + OpDefNode opDef = letDefs[i]; + if (opDef.getArity() == 0) { + Value rhs = new LazyValue(opDef.getBody(), c1, cm); + c1 = c1.cons(opDef, rhs); + } + } + return this.eval(expr1.getBody(), c1, s0, s1, control, cm); + } + + private final Value evalImplSubstInKind(SubstInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) { + Subst[] subs = expr1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, coverage ? sub.getCM() : cm)); + } + return this.eval(expr1.getBody(), c1, s0, s1, control, cm); + } + + private final Value evalImplApSubstInKind(APSubstInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) { + Subst[] subs = expr1.getSubsts(); + int slen = subs.length; + Context c1 = c; + for (int i = 0; i < slen; i++) { + Subst sub = subs[i]; + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, cm)); + } + return this.eval(expr1.getBody(), c1, s0, s1, control, cm); + } + + private final Value evalImplOpArgKind(OpArgNode expr1, Context c, TLCState s0, TLCState s1, final CostModel cm) { + SymbolNode opNode = expr1.getOp(); + Object val = this.lookup(opNode, c, false); + if (val instanceof OpDefNode) { + return setSource(expr1, new OpLambdaValue((OpDefNode)val, this, c, s0, s1, cm)); + } + return (Value)val; + } + + /* evalAppl */ + + private final Value evalAppl(final OpApplNode expr, Context c, TLCState s0, + TLCState s1, final int control, final CostModel cm) { + if (this.callStack != null) { + return evalApplWithCallStack(expr, c, s0, s1, control, cm); + } else { + return evalApplImpl(expr, c, s0, s1, control, cm); + } + } + + private final Value evalApplWithCallStack(final OpApplNode expr, Context c, TLCState s0, + TLCState s1, final int control, final CostModel cm) { + this.callStack.push(expr); + try { + return evalApplImpl(expr, c, s0, s1, control, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final Value evalApplImpl(final OpApplNode expr, Context c, TLCState s0, + TLCState s1, final int control, CostModel cm) { + if (coverage){ + cm = cm.getAndIncrement(expr); + } ExprOrOpArgNode[] args = expr.getArgs(); SymbolNode opNode = expr.getOperator(); int opcode = BuiltInOPs.getOpCode(opNode.getName()); @@ -1418,18 +1604,18 @@ public class Tool if (val instanceof LazyValue) { final LazyValue lv = (LazyValue) val; if (s1 == null) { - val = this.eval(lv.expr, lv.con, s0, null, control); + val = this.eval(lv.expr, lv.con, s0, null, control, lv.getCostModel()); } else if (lv.isUncachable() || EvalControl.isEnabled(control)) { // Never use cached LazyValues in an ENABLED expression. This is why all - // this.enabled* methods pass EvalControl.Enabled (the only exclusion being the + // this.enabled* methods pass EvalControl.Enabled (the only exception being the // call on line line 2799 which passes EvalControl.Primed). This is why we can // be sure that ENALBED expressions are not affected by the caching bug tracked // in Github issue 113 (see below). - val = this.eval(lv.expr, lv.con, s0, s1, control); + val = this.eval(lv.expr, lv.con, s0, s1, control, lv.getCostModel()); } else { val = lv.getValue(); if (val == null) { - final Value res = this.eval(lv.expr, lv.con, s0, s1, control); + final Value res = this.eval(lv.expr, lv.con, s0, s1, control, lv.getCostModel()); // This check has been suggested by Yuan Yu on 01/15/2018: // // If init-states are being generated, level has to be <= ConstantLevel for @@ -1521,13 +1707,13 @@ public class Tool } - Value res = null; + Value res = null; if (val instanceof OpDefNode) { OpDefNode opDef = (OpDefNode)val; opcode = BuiltInOPs.getOpCode(opDef.getName()); if (opcode == 0) { - Context c1 = this.getOpContext(opDef, args, c, true); - res = this.eval(opDef.getBody(), c1, s0, s1, control); + Context c1 = this.getOpContext(opDef, args, c, true, cm); + res = this.eval(opDef.getBody(), c1, s0, s1, control, cm); } } else if (val instanceof Value) { @@ -1540,15 +1726,8 @@ public class Tool } else { if (val instanceof OpValue) { - Applicable opVal = (Applicable)val; - Value[] argVals = new Value[alen]; - // evaluate the actuals: - for (int i = 0; i < alen; i++) { - argVals[i] = this.eval(args[i], c, s0, s1, control); - } - // apply the operator: - res = opVal.apply(argVals, control); - } + res = ((OpValue) val).eval(this, args, c, s0, s1, control, cm); + } } } /********************************************************************* @@ -1564,7 +1743,7 @@ public class Tool // + "!:' instead.\n" +expr); ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode) val ; Context c1 = this.getOpContext(opDef, args, c, true); - return this.eval(opDef.getBody(), c1, s0, s1, control); + return this.eval(opDef.getBody(), c1, s0, s1, control, cm); } else { Assert.fail(EC.TLC_CONFIG_UNDEFINED_OR_NO_OPERATOR, @@ -1580,29 +1759,44 @@ public class Tool { SemanticNode pred = args[0]; SemanticNode inExpr = expr.getBdedQuantBounds()[0]; - Value inVal = this.eval(inExpr, c, s0, s1, control); + Value inVal = this.eval(inExpr, c, s0, s1, control, cm); if (!(inVal instanceof Enumerable)) { Assert.fail("Attempted to compute the value of an expression of\n" + "form CHOOSE x \\in S: P, but S was not enumerable.\n" + expr); } - // To fix Bugzilla Bug 279 : TLC bug caused by TLC's not preserving the semantics of CHOOSE, + // To fix Bugzilla Bug 279 : TLC bug caused by TLC's not preserving the semantics of CHOOSE + // (@see tlc2.tool.BugzillaBug279Test), // the statement // // inVal.normalize(); // // was replaced by the following by LL on 7 Mar 2012. This fix has not yet received // the blessing of Yuan Yu, so it should be considered to be provisional. - // - Value convertedVal = SetEnumValue.convert(inVal); - if (convertedVal != null) { - inVal = convertedVal; - } else { - inVal.normalize(); - } + // + // Value convertedVal = inVal.ToSetEnum(); + // if (convertedVal != null) { + // inVal = convertedVal; + // } else { + // inVal.normalize(); + // } // end of fix. - - ValueEnumeration enumSet = ((Enumerable)inVal).elements(); + + // MAK 09/22/2018: + // The old fix above has the undesired side effect of enumerating inVal. In + // other words, e.g. a SUBSET 1..8 would be enumerated and normalized into a + // SetEnumValue. This is expensive and especially overkill, if the CHOOSE + // predicate holds for most if not all elements of inVal. In this case, we + // don't want to fully enumerate inVal but instead return the first element + // obtained from Enumerable#elements for which the predicate holds. Thus, + // Enumerable#elements(Ordering) has been added by which we make the requirement + // for elements to be normalized explicit. Implementor of Enumerable, such as + // SubsetValue are then free to implement elements that returns elements in + // normalized order without converting SubsetValue into SetEnumValue first. + + inVal.normalize(); + + ValueEnumeration enumSet = ((Enumerable)inVal).elements(Enumerable.Ordering.NORMALIZED); FormalParamNode[] bvars = expr.getBdedQuantSymbolLists()[0]; boolean isTuple = expr.isBdedQuantATuple()[0]; if (isTuple) { @@ -1610,7 +1804,7 @@ public class Tool int cnt = bvars.length; Value val; while ((val = enumSet.nextElement()) != null) { - TupleValue tv = TupleValue.convert(val); + TupleValue tv = (TupleValue) val.toTuple(); if (tv == null || tv.size() != cnt) { Assert.fail("Attempted to compute the value of an expression of form\n" + "CHOOSE <<x1, ... , xN>> \\in S: P, but S was not a set\n" + @@ -1620,12 +1814,12 @@ public class Tool for (int i = 0; i < cnt; i++) { c1 = c1.cons(bvars[i], tv.elems[i]); } - Value bval = this.eval(pred, c1, s0, s1, control); + Value bval = this.eval(pred, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", expr.toString()}); } if (((BoolValue)bval).val) { - return val; + return (Value) val; } } } @@ -1635,12 +1829,12 @@ public class Tool Value val; while ((val = enumSet.nextElement()) != null) { Context c1 = c.cons(name, val); - Value bval = this.eval(pred, c1, s0, s1, control); + Value bval = this.eval(pred, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", expr.toString()}); } if (((BoolValue)bval).val) { - return val; + return (Value) val; } } } @@ -1650,35 +1844,35 @@ public class Tool } case OPCODE_be: // BoundedExists { - ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control); + ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control, cm); SemanticNode body = args[0]; Context c1; while ((c1 = Enum.nextElement()) != null) { - Value bval = this.eval(body, c1, s0, s1, control); + Value bval = this.eval(body, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", expr.toString()}); } if (((BoolValue)bval).val) { - return ValTrue; + return BoolValue.ValTrue; } } - return ValFalse; + return BoolValue.ValFalse; } case OPCODE_bf: // BoundedForall { - ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control); + ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control, cm); SemanticNode body = args[0]; Context c1; while ((c1 = Enum.nextElement()) != null) { - Value bval = this.eval(body, c1, s0, s1, control); + Value bval = this.eval(body, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", expr.toString()}); } if (!((BoolValue)bval).val) { - return ValFalse; + return BoolValue.ValFalse; } } - return ValTrue; + return BoolValue.ValTrue; } case OPCODE_case: // Case { @@ -1691,64 +1885,64 @@ public class Tool other = pairArgs[1]; } else { - Value bval = this.eval(pairArgs[0], c, s0, s1, control); + Value bval = this.eval(pairArgs[0], c, s0, s1, control, coverage ? cm.get(pairNode) : cm); if (!(bval instanceof BoolValue)) { Assert.fail("A non-boolean expression (" + bval.getKindString() + ") was used as a condition of a CASE. " + pairArgs[0]); } if (((BoolValue)bval).val) { - return this.eval(pairArgs[1], c, s0, s1, control); + return this.eval(pairArgs[1], c, s0, s1, control, coverage ? cm.get(pairNode) : cm); } } } if (other == null) { Assert.fail("Attempted to evaluate a CASE with no conditions true.\n" + expr); } - return this.eval(other, c, s0, s1, control); + return this.eval(other, c, s0, s1, control, cm); } case OPCODE_cp: // CartesianProd { int alen = args.length; Value[] sets = new Value[alen]; for (int i = 0; i < alen; i++) { - sets[i] = this.eval(args[i], c, s0, s1, control); + sets[i] = this.eval(args[i], c, s0, s1, control, cm); } - return setSource(expr, new SetOfTuplesValue(sets)); + return setSource(expr, new SetOfTuplesValue(sets, cm)); } case OPCODE_cl: // ConjList { int alen = args.length; for (int i = 0; i < alen; i++) { - Value bval = this.eval(args[i], c, s0, s1, control); + Value bval = this.eval(args[i], c, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail("A non-boolean expression (" + bval.getKindString() + ") was used as a formula in a conjunction.\n" + args[i]); } if (!((BoolValue)bval).val) { - return ValFalse; + return BoolValue.ValFalse; } } - return ValTrue; + return BoolValue.ValTrue; } case OPCODE_dl: // DisjList { int alen = args.length; for (int i = 0; i < alen; i++) { - Value bval = this.eval(args[i], c, s0, s1, control); + Value bval = this.eval(args[i], c, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail("A non-boolean expression (" + bval.getKindString() + ") was used as a formula in a disjunction.\n" + args[i]); } if (((BoolValue)bval).val) { - return ValTrue; + return BoolValue.ValTrue; } } - return ValFalse; + return BoolValue.ValFalse; } case OPCODE_exc: // Except { int alen = args.length; - Value result = this.eval(args[0], c, s0, s1, control); + Value result = this.eval(args[0], c, s0, s1, control, cm); // SZ: variable not used ValueExcept[] expts = new ValueExcept[alen-1]; for (int i = 1; i < alen; i++) { OpApplNode pairNode = (OpApplNode)args[i]; @@ -1757,7 +1951,7 @@ public class Tool Value[] lhs = new Value[cmpts.length]; for (int j = 0; j < lhs.length; j++) { - lhs[j] = this.eval(cmpts[j], c, s0, s1, control); + lhs[j] = this.eval(cmpts[j], c, s0, s1, control, coverage ? cm.get(pairNode).get(pairArgs[0]) : cm); } Value atVal = result.select(lhs); if (atVal == null) { @@ -1766,9 +1960,9 @@ public class Tool } else { Context c1 = c.cons(EXCEPT_AT, atVal); - Value rhs = this.eval(pairArgs[1], c1, s0, s1, control); + Value rhs = this.eval(pairArgs[1], c1, s0, s1, control, coverage ? cm.get(pairNode) : cm); ValueExcept vex = new ValueExcept(lhs, rhs); - result = result.takeExcept(vex); + result = (Value) result.takeExcept(vex); } } return result; @@ -1776,11 +1970,11 @@ public class Tool case OPCODE_fa: // FcnApply { Value result = null; - Value fval = this.eval(args[0], c, s0, s1, EvalControl.setKeepLazy(control)); + Value fval = this.eval(args[0], c, s0, s1, EvalControl.setKeepLazy(control), cm); if ((fval instanceof FcnRcdValue) || (fval instanceof FcnLambdaValue)) { Applicable fcn = (Applicable)fval; - Value argVal = this.eval(args[1], c, s0, s1, control); + Value argVal = this.eval(args[1], c, s0, s1, control, cm); result = fcn.apply(argVal, control); } else if ((fval instanceof TupleValue) || @@ -1790,7 +1984,7 @@ public class Tool Assert.fail("Attempted to evaluate an expression of form f[e1, ... , eN]" + "\nwith f a tuple or record and N > 1.\n" + expr); } - Value aval = this.eval(args[1], c, s0, s1, control); + Value aval = this.eval(args[1], c, s0, s1, control, cm); result = fcn.apply(aval, control); } else { @@ -1810,34 +2004,34 @@ public class Tool Value[] dvals = new Value[domains.length]; boolean isFcnRcd = true; for (int i = 0; i < dvals.length; i++) { - dvals[i] = this.eval(domains[i], c, s0, s1, control); + dvals[i] = this.eval(domains[i], c, s0, s1, control, cm); isFcnRcd = isFcnRcd && (dvals[i] instanceof Reducible); } FcnParams params = new FcnParams(formals, isTuples, dvals); SemanticNode fbody = args[0]; - FcnLambdaValue fval = (FcnLambdaValue) setSource(expr, new FcnLambdaValue(params, fbody, this, c, s0, s1, control)); + FcnLambdaValue fval = (FcnLambdaValue) setSource(expr, new FcnLambdaValue(params, fbody, this, c, s0, s1, control, cm)); if (opcode == OPCODE_rfs) { SymbolNode fname = expr.getUnbdedQuantSymbols()[0]; fval.makeRecursive(fname); isFcnRcd = false; } if (isFcnRcd && !EvalControl.isKeepLazy(control)) { - return fval.toFcnRcd(); + return (Value) fval.toFcnRcd(); } return fval; } case OPCODE_ite: // IfThenElse { - Value bval = this.eval(args[0], c, s0, s1, control); + Value bval = this.eval(args[0], c, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail("A non-boolean expression (" + bval.getKindString() + ") was used as the condition of an IF.\n" + expr); } if (((BoolValue)bval).val) { - return this.eval(args[1], c, s0, s1, control); + return this.eval(args[1], c, s0, s1, control, cm); } - return this.eval(args[2], c, s0, s1, control); + return this.eval(args[2], c, s0, s1, control, cm); } case OPCODE_rc: // RcdConstructor { @@ -1847,28 +2041,28 @@ public class Tool for (int i = 0; i < alen; i++) { OpApplNode pairNode = (OpApplNode)args[i]; ExprOrOpArgNode[] pair = pairNode.getArgs(); - names[i] = ((StringValue)Value.getValue(pair[0])).getVal(); - vals[i] = this.eval(pair[1], c, s0, s1, control); + names[i] = ((StringValue)pair[0].getToolObject(toolId)).getVal(); + vals[i] = this.eval(pair[1], c, s0, s1, control, coverage ? cm.get(pairNode) : cm); } - return setSource(expr, new RecordValue(names, vals, false)); + return setSource(expr, new RecordValue(names, vals, false, cm)); } case OPCODE_rs: // RcdSelect { - Value rval = this.eval(args[0], c, s0, s1, control); - Value sval = Value.getValue(args[1]); + Value rval = this.eval(args[0], c, s0, s1, control, cm); + Value sval = (Value) args[1].getToolObject(toolId); if (rval instanceof RecordValue) { - Value result = ((RecordValue)rval).select(sval); + Value result = (Value) ((RecordValue)rval).select(sval); if (result == null) { Assert.fail("Attempted to select nonexistent field " + sval + " from the" + - " record\n" + Value.ppr(rval.toString()) + "\n" + expr); + " record\n" + Values.ppr(rval.toString()) + "\n" + expr); } return result; } else { - FcnRcdValue fcn = FcnRcdValue.convert(rval); + FcnRcdValue fcn = (FcnRcdValue) rval.toFcnRcd(); if (fcn == null) { Assert.fail("Attempted to select field " + sval + " from a non-record" + - " value " + Value.ppr(rval.toString()) + "\n" + expr); + " value " + Values.ppr(rval.toString()) + "\n" + expr); } return fcn.apply(sval, control); } @@ -1878,22 +2072,22 @@ public class Tool int alen = args.length; ValueVec vals = new ValueVec(alen); for (int i = 0; i < alen; i++) { - vals.addElement(this.eval(args[i], c, s0, s1, control)); + vals.addElement(this.eval(args[i], c, s0, s1, control, cm)); } - return setSource(expr, new SetEnumValue(vals, false)); + return setSource(expr, new SetEnumValue(vals, false, cm)); } case OPCODE_soa: // SetOfAll: {e(x) : x \in S} { ValueVec vals = new ValueVec(); - ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control); + ContextEnumerator Enum = this.contexts(expr, c, s0, s1, control, cm); SemanticNode body = args[0]; Context c1; while ((c1 = Enum.nextElement()) != null) { - Value val = this.eval(body, c1, s0, s1, control); + Value val = this.eval(body, c1, s0, s1, control, cm); vals.addElement(val); // vals.addElement1(val); } - return setSource(expr, new SetEnumValue(vals, false)); + return setSource(expr, new SetEnumValue(vals, false, cm)); } case OPCODE_sor: // SetOfRcds { @@ -1903,22 +2097,22 @@ public class Tool for (int i = 0; i < alen; i++) { OpApplNode pairNode = (OpApplNode)args[i]; ExprOrOpArgNode[] pair = pairNode.getArgs(); - names[i] = ((StringValue)Value.getValue(pair[0])).getVal(); - vals[i] = this.eval(pair[1], c, s0, s1, control); + names[i] = ((StringValue)pair[0].getToolObject(toolId)).getVal(); + vals[i] = this.eval(pair[1], c, s0, s1, control, coverage ? cm.get(pairNode) : cm); } - return setSource(expr, new SetOfRcdsValue(names, vals, false)); + return setSource(expr, new SetOfRcdsValue(names, vals, false, cm)); } case OPCODE_sof: // SetOfFcns { - Value lhs = this.eval(args[0], c, s0, s1, control); - Value rhs = this.eval(args[1], c, s0, s1, control); - return setSource(expr, new SetOfFcnsValue(lhs, rhs)); + Value lhs = this.eval(args[0], c, s0, s1, control, cm); + Value rhs = this.eval(args[1], c, s0, s1, control, cm); + return setSource(expr, new SetOfFcnsValue(lhs, rhs, cm)); } case OPCODE_sso: // SubsetOf { SemanticNode pred = args[0]; SemanticNode inExpr = expr.getBdedQuantBounds()[0]; - Value inVal = this.eval(inExpr, c, s0, s1, control); + Value inVal = this.eval(inExpr, c, s0, s1, control, cm); boolean isTuple = expr.isBdedQuantATuple()[0]; FormalParamNode[] bvars = expr.getBdedQuantSymbolLists()[0]; if (inVal instanceof Reducible) { @@ -1932,7 +2126,7 @@ public class Tool for (int i = 0; i < bvars.length; i++) { c1 = c1.cons(bvars[i], tuple[i]); } - Value bval = this.eval(pred, c1, s0, s1, control); + Value bval = this.eval(pred, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form {x \\in S : P(x)}" + " when P was " + bval.getKindString() + ".\n" + pred); @@ -1946,7 +2140,7 @@ public class Tool SymbolNode idName = bvars[0]; while ((elem = enumSet.nextElement()) != null) { Context c1 = c.cons(idName, elem); - Value bval = this.eval(pred, c1, s0, s1, control); + Value bval = this.eval(pred, c1, s0, s1, control, cm); if (!(bval instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form {x \\in S : P(x)}" + " when P was " + bval.getKindString() + ".\n" + pred); @@ -1956,13 +2150,13 @@ public class Tool } } } - return setSource(expr, new SetEnumValue(vals, inVal.isNormalized())); + return setSource(expr, new SetEnumValue(vals, inVal.isNormalized(), cm)); } else if (isTuple) { - return setSource(expr, new SetPredValue(bvars, inVal, pred, this, c, s0, s1, control)); + return setSource(expr, new SetPredValue(bvars, inVal, pred, this, c, s0, s1, control, cm)); } else { - return setSource(expr, new SetPredValue(bvars[0], inVal, pred, this, c, s0, s1, control)); + return setSource(expr, new SetPredValue(bvars[0], inVal, pred, this, c, s0, s1, control, cm)); } } case OPCODE_tup: // Tuple @@ -1970,9 +2164,9 @@ public class Tool int alen = args.length; Value[] vals = new Value[alen]; for (int i = 0; i < alen; i++) { - vals[i] = this.eval(args[i], c, s0, s1, control); + vals[i] = this.eval(args[i], c, s0, s1, control, cm); } - return setSource(expr, new TupleValue(vals)); + return setSource(expr, new TupleValue(vals, cm)); } case OPCODE_uc: // UnboundedChoose { @@ -1997,26 +2191,26 @@ public class Tool } case OPCODE_lnot: { - Value arg = this.eval(args[0], c, s0, s1, control); + Value arg = this.eval(args[0], c, s0, s1, control, cm); if (!(arg instanceof BoolValue)) { Assert.fail("Attempted to apply the operator ~ to a non-boolean\n(" + arg.getKindString() + ")\n" + expr); } - return (((BoolValue)arg).val) ? ValFalse : ValTrue; + return (((BoolValue)arg).val) ? BoolValue.ValFalse : BoolValue.ValTrue; } case OPCODE_subset: { - Value arg = this.eval(args[0], c, s0, s1, control); - return setSource(expr, new SubsetValue(arg)); + Value arg = this.eval(args[0], c, s0, s1, control, cm); + return setSource(expr, new SubsetValue(arg, cm)); } case OPCODE_union: { - Value arg = this.eval(args[0], c, s0, s1, control); + Value arg = this.eval(args[0], c, s0, s1, control, cm); return setSource(expr, UnionValue.union(arg)); } case OPCODE_domain: { - Value arg = this.eval(args[0], c, s0, s1, control); + Value arg = this.eval(args[0], c, s0, s1, control, cm); if (!(arg instanceof Applicable)) { Assert.fail("Attempted to apply the operator DOMAIN to a non-function\n(" + arg.getKindString() + ")\n" + expr); @@ -2027,43 +2221,43 @@ public class Tool { TLCState sfun = TLCStateFun.Empty; Context c1 = Context.branch(c); - sfun = this.enabled(args[0], ActionItemList.Empty, c1, s0, sfun); - return (sfun != null) ? ValTrue : ValFalse; + sfun = this.enabled(args[0], ActionItemList.Empty, c1, s0, sfun, cm); + return (sfun != null) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_eq: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); - return (arg1.equals(arg2)) ? ValTrue : ValFalse; + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); + return (arg1.equals(arg2)) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_land: { - Value arg1 = this.eval(args[0], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); if (!(arg1 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P /\\ Q" + " when P was\n" + arg1.getKindString() + ".\n" + expr); } if (((BoolValue)arg1).val) { - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (!(arg2 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P /\\ Q" + " when Q was\n" + arg2.getKindString() + ".\n" + expr); } return arg2; } - return ValFalse; + return BoolValue.ValFalse; } case OPCODE_lor: { - Value arg1 = this.eval(args[0], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); if (!(arg1 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P \\/ Q" + " when P was\n" + arg1.getKindString() + ".\n" + expr); } if (((BoolValue)arg1).val) { - return ValTrue; + return BoolValue.ValTrue; } - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (!(arg2 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P \\/ Q" + " when Q was\n" + arg2.getKindString() + ".\n" + expr); @@ -2072,43 +2266,43 @@ public class Tool } case OPCODE_implies: { - Value arg1 = this.eval(args[0], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); if (!(arg1 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P => Q" + " when P was\n" + arg1.getKindString() + ".\n" + expr); } if (((BoolValue)arg1).val) { - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (!(arg2 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P => Q" + " when Q was\n" + arg2.getKindString() + ".\n" + expr); } return arg2; } - return ValTrue; + return BoolValue.ValTrue; } case OPCODE_equiv: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (!(arg1 instanceof BoolValue) || !(arg2 instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form P <=> Q" + " when P or Q was not a boolean.\n" + expr); } BoolValue bval1 = (BoolValue)arg1; BoolValue bval2 = (BoolValue)arg2; - return (bval1.val == bval2.val) ? ValTrue : ValFalse; + return (bval1.val == bval2.val) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_noteq: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); - return arg1.equals(arg2) ? ValFalse : ValTrue; + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); + return arg1.equals(arg2) ? BoolValue.ValFalse : BoolValue.ValTrue; } case OPCODE_subseteq: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (!(arg1 instanceof Enumerable)) { Assert.fail("Attempted to evaluate an expression of form S \\subseteq T," + " but S was not enumerable.\n" + expr); @@ -2117,20 +2311,20 @@ public class Tool } case OPCODE_in: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); - return (arg2.member(arg1)) ? ValTrue : ValFalse; + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); + return (arg2.member(arg1)) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_notin: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); - return (arg2.member(arg1)) ? ValFalse : ValTrue; + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); + return (arg2.member(arg1)) ? BoolValue.ValFalse : BoolValue.ValTrue; } case OPCODE_setdiff: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (arg1 instanceof Reducible) { return setSource(expr, ((Reducible)arg1).diff(arg2)); } @@ -2138,8 +2332,8 @@ public class Tool } case OPCODE_cap: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (arg1 instanceof Reducible) { return setSource(expr, ((Reducible)arg1).cap(arg2)); } @@ -2151,57 +2345,71 @@ public class Tool case OPCODE_nop: // Added by LL on 2 Aug 2007 { - return eval(args[0], c, s0, s1, control); + return eval(args[0], c, s0, s1, control, cm); } case OPCODE_cup: { - Value arg1 = this.eval(args[0], c, s0, s1, control); - Value arg2 = this.eval(args[1], c, s0, s1, control); + Value arg1 = this.eval(args[0], c, s0, s1, control, cm); + Value arg2 = this.eval(args[1], c, s0, s1, control, cm); if (arg1 instanceof Reducible) { return setSource(expr, ((Reducible)arg1).cup(arg2)); } else if (arg2 instanceof Reducible) { return setSource(expr, ((Reducible)arg2).cup(arg1)); } - return setSource(expr, new SetCupValue(arg1, arg2)); + return setSource(expr, new SetCupValue(arg1, arg2, cm)); } case OPCODE_prime: { - return this.eval(args[0], c, s1, null, EvalControl.setPrimedIfEnabled(control)); + // MAK 03/2019: Cannot reproduce this but without this check the nested evaluation + // fails with a NullPointerException which subsequently is swallowed. This makes it + // impossible for a user to diagnose what is going on. Since I cannot reproduce the + // actual expression, I leave this commented for. I recall an expression along the + // lines of: + // ... + // TLCSet(23, CHOOSE p \in pc: pc[p] # pc[p]') + // ... + // The fail statement below is obviously too generic to be useful and needs to be + // clarified if the actual cause has been identified. +// if (s1 == null) { +// Assert.fail("Attempted to evaluate the following expression," + +// " but expression failed to evaluate.\n" + expr); +// } + return this.eval(args[0], c, s1, null, EvalControl.setPrimedIfEnabled(control), cm); } case OPCODE_unchanged: { - Value v0 = this.eval(args[0], c, s0, TLCState.Empty, control); - Value v1 = this.eval(args[0], c, s1, null, EvalControl.setPrimedIfEnabled(control)); - return (v0.equals(v1)) ? ValTrue : ValFalse; + Value v0 = this.eval(args[0], c, s0, TLCState.Empty, control, cm); + Value v1 = this.eval(args[0], c, s1, null, EvalControl.setPrimedIfEnabled(control), cm); + return (v0.equals(v1)) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_aa: // <A>_e { - Value res = this.eval(args[0], c, s0, s1, control); + Value res = this.eval(args[0], c, s0, s1, control, cm); if (!(res instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form <A>_e," + " but A was not a boolean.\n" + expr); } if (!((BoolValue)res).val) { - return ValFalse; + return BoolValue.ValFalse; } - Value v0 = this.eval(args[1], c, s0, TLCState.Empty, control); - Value v1 = this.eval(args[1], c, s1, null, EvalControl.setPrimedIfEnabled(control)); - return v0.equals(v1) ? ValFalse : ValTrue; + Value v0 = this.eval(args[1], c, s0, TLCState.Empty, control, cm); + Value v1 = this.eval(args[1], c, s1, null, EvalControl.setPrimedIfEnabled(control), cm); + return v0.equals(v1) ? BoolValue.ValFalse : BoolValue.ValTrue; } case OPCODE_sa: // [A]_e { - Value res = this.eval(args[0], c, s0, s1, control); + Value res = this.eval(args[0], c, s0, s1, control, cm); if (!(res instanceof BoolValue)) { Assert.fail("Attempted to evaluate an expression of form [A]_e," + " but A was not a boolean.\n" + expr); } if (((BoolValue)res).val) { - return ValTrue; + return BoolValue.ValTrue; } - Value v0 = this.eval(args[1], c, s0, TLCState.Empty, control); - Value v1 = this.eval(args[1], c, s1, null, EvalControl.setPrimedIfEnabled(control)); - return (v0.equals(v1)) ? ValTrue : ValFalse; + Value v0 = this.eval(args[1], c, s0, TLCState.Empty, control, cm); + Value v1 = this.eval(args[1], c, s1, null, EvalControl.setPrimedIfEnabled(control), cm); + return (v0.equals(v1)) ? BoolValue.ValTrue : BoolValue.ValFalse; } case OPCODE_cdot: { @@ -2265,13 +2473,6 @@ public class Tool return null; } } - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } private final Value setSource(final SemanticNode expr, final Value value) { @@ -2286,15 +2487,17 @@ public class Tool * is good iff it assigns legal explicit values to all the global * state variables. */ + @Override public final boolean isGoodState(TLCState state) { return state.allAssigned(); } /* This method determines if a state satisfies the model constraints. */ - public /*final*/ boolean isInModel(TLCState state) throws EvalException { + @Override + public final boolean isInModel(TLCState state) throws EvalException { ExprNode[] constrs = this.getModelConstraints(); for (int i = 0; i < constrs.length; i++) { - Value bval = this.eval(constrs[i], Context.Empty, state); + IValue bval = this.eval(constrs[i], Context.Empty, state, CostModel.DO_NOT_RECORD); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", constrs[i].toString()}); } @@ -2304,10 +2507,11 @@ public class Tool } /* This method determines if a pair of states satisfy the action constraints. */ - public /*final*/ boolean isInActions(TLCState s1, TLCState s2) throws EvalException { + @Override + public final boolean isInActions(TLCState s1, TLCState s2) throws EvalException { ExprNode[] constrs = this.getActionConstraints(); for (int i = 0; i < constrs.length; i++) { - Value bval = this.eval(constrs[i], Context.Empty, s1, s2, EvalControl.Clear); + Value bval = this.eval(constrs[i], Context.Empty, s1, s2, EvalControl.Clear, CostModel.DO_NOT_RECORD); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", constrs[i].toString()}); } @@ -2315,21 +2519,59 @@ public class Tool } return true; } + + @Override + public final TLCState enabled(SemanticNode pred, Context c, TLCState s0, TLCState s1) { + return enabled(pred, ActionItemList.Empty, c, s0, s1, CostModel.DO_NOT_RECORD); + } + + @Override + public final TLCState enabled(SemanticNode pred, Context c, TLCState s0, TLCState s1, ExprNode subscript, final int ail) { + ActionItemList acts = (ActionItemList) ActionItemList.Empty.cons(subscript, c, CostModel.DO_NOT_RECORD, ail); + return enabled(pred, acts, c, s0, s1, CostModel.DO_NOT_RECORD); + } + + @Override + public final TLCState enabled(SemanticNode pred, IActionItemList acts, Context c, TLCState s0, TLCState s1) { + return enabled(pred, acts, c, s0, s1, CostModel.DO_NOT_RECORD); + } /** * This method determines if an action is enabled in the given state. * More precisely, it determines if (act.pred /\ (sub' # sub)) is * enabled in the state s and context act.con. */ - public final TLCState enabled(SemanticNode pred, ActionItemList acts, - Context c, TLCState s0, TLCState s1) { - if (this.callStack != null) this.callStack.push(pred); + @Override + public final TLCState enabled(SemanticNode pred, IActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { + if (this.callStack != null) { + return enabledWithCallStack(pred, (ActionItemList) acts, c, s0, s1, cm); + } else { + return enabledImpl(pred, (ActionItemList) acts, c, s0, s1, cm); + } + } + + private final TLCState enabledWithCallStack(SemanticNode pred, ActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { + this.callStack.push(pred); try { + return enabledImpl(pred, acts, c, s0, s1, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final TLCState enabledImpl(SemanticNode pred, ActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { switch (pred.getKind()) { case OpApplKind: { OpApplNode pred1 = (OpApplNode)pred; - return this.enabledAppl(pred1, acts, c, s0, s1); + return this.enabledAppl(pred1, acts, c, s0, s1, cm); } case LetInKind: { @@ -2339,11 +2581,11 @@ public class Tool for (int i = 0; i < letDefs.length; i++) { OpDefNode opDef = letDefs[i]; if (opDef.getArity() == 0) { - Value rhs = new LazyValue(opDef.getBody(), c1); + Value rhs = new LazyValue(opDef.getBody(), c1, cm); c1 = c1.cons(opDef, rhs); } } - return this.enabled(pred1.getBody(), acts, c1, s0, s1); + return this.enabled(pred1.getBody(), acts, c1, s0, s1, cm); } case SubstInKind: { @@ -2353,9 +2595,9 @@ public class Tool Context c1 = c; for (int i = 0; i < slen; i++) { Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm)); } - return this.enabled(pred1.getBody(), acts, c1, s0, s1); + return this.enabled(pred1.getBody(), acts, c1, s0, s1, cm); } // Added by LL on 13 Nov 2009 to handle theorem and assumption names. case APSubstInKind: @@ -2366,15 +2608,15 @@ public class Tool Context c1 = c; for (int i = 0; i < slen; i++) { Subst sub = subs[i]; - c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false)); + c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm)); } - return this.enabled(pred1.getBody(), acts, c1, s0, s1); + return this.enabled(pred1.getBody(), acts, c1, s0, s1, cm); } // LabelKind class added by LL on 13 Jun 2007 case LabelKind: { LabelNode pred1 = (LabelNode)pred; - return this.enabled(pred1.getBody(), acts, c, s0, s1); + return this.enabled(pred1.getBody(), acts, c, s0, s1, cm); } default: { @@ -2383,50 +2625,66 @@ public class Tool return null; // make compiler happy } } - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } } - private final TLCState enabled(ActionItemList acts, TLCState s0, TLCState s1) { + private final TLCState enabled(ActionItemList acts, TLCState s0, TLCState s1, CostModel cm) { if (acts.isEmpty()) return s1; final int kind = acts.carKind(); SemanticNode pred = acts.carPred(); Context c = acts.carContext(); + cm = acts.cm; ActionItemList acts1 = acts.cdr(); - if (kind > ActionItemList.CONJUNCT) { - TLCState res = this.enabled(pred, acts1, c, s0, s1); + if (kind > IActionItemList.CONJUNCT) { + TLCState res = this.enabled(pred, acts1, c, s0, s1, cm); return res; } - else if (kind == ActionItemList.PRED) { - TLCState res = this.enabled(pred, acts1, c, s0, s1); + else if (kind == IActionItemList.PRED) { + TLCState res = this.enabled(pred, acts1, c, s0, s1, cm); return res; } - if (kind == ActionItemList.UNCHANGED) { - TLCState res = this.enabledUnchanged(pred, acts1, c, s0, s1); + if (kind == IActionItemList.UNCHANGED) { + TLCState res = this.enabledUnchanged(pred, acts1, c, s0, s1, cm); return res; } - Value v1 = this.eval(pred, c, s0, TLCState.Empty, EvalControl.Enabled); + Value v1 = this.eval(pred, c, s0, TLCState.Empty, EvalControl.Enabled, cm); // We are now in ENABLED and primed state. Second TLCState parameter being null // effectively disables LazyValue in evalAppl (same effect as // EvalControl.setPrimed(EvalControl.Enabled)). - Value v2 = this.eval(pred, c, s1, null, EvalControl.Primed); + Value v2 = this.eval(pred, c, s1, null, EvalControl.Primed, cm); if (v1.equals(v2)) return null; - TLCState res = this.enabled(acts1, s0, s1); + TLCState res = this.enabled(acts1, s0, s1, cm); return res; } - private final TLCState enabledAppl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1) + private final TLCState enabledAppl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm) { - if (this.callStack != null) this.callStack.push(pred); - try { + if (this.callStack != null) { + return enabledApplWithCallStack(pred, acts, c, s0, s1, cm); + } else { + return enabledApplImpl(pred, acts, c, s0, s1, cm); + } + } + + private final TLCState enabledApplWithCallStack(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm) + { + this.callStack.push(pred); + try { + return enabledApplImpl(pred, acts, c, s0, s1, cm); + } catch (TLCRuntimeException | EvalException e) { + // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) + this.callStack.freeze(); + throw e; + } finally { + this.callStack.pop(); + } + } + + private final TLCState enabledApplImpl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm) + { + if (coverage) {cm = cm.get(pred);} ExprOrOpArgNode[] args = pred.getArgs(); int alen = args.length; SymbolNode opNode = pred.getOperator(); @@ -2446,8 +2704,8 @@ public class Tool if (opcode == 0) { // Context c1 = this.getOpContext(opDef, args, c, false); - Context c1 = this.getOpContext(opDef, args, c, true); - return this.enabled(opDef.getBody(), acts, c1, s0, s1); + Context c1 = this.getOpContext(opDef, args, c, true, cm); + return this.enabled(opDef.getBody(), acts, c1, s0, s1, cm); } } @@ -2461,14 +2719,14 @@ public class Tool { ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode) val; Context c1 = this.getOpContext(opDef, args, c, true); - return this.enabled(opDef.getBody(), acts, c1, s0, s1); + return this.enabled(opDef.getBody(), acts, c1, s0, s1, cm); } if (val instanceof LazyValue) { LazyValue lv = (LazyValue) val; - return this.enabled(lv.expr, acts, lv.con, s0, s1); + return this.enabled(lv.expr, acts, lv.con, s0, s1, lv.cm); } Object bval = val; @@ -2482,16 +2740,8 @@ public class Tool { if (val instanceof OpValue) { - Applicable op = (Applicable) val; - Value[] argVals = new Value[alen]; - // evaluate the actuals: - for (int i = 0; i < alen; i++) - { - argVals[i] = this.eval(args[i], c, s0, s1, EvalControl.Enabled); - } - // apply the operator: - bval = op.apply(argVals, EvalControl.Enabled); - } + bval = ((OpValue) val).eval(this, args, c, s0, s1, EvalControl.Enabled, cm); + } } if (opcode == 0) @@ -2503,7 +2753,7 @@ public class Tool } if (((BoolValue) bval).val) { - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } return null; } @@ -2512,17 +2762,17 @@ public class Tool switch (opcode) { case OPCODE_aa: // AngleAct <A>_e { - ActionItemList acts1 = acts.cons(args[1], c, ActionItemList.CHANGED); - return this.enabled(args[0], acts1, c, s0, s1); + ActionItemList acts1 = (ActionItemList) acts.cons(args[1], c, cm, IActionItemList.CHANGED); + return this.enabled(args[0], acts1, c, s0, s1, cm); } case OPCODE_be: // BoundedExists { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Enabled); + ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Enabled, cm); Context c1; while ((c1 = Enum.nextElement()) != null) { - TLCState s2 = this.enabled(body, acts, c1, s0, s1); + TLCState s2 = this.enabled(body, acts, c1, s0, s1, cm); if (s2 != null) { return s2; } @@ -2532,19 +2782,19 @@ public class Tool case OPCODE_bf: // BoundedForall { SemanticNode body = args[0]; - ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Enabled); + ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Enabled, cm); Context c1 = Enum.nextElement(); if (c1 == null) { - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } ActionItemList acts1 = acts; Context c2; while ((c2 = Enum.nextElement()) != null) { - acts1 = acts1.cons(body, c2, ActionItemList.PRED); + acts1 = (ActionItemList) acts1.cons(body, c2, cm, IActionItemList.PRED); } - return this.enabled(body, acts1, c1, s0, s1); + return this.enabled(body, acts1, c1, s0, s1, cm); } case OPCODE_case: // Case { @@ -2558,7 +2808,7 @@ public class Tool other = pairArgs[1]; } else { - Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Enabled); + Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Enabled, cm); if (!(bval instanceof BoolValue)) { Assert.fail("In computing ENABLED, a non-boolean expression(" + bval.getKindString() @@ -2566,7 +2816,7 @@ public class Tool } if (((BoolValue) bval).val) { - return this.enabled(pairArgs[1], acts, c, s0, s1); + return this.enabled(pairArgs[1], acts, c, s0, s1, cm); } } } @@ -2574,7 +2824,7 @@ public class Tool { Assert.fail("In computing ENABLED, TLC encountered a CASE with no" + " conditions true.\n" + pred); } - return this.enabled(other, acts, c, s0, s1); + return this.enabled(other, acts, c, s0, s1, cm); } case OPCODE_cl: // ConjList case OPCODE_land: @@ -2582,16 +2832,16 @@ public class Tool ActionItemList acts1 = acts; for (int i = alen - 1; i > 0; i--) { - acts1 = acts1.cons(args[i], c, i); + acts1 = (ActionItemList) acts1.cons(args[i], c, cm, i); } - return this.enabled(args[0], acts1, c, s0, s1); + return this.enabled(args[0], acts1, c, s0, s1, cm); } case OPCODE_dl: // DisjList case OPCODE_lor: { for (int i = 0; i < alen; i++) { - TLCState s2 = this.enabled(args[i], acts, c, s0, s1); + TLCState s2 = this.enabled(args[i], acts, c, s0, s1, cm); if (s2 != null) { return s2; } @@ -2600,21 +2850,21 @@ public class Tool } case OPCODE_fa: // FcnApply { - Value fval = this.eval(args[0], c, s0, s1, EvalControl.setKeepLazy(EvalControl.Enabled)); // KeepLazy does not interfere with EvalControl.Enabled in this.evalAppl + Value fval = this.eval(args[0], c, s0, s1, EvalControl.setKeepLazy(EvalControl.Enabled), cm); // KeepLazy does not interfere with EvalControl.Enabled in this.evalAppl if (fval instanceof FcnLambdaValue) { FcnLambdaValue fcn = (FcnLambdaValue) fval; if (fcn.fcnRcd == null) { - Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Enabled); // EvalControl.Enabled passed on to nested this.evalAppl - return this.enabled(fcn.body, acts, c1, s0, s1); + Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Enabled, cm); // EvalControl.Enabled passed on to nested this.evalAppl + return this.enabled(fcn.body, acts, c1, s0, s1, cm); } fval = fcn.fcnRcd; } if (fval instanceof Applicable) { Applicable fcn = (Applicable) fval; - Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Enabled); + Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Enabled, cm); Value bval = fcn.apply(argVal, EvalControl.Enabled); // EvalControl.Enabled not taken into account by any subclass of Applicable if (!(bval instanceof BoolValue)) { @@ -2629,26 +2879,26 @@ public class Tool Assert.fail("In computing ENABLED, a non-function (" + fval.getKindString() + ") was applied as a function.\n" + pred); } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } case OPCODE_ite: // IfThenElse { - Value guard = this.eval(args[0], c, s0, s1, EvalControl.Enabled); + Value guard = this.eval(args[0], c, s0, s1, EvalControl.Enabled, cm); if (!(guard instanceof BoolValue)) { Assert.fail("In computing ENABLED, a non-boolean expression(" + guard.getKindString() + ") was used as the guard condition" + " of an IF.\n" + pred); } int idx = (((BoolValue) guard).val) ? 1 : 2; - return this.enabled(args[idx], acts, c, s0, s1); + return this.enabled(args[idx], acts, c, s0, s1, cm); } case OPCODE_sa: // SquareAct [A]_e { - TLCState s2 = this.enabled(args[0], acts, c, s0, s1); + TLCState s2 = this.enabled(args[0], acts, c, s0, s1, cm); if (s2 != null) { return s2; } - return this.enabledUnchanged(args[1], acts, c, s0, s1); + return this.enabledUnchanged(args[1], acts, c, s0, s1, cm); } case OPCODE_te: // TemporalExists case OPCODE_tf: // TemporalForAll @@ -2696,26 +2946,26 @@ public class Tool } case OPCODE_unchanged: { - return this.enabledUnchanged(args[0], acts, c, s0, s1); + return this.enabledUnchanged(args[0], acts, c, s0, s1, cm); } case OPCODE_eq: { SymbolNode var = this.getPrimedVar(args[0], c, true); if (var == null) { - Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled, cm); if (!((BoolValue) bval).val) { return null; } } else { UniqueString varName = var.getName(); - Value lval = s1.lookup(varName); - Value rval = this.eval(args[1], c, s0, s1, EvalControl.Enabled); + IValue lval = s1.lookup(varName); + Value rval = this.eval(args[1], c, s0, s1, EvalControl.Enabled, cm); if (lval == null) { - TLCState s2 = s1.bind(var, rval, pred); - return this.enabled(acts, s0, s2); + TLCState s2 = s1.bind(var, rval); + return this.enabled(acts, s0, s2, cm); } else { if (!lval.equals(rval)) { @@ -2723,11 +2973,11 @@ public class Tool } } } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } case OPCODE_implies: { - Value bval = this.eval(args[0], c, s0, s1, EvalControl.Enabled); + Value bval = this.eval(args[0], c, s0, s1, EvalControl.Enabled, cm); if (!(bval instanceof BoolValue)) { Assert.fail("While computing ENABLED of an expression of the form" + " P => Q, P was " @@ -2735,9 +2985,9 @@ public class Tool } if (((BoolValue) bval).val) { - return this.enabled(args[1], acts, c, s0, s1); + return this.enabled(args[1], acts, c, s0, s1, cm); } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } case OPCODE_cdot: { @@ -2770,15 +3020,15 @@ public class Tool SymbolNode var = this.getPrimedVar(args[0], c, true); if (var == null) { - Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled, cm); if (!((BoolValue) bval).val) { return null; } } else { UniqueString varName = var.getName(); - Value lval = s1.lookup(varName); - Value rval = this.eval(args[1], c, s0, s1, EvalControl.Enabled); + Value lval = (Value) s1.lookup(varName); + Value rval = this.eval(args[1], c, s0, s1, EvalControl.Enabled, cm); if (lval == null) { if (!(rval instanceof Enumerable)) @@ -2789,8 +3039,8 @@ public class Tool Value val; while ((val = Enum.nextElement()) != null) { - TLCState s2 = s1.bind(var, val, pred); - s2 = this.enabled(acts, s0, s2); + TLCState s2 = s1.bind(var, val); + s2 = this.enabled(acts, s0, s2, cm); if (s2 != null) { return s2; } @@ -2803,18 +3053,18 @@ public class Tool } } } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } // The following case added by LL on 13 Nov 2009 to handle subexpression names. case OPCODE_nop: { - return this.enabled(args[0], acts, c, s0, s1); + return this.enabled(args[0], acts, c, s0, s1, cm); } default: { // We handle all the other builtin operators here. - Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled); + Value bval = this.eval(pred, c, s0, s1, EvalControl.Enabled, cm); if (!(bval instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "ENABLED", "boolean", @@ -2822,36 +3072,51 @@ public class Tool } if (((BoolValue) bval).val) { - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } return null; } } + } + + private final TLCState enabledUnchanged(SemanticNode expr, ActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { + if (this.callStack != null) { + return enabledUnchangedWithCallStack(expr, acts, c, s0, s1, cm); + } else { + return enabledUnchangedImpl(expr, acts, c, s0, s1, cm); + } + } + + private final TLCState enabledUnchangedWithCallStack(SemanticNode expr, ActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { + this.callStack.push(expr); + try { + return enabledUnchangedImpl(expr, acts, c, s0, s1, cm); } catch (TLCRuntimeException | EvalException e) { // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } + this.callStack.freeze(); throw e; } finally { - if (this.callStack != null) { this.callStack.pop(); } + this.callStack.pop(); } } - - private final TLCState enabledUnchanged(SemanticNode expr, ActionItemList acts, - Context c, TLCState s0, TLCState s1) { - if (this.callStack != null) this.callStack.push(expr); - try { + + private final TLCState enabledUnchangedImpl(SemanticNode expr, ActionItemList acts, + Context c, TLCState s0, TLCState s1, CostModel cm) { + if (coverage) {cm = cm.get(expr);} SymbolNode var = this.getVar(expr, c, true); if (var != null) { // a state variable, e.g. UNCHANGED var1 UniqueString varName = var.getName(); - Value v0 = this.eval(expr, c, s0, s1, EvalControl.Enabled); - Value v1 = s1.lookup(varName); + Value v0 = this.eval(expr, c, s0, s1, EvalControl.Enabled, cm); + IValue v1 = s1.lookup(varName); if (v1 == null) { - s1 = s1.bind(var, v0, expr); - return this.enabled(acts, s0, s1); + s1 = s1.bind(var, v0); + return this.enabled(acts, s0, s1, cm); } if (v1.equals(v0)) { - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } MP.printWarning(EC.TLC_UNCHANGED_VARIABLE_CHANGED, new String[]{varName.toString() , expr.toString()}); return null; @@ -2870,11 +3135,11 @@ public class Tool if (alen != 0) { ActionItemList acts1 = acts; for (int i = 1; i < alen; i++) { - acts1 = acts1.cons(args[i], c, ActionItemList.UNCHANGED); + acts1 = (ActionItemList) acts1.cons(args[i], c, cm, IActionItemList.UNCHANGED); } - return this.enabledUnchanged(args[0], acts1, c, s0, s1); + return this.enabledUnchanged(args[0], acts1, c, s0, s1, cm); } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } if (opcode == 0 && alen == 0) { @@ -2883,20 +3148,20 @@ public class Tool if (val instanceof LazyValue) { LazyValue lv = (LazyValue)val; - return this.enabledUnchanged(lv.expr, acts, lv.con, s0, s1); + return this.enabledUnchanged(lv.expr, acts, lv.con, s0, s1, cm); } else if (val instanceof OpDefNode) { - return this.enabledUnchanged(((OpDefNode)val).getBody(), acts, c, s0, s1); + return this.enabledUnchanged(((OpDefNode)val).getBody(), acts, c, s0, s1, cm); } else if (val == null) { Assert.fail("In computing ENABLED, TLC found the undefined identifier\n" + opName + " in an UNCHANGED expression at\n" + expr); } - return this.enabled(acts, s0, s1); + return this.enabled(acts, s0, s1, cm); } } - final Value v0 = this.eval(expr, c, s0, TLCState.Empty, EvalControl.Enabled); + final Value v0 = this.eval(expr, c, s0, TLCState.Empty, EvalControl.Enabled, cm); // We are in ENABLED and primed but why pass only primed? This appears to // be the only place where we call eval from the ENABLED scope without // additionally passing EvalControl.Enabled. Not passing Enabled allows a @@ -2924,23 +3189,17 @@ public class Tool // If this bug is ever fixed to make TLC accept spec 23, EvalControl.Primed // should likely be rewritten to EvalControl.setPrimed(EvalControl.Enabled) // to disable reusage of LazyValues on line ~1384 above. - final Value v1 = this.eval(expr, c, s1, TLCState.Empty, EvalControl.Primed); + final Value v1 = this.eval(expr, c, s1, TLCState.Empty, EvalControl.Primed, cm); if (!v0.equals(v1)) { return null; } - return this.enabled(acts, s0, s1); - } catch (TLCRuntimeException | EvalException e) { - // see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor) - if (this.callStack != null) { this.callStack.freeze(); } - throw e; - } finally { - if (this.callStack != null) { this.callStack.pop(); } - } + return this.enabled(acts, s0, s1, cm); } /* This method determines if the action predicate is valid in (s0, s1). */ + @Override public final boolean isValid(Action act, TLCState s0, TLCState s1) { - Value val = this.eval(act.pred, act.con, s0, s1, EvalControl.Clear); + Value val = this.eval(act.pred, act.con, s0, s1, EvalControl.Clear, act.cm); if (!(val instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", act.pred.toString()}); } @@ -2948,17 +3207,20 @@ public class Tool } /* Returns true iff the predicate is valid in the state. */ + @Override public final boolean isValid(Action act, TLCState state) { return this.isValid(act, state, TLCState.Empty); } /* Returns true iff the predicate is valid in the state. */ + @Override public final boolean isValid(Action act) { return this.isValid(act, TLCState.Empty, TLCState.Empty); } + @Override public final boolean isValid(ExprNode expr) { - Value val = this.eval(expr, Context.Empty, TLCState.Empty); + IValue val = this.eval(expr, Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD); if (!(val instanceof BoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[]{"boolean", expr.toString()}); } @@ -2966,6 +3228,7 @@ public class Tool } /* Reconstruct the initial state whose fingerprint is fp. */ + @Override public final TLCStateInfo getState(final long fp) { class InitStateSelectorFunctor implements IStateFunctor { private final long fp; @@ -3017,6 +3280,7 @@ public class Tool * the stateNumber (relative to the given sinfo) and a pointer to * the predecessor. */ + @Override public final TLCStateInfo getState(long fp, TLCStateInfo sinfo) { final TLCStateInfo tlcStateInfo = getState(fp, sinfo.state); if (tlcStateInfo == null) { @@ -3029,6 +3293,7 @@ public class Tool } /* Reconstruct the next state of state s whose fingerprint is fp. */ + @Override public final TLCStateInfo getState(long fp, TLCState s) { IdThread.setCurrentState(s); for (int i = 0; i < this.actions.length; i++) { @@ -3038,6 +3303,7 @@ public class Tool TLCState state = nextStates.elementAt(j); long nfp = state.fingerPrint(); if (fp == nfp) { + state.setPredecessor(s); return new TLCStateInfo(state, curAction.getLocation()); } } @@ -3046,6 +3312,7 @@ public class Tool } /* Reconstruct the info for s1. */ + @Override public final TLCStateInfo getState(TLCState s1, TLCState s) { IdThread.setCurrentState(s); for (int i = 0; i < this.actions.length; i++) { @@ -3054,6 +3321,7 @@ public class Tool for (int j = 0; j < nextStates.size(); j++) { TLCState state = nextStates.elementAt(j); if (s1.equals(state)) { + state.setPredecessor(s); return new TLCStateInfo(state, curAction.getLocation()); } } @@ -3062,10 +3330,11 @@ public class Tool } /* Return the set of all permutations under the symmetry assumption. */ - public final MVPerm[] getSymmetryPerms() { + @Override + public final IMVPerm[] getSymmetryPerms() { final String name = this.config.getSymmetry(); if (name.length() == 0) { return null; } - final Object symm = this.defns.get(name); + final Object symm = this.unprocessedDefns.get(name); if (symm == null) { Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "symmetry function", name}); } @@ -3074,43 +3343,51 @@ public class Tool } // This calls tlc2.module.TLC.Permutations(Value) and returns a Value of |fcns| // = n! where n is the capacity of the symmetry set. - final Value fcns = this.eval(((OpDefNode)symm).getBody(), Context.Empty, TLCState.Empty); + final IValue fcns = this.eval(((OpDefNode)symm).getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD); if (!(fcns instanceof Enumerable)) { Assert.fail("The symmetry operator must specify a set of functions."); } - return MVPerm.permutationSubgroup((Enumerable) fcns); + return MVPerms.permutationSubgroup((Enumerable) fcns); } - public boolean hasSymmetry() { + @Override + public final boolean hasSymmetry() { if (this.config == null) { return false; } final String name = this.config.getSymmetry(); return name.length() > 0; } + @Override + public final Context getFcnContext(IFcnLambdaValue fcn, ExprOrOpArgNode[] args, + Context c, TLCState s0, TLCState s1, + final int control) { + return getFcnContext(fcn, args, c, s0, s1, control, CostModel.DO_NOT_RECORD); + } - public final Context getFcnContext(FcnLambdaValue fcn, ExprOrOpArgNode[] args, + @Override + public final Context getFcnContext(IFcnLambdaValue fcn, ExprOrOpArgNode[] args, Context c, TLCState s0, TLCState s1, - final int control) { - Context fcon = fcn.con; - int plen = fcn.params.length(); - FormalParamNode[][] formals = fcn.params.formals; - Value[] domains = fcn.params.domains; - boolean[] isTuples = fcn.params.isTuples; - Value argVal = this.eval(args[1], c, s0, s1, control); + final int control, CostModel cm) { + Context fcon = fcn.getCon(); + int plen = fcn.getParams().length(); + FormalParamNode[][] formals = fcn.getParams().getFormals(); + Value[] domains = (Value[]) fcn.getParams().getDomains(); + boolean[] isTuples = fcn.getParams().isTuples(); + Value argVal = this.eval(args[1], c, s0, s1, control, cm); if (plen == 1) { if (!domains[0].member(argVal)) { - Assert.fail("In applying the function\n" + Value.ppr(fcn.toString()) + - ",\nthe first argument is:\n" + Value.ppr(argVal.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(fcn.toString()) + + ",\nthe first argument is:\n" + Values.ppr(argVal.toString()) + "which is not in its domain.\n" + args[0]); } if (isTuples[0]) { FormalParamNode[] ids = formals[0]; - TupleValue tv = TupleValue.convert(argVal); + TupleValue tv = (TupleValue) argVal.toTuple(); if (tv == null || argVal.size() != ids.length) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe argument is:\n" + Value.ppr(argVal.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe argument is:\n" + Values.ppr(argVal.toString()) + "which does not match its formal parameter.\n" + args[0]); } Value[] elems = tv.elems; @@ -3123,7 +3400,7 @@ public class Tool } } else { - TupleValue tv = TupleValue.convert(argVal); + TupleValue tv = (TupleValue) argVal.toTuple(); if (tv == null) { Assert.fail("Attempted to apply a function to an argument not in its" + " domain.\n" + args[0]); @@ -3135,16 +3412,16 @@ public class Tool Value domain = domains[i]; if (isTuples[i]) { if (!domain.member(elems[argn])) { - Assert.fail("In applying the function\n" + Value.ppr(fcn.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(fcn.toString()) + ",\nthe argument number " + (argn+1) + " is:\n" + - Value.ppr(elems[argn].toString()) + + Values.ppr(elems[argn].toString()) + "\nwhich is not in its domain.\n" + args[0]); } - TupleValue tv1 = TupleValue.convert(elems[argn++]); + TupleValue tv1 = (TupleValue) elems[argn++].toTuple(); if (tv1 == null || tv1.size() != ids.length) { - Assert.fail("In applying the function\n" + Value.ppr(fcn.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(fcn.toString()) + ",\nthe argument number " + argn + " is:\n" + - Value.ppr(elems[argn-1].toString()) + + Values.ppr(elems[argn-1].toString()) + "which does not match its formal parameter.\n" + args[0]); } Value[] avals = tv1.elems; @@ -3155,9 +3432,9 @@ public class Tool else { for (int j = 0; j < ids.length; j++) { if (!domain.member(elems[argn])) { - Assert.fail("In applying the function\n" + Value.ppr(fcn.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(fcn.toString()) + ",\nthe argument number " + (argn+1) + " is:\n" + - Value.ppr(elems[argn].toString()) + + Values.ppr(elems[argn].toString()) + "which is not in its domain.\n" + args[0]); } fcon = fcon.cons(ids[j], elems[argn++]); @@ -3168,9 +3445,15 @@ public class Tool return fcon; } + @Override + public final IContextEnumerator contexts(OpApplNode appl, Context c, TLCState s0, + TLCState s1, final int control) { + return contexts(appl, c, s0, s1, control, CostModel.DO_NOT_RECORD); + } + /* A context enumerator for an operator application. */ public final ContextEnumerator contexts(OpApplNode appl, Context c, TLCState s0, - TLCState s1, final int control) { + TLCState s1, final int control, CostModel cm) { FormalParamNode[][] formals = appl.getBdedQuantSymbolLists(); boolean[] isTuples = appl.isBdedQuantATuple(); ExprNode[] domains = appl.getBdedQuantBounds(); @@ -3184,10 +3467,10 @@ public class Tool ValueEnumeration[] enums = new ValueEnumeration[alen]; int idx = 0; for (int i = 0; i < flen; i++) { - Value boundSet = this.eval(domains[i], c, s0, s1, control); + Value boundSet = this.eval(domains[i], c, s0, s1, control, cm); if (!(boundSet instanceof Enumerable)) { Assert.fail("TLC encountered a non-enumerable quantifier bound\n" + - Value.ppr(boundSet.toString()) + ".\n" + domains[i]); + Values.ppr(boundSet.toString()) + ".\n" + domains[i]); } FormalParamNode[] farg = formals[i]; if (isTuples[i]) { @@ -3203,116 +3486,4 @@ public class Tool } return new ContextEnumerator(vars, enums, c); } - - /** - * This method converts every definition that is constant into TLC - * value. By doing this, TLC avoids evaluating the same expression - * multiple times. - * - * The method runs for every module in the module tables. - * - * Modified by LL on 23 July 2013 so it is not run for modules that are - * instantiated and have parameters (CONSTANT or VARIABLE declarations) - */ - private void processConstantDefns() { - ModuleNode[] mods = this.moduleTbl.getModuleNodes(); - for (int i = 0; i < mods.length; i++) { - if ( (! mods[i].isInstantiated()) - || ( (mods[i].getConstantDecls().length == 0) - && (mods[i].getVariableDecls().length == 0) ) ) { - this.processConstantDefns(mods[i]); - } - } - } - - /** - * Converts the constant definitions in the corresponding value for the - * module -- that is, it "converts" (which seems to mean calling deepNormalize) - * the values substituted for the declared constants. On 17 Mar 2012 it was - * modified by LL to evaluate the OpDefNode when a defined operator is substituted - * for an ordinary declared constant (not a declared operator constant). Without this - * evaluation, the definition gets re-evaluated every time TLC evaluates the declared - * constant. LL also added a check that an operator substituted for the declared - * constant also has the correct arity. - * - * @param mod the module to run on - */ - private void processConstantDefns(ModuleNode mod) { - - // run for constant definitions - OpDeclNode[] consts = mod.getConstantDecls(); - for (int i = 0; i < consts.length; i++) { - Object val = consts[i].getToolObject(TLCGlobals.ToolId); - if (val != null && val instanceof Value) { - ((Value)val).deepNormalize(); - // System.err.println(consts[i].getName() + ": " + val); - } // The following else clause was added by LL on 17 March 2012. - else if (val != null && val instanceof OpDefNode) { - OpDefNode opDef = (OpDefNode) val; - // The following check logically belongs in Spec.processSpec, but it's not there. - // So, LL just added it here. This error cannot occur when running TLC from - // the Toolbox. - Assert.check(opDef.getArity() == consts[i].getArity(), - EC.TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS, - new String[] {consts[i].getName().toString(), opDef.getName().toString()}); - - if (opDef.getArity() == 0) { - try { - Value defVal = this.eval(opDef.getBody(), Context.Empty, TLCState.Empty); - defVal.deepNormalize(); - consts[i].setToolObject(TLCGlobals.ToolId, defVal); - } catch (Assert.TLCRuntimeException e) { - Assert.fail(EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT, - new String[] { consts[i].getName().toString(), opDef.getName().toString() }); - } - } - } - } - - // run for constant operator definitions - OpDefNode[] opDefs = mod.getOpDefs(); - for (int i = 0; i < opDefs.length; i++) { - OpDefNode opDef = opDefs[i]; - - // The following variable evaluate and its value added by LL on 24 July 2013 - // to prevent pre-evaluation of a definition from an EXTENDS of a module that - // is also instantiated. - ModuleNode moduleNode = opDef.getOriginallyDefinedInModuleNode() ; - boolean evaluate = (moduleNode == null) - || (! moduleNode.isInstantiated()) - || ( (moduleNode.getConstantDecls().length == 0) - && (moduleNode.getVariableDecls().length == 0) ) ; - - if (evaluate && opDef.getArity() == 0) { - Object realDef = this.lookup(opDef, Context.Empty, false); - if (realDef instanceof OpDefNode) { - opDef = (OpDefNode)realDef; - if (this.getLevelBound(opDef.getBody(), Context.Empty) == 0) { - try { - UniqueString opName = opDef.getName(); - // System.err.println(opName); - Value val = this.eval(opDef.getBody(), Context.Empty, TLCState.Empty); - val.deepNormalize(); - // System.err.println(opName + ": " + val); - opDef.setToolObject(TLCGlobals.ToolId, val); - Object def = this.defns.get(opName); - if (def == opDef) { - this.defns.put(opName, val); - } - } - catch (Throwable e) { - // Assert.printStack(e); - } - } - } - } - } - - // run for all inner modules - ModuleNode[] imods = mod.getInnerModules(); - for (int i = 0; i < imods.length; i++) { - this.processConstantDefns(imods[i]); - } - } - } diff --git a/tlatools/src/tlc2/tool/liveness/AbstractDiskGraph.java b/tlatools/src/tlc2/tool/liveness/AbstractDiskGraph.java index 151d0599f79d32e55086f04318fd80e286d084ef..c45d7af348b208b14a52eabdb664061fe67c9785 100644 --- a/tlatools/src/tlc2/tool/liveness/AbstractDiskGraph.java +++ b/tlatools/src/tlc2/tool/liveness/AbstractDiskGraph.java @@ -434,12 +434,42 @@ public abstract class AbstractDiskGraph { * Copy&Paste output "digraph DiskGraph {...} to a file called graphviz.txt * and call something similar to: 'dot -T svg graphviz.txt -o * "Graphviz.svg"'. It obviously needs Graphviz (http://www.graphviz.org). - * - * @param slen Length of state checks - * @param alen Length of action checks */ - public abstract String toDotViz(final int slen, final int alen); + public abstract String toDotViz(final OrderOfSolution oos); + + protected String toDotVizLegend(final OrderOfSolution oos) { + final StringBuffer sb = new StringBuffer(); + sb.append("subgraph cluster_legend {"); + sb.append("graph[style=bold];"); + sb.append("label = \"PossibleErrorModel\" style=\"solid\"\n"); + sb.append("node [ labeljust=\"l\",shape=record ]\n"); + + // State checks + int i = 1; + LiveExprNode[] checkState = oos.getCheckState(); + for (LiveExprNode liveExprNode : checkState) { + sb.append(String.format("S%s [label=\"S%s: %s\"]", i, i++, node2dot(liveExprNode))); + sb.append("\n"); + } + // Actions checks + i = 1; + checkState = oos.getCheckAction(); + for (LiveExprNode liveExprNode : checkState) { + sb.append(String.format("A%s [label=\"A%s: %s\"]", i, i++, node2dot(liveExprNode))); + sb.append("\n"); + } + + sb.append("}"); + return sb.toString(); + } + + protected static String node2dot(final LiveExprNode node) { + // Replace "\" with "\\" and """ with "\"". Replace "<" and ">" with "\<" and "\>". + return node.toString().replace("\\", "\\\\").replace("\"", "\\\"").replace("<", "\\<").replace(">", "\\>").trim() + .replace("\n", "\\l"); // Do not remove remaining (i.e. no dangling/leading) "\n". + } + /** * Only useful for debugging. * @@ -450,21 +480,21 @@ public abstract class AbstractDiskGraph { * the installation instructions at * https://github.com/abstratt/eclipsegraphviz * - * @param slen + * @param oos * Length of state checks * @param alen * Length of action checks * @param file * Destination */ - public final void writeDotViz(final int slen, final int alen, final File file) { + public final void writeDotViz(final OrderOfSolution oos, final File file) { this.createCache(); try { final BufferedWriter bwr = new BufferedWriter(new FileWriter(file)); // write contents of StringBuffer to a file - bwr.write(toDotViz(slen, alen)); + bwr.write(toDotViz(oos)); // flush the stream bwr.flush(); diff --git a/tlatools/src/tlc2/tool/liveness/AddAndCheckLiveCheck.java b/tlatools/src/tlc2/tool/liveness/AddAndCheckLiveCheck.java index afd11858d68d50233b33d66cddf4339bb752d522..7442f798fbc92e0da0d77f4d30863f4ef49ee09f 100644 --- a/tlatools/src/tlc2/tool/liveness/AddAndCheckLiveCheck.java +++ b/tlatools/src/tlc2/tool/liveness/AddAndCheckLiveCheck.java @@ -30,9 +30,8 @@ import java.io.IOException; import tlc2.output.EC; import tlc2.output.MP; -import tlc2.tool.Action; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.tool.Worker; import tlc2.util.SetOfStates; import tlc2.util.statistics.IBucketStatistics; @@ -49,8 +48,8 @@ import tlc2.util.statistics.IBucketStatistics; */ public class AddAndCheckLiveCheck extends LiveCheck { - public AddAndCheckLiveCheck(Tool tool, Action[] actions, String metadir, IBucketStatistics stats) throws IOException { - super(tool, actions, metadir, stats); + public AddAndCheckLiveCheck(ITool tool, String metadir, IBucketStatistics stats) throws IOException { + super(tool, metadir, stats); MP.printWarning(EC.UNIT_TEST, new String[]{ "!!!WARNING: TLC is running in inefficient unit testing mode!!!", ""} ); } @@ -58,10 +57,10 @@ public class AddAndCheckLiveCheck extends LiveCheck { * @see tlc2.tool.liveness.LiveCheck#addInitState(tlc2.tool.TLCState, long) */ @Override - public synchronized void addInitState(TLCState state, long stateFP) { - super.addInitState(state, stateFP); + public synchronized void addInitState(ITool tool, TLCState state, long stateFP) { + super.addInitState(tool, state, stateFP); try { - check0(false); + check0(tool, false); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { @@ -73,10 +72,10 @@ public class AddAndCheckLiveCheck extends LiveCheck { * @see tlc2.tool.liveness.LiveCheck#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates) */ @Override - public synchronized void addNextState(TLCState s0, long fp0, SetOfStates nextStates) throws IOException { - super.addNextState(s0, fp0, nextStates); + public synchronized void addNextState(ITool tool, TLCState s0, long fp0, SetOfStates nextStates) throws IOException { + super.addNextState(tool, s0, fp0, nextStates); try { - check0(false); + check0(tool, false); } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/tlatools/src/tlc2/tool/liveness/BEGraph.java b/tlatools/src/tlc2/tool/liveness/BEGraph.java index 3a73d7fbb27c9b212c9e63d4fcda0a2270094f1b..ffe148cdecfb5b81db809ebf1b06c9ef5f64ca41 100644 --- a/tlatools/src/tlc2/tool/liveness/BEGraph.java +++ b/tlatools/src/tlc2/tool/liveness/BEGraph.java @@ -15,12 +15,12 @@ public class BEGraph { /** * BEGraph represents the behaviour graph. */ - public Vect initNodes; + public Vect<BEGraphNode> initNodes; public String metadir; public NodeTable allNodes; public BEGraph(String metadir, boolean isBT) { - this.initNodes = new Vect(); + this.initNodes = new Vect<>(); this.metadir = metadir; this.allNodes = new NodeTable(127, isBT); } @@ -95,7 +95,7 @@ public class BEGraph { } } // Get the path following parent pointers: - Vect path = new Vect(); + Vect<BEGraphNode> path = new Vect<>(); BEGraphNode curNode = end; while (curNode != null) { path.addElement(curNode); diff --git a/tlatools/src/tlc2/tool/liveness/DiskGraph.java b/tlatools/src/tlc2/tool/liveness/DiskGraph.java index be8f5ba689c83d279b4ee6805ef3670e27d82b21..2db8224739a605f772c2d54fd59f5cabb845ca24 100644 --- a/tlatools/src/tlc2/tool/liveness/DiskGraph.java +++ b/tlatools/src/tlc2/tool/liveness/DiskGraph.java @@ -174,10 +174,11 @@ public class DiskGraph extends AbstractDiskGraph { } /* (non-Javadoc) - * @see tlc2.tool.liveness.AbstractDiskGraph#toDotViz(int, int) + * @see tlc2.tool.liveness.AbstractDiskGraph#toDotViz(tlc2.tool.liveness.OrderOfSolution) */ - public final String toDotViz(final int slen, final int alen) { - + public final String toDotViz(final OrderOfSolution oos) { + final int slen = oos.getCheckState().length; + final int alen = oos.getCheckAction().length; // The following code relies on gnodes not being null, thus safeguard // against accidental invocations. // Essentially one has to wrap the toDotViz call with @@ -192,6 +193,9 @@ public class DiskGraph extends AbstractDiskGraph { sb.append("digraph DiskGraph {\n"); sb.append("nodesep = 0.7\n"); sb.append("rankdir=LR;\n"); // Left to right rather than top to bottom + sb.append(toDotVizLegend(oos)); + sb.append("subgraph cluster_graph {\n"); + sb.append("color=\"white\";\n"); // no border. long nodePtr = this.nodeRAF.getFilePointer(); long nodePtrPtr = this.nodePtrRAF.getFilePointer(); long len = this.nodePtrRAF.length(); @@ -203,7 +207,7 @@ public class DiskGraph extends AbstractDiskGraph { GraphNode gnode = this.getNode(fp, tidx, loc); sb.append(gnode.toDotViz(isInitState(gnode), false, slen, alen)); } - sb.append("}"); + sb.append("}}"); this.nodeRAF.seek(nodePtr); this.nodePtrRAF.seek(nodePtrPtr); } catch (IOException e) { diff --git a/tlatools/src/tlc2/tool/liveness/GraphNode.java b/tlatools/src/tlc2/tool/liveness/GraphNode.java index 77134867d4d661aeaa71a5a8710b794382efb19f..1c0371f4464bb74a640b15331a3531e5cc002000 100644 --- a/tlatools/src/tlc2/tool/liveness/GraphNode.java +++ b/tlatools/src/tlc2/tool/liveness/GraphNode.java @@ -434,7 +434,17 @@ public class GraphNode extends AbstractGraphNode { // label iff the first 6 (+2) chars of their fingerprint match. However // the graph will still contain all nodes regardless of the label // collision due to id. - final String label = Long.toString(this.stateFP).substring(0, 6) + (hasTableau ? "." + this.tindex : ""); + String label = Long.toString(this.stateFP).substring(0, 6) + (hasTableau ? "." + this.tindex : ""); + if (slen > 0) { + label += "\n"; + for (int i = 0; i < slen; i++) { + if (getCheckState(i)) { + label += "t"; + } else { + label += "f"; + } + } + } final StringBuffer buf = new StringBuffer(); if (isInitState) { buf.append("\"" + id + "\" [style = filled][label = \"" + label + "\"]\n"); // node's label diff --git a/tlatools/src/tlc2/tool/liveness/ILiveCheck.java b/tlatools/src/tlc2/tool/liveness/ILiveCheck.java index 2c37303b8cfaaf8a289e1488efd37bfca6312a7a..688ad737a155a213b5e0e65621cf5baf0fa92743 100644 --- a/tlatools/src/tlc2/tool/liveness/ILiveCheck.java +++ b/tlatools/src/tlc2/tool/liveness/ILiveCheck.java @@ -27,9 +27,9 @@ package tlc2.tool.liveness; import java.io.IOException; +import tlc2.tool.ITool; import tlc2.tool.StateVec; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.SetOfStates; import tlc2.util.statistics.IBucketStatistics; @@ -39,40 +39,40 @@ public interface ILiveCheck { * This method records that state is an initial state in the behavior graph. * It is called when a new initial state is generated. */ - void addInitState(TLCState state, long stateFP); + void addInitState(ITool tool, TLCState state, long stateFP); /** * This method adds new nodes into the behavior graph induced by s0. It is * called after the successors of s0 are computed. */ - void addNextState(TLCState s0, long fp0, SetOfStates nextStates) throws IOException; + void addNextState(ITool tool, TLCState s0, long fp0, SetOfStates nextStates) throws IOException; /** - * true iff a call to {@link ILiveCheck#check(boolean)} would indeed result in liveness checking. + * true iff a call to {@link ILiveCheck#check(ITool, boolean)} would indeed result in liveness checking. */ boolean doLiveCheck(); /** * Check liveness properties for the current (potentially partial) state graph. Returns * true iff it finds no errors. - * * @param forceCheck * Always checks liveness if true, otherwise heuristics about the * partial graph are taken into account if it is worthwhile to * check liveness. - * @return true iff it finds no errors or if liveness has not been checked - * on the partial graph because it was deemed worthless. + * + * @return <code>EC.NO_ERROR</code> iff it finds no errors or if liveness has not been checked + * on the partial graph because it was deemed worthless. Otherwise an EC. */ - boolean check(boolean forceCheck) throws Exception; + int check(ITool tool, boolean forceCheck) throws Exception; /** * No states can be added with add*State once finalCheck has been called. * * @see ILiveCheck#check() - * @return + * @return an error code, or <code>EC.NO_ERROR</code> on success * @throws Exception */ - boolean finalCheck() throws Exception; + int finalCheck(ITool tool) throws Exception; /* simulation mode */ @@ -89,19 +89,17 @@ public interface ILiveCheck { * is done as part of checkTrace. * <p> * checkTrace can be called multiple times until ILiveCheck has been closed (see close()). - * * @param trace + * * @throws IOException * @throws InterruptedException */ - void checkTrace(final StateVec trace) throws IOException, InterruptedException; + void checkTrace(ITool tool, final StateVec trace) throws IOException, InterruptedException; /* auxiliary methods */ String getMetaDir(); - Tool getTool(); - IBucketStatistics getOutDegreeStatistics(); ILiveChecker getChecker(int idx); diff --git a/tlatools/src/tlc2/tool/liveness/ILiveChecker.java b/tlatools/src/tlc2/tool/liveness/ILiveChecker.java index 7d4d0311c9978a62608a40f8677fbd9198721ee1..f4b84ca16fdeafca24932bdcf3ea265ae793869f 100644 --- a/tlatools/src/tlc2/tool/liveness/ILiveChecker.java +++ b/tlatools/src/tlc2/tool/liveness/ILiveChecker.java @@ -28,6 +28,7 @@ package tlc2.tool.liveness; import java.io.IOException; +import tlc2.tool.ITool; import tlc2.tool.TLCState; import tlc2.util.BitVector; import tlc2.util.SetOfStates; @@ -38,14 +39,14 @@ public interface ILiveChecker { * This method records that state is an initial state in the behavior graph. * It is called when a new initial state is generated. */ - void addInitState(TLCState state, long stateFP); + void addInitState(ITool tool, TLCState state, long stateFP); /** * This method adds new nodes into the behavior graph induced by s0. It is * called after the successors of s0 are computed. */ - void addNextState(TLCState s0, long fp0, SetOfStates nextStates, BitVector checkActionResults, - boolean[] checkStateResults) throws IOException; + void addNextState(ITool tool, TLCState s0, long fp0, SetOfStates nextStates, + BitVector checkActionResults, boolean[] checkStateResults) throws IOException; AbstractDiskGraph getDiskGraph(); diff --git a/tlatools/src/tlc2/tool/liveness/LNAction.java b/tlatools/src/tlc2/tool/liveness/LNAction.java index 99dbb03ab6c41aafeab229daec2389117b4c8283..4f8cc8ee220be367044d211c402a66d79cf1f840 100644 --- a/tlatools/src/tlc2/tool/liveness/LNAction.java +++ b/tlatools/src/tlc2/tool/liveness/LNAction.java @@ -8,11 +8,11 @@ package tlc2.tool.liveness; import tla2sany.semantic.ExprNode; import tlc2.output.EC; import tlc2.tool.EvalControl; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.Context; -import tlc2.value.BoolValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; +import tlc2.value.IValue; import util.Assert; import util.WrongInvocationException; @@ -59,10 +59,10 @@ public class LNAction extends LiveExprNode { return true; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { if (this.subscript != null) { - Value v1 = tool.eval(this.subscript, con, s1, TLCState.Empty, EvalControl.Clear); - Value v2 = tool.eval(this.subscript, con, s2, null, EvalControl.Clear); + IValue v1 = tool.eval(this.subscript, con, s1, TLCState.Empty, EvalControl.Clear); + IValue v2 = tool.eval(this.subscript, con, s2, null, EvalControl.Clear); boolean isStut = v1.equals(v2); if (this.isBox) { if (isStut) { @@ -74,11 +74,11 @@ public class LNAction extends LiveExprNode { } } } - Value val = tool.eval(this.body, con, s1, s2, EvalControl.Clear); - if (!(val instanceof BoolValue)) { + IValue val = tool.eval(this.body, con, s1, s2, EvalControl.Clear); + if (!(val instanceof IBoolValue)) { Assert.fail(EC.TLC_LIVE_ENCOUNTERED_NONBOOL_PREDICATE); } - return ((BoolValue) val).val; + return ((IBoolValue) val).getVal(); } public final void toString(StringBuffer sb, String padding) { diff --git a/tlatools/src/tlc2/tool/liveness/LNAll.java b/tlatools/src/tlc2/tool/liveness/LNAll.java index 40c86b77faeab571300745a9e03ea3b72e058771..9223226cb472b296f7df4fd8985f37efd2ddf823 100644 --- a/tlatools/src/tlc2/tool/liveness/LNAll.java +++ b/tlatools/src/tlc2/tool/liveness/LNAll.java @@ -6,8 +6,8 @@ package tlc2.tool.liveness; import tlc2.output.EC; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import util.Assert; /** @@ -39,7 +39,7 @@ class LNAll extends LiveExprNode { return this.body.containAction(); } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { Assert.fail(EC.TLC_LIVE_CANNOT_EVAL_FORMULA, ALWAYS); return false; // make compiler happy } diff --git a/tlatools/src/tlc2/tool/liveness/LNBool.java b/tlatools/src/tlc2/tool/liveness/LNBool.java index b3d5264f3c7d4a439646d0ddc71cdfccb46ccba6..399fbc27b78fc1b3c89f6a8e3018eca999ad0afe 100644 --- a/tlatools/src/tlc2/tool/liveness/LNBool.java +++ b/tlatools/src/tlc2/tool/liveness/LNBool.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; class LNBool extends LiveExprNode { public static final LNBool TRUE = new LNBool(true); @@ -18,7 +18,7 @@ class LNBool extends LiveExprNode { this.b = b; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { return this.b; } diff --git a/tlatools/src/tlc2/tool/liveness/LNConj.java b/tlatools/src/tlc2/tool/liveness/LNConj.java index 4a7b12ee4dcd3bc31f98218667884a953928fe9a..38f0309af3b8e078d27103740d761cdb4ff68279 100644 --- a/tlatools/src/tlc2/tool/liveness/LNConj.java +++ b/tlatools/src/tlc2/tool/liveness/LNConj.java @@ -5,28 +5,28 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.Vect; class LNConj extends LiveExprNode { - private final Vect conjs; // The conjuncts + private final Vect<LiveExprNode> conjs; // The conjuncts private int info; public LNConj(int size) { - this.conjs = new Vect(size); + this.conjs = new Vect<>(size); this.info = 0; } public LNConj(LiveExprNode n) { - this.conjs = new Vect(1); + this.conjs = new Vect<>(1); this.conjs.addElement(n); int level = n.getLevel(); this.info = n.containAction() ? level + 8 : level; } public LNConj(LiveExprNode n1, LiveExprNode n2) { - this.conjs = new Vect(2); + this.conjs = new Vect<>(2); this.conjs.addElement(n1); this.conjs.addElement(n2); boolean hasAct = n1.containAction() || n2.containAction(); @@ -34,7 +34,7 @@ class LNConj extends LiveExprNode { this.info = hasAct ? level + 8 : level; } - public LNConj(Vect conjs) { + public LNConj(Vect<LiveExprNode> conjs) { this.conjs = conjs; boolean hasAct = false; int level = 0; @@ -76,7 +76,7 @@ class LNConj extends LiveExprNode { return (this.info & 8) > 0; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { int sz = this.conjs.size(); for (int i = 0; i < sz; i++) { LiveExprNode item = (LiveExprNode) this.conjs.elementAt(i); @@ -171,7 +171,7 @@ class LNConj extends LiveExprNode { } // We now construct the cross product: - Vect nes = new Vect(count); + Vect<LiveExprNode> nes = new Vect<>(count); int total = 1; for (int i = 0; i < count; i++) { LiveExprNode elem = temp[i]; @@ -194,7 +194,7 @@ class LNConj extends LiveExprNode { return new LNConj(nes); } int nesSize = nes.size(); - Vect res = new Vect(total); + Vect<LiveExprNode> res = new Vect<>(total); for (int i = 0; i < total; i++) { res.addElement(new LNConj(nesSize)); } diff --git a/tlatools/src/tlc2/tool/liveness/LNDisj.java b/tlatools/src/tlc2/tool/liveness/LNDisj.java index cbf32ead1a3683110bd799e61f46750ff2819bf6..9a1a8843635c21e62c52ca049add1637a89e8144 100644 --- a/tlatools/src/tlc2/tool/liveness/LNDisj.java +++ b/tlatools/src/tlc2/tool/liveness/LNDisj.java @@ -5,28 +5,28 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.Vect; class LNDisj extends LiveExprNode { - private final Vect disjs; // The disjuncts + private final Vect<LiveExprNode> disjs; // The disjuncts private int info; public LNDisj(int size) { - this.disjs = new Vect(size); + this.disjs = new Vect<>(size); this.info = 0; } public LNDisj(LiveExprNode n) { - this.disjs = new Vect(1); + this.disjs = new Vect<>(1); this.disjs.addElement(n); int level = n.getLevel(); this.info = n.containAction() ? level + 8 : level; } public LNDisj(LiveExprNode n1, LiveExprNode n2) { - this.disjs = new Vect(2); + this.disjs = new Vect<>(2); this.disjs.addElement(n1); this.disjs.addElement(n2); boolean hasAct = n1.containAction() || n2.containAction(); @@ -34,7 +34,7 @@ class LNDisj extends LiveExprNode { this.info = hasAct ? level + 8 : level; } - public LNDisj(Vect disjs) { + public LNDisj(Vect<LiveExprNode> disjs) { this.disjs = disjs; boolean hasAct = false; int level = 0; @@ -76,7 +76,7 @@ class LNDisj extends LiveExprNode { return (this.info & 8) > 0; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { int sz = disjs.size(); for (int i = 0; i < sz; i++) { LiveExprNode item = (LiveExprNode) disjs.elementAt(i); diff --git a/tlatools/src/tlc2/tool/liveness/LNEven.java b/tlatools/src/tlc2/tool/liveness/LNEven.java index c08ded5e84a88ed8143891f4577d27776d373461..3967a7d47ef30dca6f8264c0ce6afc306b1af1bb 100644 --- a/tlatools/src/tlc2/tool/liveness/LNEven.java +++ b/tlatools/src/tlc2/tool/liveness/LNEven.java @@ -6,8 +6,8 @@ package tlc2.tool.liveness; import tlc2.output.EC; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import util.Assert; /** @@ -36,7 +36,7 @@ class LNEven extends LiveExprNode { return this.body.containAction(); } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { Assert.fail(EC.TLC_LIVE_CANNOT_EVAL_FORMULA, EVENTUALLY); return false; // make compiler happy } diff --git a/tlatools/src/tlc2/tool/liveness/LNNeg.java b/tlatools/src/tlc2/tool/liveness/LNNeg.java index 439023e73abb91c79bdb89bd1cafca4c91f46fed..0602b5e08999043835234798b1d74b003ca35cea 100644 --- a/tlatools/src/tlc2/tool/liveness/LNNeg.java +++ b/tlatools/src/tlc2/tool/liveness/LNNeg.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; public class LNNeg extends LiveExprNode { private final LiveExprNode body; @@ -27,7 +27,7 @@ public class LNNeg extends LiveExprNode { return this.body.containAction(); } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { return !this.body.eval(tool, s1, s2); } diff --git a/tlatools/src/tlc2/tool/liveness/LNNext.java b/tlatools/src/tlc2/tool/liveness/LNNext.java index ee09c5146d1c7516f494a25d3f8a161039a043e2..c15ee7002ad21ce46eb5f83fac1c37cbde3b1f30 100644 --- a/tlatools/src/tlc2/tool/liveness/LNNext.java +++ b/tlatools/src/tlc2/tool/liveness/LNNext.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; class LNNext extends LiveExprNode { private final LiveExprNode body; @@ -27,7 +27,7 @@ class LNNext extends LiveExprNode { return this.body.containAction(); } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { return this.body.eval(tool, s2, TLCState.Empty); } diff --git a/tlatools/src/tlc2/tool/liveness/LNState.java b/tlatools/src/tlc2/tool/liveness/LNState.java index 59f786a7c4d1c7bd46d5e29dbf2b4bb4e082515d..664bdb36070915d1ae7315360cf31ecd735288a0 100644 --- a/tlatools/src/tlc2/tool/liveness/LNState.java +++ b/tlatools/src/tlc2/tool/liveness/LNState.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.Context; abstract class LNState extends LiveExprNode { @@ -25,7 +25,7 @@ abstract class LNState extends LiveExprNode { return false; } - public final boolean eval(Tool tool, TLCState s) { + public final boolean eval(ITool tool, TLCState s) { return this.eval(tool, s, TLCState.Empty); } diff --git a/tlatools/src/tlc2/tool/liveness/LNStateAST.java b/tlatools/src/tlc2/tool/liveness/LNStateAST.java index c37e787ab93735f879068a6ddcb5ca92cc05d941..2618eb8dcfe1159b8c3e6101dd425c80462a2e2f 100644 --- a/tlatools/src/tlc2/tool/liveness/LNStateAST.java +++ b/tlatools/src/tlc2/tool/liveness/LNStateAST.java @@ -10,11 +10,11 @@ import tla2sany.semantic.ExprNode; import tla2sany.semantic.OpApplNode; import tla2sany.st.TreeNode; import tlc2.output.EC; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.Context; -import tlc2.value.BoolValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; +import tlc2.value.IValue; import util.Assert; /** @@ -35,12 +35,12 @@ class LNStateAST extends LNState { return this.body; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { - Value val = tool.eval(this.body, getContext(), s1); - if (!(val instanceof BoolValue)) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { + IValue val = tool.eval(this.body, getContext(), s1); + if (!(val instanceof IBoolValue)) { Assert.fail(EC.TLC_LIVE_STATE_PREDICATE_NON_BOOL); } - return ((BoolValue) val).val; + return ((IBoolValue) val).getVal(); } public final void toString(StringBuffer sb, String padding) { diff --git a/tlatools/src/tlc2/tool/liveness/LNStateEnabled.java b/tlatools/src/tlc2/tool/liveness/LNStateEnabled.java index b07b2275427fc737d62115d2f89b1373428726b1..3f75a50664ef91eccdf251d8300d7ef42ff6012e 100644 --- a/tlatools/src/tlc2/tool/liveness/LNStateEnabled.java +++ b/tlatools/src/tlc2/tool/liveness/LNStateEnabled.java @@ -9,10 +9,10 @@ import tla2sany.parser.SyntaxTreeNode; import tla2sany.semantic.ExprNode; import tla2sany.semantic.OpApplNode; import tla2sany.st.TreeNode; -import tlc2.tool.ActionItemList; +import tlc2.tool.IActionItemList; +import tlc2.tool.ITool; import tlc2.tool.TLCState; import tlc2.tool.TLCStateFun; -import tlc2.tool.Tool; import tlc2.util.Context; /** @@ -41,19 +41,19 @@ class LNStateEnabled extends LNState { this.isBox = isBox; } - public final boolean eval(Tool tool, TLCState s1, TLCState s2) { + public final boolean eval(ITool tool, TLCState s1, TLCState s2) { // Note that s2 is useless. if (this.isBox && this.subscript != null) { return true; } - ActionItemList acts = ActionItemList.Empty; TLCState sfun = TLCStateFun.Empty; Context c1 = Context.branch(getContext()); if (this.subscript != null) { - acts = acts.cons(this.subscript, c1, ActionItemList.CHANGED); + sfun = tool.enabled(this.pred, c1, s1, sfun, this.subscript, IActionItemList.CHANGED); + } else { + sfun = tool.enabled(this.pred, c1, s1, sfun); } - sfun = tool.enabled(this.pred, acts, c1, s1, sfun); return sfun != null; } diff --git a/tlatools/src/tlc2/tool/liveness/LiveCheck.java b/tlatools/src/tlc2/tool/liveness/LiveCheck.java index 342606f47caa504211d1ef21d44ffcae0e4e4212..a6387a7340509da3908d6cd8ef8ad65a1ec00a34 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveCheck.java +++ b/tlatools/src/tlc2/tool/liveness/LiveCheck.java @@ -16,10 +16,11 @@ import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.Action; import tlc2.tool.IStateFunctor; +import tlc2.tool.ITool; import tlc2.tool.ModelChecker; import tlc2.tool.StateVec; import tlc2.tool.TLCState; -import tlc2.tool.Tool; +import tlc2.tool.impl.Tool; import tlc2.util.BitVector; import tlc2.util.FP64; import tlc2.util.IStateWriter; @@ -33,35 +34,34 @@ import util.SimpleFilenameToStream; public class LiveCheck implements ILiveCheck { - private final Action[] actions; - private final Tool myTool; private final String metadir; private final IBucketStatistics outDegreeGraphStats; private final ILiveChecker[] checker; - public LiveCheck(Tool tool, Action[] acts, String mdir, IBucketStatistics bucketStatistics) throws IOException { - this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, new NoopStateWriter()); + public LiveCheck(ITool tool, String mdir, IBucketStatistics bucketStatistics) throws IOException { + this(tool, Liveness.processLiveness(tool), mdir, bucketStatistics, new NoopStateWriter()); } - public LiveCheck(Tool tool, Action[] acts, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { - this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, stateWriter); + public LiveCheck(ITool tool, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { + this(tool, Liveness.processLiveness(tool), mdir, bucketStatistics, stateWriter); } - public LiveCheck(Tool tool, Action[] acts, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics) throws IOException { - this(tool, acts, solutions, mdir, bucketStatistics, new NoopLivenessStateWriter()); + public LiveCheck(ITool tool, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics) throws IOException { + this(tool, solutions, mdir, bucketStatistics, new NoopLivenessStateWriter()); } - public LiveCheck(Tool tool, Action[] acts, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { - myTool = tool; - actions = acts; + public LiveCheck(ITool tool, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { metadir = mdir; outDegreeGraphStats = bucketStatistics; checker = new ILiveChecker[solutions.length]; for (int soln = 0; soln < solutions.length; soln++) { + final ILivenessStateWriter writer = stateWriter.isNoop() || !stateWriter.isDot() + ? new NoopLivenessStateWriter() + : new DotLivenessStateWriter(stateWriter); if (!solutions[soln].hasTableau()) { - checker[soln] = new LiveChecker(solutions[soln], soln, bucketStatistics, stateWriter.isNoop() ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(stateWriter)); + checker[soln] = new LiveChecker(solutions[soln], soln, bucketStatistics, writer); } else { - checker[soln] = new TableauLiveChecker(solutions[soln], soln, bucketStatistics, stateWriter.isNoop() ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(stateWriter)); + checker[soln] = new TableauLiveChecker(solutions[soln], soln, bucketStatistics, writer); } } } @@ -69,16 +69,16 @@ public class LiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#addInitState(tlc2.tool.TLCState, long) */ - public void addInitState(TLCState state, long stateFP) { + public void addInitState(ITool tool, TLCState state, long stateFP) { for (int i = 0; i < checker.length; i++) { - checker[i].addInitState(state, stateFP); + checker[i].addInitState(tool, state, stateFP); } } /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates) */ - public void addNextState(TLCState s0, long fp0, SetOfStates nextStates) throws IOException { + public void addNextState(ITool tool, TLCState s0, long fp0, SetOfStates nextStates) throws IOException { for (int i = 0; i < checker.length; i++) { final ILiveChecker check = checker[i]; final OrderOfSolution oos = check.getSolution(); @@ -104,14 +104,14 @@ public class LiveCheck implements ILiveCheck { final BitVector checkActionResults = new BitVector(alen * nextStates.size()); for (int sidx = 0; sidx < nextStates.size(); sidx++) { final TLCState s1 = nextStates.next(); - oos.checkAction(s0, s1, checkActionResults, alen * sidx); + oos.checkAction(tool, s0, s1, checkActionResults, alen * sidx); } nextStates.resetNext(); - check.addNextState(s0, fp0, nextStates, checkActionResults, oos.checkState(s0)); + check.addNextState(tool, s0, fp0, nextStates, checkActionResults, oos.checkState(tool, s0)); // Write the content of the current graph to a file in GraphViz // format. Useful when debugging! -// check.getDiskGraph().writeDotViz(oos.getCheckState().length, alen, new java.io.File( +// check.getDiskGraph().writeDotViz(oos, new java.io.File( // metadir + java.io.File.separator + "dgraph_" + i + "_" + System.currentTimeMillis() + ".dot")); } } @@ -150,17 +150,15 @@ public class LiveCheck implements ILiveCheck { return false; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#check(boolean) - */ - public boolean check(boolean forceCheck) throws Exception { + @Override + public int check(ITool tool, boolean forceCheck) throws Exception { if (forceCheck) { - return check0(false); + return check0(tool, false); } if (!TLCGlobals.doLiveness()) { // The user requested to only check liveness once, on the complete // state graph. - return true; + return EC.NO_ERROR; } for (int i = 0; i < checker.length; i++) { // see note in doLiveCheck() above! @@ -169,19 +167,17 @@ public class LiveCheck implements ILiveCheck { final long sizeCurrently = diskGraph.size(); final double delta = (sizeCurrently - sizeAtLastCheck) / (sizeAtLastCheck * 1.d); if (delta > TLCGlobals.livenessThreshold) { - return check0(false); + return check0(tool, false); } } - return true; + return EC.NO_ERROR; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#finalCheck() - */ - public boolean finalCheck() throws InterruptedException, IOException { + @Override + public int finalCheck(ITool tool) throws InterruptedException, IOException { // Do *not* re-create the nodePtrTable after the check which takes a // while for larger disk graphs. - return check0(true); + return check0(tool, true); } /** @@ -190,7 +186,7 @@ public class LiveCheck implements ILiveCheck { * liveness check. If this is the final/last check, it's pointless * to re-create the nodePtrTable. */ - protected boolean check0(final boolean finalCheck) throws InterruptedException, IOException { + protected int check0(final ITool tool, final boolean finalCheck) throws InterruptedException, IOException { final long startTime = System.currentTimeMillis(); // Sum up the number of nodes in all disk graphs to indicate the amount @@ -223,12 +219,12 @@ public class LiveCheck implements ILiveCheck { int wNum = Math.min(slen, TLCGlobals.getNumWorkers()); if (wNum == 1) { - LiveWorker worker = new LiveWorker(0, 1, this, queue, finalCheck); + LiveWorker worker = new LiveWorker(tool, 0, 1, this, queue, finalCheck); worker.run(); } else { final LiveWorker[] workers = new LiveWorker[wNum]; for (int i = 0; i < wNum; i++) { - workers[i] = new LiveWorker(i, wNum, this, queue, finalCheck); + workers[i] = new LiveWorker(tool, i, wNum, this, queue, finalCheck); workers[i].start(); } for (int i = 0; i < wNum; i++) { @@ -238,7 +234,7 @@ public class LiveCheck implements ILiveCheck { if (LiveWorker.hasErrFound()) { MP.printMessage(EC.TLC_CHECKING_TEMPORAL_PROPS_END, TLC.convertRuntimeToHumanReadable(System.currentTimeMillis() - startTime)); - return false; + return EC.TLC_TEMPORAL_PROPERTY_VIOLATED; } // Reset after checking unless it's the final check: @@ -249,15 +245,15 @@ public class LiveCheck implements ILiveCheck { } MP.printMessage(EC.TLC_CHECKING_TEMPORAL_PROPS_END, TLC.convertRuntimeToHumanReadable(System.currentTimeMillis() - startTime)); - return true; + return EC.NO_ERROR; } /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#checkTrace(tlc2.tool.StateVec) */ - public void checkTrace(final StateVec stateTrace) throws InterruptedException, IOException { + public void checkTrace(ITool tool, final StateVec stateTrace) throws InterruptedException, IOException { // Add the first state to the LiveCheck as the current init state - addInitState(stateTrace.elementAt(0), stateTrace.elementAt(0).fingerPrint()); + addInitState(tool, stateTrace.elementAt(0), stateTrace.elementAt(0).fingerPrint()); // Add the remaining states... final SetOfStates successors = new SetOfStates(stateTrace.size() * 2); @@ -278,16 +274,17 @@ public class LiveCheck implements ILiveCheck { // Add the successor in the trace final TLCState successor = stateTrace.elementAt(i + 1); successors.put(successor); - addNextState(tlcState, fingerPrint, successors); + addNextState(tool, tlcState, fingerPrint, successors); } // Add last state in trace for which *no* successors have been generated final TLCState lastState = stateTrace.elementAt(stateTrace.size() - 1); - addNextState(lastState, lastState.fingerPrint(), new SetOfStates(0)); + addNextState(tool, lastState, lastState.fingerPrint(), new SetOfStates(0)); // Do *not* re-create the nodePtrTbl when it is thrown away anyway. - if (!check0(true)) { - throw new LiveException(); + final int result = check0(tool, true); + if (result != EC.NO_ERROR) { + throw new LiveException(result); } // We are done with the current subsequence of the behavior. Reset LiveCheck @@ -302,13 +299,6 @@ public class LiveCheck implements ILiveCheck { return metadir; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#getTool() - */ - public Tool getTool() { - return myTool; - } - /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#getOutDegreeStatistics() */ @@ -442,7 +432,7 @@ public class LiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.LiveCheck.ILiveChecker#addInitState(tlc2.tool.TLCState, long) */ - public void addInitState(TLCState state, long stateFP) { + public void addInitState(ITool tool, TLCState state, long stateFP) { dgraph.addInitNode(stateFP, -1); writer.writeState(state); } @@ -450,8 +440,8 @@ public class LiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveChecker#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates, tlc2.util.BitVector, boolean[]) */ - public void addNextState(final TLCState s0, final long fp0, final SetOfStates nextStates, - final BitVector checkActionResults, final boolean[] checkStateResults) throws IOException { + public void addNextState(ITool tool, final TLCState s0, final long fp0, + final SetOfStates nextStates, final BitVector checkActionResults, final boolean[] checkStateResults) throws IOException { int cnt = 0; // if there is no tableau ... final int succCnt = nextStates.size(); @@ -536,13 +526,13 @@ public class LiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.LiveChecker#addInitState(tlc2.tool.TLCState, long) */ - public void addInitState(final TLCState state, final long stateFP) { + public void addInitState(final ITool tool, final TLCState state, final long stateFP) { // (state, tnode) is a root node if tnode is an initial tableau // node and tnode is consistent with state. int initCnt = oos.getTableau().getInitCnt(); for (int i = 0; i < initCnt; i++) { TBGraphNode tnode = oos.getTableau().getNode(i); - if (tnode.isConsistent(state, myTool)) { + if (tnode.isConsistent(state, tool)) { dgraph.addInitNode(stateFP, tnode.getIndex()); dgraph.recordNode(stateFP, tnode.getIndex()); writer.writeState(state, tnode); @@ -553,8 +543,8 @@ public class LiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveChecker#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates, tlc2.util.BitVector, boolean[]) */ - public void addNextState(final TLCState s0, final long fp0, final SetOfStates nextStates, - final BitVector checkActionResults, final boolean[] checkStateResults) throws IOException { + public void addNextState(final ITool tool, final TLCState s0, final long fp0, + final SetOfStates nextStates, final BitVector checkActionResults, final boolean[] checkStateResults) throws IOException { int cnt = 0; final int succCnt = nextStates.size(); @@ -566,13 +556,12 @@ public class LiveCheck implements ILiveCheck { // trades speed for additional memory usage (BitVector). final TBGraph tableau = oos.getTableau(); final BitVector consistency = new BitVector(tableau.size() * succCnt); - @SuppressWarnings("unchecked") final Enumeration<TBGraphNode> elements = tableau.elements(); while(elements.hasMoreElements()) { final TBGraphNode tableauNode = elements.nextElement(); for (int sidx = 0; sidx < succCnt; sidx++) { final TLCState s1 = nextStates.next(); - if(tableauNode.isConsistent(s1, myTool)) { + if(tableauNode.isConsistent(s1, tool)) { // BitVector is divided into a segment for each // tableau node. Inside each segment, addressing is done // via each state. Use identical addressing below @@ -636,7 +625,7 @@ public class LiveCheck implements ILiveCheck { if (ptr1 == -1) { dgraph.recordNode(successor, tnode1.getIndex()); if (isDone) { - addNextState(s1, successor, tnode1, oos, dgraph); + addNextState(tool, s1, successor, tnode1, oos, dgraph); } } } @@ -674,9 +663,9 @@ public class LiveCheck implements ILiveCheck { * Hopefully, this case does not occur very frequently because it * generates successor nodes. */ - private void addNextState(final TLCState s, final long fp, final TBGraphNode tnode, final OrderOfSolution oos, final TableauDiskGraph dgraph) + private void addNextState(final ITool tool, final TLCState s, final long fp, final TBGraphNode tnode, final OrderOfSolution oos, final TableauDiskGraph dgraph) throws IOException { - final boolean[] checkStateRes = oos.checkState(s); + final boolean[] checkStateRes = oos.checkState(tool, s); final int slen = checkStateRes.length; final int alen = oos.getCheckAction().length; final GraphNode node = dgraph.getNode(fp, tnode.getIndex()); @@ -689,16 +678,16 @@ public class LiveCheck implements ILiveCheck { // Add edges induced by s -> s (self-loop) coming from the tableau // graph: final int nextSize = tnode.nextSize(); - final BitVector checkActionResults = nextSize > 0 ? oos.checkAction(s, s, new BitVector(alen), 0) : null; + final BitVector checkActionResults = nextSize > 0 ? oos.checkAction(tool, s, s, new BitVector(alen), 0) : null; for (int i = 0; i < nextSize; i++) { final TBGraphNode tnode1 = tnode.nextAt(i); final int tidx1 = tnode1.getIndex(); final long ptr1 = dgraph.getPtr(fp, tidx1); - if (tnode1.isConsistent(s, myTool) && (ptr1 == -1 || !node.transExists(fp, tidx1))) { + if (tnode1.isConsistent(s, tool) && (ptr1 == -1 || !node.transExists(fp, tidx1))) { node.addTransition(fp, tidx1, slen, alen, checkActionResults, 0, (nextSize - cnt)); if (ptr1 == -1) { dgraph.recordNode(fp, tnode1.getIndex()); - addNextState(s, fp, tnode1, oos, dgraph); + addNextState(tool, s, fp, tnode1, oos, dgraph); } } cnt++; @@ -707,21 +696,22 @@ public class LiveCheck implements ILiveCheck { // Add edges induced by s -> s1 (where s1 is a successor of s in the // state graph): cnt = 0; + final Action[] actions = tool.getActions(); for (int i = 0; i < actions.length; i++) { - final StateVec nextStates = myTool.getNextStates(actions[i], s); + final StateVec nextStates = tool.getNextStates(actions[i], s); final int nextCnt = nextStates.size(); for (int j = 0; j < nextCnt; j++) { final TLCState s1 = nextStates.elementAt(j); - if (myTool.isInModel(s1) && myTool.isInActions(s, s1)) { + if (tool.isInModel(s1) && tool.isInActions(s, s1)) { final long fp1 = s1.fingerPrint(); - final BitVector checkActionRes = oos.checkAction(s, s1, new BitVector(alen), 0); + final BitVector checkActionRes = oos.checkAction(tool, s, s1, new BitVector(alen), 0); boolean isDone = dgraph.isDone(fp1); for (int k = 0; k < tnode.nextSize(); k++) { final TBGraphNode tnode1 = tnode.nextAt(k); final int tidx1 = tnode1.getIndex(); long ptr1 = dgraph.getPtr(fp1, tidx1); final int total = actions.length * nextCnt * tnode.nextSize(); - if (tnode1.isConsistent(s1, myTool) && (ptr1 == -1 || !node.transExists(fp1, tidx1))) { + if (tnode1.isConsistent(s1, tool) && (ptr1 == -1 || !node.transExists(fp1, tidx1))) { node.addTransition(fp1, tidx1, slen, alen, checkActionRes, 0, (total - cnt)); writer.writeState(s, tnode, s1, tnode1, checkActionRes, 0, alen, false, Visualization.DOTTED); // Record that we have seen <fp1, tnode1>. If @@ -730,7 +720,7 @@ public class LiveCheck implements ILiveCheck { if (ptr1 == -1) { dgraph.recordNode(fp1, tidx1); if (isDone) { - addNextState(s1, fp1, tnode1, oos, dgraph); + addNextState(tool, s1, fp1, tnode1, oos, dgraph); } } } @@ -780,8 +770,7 @@ public class LiveCheck implements ILiveCheck { // Re-create the tool to do the init states down below (LiveCheck#init // doesn't really need tool). - final Tool tool = new Tool("", "MC", "MC", new SimpleFilenameToStream()); - tool.init(true, null); + final ITool tool = new Tool("", "MC", "MC", new SimpleFilenameToStream()); // Initialize tool's actions explicitly. LiveCheck#printTrace is // going to access the actions and fails with a NPE unless @@ -802,7 +791,7 @@ public class LiveCheck implements ILiveCheck { * @see tlc2.tool.IStateFunctor#addElement(tlc2.tool.TLCState) */ public Object addElement(TLCState state) { - liveCheck.addInitState(state, state.fingerPrint()); + liveCheck.addInitState(tool, state, state.fingerPrint()); return true; } }); diff --git a/tlatools/src/tlc2/tool/liveness/LiveCheck1.java b/tlatools/src/tlc2/tool/liveness/LiveCheck1.java index 8792007a7ba1b20dcdb97c43fd008274eb6a0317..27a711604be93a68279d2dc52967e6b31526a26e 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveCheck1.java +++ b/tlatools/src/tlc2/tool/liveness/LiveCheck1.java @@ -13,10 +13,10 @@ import tlc2.output.MP; import tlc2.output.StatePrinter; import tlc2.tool.Action; import tlc2.tool.EvalException; +import tlc2.tool.ITool; import tlc2.tool.StateVec; import tlc2.tool.TLCState; import tlc2.tool.TLCStateInfo; -import tlc2.tool.Tool; import tlc2.util.FP64; import tlc2.util.LongObjTable; import tlc2.util.MemObjectStack; @@ -30,7 +30,7 @@ public class LiveCheck1 implements ILiveCheck { /** * Implementation of liveness checking based on MP book. */ - private Tool myTool; + private ITool myTool; private String metadir = ""; private Action[] actions; private OrderOfSolution[] solutions; @@ -72,13 +72,13 @@ public class LiveCheck1 implements ILiveCheck { */ private BEGraphNode initNode = null; - public LiveCheck1(Tool tool) { + public LiveCheck1(ITool tool) { myTool = tool; solutions = Liveness.processLiveness(myTool); bgraphs = new BEGraph[0]; } - public void init(Tool tool, Action[] acts, String mdir) { + public void init(ITool tool, Action[] acts, String mdir) { myTool = tool; metadir = mdir; actions = acts; @@ -115,14 +115,14 @@ public class LiveCheck1 implements ILiveCheck { * state trace (a sequence of states). Assume trace.length > 0. It returns * the set of initial states. */ - Vect constructBEGraph(OrderOfSolution os) { - Vect initNodes = new Vect(1); + Vect<BEGraphNode> constructBEGraph(final ITool tool, OrderOfSolution os) { + Vect<BEGraphNode> initNodes = new Vect<>(1); int slen = os.getCheckState().length; int alen = os.getCheckAction().length; TLCState srcState = stateTrace.elementAt(0); // the initial state long srcFP = srcState.fingerPrint(); - boolean[] checkStateRes = os.checkState(srcState); - boolean[] checkActionRes = os.checkAction(srcState, srcState); + boolean[] checkStateRes = os.checkState(tool, srcState); + boolean[] checkActionRes = os.checkAction(tool, srcState, srcState); if (!os.hasTableau()) { // If there is no tableau, construct begraph with trace. LongObjTable allNodes = new LongObjTable(127); @@ -137,12 +137,12 @@ public class LiveCheck1 implements ILiveCheck { BEGraphNode destNode = (BEGraphNode) allNodes.get(destFP); if (destNode == null) { destNode = new BEGraphNode(destFP); - destNode.setCheckState(os.checkState(srcState)); - destNode.addTransition(destNode, slen, alen, os.checkAction(destState, destState)); - srcNode.addTransition(destNode, slen, alen, os.checkAction(srcState, destState)); + destNode.setCheckState(os.checkState(tool, srcState)); + destNode.addTransition(destNode, slen, alen, os.checkAction(tool, destState, destState)); + srcNode.addTransition(destNode, slen, alen, os.checkAction(tool, srcState, destState)); allNodes.put(destFP, destNode); } else if (!srcNode.transExists(destNode)) { - srcNode.addTransition(destNode, slen, alen, os.checkAction(srcState, destState)); + srcNode.addTransition(destNode, slen, alen, os.checkAction(tool, srcState, destState)); } srcNode = destNode; srcState = destState; @@ -150,7 +150,7 @@ public class LiveCheck1 implements ILiveCheck { } else { // If there is tableau, construct begraph of (tableau X trace). LongObjTable allNodes = new LongObjTable(255); - Vect srcNodes = new Vect(); + Vect<BEGraphNode> srcNodes = new Vect<>(); int initCnt = os.getTableau().getInitCnt(); for (int i = 0; i < initCnt; i++) { TBGraphNode tnode = os.getTableau().getNode(i); @@ -175,11 +175,11 @@ public class LiveCheck1 implements ILiveCheck { } } for (int i = 1; i < stateTrace.size(); i++) { - Vect destNodes = new Vect(); + Vect<BEGraphNode> destNodes = new Vect<>(); TLCState destState = stateTrace.elementAt(i); long destStateFP = destState.fingerPrint(); - checkStateRes = os.checkState(destState); - checkActionRes = os.checkAction(srcState, destState); + checkStateRes = os.checkState(myTool, destState); + checkActionRes = os.checkAction(tool, srcState, destState); for (int j = 0; j < srcNodes.size(); j++) { BEGraphNode srcNode = (BEGraphNode) srcNodes.elementAt(j); TBGraphNode tnode = srcNode.getTNode(os.getTableau()); @@ -200,7 +200,7 @@ public class LiveCheck1 implements ILiveCheck { } } } - checkActionRes = os.checkAction(destState, destState); + checkActionRes = os.checkAction(tool, destState, destState); for (int j = 0; j < destNodes.size(); j++) { BEGraphNode srcNode = (BEGraphNode) destNodes.elementAt(j); TBGraphNode tnode = srcNode.getTNode(os.getTableau()); @@ -232,14 +232,14 @@ public class LiveCheck1 implements ILiveCheck { * This method adds new nodes into the behavior graph when a new initial * state is generated. */ - public void addInitState(TLCState state, long stateFP) { + public void addInitState(ITool tool, TLCState state, long stateFP) { for (int soln = 0; soln < solutions.length; soln++) { OrderOfSolution os = solutions[soln]; BEGraph bgraph = bgraphs[soln]; int slen = os.getCheckState().length; int alen = os.getCheckAction().length; - boolean[] checkStateRes = os.checkState(state); - boolean[] checkActionRes = os.checkAction(state, state); + boolean[] checkStateRes = os.checkState(tool, state); + boolean[] checkActionRes = os.checkAction(tool, state, state); // Adding nodes and transitions: if (!os.hasTableau()) { // if there is no tableau ... @@ -272,11 +272,11 @@ public class LiveCheck1 implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates) */ - public void addNextState(TLCState s0, long fp0, SetOfStates nextStates) throws IOException { + public void addNextState(final ITool tool, TLCState s0, long fp0, SetOfStates nextStates) throws IOException { for (int i = 0; i < nextStates.size(); i++) { final TLCState s2 = nextStates.next(); final long fp2 = s2.fingerPrint(); - addNextState(s0, fp0, s2, fp2); + addNextState(tool, s0, fp0, s2, fp2); } nextStates.resetNext(); } @@ -286,7 +286,7 @@ public class LiveCheck1 implements ILiveCheck { * generated. The argument s2 is the new state. The argument s1 is parent * state of s2. */ - public synchronized void addNextState(TLCState s1, long fp1, TLCState s2, long fp2) { + public synchronized void addNextState(final ITool tool, TLCState s1, long fp1, TLCState s2, long fp2) { for (int soln = 0; soln < solutions.length; soln++) { OrderOfSolution os = solutions[soln]; BEGraph bgraph = bgraphs[soln]; @@ -299,12 +299,12 @@ public class LiveCheck1 implements ILiveCheck { BEGraphNode node2 = bgraph.allNodes.getBENode(fp2); if (node2 == null) { node2 = new BEGraphNode(fp2); - node2.setCheckState(os.checkState(s2)); - node1.addTransition(node2, slen, alen, os.checkAction(s1, s2)); - node2.addTransition(node2, slen, alen, os.checkAction(s2, s2)); + node2.setCheckState(os.checkState(tool, s2)); + node1.addTransition(node2, slen, alen, os.checkAction(tool, s1, s2)); + node2.addTransition(node2, slen, alen, os.checkAction(tool, s2, s2)); bgraph.allNodes.putBENode(node2); } else if (!node1.transExists(node2)) { - boolean[] checkActionRes = os.checkAction(s1, s2); + boolean[] checkActionRes = os.checkAction(tool, s1, s2); node1.addTransition(node2, slen, alen, checkActionRes); } } else { @@ -316,7 +316,7 @@ public class LiveCheck1 implements ILiveCheck { } boolean[] checkStateRes = null; // Add edges induced by s1 --> s2: - boolean[] checkActionRes = os.checkAction(s1, s2); + boolean[] checkActionRes = os.checkAction(tool, s1, s2); boolean[] checkActionRes1 = null; for (int i = 0; i < srcNodes.length; i++) { BTGraphNode srcNode = srcNodes[i]; @@ -328,20 +328,20 @@ public class LiveCheck1 implements ILiveCheck { if (tnode1.isConsistent(s2, myTool)) { destNode = new BTGraphNode(fp2, tnode1.getIndex()); if (checkStateRes == null) { - checkStateRes = os.checkState(s2); + checkStateRes = os.checkState(tool, s2); } destNode.setCheckState(checkStateRes); srcNode.addTransition(destNode, slen, alen, checkActionRes); int idx = bgraph.allNodes.putBTNode(destNode); // add edges induced by s2 --> s2: if (checkActionRes1 == null) { - checkActionRes1 = os.checkAction(s2, s2); + checkActionRes1 = os.checkAction(tool, s2, s2); } addNodesForStut(s2, fp2, destNode, checkStateRes, checkActionRes1, os, bgraph); // if s2 is done, we have to do something for // destNode: if (bgraph.allNodes.isDone(idx)) { - addNextState(s2, fp2, destNode, os, bgraph); + addNextState(tool, s2, fp2, destNode, os, bgraph); } } } else if (!srcNode.transExists(destNode)) { @@ -384,7 +384,7 @@ public class LiveCheck1 implements ILiveCheck { * after s has been done. So, we still have to compute the children of (s, * t). Hopefully, this case will not occur very frequently. */ - private void addNextState(TLCState s, long fp, BTGraphNode node, OrderOfSolution os, BEGraph bgraph) { + private void addNextState(final ITool tool, TLCState s, long fp, BTGraphNode node, OrderOfSolution os, BEGraph bgraph) { TBGraphNode tnode = node.getTNode(os.getTableau()); int slen = os.getCheckState().length; int alen = os.getCheckAction().length; @@ -405,25 +405,25 @@ public class LiveCheck1 implements ILiveCheck { if (tnode1.isConsistent(s1, myTool)) { destNode = new BTGraphNode(fp1, tnode1.getIndex()); if (checkStateRes == null) { - checkStateRes = os.checkState(s1); + checkStateRes = os.checkState(tool, s1); } if (checkActionRes == null) { - checkActionRes = os.checkAction(s, s1); + checkActionRes = os.checkAction(tool, s, s1); } destNode.setCheckState(checkStateRes); node.addTransition(destNode, slen, alen, checkActionRes); if (checkActionRes1 == null) { - checkActionRes1 = os.checkAction(s1, s1); + checkActionRes1 = os.checkAction(tool, s1, s1); } addNodesForStut(s1, fp1, destNode, checkStateRes, checkActionRes1, os, bgraph); int idx = bgraph.allNodes.putBTNode(destNode); if (bgraph.allNodes.isDone(idx)) { - addNextState(s1, fp1, destNode, os, bgraph); + addNextState(tool, s1, fp1, destNode, os, bgraph); } } } else if (!node.transExists(destNode)) { if (checkActionRes == null) { - checkActionRes = os.checkAction(s, s1); + checkActionRes = os.checkAction(tool, s, s1); } node.addTransition(destNode, slen, alen, checkActionRes); } @@ -450,10 +450,11 @@ public class LiveCheck1 implements ILiveCheck { * "bad" cycle. A "bad" cycle gives rise to a violation of liveness * property. */ - public synchronized boolean check(boolean forceCheck) { + @Override + public synchronized int check(ITool tool, boolean forceCheck) { int slen = solutions.length; if (slen == 0) { - return true; + return EC.NO_ERROR; } for (int soln = 0; soln < slen; soln++) { @@ -477,18 +478,18 @@ public class LiveCheck1 implements ILiveCheck { } // Previous for loop with throw LivenessException anyway, thus no harm // returning true regardless. - return true; + return EC.NO_ERROR; } /** * Checks if the behavior graph constructed from a state trace contains any * "bad" cycle. */ - public void checkTrace(final StateVec trace) { + public synchronized void checkTrace(ITool tool, final StateVec trace) { stateTrace = trace; for (int soln = 0; soln < solutions.length; soln++) { OrderOfSolution os = solutions[soln]; - Vect initNodes = constructBEGraph(os); + Vect<BEGraphNode> initNodes = constructBEGraph(tool, os); // Liveness.printTBGraph(os.tableau); // ToolIO.err.println(os.behavior.toString()); @@ -774,7 +775,7 @@ public class LiveCheck1 implements ILiveCheck { // April // 2012 } - throw new LiveException("LiveCheck: Found error trace."); + throw new LiveException(EC.TLC_TEMPORAL_PROPERTY_VIOLATED, "LiveCheck: Found error trace."); } /** @@ -809,7 +810,7 @@ public class LiveCheck1 implements ILiveCheck { /* This method checks whether a scc satisfies currentPEM. */ void checkComponent(BEGraphNode node) { - Vect nodes = extractComponent(node); + Vect<BEGraphNode> nodes = extractComponent(node); if (nodes != null) { PossibleErrorModel[] pems = currentOOS.getPems(); for (int i = 0; i < pems.length; i++) { @@ -838,13 +839,13 @@ public class LiveCheck1 implements ILiveCheck { * trivial one. It also assigns a new number to all the nodes in the * component. */ - Vect extractComponent(BEGraphNode node) { + Vect<BEGraphNode> extractComponent(BEGraphNode node) { BEGraphNode node1 = (BEGraphNode) comStack.pop(); if (node == node1 && !node.transExists(node)) { node.setNumber(MAX_FIRST); return null; } - Vect nodes = new Vect(); + Vect<BEGraphNode> nodes = new Vect<>(); numFirstCom = secondNum++; numSecondCom = thirdNum; node1.setNumber(numFirstCom); @@ -914,11 +915,9 @@ public class LiveCheck1 implements ILiveCheck { return false; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#finalCheck() - */ - public boolean finalCheck() throws Exception { - return check(true); + @Override + public int finalCheck(ITool tool) throws Exception { + return check(tool, true); } /* (non-Javadoc) @@ -931,7 +930,7 @@ public class LiveCheck1 implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#getTool() */ - public Tool getTool() { + public ITool getTool() { return myTool; } diff --git a/tlatools/src/tlc2/tool/liveness/LiveException.java b/tlatools/src/tlc2/tool/liveness/LiveException.java index 83f3ffd45b2b2827e7e9cca148e7cb87cd5303c4..783993063169ea03219367e4f9837ed68151ca83 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveException.java +++ b/tlatools/src/tlc2/tool/liveness/LiveException.java @@ -7,11 +7,15 @@ package tlc2.tool.liveness; public class LiveException extends RuntimeException { - public LiveException() { + public final int errorCode; + + public LiveException(int errorCode) { super(); + this.errorCode = errorCode; } - public LiveException(String msg) { + public LiveException(int errorCode, String msg) { super(msg); + this.errorCode = errorCode; } } diff --git a/tlatools/src/tlc2/tool/liveness/LiveExprNode.java b/tlatools/src/tlc2/tool/liveness/LiveExprNode.java index 51a37a377a378b7f9b47d90a8646b2bdcacb6b7e..5322e39bf25c9b6375dc8a79100a10d2952d576e 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveExprNode.java +++ b/tlatools/src/tlc2/tool/liveness/LiveExprNode.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; /** * LNConj - a conjunction. (contains list of conjuncts) LNDisj - a disjunction. @@ -48,7 +48,7 @@ public abstract class LiveExprNode { * @param tool (Technical Tool implementation) * @return true iff both states are consistent with this {@link LiveExprNode}. */ - public abstract boolean eval(Tool tool, TLCState s1, TLCState s2); + public abstract boolean eval(ITool tool, TLCState s1, TLCState s2); /* The string representation. */ public final String toString() { diff --git a/tlatools/src/tlc2/tool/liveness/LiveWorker.java b/tlatools/src/tlc2/tool/liveness/LiveWorker.java index 2f12432af3f99eb6a8344a073aa9407ba35ed5eb..1bd8d4c6b871c3a2b4b99c643e8e3d8d98a743a0 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveWorker.java +++ b/tlatools/src/tlc2/tool/liveness/LiveWorker.java @@ -19,6 +19,7 @@ import tlc2.output.EC; import tlc2.output.MP; import tlc2.output.StatePrinter; import tlc2.tool.EvalException; +import tlc2.tool.ITool; import tlc2.tool.TLCStateInfo; import tlc2.util.IdThread; import tlc2.util.IntStack; @@ -65,8 +66,11 @@ public class LiveWorker extends IdThread { */ private final int numWorkers; - public LiveWorker(int id, int numWorkers, final ILiveCheck liveCheck, final BlockingQueue<ILiveChecker> queue, final boolean finalCheck) { + private final ITool tool; + + public LiveWorker(final ITool tool, int id, int numWorkers, final ILiveCheck liveCheck, final BlockingQueue<ILiveChecker> queue, final boolean finalCheck) { super(id); + this.tool = tool; this.numWorkers = numWorkers; this.liveCheck = liveCheck; this.queue = queue; @@ -136,7 +140,7 @@ public class LiveWorker extends IdThread { * @see http://dx.doi.org/10.1137%2F0201010 * */ - private final void checkSccs() throws IOException, InterruptedException, ExecutionException { + private final void checkSccs(final ITool tool) throws IOException, InterruptedException, ExecutionException { // Initialize this.dg: this.dg.makeNodePtrTbl(); @@ -287,7 +291,7 @@ public class LiveWorker extends IdThread { // element (endstate - 1). This goes on until either the // initial state is reached or an intermediate state has // unexplored successors with DFS. - final boolean isOK = this.checkComponent(curState, curTidx, comStack); + final boolean isOK = this.checkComponent(tool, curState, curTidx, comStack); if (!isOK) { // Found a "bad" cycle of one to comStack.size() // nodes, no point in searching for more SCCs as we @@ -375,9 +379,8 @@ public class LiveWorker extends IdThread { // P-satisfiability. // // This check is related to the fairness spec. - // Usually, it evals to true when no or weak - // fairness have been specified. False on strong - // fairness. + // Skip to check the other conjuncts of the PossibleErrorModel (PEM) if the + // action check is false (thus does not satisfy the PEM). if (gnode.getCheckAction(slen, alen, i, eaaction)) { // If the node's nextLink still points to // disk, it means it has no link assigned @@ -500,7 +503,7 @@ public class LiveWorker extends IdThread { * @throws ExecutionException * @throws InterruptedException */ - private boolean checkComponent(final long state, final int tidx, final IntStack comStack) throws IOException, InterruptedException, ExecutionException { + private boolean checkComponent(final ITool tool, final long state, final int tidx, final IntStack comStack) throws IOException, InterruptedException, ExecutionException { final long comStackSize = comStack.size(); // There is something to pop and each is a well formed tuple <<fp, tidx, loc>> assert comStackSize >= 5 && comStackSize % 5 == 0; // long + int + long @@ -528,7 +531,7 @@ public class LiveWorker extends IdThread { // collision handling. NodePtrTable uses open addressing (see // http://en.wikipedia.org/wiki/Open_addressing). // - // Initializing the NTPT with 128 buckets/slows is a significant memory + // Initializing the TNPT with 128 buckets/slots is a significant memory // overhead (especially when comStack contains < 10 elements) which // regularly results in OutOfMemoryErrors being thrown. To alleviate the // problem the key-space of the comStack elements could be checked and @@ -566,6 +569,7 @@ public class LiveWorker extends IdThread { final boolean[] AEStateRes = new boolean[aeslen]; final boolean[] AEActionRes = new boolean[aealen]; final boolean[] promiseRes = new boolean[plen]; + final int[] eaaction = this.pem.EAAction; // Extract a node from the nodePtrTable "com". // Note the upper limit is NodePtrTable#getSize() instead of @@ -634,13 +638,51 @@ public class LiveWorker extends IdThread { // processed SCC (com). Successors, which are not part of // the current SCC have obviously no relevance here. After // all, we check the SCC. - if (com.getLoc(nextState, nextTidx) != -1) { - for (int j = 0; j < aealen; j++) { - // Only set false to true, but never true to false. - if (!AEActionRes[j]) { - final int idx = this.pem.AEAction[j]; - AEActionRes[j] = curNode.getCheckAction(slen, alen, i, idx); - } + if (com.getLoc(nextState, nextTidx) == -1) { + continue; + } + // MAK 10/23/2018: + // Line 380 above "if(gnode.getCheckAction)" causes a transition A from state s + // -> t to be skipped even if a belongs to an SCC iff the transition A does not + // satisfy the EA action of the PossibleErrorModel (if the EA action(s) is not + // satisfied, the PEM cannot hold at all). + // However, some state graphs are such that there exists not just the transition + // A from s -> t but a second transition A' from t -> s - which satisfies the EA + // action(s) of the PEM. In the case of a "bidirectional" transition, the states + // s and t will be in the set of states 'com' (which make up the SCC). Thus, the + // transition A from s -> t will be incorrectly traversed here unless it is + // skipped (again). Not skipping the transition A will result in TLC reporting a + // (bogus) counterexample even if the liveness is not violated. + // + // Consider the spec BT for which TLC incorrectly reports a liveness property + // violation and prints a bogus counterexample: + // + // ---- BT ----- + // EXTENDS Naturals + // VARIABLE x + // A == \/ x' = (x + 1) % 3 + // B == x' \in 0..2 + // Spec == (x=0) /\ [][A \/ B]_x/\ WF_x(A) + // Prop == Spec /\ WF_x(A) /\ []<><<A>>_x + // ============= + // + // > Temporal properties were violated. + // > The following behavior constitutes a counter-example: + // > 1: <Initial predicate> + // > x = 0 + // > 2: <A line xx...BT> + // > x = 1 + // > 1: Back to state: <B line xx... BT> + // + // (see tlc2.tool.BidirectionalTransitions1Test and BidirectionalTransitions2Test) + if(!curNode.getCheckAction(slen, alen, i, eaaction)) { + continue; + } + for (int j = 0; j < aealen; j++) { + // Only set false to true, but never true to false. + if (!AEActionRes[j]) { + final int idx = this.pem.AEAction[j]; + AEActionRes[j] = curNode.getCheckAction(slen, alen, i, idx); } } } @@ -694,7 +736,7 @@ public class LiveWorker extends IdThread { // conditions are satisfied. So, print a counter-example (if this thread // is the first one to find a counter-example)! if (setErrFound()) { - this.printTrace(state, tidx, com); + this.printTrace(tool, state, tidx, com); } return false; } @@ -753,7 +795,7 @@ public class LiveWorker extends IdThread { * @throws ExecutionException * @throws InterruptedException */ - private void printTrace(final long state, final int tidx, final TableauNodePtrTable nodeTbl) throws IOException, InterruptedException, ExecutionException { + private void printTrace(ITool tool, final long state, final int tidx, final TableauNodePtrTable nodeTbl) throws IOException, InterruptedException, ExecutionException { // writeDotViz(state, tidx, nodeTbl, new java.io.File(liveCheck.getMetaDir() + java.io.File.separator // + "pSatisfiableSCC_" + System.currentTimeMillis() + ".dot")); @@ -782,7 +824,7 @@ public class LiveWorker extends IdThread { // LongVec with just a single element. This happens when the parameter // state is one of the init states already. long fp = prefix.elementAt(plen - 1); - TLCStateInfo sinfo = liveCheck.getTool().getState(fp); + TLCStateInfo sinfo = tool.getState(fp); if (sinfo == null) { throw new EvalException(EC.TLC_FAILED_TO_RECOVER_INIT); } @@ -798,7 +840,7 @@ public class LiveWorker extends IdThread { // It won't be correct to shorten a path <<fp1,fp2,fp1>> to // <<fp2,fp1>> though. if (curFP != fp) { - sinfo = liveCheck.getTool().getState(curFP, sinfo); + sinfo = tool.getState(curFP, sinfo); states.add(sinfo); fp = curFP; } @@ -848,7 +890,17 @@ public class LiveWorker extends IdThread { // Wait for the prefix-path to be searched/generated and fully printed. // get() is a blocking call that makes this thread wait for the executor // to finish its job of searching and printing the prefix-path. - final List<TLCStateInfo> states = future.get(); + List<TLCStateInfo> states = new ArrayList<>(0); + try { + states = future.get(); + } catch (ExecutionException ee) { + // Do not "leak" ExecutionException to user if root cause is actually an + // EvalException. + if (ee.getCause() instanceof EvalException) { + throw (EvalException) ee.getCause(); + } + throw ee; + } /* * At this point everything from the initial state up to the start state @@ -872,7 +924,7 @@ public class LiveWorker extends IdThread { // efficiency reason. Regenerating the next state might be // expensive. if (curFP != sinfo.fingerPrint()) { - sinfo = liveCheck.getTool().getState(curFP, sinfo); + sinfo = tool.getState(curFP, sinfo); StatePrinter.printState(sinfo); } } @@ -886,7 +938,7 @@ public class LiveWorker extends IdThread { if (sinfo.fingerPrint() == cycleState.fingerPrint()) { StatePrinter.printStutteringState(stateNumber); } else { - sinfo = liveCheck.getTool().getState(cycleState.fingerPrint(), sinfo); + sinfo = tool.getState(cycleState.fingerPrint(), sinfo); // The print stmts below claim there is a cycle, thus assert that // there is indeed one. Index-based lookup into states array is // reduced by one because cyclePos is human-readable. @@ -898,6 +950,10 @@ public class LiveWorker extends IdThread { // BFS search private LongVec bfsPostFix(final long state, final int tidx, final TableauNodePtrTable nodeTbl, GraphNode curNode) throws IOException { + final int slen = this.oos.getCheckState().length; + final int alen = this.oos.getCheckAction().length; + final int[] eaaction = this.pem.EAAction; + final LongVec postfix = new LongVec(16); final long startState = curNode.stateFP; final long startTidx = curNode.tindex; @@ -944,6 +1000,13 @@ public class LiveWorker extends IdThread { continue SUCCESSORS; } + // Prevent bogus counterexample: Do not close the loop by taking an action which + // does not satisfy the PossibleErrorModel (read more about it on line 640 in + // checkComponent). + if(!curNode.getCheckAction(slen, alen, j, eaaction)) { + continue; + } + if (nextState == state && nextTidx == tidx) { // We have found a path from startState to state, // now backtrack the path the outer loop took to get @@ -992,6 +1055,7 @@ public class LiveWorker extends IdThread { final boolean[] AEStateRes = new boolean[this.pem.AEState.length]; final boolean[] AEActionRes = new boolean[this.pem.AEAction.length]; final boolean[] promiseRes = new boolean[this.oos.getPromises().length]; + final int[] eaaction = this.pem.EAAction; // The number/count of all liveness checks. The while loop A) terminates // once it has accumulated all states that violate all checks (we know // that the states in nodeTbl have to violate the liveness property @@ -1052,18 +1116,26 @@ public class LiveWorker extends IdThread { nodes = nodeTbl.getNodes(nextState); if (nodes != null) { tloc = nodeTbl.getIdx(nodes, nextTidx); - if (tloc != -1) { - // <nextState, nextTidx> is in nodeTbl. - nextState1 = nextState; - nextTidx1 = nextTidx; - tloc1 = tloc; - nodes1 = nodes; - for (int j = 0; j < this.pem.AEAction.length; j++) { - int idx = this.pem.AEAction[j]; - if (!AEActionRes[j] && curNode.getCheckAction(slen, alen, i, idx)) { - AEActionRes[j] = true; - cnt--; - } + // See checkComponent line 637. + if (tloc == -1) { + continue; + } + // Prevent bogus counterexample: Do not close the loop by taking an action which + // does not satisfy the PossibleErrorModel (read more about it on line 640 in + // checkComponent). + if(!curNode.getCheckAction(slen, alen, i, eaaction)) { + continue; + } + // <nextState, nextTidx> is in nodeTbl. + nextState1 = nextState; + nextTidx1 = nextTidx; + tloc1 = tloc; + nodes1 = nodes; + for (int j = 0; j < this.pem.AEAction.length; j++) { + int idx = this.pem.AEAction[j]; + if (!AEActionRes[j] && curNode.getCheckAction(slen, alen, i, idx)) { + AEActionRes[j] = true; + cnt--; } } } @@ -1164,7 +1236,7 @@ public class LiveWorker extends IdThread { for (int i = 0; i < pems.length; i++) { if (!hasErrFound()) { this.pem = pems[i]; - this.checkSccs(); + this.checkSccs(tool); } } this.dg.destroyCache(); diff --git a/tlatools/src/tlc2/tool/liveness/Liveness.java b/tlatools/src/tlc2/tool/liveness/Liveness.java index aca58837ac057b393bcdba53032ff3ed805e4aa5..77a71cf37aaae2960df20d5020adb62e8050d961 100644 --- a/tlatools/src/tlc2/tool/liveness/Liveness.java +++ b/tlatools/src/tlc2/tool/liveness/Liveness.java @@ -19,29 +19,30 @@ import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.Action; import tlc2.tool.BuiltInOPs; -import tlc2.tool.ContextEnumerator; import tlc2.tool.EvalControl; -import tlc2.tool.Spec; +import tlc2.tool.IContextEnumerator; +import tlc2.tool.ITool; +import tlc2.tool.ModelChecker; +import tlc2.tool.Specs; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.tool.ToolGlobals; import tlc2.util.Context; import tlc2.util.Vect; -import tlc2.value.BoolValue; -import tlc2.value.FcnLambdaValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; +import tlc2.value.IFcnLambdaValue; +import tlc2.value.IValue; import util.Assert; import util.ToolIO; public class Liveness implements ToolGlobals, ASTConstants { - private static LiveExprNode astToLive(Tool tool, ExprNode expr, Context con, int level) { + private static LiveExprNode astToLive(ITool tool, ExprNode expr, Context con, int level) { if (level == 0) { - Value val = tool.eval(expr, con, TLCState.Empty); - if (!(val instanceof BoolValue)) { + IValue val = tool.eval(expr, con, TLCState.Empty); + if (!(val instanceof IBoolValue)) { Assert.fail(EC.TLC_EXPECTED_VALUE, new String[] { "boolean", expr.toString() }); } - return (((BoolValue) val).val) ? LNBool.TRUE : LNBool.FALSE; + return ((IBoolValue) val).getVal() ? LNBool.TRUE : LNBool.FALSE; } else if (level == 1) { return new LNStateAST(expr, con); } else { @@ -58,7 +59,7 @@ public class Liveness implements ToolGlobals, ASTConstants { * the predicate body with []p. For the moment, we require that arguments to * predicates be computable from its context. */ - private static LiveExprNode astToLive(Tool tool, ExprNode expr, Context con) { + private static LiveExprNode astToLive(ITool tool, ExprNode expr, Context con) { switch (expr.getKind()) { case OpApplKind: { OpApplNode expr1 = (OpApplNode) expr; @@ -80,7 +81,7 @@ public class Liveness implements ToolGlobals, ASTConstants { return astToLive(tool, expr1.getBody(), con1); } default: { - int level = Spec.getLevel(expr, con); + int level = Specs.getLevel(expr, con); if (level > 2) { Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); } @@ -89,7 +90,7 @@ public class Liveness implements ToolGlobals, ASTConstants { } } - private static LiveExprNode astToLiveAppl(Tool tool, OpApplNode expr, Context con) { + private static LiveExprNode astToLiveAppl(ITool tool, OpApplNode expr, Context con) { ExprOrOpArgNode[] args = expr.getArgs(); int alen = args.length; SymbolNode opNode = expr.getOperator(); @@ -109,7 +110,7 @@ public class Liveness implements ToolGlobals, ASTConstants { FormalParamNode[] formals = opDef.getParams(); Context con1 = con; for (int i = 0; i < alen; i++) { - Value argVal = tool.eval(args[i], con, TLCState.Empty); + IValue argVal = tool.eval(args[i], con, TLCState.Empty); con1 = con1.cons(formals[i], argVal); } LiveExprNode res = astToLive(tool, opDef.getBody(), con1); @@ -121,12 +122,12 @@ public class Liveness implements ToolGlobals, ASTConstants { } catch (Exception e) { /* SKIP */ } } - } else if (val instanceof BoolValue) { - return (((BoolValue) val).val) ? LNBool.TRUE : LNBool.FALSE; + } else if (val instanceof IBoolValue) { + return ((IBoolValue) val).getVal() ? LNBool.TRUE : LNBool.FALSE; } if (opcode == 0) { - int level = Spec.getLevel(expr, con); + int level = Specs.getLevel(expr, con); if (level > 2) { Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); } @@ -139,7 +140,7 @@ public class Liveness implements ToolGlobals, ASTConstants { { ExprNode body = (ExprNode) args[0]; try { - ContextEnumerator Enum = tool.contexts(expr, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); + IContextEnumerator Enum = tool.contexts(expr, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); Context con1; LNDisj res = new LNDisj(0); while ((con1 = Enum.nextElement()) != null) { @@ -154,7 +155,7 @@ public class Liveness implements ToolGlobals, ASTConstants { } catch (Exception e) { // Catching Exception here seem dangerous // Assert.printStack(e); - int level = Spec.getLevel(expr, con); + int level = Specs.getLevel(expr, con); if (level > 2) { Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); ; @@ -166,7 +167,7 @@ public class Liveness implements ToolGlobals, ASTConstants { { ExprNode body = (ExprNode) args[0]; try { - ContextEnumerator Enum = tool.contexts(expr, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); + IContextEnumerator Enum = tool.contexts(expr, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); Context con1; LNConj res = new LNConj(0); while ((con1 = Enum.nextElement()) != null) { @@ -181,7 +182,7 @@ public class Liveness implements ToolGlobals, ASTConstants { } catch (Exception e) { // Catching Exception here seem dangerous // Assert.printStack(e); - int level = Spec.getLevel(expr, con); + int level = Specs.getLevel(expr, con); if (level > 2) { if (e instanceof Assert.TLCRuntimeException) { Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, new String[] {expr.toString(), e.getMessage()}); @@ -221,17 +222,17 @@ public class Liveness implements ToolGlobals, ASTConstants { case OPCODE_fa: // FcnApply { try { - Value fval = tool.eval(args[0], con, TLCState.Empty); - if (fval instanceof FcnLambdaValue) { - FcnLambdaValue fcn = (FcnLambdaValue) fval; - if (fcn.fcnRcd == null) { + IValue fval = tool.eval(args[0], con, TLCState.Empty); + if (fval instanceof IFcnLambdaValue) { + IFcnLambdaValue fcn = (IFcnLambdaValue) fval; + if (!fcn.hasRcd()) { // this could be a bug, since con1 is created but not // used // SZ Jul 13, 2009: removed to kill the warning // SZ Feb 20, 2009: variable never read locally // Context con1 = tool.getFcnContext(fcn, args, con, TLCState.Empty, TLCState.Empty, EvalControl.Clear); - return astToLive(tool, (ExprNode) fcn.body, con); + return astToLive(tool, (ExprNode) fcn.getBody(), con); } } } catch (Exception e) { /* SKIP */ @@ -315,6 +316,12 @@ public class Liveness implements ToolGlobals, ASTConstants { LiveExprNode lnArg = astToLive(tool, (ExprNode) args[0], con); return new LNEven(lnArg); } + case OPCODE_aa: { // AngleAct <A>_e + assert Specs.getLevel(expr, con) == 2; + final ExprNode body = (ExprNode) args[0]; // the A in <<A>>_e + final ExprNode subs = (ExprNode) args[1]; // the e in <<A>>_e + return new LNAction(body, con, subs, false); + } // The following case added by LL on 13 Nov 2009 to handle subexpression // names. @@ -322,11 +329,23 @@ public class Liveness implements ToolGlobals, ASTConstants { return astToLive(tool, (ExprNode) args[0], con); } default: { - // We handle all the other built-in operators here. - int level = Spec.getLevel(expr, con); + // We handle all the other built-in operators here. Surprisingly, even OPCODE_aa + // (AngleAct <A>_e) is handled here and not as the dedicated case statement below + // such that e gets passed as subscript to LNAction: + // + // case OPCODE_aa: { // AngleAct <A>_e + // assert Spec.getLevel(expr, con) == 2; + // final ExprNode body = (ExprNode) args[0]; // the A in <<A>>_e + // final ExprNode subscript = (ExprNode) args[1]; // the e in <<A>>_e + // return new LNAction(body, con, subscript, false); + // } + // + // The default handling here results in LNAction#subscript to be null skipping + // the subscript related branch in LNAction#eval(Tool, TLCState, TLCState). This + // poses no problem though because Tool#evalAppl eventually checks if e' = e. + int level = Specs.getLevel(expr, con); if (level > 2) { Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); - ; } return astToLive(tool, expr, con, level); } @@ -337,7 +356,7 @@ public class Liveness implements ToolGlobals, ASTConstants { * Parse the temporals and impliedTemporals given in the config file. It * returns null if there is nothing to check. */ - private static LiveExprNode parseLiveness(Tool tool) { + private static LiveExprNode parseLiveness(ITool tool) { Action[] fairs = tool.getTemporals(); LNConj lnc = new LNConj(fairs.length); for (int i = 0; i < fairs.length; i++) { @@ -411,7 +430,7 @@ public class Liveness implements ToolGlobals, ASTConstants { * <i>fairness</i> formulae where check1, check2, ... are the actual * <i>liveness properties</i> to be checked. */ - public static OrderOfSolution[] processLiveness(Tool tool) { + public static OrderOfSolution[] processLiveness(final ITool tool) { LiveExprNode lexpr = parseLiveness(tool); if (lexpr == null) { @@ -471,7 +490,7 @@ public class Liveness implements ToolGlobals, ASTConstants { // up \/ and /\ above them. tfbin contains the different tf's. // pembin is a vect of vect-of-pems collecting each tf's pems. final TBPar tfbin = new TBPar(dnf.getCount()); - final Vect pembin = new Vect(dnf.getCount()); + final Vect<Vect<OSExprPem>> pembin = new Vect<>(dnf.getCount()); for (int i = 0; i < dnf.getCount(); i++) { int found = -1; final LiveExprNode tf = tfs[i]; @@ -484,9 +503,9 @@ public class Liveness implements ToolGlobals, ASTConstants { if (found == -1) { found = tfbin.size(); tfbin.addElement(tf); - pembin.addElement(new Vect()); + pembin.addElement(new Vect<OSExprPem>()); } - ((Vect) pembin.elementAt(found)).addElement(pems[i]); + ((Vect<OSExprPem>) pembin.elementAt(found)).addElement(pems[i]); } // We then create an OrderOfSolution for each tf in tfbin. @@ -495,12 +514,12 @@ public class Liveness implements ToolGlobals, ASTConstants { final LiveExprNode tf = tfbin.exprAt(i); if (tf == null) { - oss[i] = new OrderOfSolution(new LNEven[0], tool); + oss[i] = new OrderOfSolution(new LNEven[0]); } else { final LiveExprNode tf1 = tf.makeBinary(); final TBPar promises = new TBPar(10); tf1.extractPromises(promises); - oss[i] = new OrderOfSolution(new TBGraph(tf1), new LNEven[promises.size()], tool); + oss[i] = new OrderOfSolution(new TBGraph(tf1), new LNEven[promises.size()]); for (int j = 0; j < promises.size(); j++) { oss[i].getPromises()[j] = (LNEven) promises.exprAt(j); } @@ -508,9 +527,9 @@ public class Liveness implements ToolGlobals, ASTConstants { // We lump all the pems into a single checkState and checkAct, // and oss[i].pems will simply be integer lookups into them. - final Vect stateBin = new Vect(); - final Vect actionBin = new Vect(); - final Vect tfPems = (Vect) pembin.elementAt(i); + final Vect<LiveExprNode> stateBin = new Vect<>(); + final Vect<LiveExprNode> actionBin = new Vect<>(); + final Vect<OSExprPem> tfPems = (Vect<OSExprPem>) pembin.elementAt(i); oss[i].setPems(new PossibleErrorModel[tfPems.size()]); for (int j = 0; j < tfPems.size(); j++) { final OSExprPem pem = (OSExprPem) tfPems.elementAt(j); @@ -538,7 +557,7 @@ public class Liveness implements ToolGlobals, ASTConstants { * Given a list of checks, ensures that the checks are in the bin. It * returns an array of index of the checks in the bin. */ - private static int addToBin(LiveExprNode check, Vect bin) { + private static int addToBin(LiveExprNode check, Vect<LiveExprNode> bin) { if (check == null) { return -1; } @@ -556,7 +575,7 @@ public class Liveness implements ToolGlobals, ASTConstants { return idx; } - private static int[] addToBin(Vect checks, Vect bin) { + private static int[] addToBin(Vect<LiveExprNode> checks, Vect<LiveExprNode> bin) { int[] index = new int[checks.size()]; for (int i = 0; i < checks.size(); i++) { LiveExprNode check = (LiveExprNode) checks.elementAt(i); @@ -625,16 +644,16 @@ public class Liveness implements ToolGlobals, ASTConstants { * PossibleErrorModel and OrderOfSolution. */ private static class OSExprPem { - Vect EAAction; // <>[]action's - Vect AEState; // []<>state's - Vect AEAction; // []<>action's - Vect tfs; // other temp formulae with no actions + Vect<LiveExprNode> EAAction; // <>[]action's + Vect<LiveExprNode> AEState; // []<>state's + Vect<LiveExprNode> AEAction; // []<>action's + Vect<LiveExprNode> tfs; // other temp formulae with no actions public OSExprPem() { - this.EAAction = new Vect(); - this.AEState = new Vect(); - this.AEAction = new Vect(); - this.tfs = new Vect(); + this.EAAction = new Vect<>(); + this.AEState = new Vect<>(); + this.AEAction = new Vect<>(); + this.tfs = new Vect<>(); } } diff --git a/tlatools/src/tlc2/tool/liveness/NoOpLiveCheck.java b/tlatools/src/tlc2/tool/liveness/NoOpLiveCheck.java index c22ac5d7987da114672d30fcf20098bde5e8c2cf..02d93ca04fd0b8b85b7e7e7c4ae244d050589756 100644 --- a/tlatools/src/tlc2/tool/liveness/NoOpLiveCheck.java +++ b/tlatools/src/tlc2/tool/liveness/NoOpLiveCheck.java @@ -28,20 +28,21 @@ package tlc2.tool.liveness; import java.io.IOException; +import tlc2.output.EC; +import tlc2.tool.ITool; import tlc2.tool.StateVec; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.SetOfStates; import tlc2.util.statistics.DummyBucketStatistics; import tlc2.util.statistics.IBucketStatistics; public class NoOpLiveCheck implements ILiveCheck { - private final Tool tool; + private final ITool tool; private final String metadir; private final IBucketStatistics stats; - public NoOpLiveCheck(Tool tool, String metadir) { + public NoOpLiveCheck(ITool tool, String metadir) { this.tool = tool; this.metadir = metadir; this.stats = new DummyBucketStatistics(); @@ -50,13 +51,13 @@ public class NoOpLiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#addInitState(tlc2.tool.TLCState, long) */ - public void addInitState(TLCState state, long stateFP) { + public void addInitState(ITool tool, TLCState state, long stateFP) { } /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#addNextState(tlc2.tool.TLCState, long, tlc2.util.SetOfStates) */ - public void addNextState(TLCState s0, long fp0, SetOfStates nextStates) throws IOException { + public void addNextState(ITool tool, TLCState s0, long fp0, SetOfStates nextStates) throws IOException { } /* (non-Javadoc) @@ -66,24 +67,20 @@ public class NoOpLiveCheck implements ILiveCheck { return false; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#check(boolean) - */ - public boolean check(boolean forceCheck) throws Exception { - return true; + @Override + public int check(ITool tool, boolean forceCheck) throws Exception { + return EC.NO_ERROR; } - /* (non-Javadoc) - * @see tlc2.tool.liveness.ILiveCheck#finalCheck() - */ - public boolean finalCheck() throws Exception { - return true; + @Override + public int finalCheck(ITool tool) throws Exception { + return EC.NO_ERROR; } /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#checkTrace(tlc2.tool.StateVec) */ - public void checkTrace(StateVec trace) throws IOException, InterruptedException { + public void checkTrace(ITool tool, StateVec trace) throws IOException, InterruptedException { } /* (non-Javadoc) @@ -96,7 +93,7 @@ public class NoOpLiveCheck implements ILiveCheck { /* (non-Javadoc) * @see tlc2.tool.liveness.ILiveCheck#getTool() */ - public Tool getTool() { + public ITool getTool() { return tool; } diff --git a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java index 775b55768681d3a62cfeff20c366305c7e7dbc55..2555ca56a7936665e8f38e9b51fd3dfd10a7832a 100644 --- a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java +++ b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java @@ -117,4 +117,12 @@ public class NoopLivenessStateWriter implements ILivenessStateWriter { public boolean isNoop() { return true; } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isDot() + */ + @Override + public boolean isDot() { + return false; + } } diff --git a/tlatools/src/tlc2/tool/liveness/OrderOfSolution.java b/tlatools/src/tlc2/tool/liveness/OrderOfSolution.java index 69e7b514163f8d84fe87a77caab15b128dbca079..0c0513de92d0ff069a00b1e1e87e0c461619c8da 100644 --- a/tlatools/src/tlc2/tool/liveness/OrderOfSolution.java +++ b/tlatools/src/tlc2/tool/liveness/OrderOfSolution.java @@ -7,8 +7,8 @@ package tlc2.tool.liveness; import java.io.PrintStream; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.BitVector; /* @@ -63,16 +63,14 @@ public class OrderOfSolution { private LiveExprNode[] checkState; // state subformula private LiveExprNode[] checkAction; // action subformula private PossibleErrorModel[] pems; - private final Tool tool; - public OrderOfSolution(final LNEven[] livenessEventually, Tool aTool) { - this(null, livenessEventually, aTool); + public OrderOfSolution(final LNEven[] livenessEventually) { + this(null, livenessEventually); } - public OrderOfSolution(final TBGraph aTableau, final LNEven[] livenessEventually, Tool aTool) { + public OrderOfSolution(final TBGraph aTableau, final LNEven[] livenessEventually) { tableau = aTableau; promises = livenessEventually; - this.tool = aTool; } public final void printPromises(PrintStream ps) { @@ -135,7 +133,7 @@ public class OrderOfSolution { return checkState; } - public boolean[] checkState(final TLCState state) { + public boolean[] checkState(ITool tool, final TLCState state) { final boolean[] result = new boolean[checkState.length]; for (int i = 0; i < checkState.length; i++) { result[i] = checkState[i].eval(tool, state, null); @@ -148,7 +146,7 @@ public class OrderOfSolution { } // legacy LiveCheck1 - public boolean[] checkAction(final TLCState state0, final TLCState state1) { + public boolean[] checkAction(ITool tool, final TLCState state0, final TLCState state1) { final boolean[] result = new boolean[checkAction.length]; for (int i = 0; i < checkAction.length; i++) { result[i] = checkAction[i].eval(tool, state0, state1); @@ -156,7 +154,7 @@ public class OrderOfSolution { return result; } - public BitVector checkAction(final TLCState state0, final TLCState state1, final BitVector result, final int offset) { + public BitVector checkAction(ITool tool, final TLCState state0, final TLCState state1, final BitVector result, final int offset) { for (int i = 0; i < checkAction.length; i++) { if (checkAction[i].eval(tool, state0, state1)) { result.set(offset + i); diff --git a/tlatools/src/tlc2/tool/liveness/TBGraph.java b/tlatools/src/tlc2/tool/liveness/TBGraph.java index f40011d6073768cf40aa189ecf0bd2ff9d7bdd8a..1f7e16b30b3ebc2ea56e1c11e03a4c9bc93ed443 100644 --- a/tlatools/src/tlc2/tool/liveness/TBGraph.java +++ b/tlatools/src/tlc2/tool/liveness/TBGraph.java @@ -8,7 +8,7 @@ package tlc2.tool.liveness; import tlc2.util.Vect; @SuppressWarnings("serial") -public class TBGraph extends Vect { +public class TBGraph extends Vect<TBGraphNode> { /** * TBGraph represents the nodes in the tableau graph. */ diff --git a/tlatools/src/tlc2/tool/liveness/TBGraphNode.java b/tlatools/src/tlc2/tool/liveness/TBGraphNode.java index 551eed17c8ca07d44a0736b0dbc3557bb92c46ae..c2265aa6678c29d652cb15c7e71437e66eae46f6 100644 --- a/tlatools/src/tlc2/tool/liveness/TBGraphNode.java +++ b/tlatools/src/tlc2/tool/liveness/TBGraphNode.java @@ -5,8 +5,8 @@ package tlc2.tool.liveness; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.util.SetOfLong; import tlc2.util.Vect; @@ -19,7 +19,7 @@ public class TBGraphNode { * if a state-node is consistent with a tableau-node. */ private final TBPar par; // particle - public final Vect nexts; // outlinks + public final Vect<TBGraphNode> nexts; // outlinks private int index; // unique id for this node private final LiveExprNode[] statePreds; // state predicates in the particle @@ -35,7 +35,7 @@ public class TBGraphNode { public TBGraphNode(TBPar par) { this.par = par; this.index = 0; - this.nexts = new Vect(); + this.nexts = new Vect<>(); TBPar preds = new TBPar(par.size()); for (int i = 0; i < par.size(); i++) { LiveExprNode ln = par.exprAt(i); @@ -90,7 +90,7 @@ public class TBGraphNode { * values according to all state predicates of the tableau node. The state * predicates are deduced from the particles during tableau construction. */ - public boolean isConsistent(TLCState state, Tool tool) { + public boolean isConsistent(TLCState state, ITool tool) { for (int j = 0; j < this.statePreds.length; j++) { if (!this.statePreds[j].eval(tool, state, null)) { return false; diff --git a/tlatools/src/tlc2/tool/liveness/TBPar.java b/tlatools/src/tlc2/tool/liveness/TBPar.java index 851263bd1aa81aea801e11db18a48b7141400e6d..fffa55ffb19b3af26a67e42a83e533c046979ff6 100644 --- a/tlatools/src/tlc2/tool/liveness/TBPar.java +++ b/tlatools/src/tlc2/tool/liveness/TBPar.java @@ -27,7 +27,7 @@ import util.Assert; * with p. 43 fig. 0.15), thus it uses the PART-TAB algorithm (p. 456) for the * tableau construction. */ -public class TBPar extends Vect { +public class TBPar extends Vect<LiveExprNode> { public TBPar(int i) { super(i); @@ -109,8 +109,8 @@ public class TBPar extends Vect { */ public TBParVec particleClosure() { TBPar positive_closure = this.positiveClosure(); - Vect alphas = positive_closure.alphaTriples(); - Vect betas = positive_closure.betaTriples(); + Vect<TBTriple> alphas = positive_closure.alphaTriples(); + Vect<TBTriple> betas = positive_closure.betaTriples(); return particleClosure(this, alphas, betas); } @@ -208,8 +208,8 @@ public class TBPar extends Vect { * closed. All junctions must have been binarified at this stage by * makeBinary, otherwise it may give the wrong answer and crash. */ - public final Vect alphaTriples() { - Vect ts = new Vect(); + public final Vect<TBTriple> alphaTriples() { + Vect<TBTriple> ts = new Vect<>(); for (int i = 0; i < this.size(); i++) { LiveExprNode ln = this.exprAt(i); if (ln instanceof LNAll) { @@ -222,8 +222,8 @@ public class TBPar extends Vect { return ts; } - public final Vect betaTriples() { - Vect ts = new Vect(); + public final Vect<TBTriple> betaTriples() { + Vect<TBTriple> ts = new Vect<>(); for (int i = 0; i < this.size(); i++) { LiveExprNode ln = this.exprAt(i); if (ln instanceof LNEven) { diff --git a/tlatools/src/tlc2/tool/liveness/TBParVec.java b/tlatools/src/tlc2/tool/liveness/TBParVec.java index 76856c648c255217940d1d0b51e35564810ed6e7..a0b39d074ea84f10a365941a4c1ab897b949fc55 100644 --- a/tlatools/src/tlc2/tool/liveness/TBParVec.java +++ b/tlatools/src/tlc2/tool/liveness/TBParVec.java @@ -7,7 +7,7 @@ package tlc2.tool.liveness; import tlc2.util.Vect; -public class TBParVec extends Vect { +public class TBParVec extends Vect<TBPar> { public TBParVec(int size) { super(size); diff --git a/tlatools/src/tlc2/tool/liveness/TableauDiskGraph.java b/tlatools/src/tlc2/tool/liveness/TableauDiskGraph.java index 7960a2cac0c7e9b11bc6d0fb9bf991610d70f578..e3a19defa82283b6fa9c22005a87fb64bc591666 100644 --- a/tlatools/src/tlc2/tool/liveness/TableauDiskGraph.java +++ b/tlatools/src/tlc2/tool/liveness/TableauDiskGraph.java @@ -30,6 +30,7 @@ import java.io.IOException; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.ITool; import tlc2.util.LongVec; import tlc2.util.MemIntQueue; import tlc2.util.statistics.IBucketStatistics; @@ -69,7 +70,7 @@ public class TableauDiskGraph extends AbstractDiskGraph { * long as it has been recorded with recordNode(). * <p> * A node is logically undone when it's an initial state and added via - * {@link LiveCheck#addInitState(tlc2.tool.TLCState, long)} but not yet + * {@link LiveCheck#addInitState(ITool, tlc2.tool.TLCState, long)} but not yet * added via * {@link LiveCheck#addNextState(tlc2.tool.TLCState, long, tlc2.tool.StateVec, LongVec)} * . A second case is when a successor node in the behavior graph is added @@ -264,9 +265,11 @@ public class TableauDiskGraph extends AbstractDiskGraph { } /* (non-Javadoc) - * @see tlc2.tool.liveness.AbstractDiskGraph#toDotViz(int, int) + * @see tlc2.tool.liveness.AbstractDiskGraph#toDotViz(tlc2.tool.liveness.OrderOfSolution) */ - public final String toDotViz(final int slen, final int alen) { + public final String toDotViz(final OrderOfSolution oos) { + final int slen = oos.getCheckState().length; + final int alen = oos.getCheckAction().length; // The following code relies on gnodes not being null, thus safeguard // against accidental invocations. @@ -282,6 +285,9 @@ public class TableauDiskGraph extends AbstractDiskGraph { sb.append("digraph DiskGraph {\n"); sb.append("nodesep = 0.7\n"); sb.append("rankdir=LR;\n"); // Left to right rather than top to bottom + sb.append(toDotVizLegend(oos)); + sb.append("subgraph cluster_graph {\n"); + sb.append("color=\"white\";\n"); // no border. //TODO Reading the file front to end potentially yields node duplicates in the output. Better to create a (temporary) nodeptrtable and traverse it instead. long nodePtr = this.nodeRAF.getFilePointer(); long nodePtrPtr = this.nodePtrRAF.getFilePointer(); @@ -294,7 +300,7 @@ public class TableauDiskGraph extends AbstractDiskGraph { GraphNode gnode = this.getNode(fp, tidx, loc); sb.append(gnode.toDotViz(isInitState(gnode), true, slen, alen)); } - sb.append("}"); + sb.append("}}"); this.nodeRAF.seek(nodePtr); this.nodePtrRAF.seek(nodePtrPtr); } catch (IOException e) { diff --git a/tlatools/src/tlc2/tool/management/ModelCheckerMXWrapper.java b/tlatools/src/tlc2/tool/management/ModelCheckerMXWrapper.java index cffe22ffe0bec357992921affef228777a027711..f8f56b3d7f5b7026fd2d8492f85507e59ac5b848 100644 --- a/tlatools/src/tlc2/tool/management/ModelCheckerMXWrapper.java +++ b/tlatools/src/tlc2/tool/management/ModelCheckerMXWrapper.java @@ -2,8 +2,6 @@ package tlc2.tool.management; -import java.io.IOException; - import javax.management.NotCompliantMBeanException; import tlc2.TLC; @@ -18,6 +16,8 @@ import tlc2.tool.fp.DiskFPSet; */ public class ModelCheckerMXWrapper extends TLCStandardMBean implements TLCStatisticsMXBean { + public static final String OBJ_NAME = "tlc2.tool:type=ModelChecker"; + private final ModelChecker modelChecker; private final TLC tlc; @@ -27,7 +27,7 @@ public class ModelCheckerMXWrapper extends TLCStandardMBean implements TLCStatis this.modelChecker = aModelChecker; this.tlc = tlc; // register all TLCStatisticsMXBeans under the same name - registerMBean("tlc2.tool:type=ModelChecker"); + registerMBean(OBJ_NAME); } /* (non-Javadoc) @@ -55,7 +55,7 @@ public class ModelCheckerMXWrapper extends TLCStandardMBean implements TLCStatis * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#getStateQueueSize() */ public long getStateQueueSize() { - return modelChecker.theStateQueue.size(); + return modelChecker.getStateQueueSize(); } /* (non-Javadoc) @@ -76,13 +76,7 @@ public class ModelCheckerMXWrapper extends TLCStandardMBean implements TLCStatis * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#getProgress() */ public int getProgress() { - try { - return modelChecker.trace.getLevelForReporting(); - } catch (IOException e) { - // The modelchecker trace file might be closed already (e.g. it - // gets closed at the end of the modelchecker run) - return -1; - } + return modelChecker.getProgress(); } /* (non-Javadoc) @@ -145,4 +139,25 @@ public class ModelCheckerMXWrapper extends TLCStandardMBean implements TLCStatis public String getModelName() { return tlc.getModelName(); } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#stop() + */ + public void stop() { + modelChecker.stop(); + } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#suspend() + */ + public void suspend() { + modelChecker.suspend(); + } + + /* (non-Javadoc) + * @see tlc2.tool.distributed.management.TLCStatisticsMXBean#resume() + */ + public void resume() { + modelChecker.resume(); + } } diff --git a/tlatools/src/tlc2/tool/management/StateMonitor.java b/tlatools/src/tlc2/tool/management/StateMonitor.java new file mode 100644 index 0000000000000000000000000000000000000000..90eb4cd236e827ff46826b1354e739cce54927c1 --- /dev/null +++ b/tlatools/src/tlc2/tool/management/StateMonitor.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.management; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Scanner; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; + +import tlc2.tool.distributed.management.TLCStatisticsMXBean; + +/* + * This class does not compile in the Eclipse IDE on Ubuntu 18.04 with JaveSE1.8 linked to the + * 8u201-1~webupd8~1 JVM installed from webupd8 and probably fails to compile elsewhere too, + * because Eclipse fails to find the com.sun.tools.attach classes. The fix is to add the JDK's + * tools.jar to the Java installation. On Java 11 this doesn't seem to be an issue. + */ +public class StateMonitor { + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ + + public static void main(String[] args) throws IOException, MalformedObjectNameException, InterruptedException, AttachNotSupportedException { + int interval = 10; // 10sec interval by default + if (args.length == 1) { + interval = Integer.valueOf(args[0]); + } + + JMXServiceURL url = null; + try { + final List<VirtualMachineDescriptor> vmds = com.sun.tools.attach.VirtualMachine.list(); + vmds.sort(new Comparator<VirtualMachineDescriptor>() { + @Override + public int compare(VirtualMachineDescriptor o1, VirtualMachineDescriptor o2) { + // Sort those vms higher whose display name contains TLC. + final boolean c1 = o1.displayName().contains("TLC"); + final boolean c2 = o2.displayName().contains("TLC"); + if (c1 ^ c2) { + if (c1) { + return -1; + } + return 1; + } + return 0; + } + }); + + int index = 1; + try (Scanner scanner = new Scanner(System.in)) { + rd: while (true) { + index = 1; + System.out.printf("============\n"); + for (VirtualMachineDescriptor vmd : vmds) { + System.out.printf("[%s]: pid=%s, name=%s\n", index++, vmd.id(), vmd.displayName()); + } + System.out.printf("Please select the number of the Java VM running TLC to connect to:\n"); + if (scanner.hasNextInt()) { + index = scanner.nextInt(); + + // Check index is within bounds. + if (index >= 1 && index <= vmds.size()) { + break rd; + } + } + System.err.printf("Invalid selection %s\n", index); + } + } + final VirtualMachineDescriptor tlcVMD = vmds.get(index - 1); + final VirtualMachine vm = tlcVMD.provider().attachVirtualMachine(tlcVMD); + final String address = vm.startLocalManagementAgent(); + url = new JMXServiceURL(address); + System.out.printf("Connecting to TLC running at %s.\n(Hit Ctrl+c to terminate)\n", url); + } catch (NumberFormatException nfe) { + // If monitored VM has been launched with explicit port, use service url instead + // of CAL: + // -Dcom.sun.management.jmxremote + // -Dcom.sun.management.jmxremote.port=10995 + // -Dcom.sun.management.jmxremote.ssl=false + // -Dcom.sun.management.jmxremote.authenticate=false + // => "service:jmx:rmi:///jndi/rmi://localhost:10995/jmxrmi". + url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + "/jmxrmi"); + System.out.printf("Connecting to TLC running at %s.\n(Hit Ctrl+c to terminate)\n", url); + } + + final JMXConnector jmxConnector = JMXConnectorFactory.connect(url); + final MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection(); + // ObjectName should be same as your MBean name + final ObjectName mbeanName = new ObjectName(ModelCheckerMXWrapper.OBJ_NAME); + + // Get MBean proxy instance that will be used to make calls to registered MBean + final TLCStatisticsMXBean mbeanProxy = (TLCStatisticsMXBean) MBeanServerInvocationHandler + .newProxyInstance(mbeanServerConnection, mbeanName, TLCStatisticsMXBean.class, true); + + while (true) { + System.out.printf("############ %s ############\n%s", SDF.format(new Date()), mbeanProxy.getCurrentState()); + Thread.sleep(interval * 1000L); + } + + // No need to close the connection because JVM itself terminates. + //jmxConnector.close(); + } +} diff --git a/tlatools/src/tlc2/tool/queue/ByteArrayQueue.java b/tlatools/src/tlc2/tool/queue/ByteArrayQueue.java new file mode 100644 index 0000000000000000000000000000000000000000..7a5228f25b6ec83b973d9eac0a80e422f06a594f --- /dev/null +++ b/tlatools/src/tlc2/tool/queue/ByteArrayQueue.java @@ -0,0 +1,474 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 30 Apr 2007 at 13:18:27 PST by lamport +// modified on Tue Feb 13 18:38:24 PST 2001 by yuanyu + +package tlc2.tool.queue; + +import java.io.IOException; + +import tlc2.TLCGlobals; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.tool.StateVec; +import tlc2.tool.TLCState; +import tlc2.tool.Worker; + +/* + * This class is identical to StateQueue except that it internally works + * on byte[] whereas StateQueue's internal data is TLCStates. In other words, + * serialization of TLCState to a byte[] occurs outside the critical section. + */ +public abstract class ByteArrayQueue implements IStateQueue { + /** + * In model checking, this is the sequence of states waiting to be explored + * further. When the queue is empty, the checking is completed. + */ + protected long len = 0; // the queue length + private int numWaiting = 0; // the number of waiting threads + private volatile boolean finish = false; // terminate + /** + * Signals {@link Worker} that checkpointing is going happen next. + */ + private boolean stop = false; // suspend all workers. + /** + * Synchronizes between workers and checkpointing. More precisely it is used + * to notify (wake up) the checkpointing thread once the last worker is + * done. + */ + private Object mu = new Object(); + + + private final byte[] toBytes(final TLCState state) { + try { + final DiskByteArrayQueue.ByteValueOutputStream vos = new DiskByteArrayQueue.ByteValueOutputStream(); + state.write(vos); + return vos.toByteArray(); + } catch (IOException notExpectedToHappen) { + // With ByteArrayOutputStream + notExpectedToHappen.printStackTrace(); + } + return null; + } + + private final byte[] toBytes(final TLCState state, final DiskByteArrayQueue.ByteValueOutputStream vos) { + try { + state.write(vos); + return vos.toByteArray(); + } catch (IOException notExpectedToHappen) { + // With ByteArrayOutputStream + notExpectedToHappen.printStackTrace(); + } + return null; + } + + private final TLCState toState(final byte[] bytes) { + try { + final TLCState state = TLCState.Empty.createEmpty(); + state.read(new DiskByteArrayQueue.ByteValueInputStream(bytes)); + return state; + } catch (IOException notExpectedToHappen) { + // With ByteValueInputStream + notExpectedToHappen.printStackTrace(); + } + return null; + } + + /* Enqueues the state. It is not thread-safe. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#enqueue(tlc2.tool.TLCState) + */ + @Override + public final void enqueue(final TLCState state) { + enqueue(toBytes(state)); + } + + private final void enqueue(final byte[] state) { + this.enqueueInner(state); + this.len++; + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#dequeue() + */ + @Override + public final TLCState dequeue() { + final byte[] bytes = dequeueRaw(); + if (bytes != null) { + return toState(bytes); + } + return null; + } + + private final byte[] dequeueRaw() { + if (isEmpty()) { + return null; + } + final byte[] state = this.dequeueInner(); + this.len--; + return state; + } + + /* Enqueues a state. Wake up any waiting thread. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#sEnqueue(tlc2.tool.TLCState) + */ + @Override + public final void sEnqueue(final TLCState state) { + sEnqueue(toBytes(state)); + } + + private final synchronized void sEnqueue(final byte[] state) { + this.enqueueInner(state); + this.len++; + if (this.numWaiting > 0 && !this.stop) { + this.notifyAll(); + } + } + + /* Enqueues a list of states. Wake up any waiting thread. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#sEnqueue(tlc2.tool.TLCState[]) + */ + @Override + public final void sEnqueue(final TLCState[] states) { + final byte[][] bytes = new byte[states.length][]; + for (int i = 0; i < states.length; i++) { + bytes[i] = toBytes(states[i]); + } + sEnqueue(bytes); + } + + private final synchronized void sEnqueue(final byte[][] states) { + for (int i = 0; i < states.length; i++) { + this.enqueueInner(states[i]); + } + this.len += states.length; + if (this.numWaiting > 0 && !this.stop) { + this.notifyAll(); + } + } + @Override + public final void sEnqueue(final StateVec stateVec) { + sEnqueue(stateVec, stateVec.size()); + } + +// @Override + public final void sEnqueue(final StateVec stateVec, int n) { + if (n == 0) { + return; + } + + final DiskByteArrayQueue.ByteValueOutputStream vos = new DiskByteArrayQueue.ByteValueOutputStream(); + final byte[][] bytes = new byte[n][]; + for (int i = 0; i < stateVec.size(); i++) { + final TLCState state = stateVec.elementAt(i); + if (state != null) { + bytes[n - 1] = toBytes(state, vos); + n--; + } + } + sEnqueue(bytes); + } + + @Override + public final TLCState sPeek() { + final byte[] bytes = sPeekRaw(); + if (bytes != null) { + return toState(bytes); + } + return null; + } + + private final synchronized byte[] sPeekRaw() { + if (this.isAvail()) { + return this.peekInner(); + } + return null; + } + + /* Return the first element in the queue. Wait if empty. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#sDequeue() + */ + @Override + public final TLCState sDequeue() { + final byte[] bytes = sDequeueRaw(); + if (bytes != null) { + return toState(bytes); + } + return null; + } + + private final synchronized byte[] sDequeueRaw() { + if (this.isAvail()) { + final byte[] state = this.dequeueInner(); + assert state != null : "Null state found on queue"; + this.len--; + return state; + } + return null; + } + + @Override + public final TLCState[] sDequeue(int cnt) { + final byte[][] bytes = sDequeueRaw(cnt); + if (bytes != null) { + final TLCState[] array = new TLCState[cnt]; + for (int i = 0; i < array.length; i++) { + array[i] = toState(bytes[i]); + } + return array; + } + return null; + } + + private final synchronized byte[][] sDequeueRaw(int cnt) { + assert cnt > 0 : "Nonpositive number of states requested."; + if (this.isAvail()) { + if (cnt > len) { + // in this case, casting len to int is safe + cnt = (int) len; + } + final byte[][] states = new byte[cnt][]; + int idx; + for (idx = 0; idx < cnt && this.len > 0; idx++) { + states[idx] = this.dequeueInner(); + this.len--; + } + if (idx == cnt) { + return states; + } + + // cnt >= index, shrink resulting array + // dead code due to resetting cnt == len if cnt > len + final byte[][] res = new byte[idx][]; + for (int i = 0; i < idx; i++) { + res[i] = states[i]; + } + return res; + } + return null; + } + + /** + * Checks if states are available. If no states are available, the callee + * will be put to sleep until new states are available or another callee + * signals work done. This is determined by the fact, that all other workers + * are waiting for states. + * + * @return true if states are available in the queue. + */ + private final boolean isAvail() { + /* + * isAvail is only called from within sDequeue() and sDequeue(..) and + * thus is always synchronized on this. + */ + + if (this.finish) { + return false; + } + while (isEmpty() || this.stop) { + this.numWaiting++; + // the last worker accessing notices that all other workers are + // waiting. This indicates that all work is done. + if (this.numWaiting >= TLCGlobals.getNumWorkers()) { + if (isEmpty()) { + this.numWaiting--; + return false; + } + // TODO what happens if control flow exits without ever + // notifying the checkpoint (mu.wait()) thread? In case + // of distributed TLC, this is the main thread of + // TLCServer. + synchronized (this.mu) { + this.mu.notify(); + } + } + try { + this.wait(); + } catch (Exception e) { + MP.printError(EC.GENERAL, "making a worker wait for a state from the queue", e); // LL changed call 7 April 2012 + System.exit(1); + } + this.numWaiting--; + if (this.finish) { + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#finishAll() + */ + @Override + public synchronized void finishAll() { + this.finish = true; + // Notify all other worker threads. + this.notifyAll(); + // Need to wake main thread that waits (mu.wait()) to suspend access to + // the squeue (see suspendAll). The main thread might attempt to do its + // periodic work (tlc2.tool.ModelChecker.doPeriodicWork()) the moment + // all worker threads finish. Since suspendAll assumes the main thread + // is woken up (potentially) multiple times from sleeping indefinitely + // in the while loop before it finally returns after locking the + // StateQueue, we have to live up to this assumption. + // + // synchronized(this.mu) does not block when the main thread waits on + // this.mu in suspend all. We merely have to follow proper thread access. + synchronized (this.mu) { + // Technically notify() would do. + this.mu.notify(); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#suspendAll() + */ + @Override + public final boolean suspendAll() { + boolean needWait = false; + synchronized (this) { + if (this.finish) { + return false; + } + this.stop = true; + needWait = needsWaiting(); + } + // Wait for all worker threads to stop. + while (needWait) { + synchronized (this.mu) { + try { + // finishAll & suspendAll race: + // + // suspendAll from main is on the heels of finishAll, but + // not quite as fast. SuspendAll's synchronized(this.mu) + // is executed one clock tick after finishAll's thus waiting + // for finishAll() to notify all waiters of this.mu. + // With main being the only potential waiter in the system + // nobody gets notified and the lock on this released + // subsequently. + // Now it's suspendAll's turn. It acquires the lock on + // this.mu and immediately after goes to wait on it + // (this.mu) to be waken by worker threads eventually. + // Unfortunately, there are none left in the system. All + // have long finishedAll. + // + // The fix is to check the this.finish variable one more + // time directly after suspendAll acquires the lock this.mu, + // it checks if it still has to wait for workers. To make + // sure it reads the most recent value, it's declared + // volatile to establish a happens-before relation (since + // Java5's memory model) between workers and main. Otherwise + // the VM might decide to let main read a cached value of + // false of this.finish. + if (this.finish) { + return false; + } + // waiting here assumes that subsequently a worker + // is going to wake us up by calling isAvail() or + // this.mu.notify*() + this.mu.wait(); + } catch (Exception e) { + MP.printError(EC.GENERAL, "waiting for a worker to wake up", e); // LL changed call 7 April 2012 + System.exit(1); + } + } + synchronized (this) { + if (this.finish) { + return false; + } + needWait = needsWaiting(); + } + } + return true; + } + + /** + * @return + */ + private boolean needsWaiting() { + //MAK 04/2012: Commented to fix an EOFException when liveness checking is enabled +// // no need to wait without workers present +// if (this.numWaiting < 1) { +// return false; +// } + // if all workers wait at once, it indicates that all work is + // done and suspending all workers can happen right away without + // waiting. + return this.numWaiting < TLCGlobals.getNumWorkers(); + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#resumeAll() + */ + @Override + public final synchronized void resumeAll() { + this.stop = false; + this.notifyAll(); + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#resumeAllStuck() + */ + @Override + public void resumeAllStuck() { + // needsWaiting() read might have been incorrect if a TLCWorkerRMI dies + // unexpectedly, thus this recovers a potentially stuck checkpointing + // run. + if (stop) { + synchronized (mu) { + mu.notifyAll(); + } + } + // + if (!stop && !isEmpty() && this.numWaiting > 0) { + synchronized (this) { + this.notifyAll(); + } + } + } + + /* This method returns the size of the state queue. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#size() + */ + @Override + public final long size() { + return this.len; + } + + /** + * @return true iff the inner queue does not contain states + */ + @Override + public boolean isEmpty() { + return len < 1; + } + + /* This method must be implemented in the subclass. */ + abstract void enqueueInner(byte[] state); + + /* This method must be implemented in the subclass. */ + abstract byte[] dequeueInner(); + + /* This method must be implemented in the subclass. */ + abstract byte[] peekInner(); + + /* Checkpoint. */ + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#beginChkpt() + */ + public abstract void beginChkpt() throws IOException; + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#commitChkpt() + */ + public abstract void commitChkpt() throws IOException; + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#recover() + */ + public abstract void recover() throws IOException; +} diff --git a/tlatools/src/tlc2/tool/queue/DiskByteArrayQueue.java b/tlatools/src/tlc2/tool/queue/DiskByteArrayQueue.java new file mode 100644 index 0000000000000000000000000000000000000000..1deadcf6acaa683f2a63c3e2006bac8dffb0af98 --- /dev/null +++ b/tlatools/src/tlc2/tool/queue/DiskByteArrayQueue.java @@ -0,0 +1,945 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 30 Apr 2007 at 9:25:48 PST by lamport +// modified on Thu Feb 8 23:32:12 PST 2001 by yuanyu + +package tlc2.tool.queue; + +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.file.Files; +import java.util.Arrays; + +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.ValueConstants; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.RecordValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.TupleValue; +import util.Assert; +import util.BufferedDataInputStream; +import util.BufferedDataOutputStream; +import util.FileUtil; +import util.IDataInputStream; +import util.IDataOutputStream; +import util.UniqueString; +import util.WrongInvocationException; + +/** + * A {@link DiskByteArrayQueue} uses the local hard disc as a backing store for + * states. An in-memory buffer of size {@link DiskByteArrayQueue}{@link #BufSize} + */ +public class DiskByteArrayQueue extends ByteArrayQueue { + // TODO dynamic bufsize based on current VM parameters? + private final static int BufSize = Integer.getInteger(DiskStateQueue.class.getName() + ".BufSize", 8192); + + /* + * Invariants: I1. Entries in deqBuf are in the indices: [deqIndex, + * deqBuffer.length ) I2. Entries in enqBuf are in the indices: [ 0, + * enqIndex ) I3. 0 <= deqIndex <= deqBuf.length, where deqIndex == 0 => + * buffer full deqIndex == deqBuf.length => buffer empty I4. 0 <= enqIndex + * <= enqBuf.length, where enqIndex == 0 => buffer empty enqIndex == + * enqBuf.length => buffer full + */ + + /* Fields */ + private final String filePrefix; + protected byte[][] deqBuf, enqBuf; + protected int deqIndex, enqIndex; + protected ByteArrayPoolReader reader; + protected ByteArrayPoolWriter writer; + + /** + * The SPC takes care of deleting swap files on the lower end of the range + * (loPool, hiPool). It terminates, when the first checkpoint is written at + * which point checkpointing itself takes care of removing obsolete swap + * files. + */ + protected final StatePoolCleaner cleaner; + private int loPool, hiPool, lastLoPool, newLastLoPool; + private File loFile; + + // TESTING ONLY! + DiskByteArrayQueue() throws IOException { + this(Files.createTempDirectory("DiskByteArrayQueue").toFile().toString()); + } + + /* Constructors */ + public DiskByteArrayQueue(String diskdir) { + this.deqBuf = new byte[BufSize][]; + this.enqBuf = new byte[BufSize][]; + this.deqIndex = BufSize; + this.enqIndex = 0; + this.loPool = 1; + this.hiPool = 0; + this.lastLoPool = 0; + this.filePrefix = diskdir + FileUtil.separator; + File rFile = new File(this.filePrefix + Integer.toString(0)); + this.reader = new ByteArrayPoolReader(BufSize, rFile); + this.reader.setDaemon(true); + this.loFile = new File(this.filePrefix + Integer.toString(this.loPool)); + this.reader.start(); + this.writer = new ByteArrayPoolWriter(BufSize, this.reader); + this.writer.setDaemon(true); + this.writer.start(); + this.cleaner = new StatePoolCleaner(); + this.cleaner.setDaemon(true); + this.cleaner.start(); + } + + final void enqueueInner(byte[] state) { + if (this.enqIndex == this.enqBuf.length) { + // enqBuf is full; flush it to disk + try { + String pstr = Integer.toString(this.hiPool); + File file = new File(this.filePrefix + pstr); + this.enqBuf = this.writer.doWork(this.enqBuf, file); + this.hiPool++; + this.enqIndex = 0; + } catch (Exception e) { + Assert.fail(EC.SYSTEM_ERROR_WRITING_STATES, + new String[] { "queue", (e.getMessage() == null) ? e.toString() : e.getMessage() }); + } + } + this.enqBuf[this.enqIndex++] = state; + } + + final byte[] dequeueInner() { + if (this.deqIndex == this.deqBuf.length) { + this.fillDeqBuffer(); + } + return this.deqBuf[this.deqIndex++]; + } + + byte[] peekInner() { + if (this.deqIndex == this.deqBuf.length) { + this.fillDeqBuffer(); + } + return this.deqBuf[this.deqIndex]; + } + + private final void fillDeqBuffer() { + try { + if (this.loPool + 1 <= this.hiPool) { + // We are sure there are disk files. + if (this.loPool + 1 >= this.hiPool) { + // potential read-write conflict on a file + this.writer.ensureWritten(); + } + this.deqBuf = this.reader.doWork(this.deqBuf, this.loFile); + this.deqIndex = 0; + this.loPool++; + String pstr = Integer.toString(this.loPool); + this.loFile = new File(this.filePrefix + pstr); + } else { + // We still need to check if a file is buffered. + this.writer.ensureWritten(); + byte[][] buf = this.reader.getCache(this.deqBuf, this.loFile); + if (buf != null) { + this.deqBuf = buf; + this.deqIndex = 0; + this.loPool++; + String pstr = Integer.toString(this.loPool); + this.loFile = new File(this.filePrefix + pstr); + } else { + // copy entries from enqBuf to deqBuf. + this.deqIndex = this.deqBuf.length - this.enqIndex; + System.arraycopy(this.enqBuf, 0, this.deqBuf, this.deqIndex, this.enqIndex); + this.enqIndex = 0; + } + } + // Notify the cleaner to do its job unless its waits for more work + // to pile up. + if ((loPool - lastLoPool) > 100) { //TODO Take BufSize into account. It defines the disc file size. + synchronized (this.cleaner) { + this.cleaner.deleteUpTo = loPool - 1; + this.cleaner.notifyAll(); + } + } + } catch (Exception e) { + Assert.fail(EC.SYSTEM_ERROR_READING_STATES, new String[] { "queue", + (e.getMessage() == null) ? e.toString() : e.getMessage() }); + } + } + + /* Checkpoint. */ + public final void beginChkpt() throws IOException { + synchronized (this.cleaner) { + // Checkpointing takes precedence over periodic cleaning + // (cleaner would otherwise delete checkpoint files as it know + // nothing of checkpoints). + this.cleaner.finished = true; + this.cleaner.notifyAll(); + } + + String filename = this.filePrefix + "queue.tmp"; + final BufferedDataOutputStream vos = new BufferedDataOutputStream(filename); + vos.writeLong(this.len); + vos.writeInt(this.loPool); + vos.writeInt(this.hiPool); + vos.writeInt(this.enqIndex); + vos.writeInt(this.deqIndex); + for (int i = 0; i < this.enqIndex; i++) { + vos.writeInt(this.enqBuf[i].length); + vos.write(this.enqBuf[i]); + } + for (int i = this.deqIndex; i < this.deqBuf.length; i++) { + vos.writeInt(this.deqBuf[i].length); + vos.write(this.deqBuf[i]); + } + vos.close(); + this.newLastLoPool = this.loPool - 1; + } + + public final void commitChkpt() throws IOException { + for (int i = this.lastLoPool; i < this.newLastLoPool; i++) { + String pstr = Integer.toString(i); + File oldPool = new File(this.filePrefix + pstr); + if (!oldPool.delete()) { + String msg = "DiskStateQueue.commitChkpt: cannot delete " + oldPool; + throw new IOException(msg); + } + } + this.lastLoPool = this.newLastLoPool; + File oldChkpt = new File(this.filePrefix + "queue.chkpt"); + File newChkpt = new File(this.filePrefix + "queue.tmp"); + if ((oldChkpt.exists() && !oldChkpt.delete()) || !newChkpt.renameTo(oldChkpt)) { + String msg = "DiskStateQueue.commitChkpt: cannot delete " + oldChkpt; + throw new IOException(msg); + } + } + + public final void recover() throws IOException { + String filename = this.filePrefix + "queue.chkpt"; + final BufferedDataInputStream vis = new BufferedDataInputStream(filename); + this.len = vis.readLong(); + this.loPool = vis.readInt(); + this.hiPool = vis.readInt(); + this.enqIndex = vis.readInt(); + this.deqIndex = vis.readInt(); + this.lastLoPool = this.loPool - 1; + + for (int i = 0; i < this.enqIndex; i++) { + this.enqBuf[i] = new byte[vis.readInt()]; + vis.read(this.enqBuf[i]); + } + for (int i = this.deqIndex; i < this.deqBuf.length; i++) { + this.deqBuf[i] = new byte[vis.readInt()]; + vis.read(this.deqBuf[i]); + } + vis.close(); + File file = new File(this.filePrefix + Integer.toString(this.lastLoPool)); + boolean canRead = (this.lastLoPool < this.hiPool); + this.reader.restart(file, canRead); + String pstr = Integer.toString(this.loPool); + this.loFile = new File(this.filePrefix + pstr); + } + + public void finishAll() { + super.finishAll(); + synchronized (this.writer) { + this.writer.notifyAll(); + } + synchronized (this.reader) { + this.reader.setFinished(); + this.reader.notifyAll(); + } + synchronized (this.cleaner) { + this.cleaner.finished = true; + this.cleaner.notifyAll(); + } + } + + private class StatePoolCleaner extends Thread { + + private volatile boolean finished = false; + public int deleteUpTo; + + private StatePoolCleaner() { + super("RawTLCStatePoolCleaner"); + } + + /* (non-Javadoc) + * @see java.lang.Thread#run() + */ + public void run() { + try { + synchronized (this) { + while (!this.finished) { + this.wait(); + if (this.finished) { + return; + } + + for (int i = lastLoPool; i < deleteUpTo; i++) { + final File oldPoolFile = new File(filePrefix + Integer.toString(i)); + if (!oldPoolFile.delete()) { + // No reason to terminate/kill TLC when the cleanup fails. + // Contrary to StatePoolReader/Write, cleanup is optional + // functionality whose purpose is to prevent the disc from + // filling up. If the cleaner fails, the user can still + // manually delete the files. + MP.printWarning(EC.SYSTEM_ERROR_CLEANING_POOL, oldPoolFile.getCanonicalPath()); + } + } + lastLoPool = deleteUpTo; + } + } + } catch (Exception e) { + // Assert.printStack(e); + MP.printError(EC.SYSTEM_ERROR_CLEANING_POOL, e.getMessage(), e); + System.exit(1); + } + } + } + + private static final class ByteArrayPoolWriter extends Thread { + + private byte[][] buf; + private File poolFile; // the file to be written + private final ByteArrayPoolReader reader; // the consumer if not null + + public ByteArrayPoolWriter(int bufSize, ByteArrayPoolReader reader) { + super("RawTLCStatePoolWriter"); + this.buf = new byte[bufSize][]; + this.poolFile = null; + this.reader = reader; + } + + /* + * This method first completes the preceding write if not started. + * It then notifies this writer to flush enqBuf to file. In practice, + * we expect the preceding write to have been completed. + */ + public final synchronized byte[][] doWork(byte[][] enqBuf, File file) + throws IOException { + if (this.poolFile != null) { + final BufferedDataOutputStream vos = new BufferedDataOutputStream(this.poolFile); + for (int i = 0; i < this.buf.length; i++) { + vos.writeInt(this.buf[i].length); + vos.write(this.buf[i]); + } + vos.close(); + } + byte[][] res = this.buf; + this.buf = enqBuf; + this.poolFile = file; + this.notify(); + return res; + } + + /* Spin waiting for the write to complete. */ + public final void ensureWritten() throws InterruptedException { + synchronized(this) { + while (this.poolFile != null) { + this.wait(); + } + } + } + + public final synchronized void beginChkpt(ObjectOutputStream oos) + throws IOException { + boolean hasFile = (this.poolFile == null) ? false : true; + oos.writeBoolean(hasFile); + if (hasFile) { + oos.writeObject(this.poolFile); + for (int i = 0; i < this.buf.length; i++) { + oos.writeObject(this.buf[i]); + } + } + } + + /* Note this method is not synchronized. */ + public final void recover(ObjectInputStream ois) throws IOException { + boolean hasFile = ois.readBoolean(); + if (hasFile) { + try { + this.poolFile = (File)ois.readObject(); + for (int i = 0; i < this.buf.length; i++) { + this.buf[i] = (byte[])ois.readObject(); + } + } + catch (ClassNotFoundException e) + { + Assert.fail(EC.SYSTEM_CHECKPOINT_RECOVERY_CORRUPT, e); + } + } + else { + this.poolFile = null; + } + } + + /** + * Write "buf" to "poolFile". The objects in the queue are written + * using Java's object serialization facilities. + */ + public void run() { + try { + synchronized(this) { + while (true) { + while (this.poolFile == null) { + this.wait(); + // we are done without ever receiving a pool file + if(this.poolFile == null) { + return; + } + } + final BufferedDataOutputStream vos = new BufferedDataOutputStream(this.poolFile); + for (int i = 0; i < this.buf.length; i++) { + vos.writeInt(this.buf[i].length); + vos.write(this.buf[i]); + } + vos.close(); + this.poolFile = null; + this.notify(); + if (this.reader != null) this.reader.wakeup(); + } + } + } + catch (Exception e) { + // Assert.printStack(e); + MP.printError(EC.SYSTEM_ERROR_WRITING_POOL, e.getMessage(), e); + System.exit(1); + } + } + } + + private static final class ByteArrayPoolReader extends Thread { + + public ByteArrayPoolReader(int bufSize, File file) { + super("RawTLCStatePoolReader"); + this.buf = new byte[bufSize][]; + this.poolFile = file; + this.isFull = false; + this.canRead = false; + } + + private byte[][] buf; + private File poolFile; // the file to be read + private boolean isFull; // true iff the buf is filled + private boolean canRead; // true iff the file can be read + private boolean finished = false; + + public final synchronized void wakeup() { + this.canRead = true; + this.notify(); + } + + public final synchronized void restart(File file, boolean canRead) { + this.poolFile = file; + this.isFull = false; + this.canRead = canRead; + this.notify(); + } + + /* + * In the most common case, this method expects to see the buffer is + * full, it returns its buffer and notifies this reader to read the + * content of the file. + */ + public final synchronized byte[][] doWork(byte[][] deqBuf, File file) + throws IOException, ClassNotFoundException { + if (this.isFull) { + assert this.poolFile == null : EC.SYSTEM_FILE_NULL; + byte[][] res = this.buf; + this.buf = deqBuf; + this.poolFile = file; + this.isFull = false; // <file, false> + this.canRead = true; + this.notify(); + return res; + } + else if (this.poolFile != null) { + final BufferedDataInputStream vis = new BufferedDataInputStream(this.poolFile); + for (int i = 0; i < deqBuf.length; i++) { + deqBuf[i] = new byte[vis.readInt()]; + vis.read(deqBuf[i]); + } + vis.close(); + this.poolFile = file; // <file, false> + this.canRead = true; + this.notify(); + return deqBuf; + } + else { + final BufferedDataInputStream vis = new BufferedDataInputStream(this.poolFile); + for (int i = 0; i < deqBuf.length; i++) { + deqBuf[i] = new byte[vis.readInt()]; + vis.read(deqBuf[i]); + } + vis.close(); // <null, false> + return deqBuf; + } + } + + /* + * Returns the cached buffer if filled. Otherwise, returns null. + */ + public final synchronized byte[][] getCache(byte[][] deqBuf, File file) + throws IOException, ClassNotFoundException { + if (this.isFull) { + assert this.poolFile == null : EC.SYSTEM_FILE_NULL; + byte[][] res = this.buf; + this.buf = deqBuf; + this.poolFile = file; + this.isFull = false; // <file, false> + this.canRead = false; + return res; + } + else if (this.poolFile != null && this.canRead) { + // this should seldom occur. + final BufferedDataInputStream vis = new BufferedDataInputStream(this.poolFile); + for (int i = 0; i < deqBuf.length; i++) { + deqBuf[i] = new byte[vis.readInt()]; + vis.read(deqBuf[i]); + } + vis.close(); + // this.poolFile.delete(); + this.poolFile = file; // <file, false> + this.canRead = false; + return deqBuf; + } + return null; + } + + public final synchronized void beginChkpt(ObjectOutputStream oos) + throws IOException { + boolean hasFile = this.poolFile != null; + oos.writeBoolean(hasFile); + oos.writeBoolean(this.canRead); + oos.writeBoolean(this.isFull); + if (hasFile) { + oos.writeObject(this.poolFile); + } + if (this.isFull) { + for (int i = 0; i < this.buf.length; i++) { + oos.writeObject(this.buf[i]); + } + } + } + + /* Note that this method is not synchronized. */ + public final void recover(ObjectInputStream ois) throws IOException { + boolean hasFile = ois.readBoolean(); + this.canRead = ois.readBoolean(); + this.isFull = ois.readBoolean(); + try { + if (hasFile) { + this.poolFile = (File)ois.readObject(); + } + if (this.isFull) { + for (int i = 0; i < this.buf.length; i++) { + this.buf[i] = (byte[])ois.readObject(); + } + } + } + catch (ClassNotFoundException e) + { + Assert.fail(EC.SYSTEM_CHECKPOINT_RECOVERY_CORRUPT, e); + } + } + + /** + * Read the contents of "poolFile" into "buf". The objects in the + * file are read using Java's object serialization facilities. + */ + public void run() { + try { + synchronized(this) { + while (true) { + while (this.poolFile == null || this.isFull || !this.canRead) { + this.wait(); + if(this.finished ) { + return; + } + } + final BufferedDataInputStream vis = new BufferedDataInputStream(this.poolFile); + for (int i = 0; i < this.buf.length; i++) { + this.buf[i] = new byte[vis.readInt()]; + vis.read(this.buf[i]); + } + vis.close(); + this.poolFile = null; + this.isFull = true; // <null, true> + } + } + } + catch (Exception e) + { + // Assert.printStack(e); + MP.printError(EC.SYSTEM_ERROR_READING_POOL, e.getMessage(), e); + System.exit(1); + } + } + + public void setFinished() { + finished = true; + } + } + + static final class ByteValueOutputStream implements IValueOutputStream, IDataOutputStream { + + private byte[] bytes; + + private int idx; + + public ByteValueOutputStream() { + this.bytes = new byte[16]; // TLCState "header" already has 6 bytes. + this.idx = 0; + } + + private void ensureCapacity(int minCap) { + if (minCap - bytes.length > 0) { + int oldCap = bytes.length; + int newCap = oldCap << 1; // double size + if (newCap - minCap < 0) { + newCap = minCap; + } + bytes = Arrays.copyOf(bytes, newCap); + } + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeShort(short) + */ + @Override + public final void writeShort(short s) throws IOException { + ensureCapacity(idx + 2); + this.bytes[idx++] = (byte) ((s >>> 8) & 0xff); + this.bytes[idx++] = (byte) (s & 0xff); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeInt(int) + */ + @Override + public final void writeInt(int i) throws IOException { + ensureCapacity(idx + 4); + this.bytes[idx++] = (byte) ((i >>> 24) & 0xff); + this.bytes[idx++] = (byte) ((i >>> 16) & 0xff); + this.bytes[idx++] = (byte) ((i >>> 8) & 0xff); + this.bytes[idx++] = (byte) (i & 0xff); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeLong(long) + */ + @Override + public final void writeLong(long l) throws IOException { + ensureCapacity(idx + 8); + this.bytes[idx++] = (byte) ((l >>> 56) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 48) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 40) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 32) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 24) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 16) & 0xff); + this.bytes[idx++] = (byte) ((l >>> 8) & 0xff); + this.bytes[idx++] = (byte) (l & 0xff); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#close() + */ + @Override + public final void close() throws IOException { + // No-op + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeShortNat(short) + */ + @Override + public final void writeShortNat(short x) throws IOException { + if (x > 0x7f) { + this.writeShort((short) -x); + } else { + this.writeByte((byte) x); + } + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeNat(int) + */ + @Override + public final void writeNat(int x) throws IOException { + if (x > 0x7fff) { + this.writeInt(-x); + } else { + this.writeShort((short) x); + } + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeLongNat(long) + */ + @Override + public final void writeLongNat(long x) throws IOException { + if (x <= 0x7fffffff) { + this.writeInt((int) x); + } else { + this.writeLong(-x); + } + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeByte(byte) + */ + @Override + public final void writeByte(byte b) throws IOException { + ensureCapacity(idx + 1); + this.bytes[idx++] = b; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#writeBoolean(boolean) + */ + @Override + public final void writeBoolean(boolean bool) throws IOException { + byte b = (bool ? (byte)1 : (byte)0); + this.writeByte(b); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#getOutputStream() + */ + @Override + public final IDataOutputStream getOutputStream() { + return this; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueOutputStream#put(java.lang.Object) + */ + @Override + public final int put(Object obj) { + return -1; + } + + public final byte[] toByteArray() { + final byte[] copyOf = Arrays.copyOf(bytes, idx); + idx = 0; + return copyOf; + } + + /* (non-Javadoc) + * @see util.IDataOutputStream#writeString(java.lang.String) + */ + @Override + public final void writeString(String str) throws IOException { + final int length = str.length(); + ensureCapacity(idx + length); + + final char[] c = new char[length]; + str.getChars(0, length, c, 0); + + for (int i = 0; i < c.length; i++) { + this.bytes[idx++] = (byte) c[i]; + } + } + } + + static final class ByteValueInputStream implements ValueConstants, IValueInputStream, IDataInputStream { + + private final byte[] bytes; + + private int idx = 0; + + public ByteValueInputStream(byte[] bytes) { + this.bytes = bytes; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#read() + */ + @Override + public final IValue read() throws IOException { + final byte kind = this.readByte(); + + switch (kind) { + case BOOLVALUE: { + return (this.readBoolean()) ? BoolValue.ValTrue : BoolValue.ValFalse; + } + case INTVALUE: { + return IntValue.gen(this.readInt()); + } + case STRINGVALUE: { + return StringValue.createFrom(this); + } + case MODELVALUE: { + return ModelValue.mvs[this.readShort()]; + } + case INTERVALVALUE: { + return new IntervalValue(this.readInt(), this.readInt()); + } + case RECORDVALUE: { + return RecordValue.createFrom(this); + } + case FCNRCDVALUE: { + return FcnRcdValue.createFrom(this); + } + case SETENUMVALUE: { + return SetEnumValue.createFrom(this); + } + case TUPLEVALUE: { + return TupleValue.createFrom(this); + } + default: { + throw new WrongInvocationException("ValueInputStream: Can not unpickle a value of kind " + kind); + } + } + } + + private final boolean readBoolean() throws EOFException, IOException { + return (bytes[idx++] != 0); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readShort() + */ + @Override + public final int readShort() throws IOException { + return (short) ((bytes[idx++] << 8) | (bytes[idx++] & 0xff)); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readInt() + */ + @Override + public final int readInt() throws IOException { + int res = bytes[idx++]; + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + return res; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readLong() + */ + @Override + public final long readLong() throws IOException { + long res = bytes[idx++]; + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + res <<= 8; res |= (bytes[idx++] & 0xff); + return res; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#close() + */ + @Override + public final void close() throws IOException { + // No-op + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readNat() + */ + @Override + public final int readNat() throws IOException { + int res = this.readShort(); + if (res >= 0) return res; + res = (res << 16) | (this.readShort() & 0xFFFF); + return -res; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readShortNat() + */ + @Override + public final short readShortNat() throws IOException { + short res = this.readByte(); + if (res >= 0) return res; + return (short) -((res << 8) | (this.readByte() & 0xFF)); + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readLongNat() + */ + @Override + public final long readLongNat() throws IOException { + long res = this.readInt(); + if (res >= 0) return res; + res = (res << 32) | ((long)this.readInt() & 0xFFFFFFFFL); + return -res; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#readByte() + */ + @Override + public final byte readByte() throws EOFException, IOException { + return bytes[idx++]; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#assign(java.lang.Object, int) + */ + @Override + public final void assign(Object obj, int idx) { + // No-op + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#getIndex() + */ + @Override + public final int getIndex() { + return -1; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#getInputStream() + */ + @Override + public final IDataInputStream getInputStream() { + return this; + } + + /* (non-Javadoc) + * @see tlc2.value.IValueInputStream#getValue(int) + */ + @Override + public final UniqueString getValue(int idx) { + throw new WrongInvocationException("Not supported"); + } + + /* (non-Javadoc) + * @see util.IDataInputStream#readString(int) + */ + @Override + public final String readString(int length) throws IOException { + final char[] s = new char[length]; + for (int i = 0; i < s.length; i++) { + s[i] = (char) this.bytes[idx++]; + } + return new String(s); + } + } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#delete() + */ + @Override + public void delete() { + finishAll(); + new File(this.filePrefix).delete(); + } +} diff --git a/tlatools/src/tlc2/tool/queue/DiskStateQueue.java b/tlatools/src/tlc2/tool/queue/DiskStateQueue.java index fcac709f612ab887bbb3fc586673a4fa38b4c505..4acf373684100378ffc4d2fa3208ab5dccdeeccb 100644 --- a/tlatools/src/tlc2/tool/queue/DiskStateQueue.java +++ b/tlatools/src/tlc2/tool/queue/DiskStateQueue.java @@ -7,6 +7,7 @@ package tlc2.tool.queue; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import tlc2.output.EC; import tlc2.output.MP; @@ -51,6 +52,11 @@ public class DiskStateQueue extends StateQueue { private int loPool, hiPool, lastLoPool, newLastLoPool; private File loFile; + // TESTING ONLY! + DiskStateQueue() throws IOException { + this(Files.createTempDirectory("DiskStateQueue").toFile().toString()); + } + /* Constructors */ public DiskStateQueue(String diskdir) { this.deqBuf = new TLCState[BufSize]; @@ -280,4 +286,13 @@ public class DiskStateQueue extends StateQueue { } } } + + /* (non-Javadoc) + * @see tlc2.tool.queue.IStateQueue#delete() + */ + @Override + public void delete() { + finishAll(); + new File(this.filePrefix).delete(); + } } diff --git a/tlatools/src/tlc2/tool/queue/IStateQueue.java b/tlatools/src/tlc2/tool/queue/IStateQueue.java index 7935de87d6e2e83c0820eaab6bfae47349fa0d25..e2ed3d6631ba35136454cac1a5b6cdf3a0fc8742 100644 --- a/tlatools/src/tlc2/tool/queue/IStateQueue.java +++ b/tlatools/src/tlc2/tool/queue/IStateQueue.java @@ -2,6 +2,7 @@ package tlc2.tool.queue; import java.io.IOException; +import tlc2.tool.StateVec; import tlc2.tool.TLCState; import tlc2.tool.Worker; @@ -21,7 +22,8 @@ public interface IStateQueue { /* Enqueues a list of states. Wake up any waiting thread. */ public abstract void sEnqueue(final TLCState states[]); - + public abstract void sEnqueue(final StateVec stateVec); + /* Return the first element in the queue. Wait if empty. */ public abstract TLCState sDequeue(); @@ -83,4 +85,10 @@ public interface IStateQueue { public abstract void recover() throws IOException; public abstract boolean isEmpty(); + + /** + * TESTING ONLY! + * Delete disk files if any. + */ + abstract void delete() throws IOException; } \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/queue/MemStateQueue.java b/tlatools/src/tlc2/tool/queue/MemStateQueue.java index fe46f15df54413f6770be8d7ac00b0489fae5628..b5b36c9b37e78dad1c0b590d22fbe7c6d4b20fed 100644 --- a/tlatools/src/tlc2/tool/queue/MemStateQueue.java +++ b/tlatools/src/tlc2/tool/queue/MemStateQueue.java @@ -7,6 +7,7 @@ package tlc2.tool.queue; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import tlc2.output.EC; import tlc2.tool.TLCState; @@ -23,6 +24,13 @@ public final class MemStateQueue extends StateQueue { private int start = 0; private String diskdir; + /** + * TESTING ONLY! + */ + MemStateQueue() throws IOException { + this(Files.createTempDirectory("MemStateQueue").toFile().toString()); + } + public MemStateQueue(String metadir) { this.states = new TLCState[InitialSize]; this.start = 0; diff --git a/tlatools/src/tlc2/tool/queue/StateQueue.java b/tlatools/src/tlc2/tool/queue/StateQueue.java index f498c4c7479a8893c8f11a24681f650603c22656..e37d9287c8da8d00f2d284c4e1faac9ec7a8fe56 100644 --- a/tlatools/src/tlc2/tool/queue/StateQueue.java +++ b/tlatools/src/tlc2/tool/queue/StateQueue.java @@ -10,9 +10,9 @@ import java.io.IOException; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.StateVec; import tlc2.tool.TLCState; import tlc2.tool.Worker; -import util.Assert; /** * @@ -84,6 +84,22 @@ public abstract class StateQueue implements IStateQueue { this.notifyAll(); } } + + public final synchronized void sEnqueue(final StateVec stateVec) { + int cnt = 0; + for (int j = 0; j < stateVec.size(); j++) { + TLCState state = stateVec.elementAt(j); + if (state != null) { + this.enqueueInner(state); + cnt++; + } + } + this.len += cnt; + if (this.numWaiting > 0 && !this.stop) { + this.notifyAll(); + } + } + public final synchronized TLCState sPeek() { if (this.isAvail()) { @@ -100,7 +116,7 @@ public abstract class StateQueue implements IStateQueue { if (this.isAvail()) { final TLCState state = this.dequeueInner(); // LL modified error message on 7 April 2012 - Assert.check(state != null, "Null state found on queue"); + assert state != null : "Null state found on queue"; this.len--; return state; } @@ -111,7 +127,7 @@ public abstract class StateQueue implements IStateQueue { * @see tlc2.tool.queue.IStateQueue#sDequeue(int) */ public final synchronized TLCState[] sDequeue(int cnt) { - Assert.check(cnt > 0, "Nonpositive number of states requested."); + assert cnt > 0 : "Nonpositive number of states requested."; if (this.isAvail()) { if (cnt > len) { // in this case, casting len to int is safe @@ -352,4 +368,9 @@ public abstract class StateQueue implements IStateQueue { * @see tlc2.tool.queue.IStateQueue#recover() */ public abstract void recover() throws IOException; + + @Override + public void delete() throws IOException { + // no-op + } } diff --git a/tlatools/src/tlc2/util/ByteUtils.java b/tlatools/src/tlc2/util/ByteUtils.java index c7f3195b462086e50bb03eefd189cfcfbefcdba0..0eaa6b2248c498d8e5d61b47a15424f0be8da1a9 100644 --- a/tlatools/src/tlc2/util/ByteUtils.java +++ b/tlatools/src/tlc2/util/ByteUtils.java @@ -68,14 +68,14 @@ public class ByteUtils { * The Java Language Specification. */ public static long byteArrayToLong(byte[] b) { - long i0 = (b[0] & 0xFF) << 56; - long i1 = (b[1] & 0xFF) << 48; - long i2 = (b[2] & 0xFF) << 40; - long i3 = (b[3] & 0xFF) << 32; - long i4 = (b[4] & 0xFF) << 24; - long i5 = (b[5] & 0xFF) << 16; - long i6 = (b[6] & 0xFF) << 8; - long i7 = (b[7] & 0xFF); + long i0 = (long) (b[0] & 0xFF) << 56; + long i1 = (long) (b[1] & 0xFF) << 48; + long i2 = (long) (b[2] & 0xFF) << 40; + long i3 = (long) (b[3] & 0xFF) << 32; + long i4 = (long) (b[4] & 0xFF) << 24; + long i5 = (long) (b[5] & 0xFF) << 16; + long i6 = (long) (b[6] & 0xFF) << 8; + long i7 = (long) (b[7] & 0xFF); return (i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7); } diff --git a/tlatools/src/tlc2/util/DotStateWriter.java b/tlatools/src/tlc2/util/DotStateWriter.java index 14eae03683fd2c40dfec33817787dfeb94169687..2db4c067e37fa0ee15e28b8c5526c2786af4b43a 100644 --- a/tlatools/src/tlc2/util/DotStateWriter.java +++ b/tlatools/src/tlc2/util/DotStateWriter.java @@ -39,6 +39,11 @@ import tlc2.tool.TLCState; * Writes the given state in dot notation. * * @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) + * + * + * To ASCII-render a graph (on Debian|Ubuntu) install cpanminus, sudo cpanm Graph::Easy and run: + * cat your.dot | graph-easy --from=dot --as_ascii + * (https://stackoverflow.com/questions/3211801/graphviz-and-ascii-output) */ public class DotStateWriter extends StateWriter { @@ -52,7 +57,7 @@ public class DotStateWriter extends StateWriter { private final Map<String, Integer> actionToColors = new HashMap<>(); // A mapping from ranks to nodes. - private final Map<Short, Set<Long>> rankToNodes = new HashMap<>(); + private final Map<Integer, Set<Long>> rankToNodes = new HashMap<>(); // Determines whether or not transition edges should be colorized in the state // graph. @@ -105,23 +110,30 @@ public class DotStateWriter extends StateWriter { this.writer.flush(); } + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isDot() + */ + @Override + public boolean isDot() { + return true; + } + /* (non-Javadoc) * @see tlc2.util.StateWriter#writeState(tlc2.tool.TLCState) */ public synchronized void writeState(final TLCState state) { // Marker the state as an initial state by using a filled style. this.writer.append(Long.toString(state.fingerPrint())); - this.writer.append(" [style = filled]"); this.writer.append(" [label=\""); this.writer.append(states2dot(state)); - this.writer.append("\"]"); + this.writer.append("\",style = filled]"); this.writer.append("\n"); maintainRanks(state); } protected void maintainRanks(final TLCState state) { - rankToNodes.computeIfAbsent(state.level, k -> new HashSet<Long>()).add(state.fingerPrint()); + rankToNodes.computeIfAbsent(state.getLevel(), k -> new HashSet<Long>()).add(state.fingerPrint()); } /* (non-Javadoc) @@ -162,28 +174,28 @@ public class DotStateWriter extends StateWriter { this.writer.append(" -> "); this.writer.append(successorsFP); if (visualization == Visualization.STUTTERING) { - this.writer.append(" [style=\"dashed\"]"); - } - - // Add the transition edge label. - if(action!=null) { - String transitionLabel = this.dotTransitionLabel(state, successor, action); - this.writer.append(transitionLabel); - } - - this.writer.append(";\n"); - - // If the successor is new, print the state's label. Labels are printed - // when writeState sees the successor. It does not print the label for - // the current state. If it would print the label for the current state, - // the init state labels would be printed twice. - if (successorStateIsNew) { - // Write the successor's label. - this.writer.append(successorsFP); - this.writer.append(" [label=\""); - this.writer.append(states2dot(successor)); - this.writer.append("\"]"); + this.writer.append(" [style=\"dashed\"];\n"); + } else { + // Add the transition edge label. + if(action!=null) { + String transitionLabel = this.dotTransitionLabel(state, successor, action); + this.writer.append(transitionLabel); + } + this.writer.append(";\n"); + + // If the successor is new, print the state's label. Labels are printed + // when writeState sees the successor. It does not print the label for + // the current state. If it would print the label for the current state, + // the init state labels would be printed twice. + if (successorStateIsNew) { + // Write the successor's label. + this.writer.append(successorsFP); + this.writer.append(" [label=\""); + this.writer.append(states2dot(successor)); + this.writer.append("\"]"); + this.writer.append(";\n"); + } } maintainRanks(state); @@ -233,7 +245,7 @@ public class DotStateWriter extends StateWriter { // Only add action label if specified. final String actionName = actionLabels ? action.getName().toString() : "" ; - final String labelFmtStr = " [label=\"%s\" color=\"%s\" fontcolor=\"%s\"]"; + final String labelFmtStr = " [label=\"%s\",color=\"%s\",fontcolor=\"%s\"]"; return String.format(labelFmtStr, actionName, color, color); } @@ -250,10 +262,10 @@ public class DotStateWriter extends StateWriter { sb.append(String.format("subgraph %s {", "cluster_legend")); sb.append("graph[style=bold];"); sb.append("label = \"Next State Actions\" style=\"solid\"\n"); - sb.append(String.format("node [ labeljust=\"l\" colorscheme=\"%s\" style=filled shape=record ]\n", + sb.append(String.format("node [ labeljust=\"l\",colorscheme=\"%s\",style=filled,shape=record ]\n", dotColorScheme)); for (String action : actions) { - String str = String.format("%s [label=\"%s\" fillcolor=%d]", action, action, + String str = String.format("%s [label=\"%s\",fillcolor=%d]", action, action, this.actionToColors.get(action)); sb.append(str); sb.append("\n"); @@ -282,7 +294,8 @@ public class DotStateWriter extends StateWriter { protected static String states2dot(final TLCState state) { // Replace "\" with "\\" and """ with "\"". - return state.toString().replace("\\", "\\\\").replace("\"", "\\\"").trim(); + return state.toString().replace("\\", "\\\\").replace("\"", "\\\"").trim() + .replace("\n", "\\n"); // Do not remove remaining (i.e. no danling/leading) "\n". } /* (non-Javadoc) diff --git a/tlatools/src/tlc2/util/FP64.java b/tlatools/src/tlc2/util/FP64.java index 71a15f1ee523dcc36ee281479cc2623aa57db170..7660e0e7b227d472ee05c4917866405f59477943 100644 --- a/tlatools/src/tlc2/util/FP64.java +++ b/tlatools/src/tlc2/util/FP64.java @@ -203,7 +203,16 @@ public class FP64 { /** Unlikely fingerprint? */ public static final long Zero = 0L; - /* This file provides procedures that construct fingerprints of + /* Background Reading: + - Galois Field (GF) or Finite Field + https://en.wikipedia.org/wiki/Finite_field + - GHash/MAC + https://en.wikipedia.org/wiki/Galois/Counter_Mode + - Universal Hashing + https://en.wikipedia.org/wiki/Universal_hashing + ---- + + This file provides procedures that construct fingerprints of strings of bytes via operations in GF[2^64]. GF[64] is represented as the set polynomials of degree 64 with coefficients in Z(2), modulo an irreducible polynomial P of degree 64. The computer diff --git a/tlatools/src/tlc2/util/IStateWriter.java b/tlatools/src/tlc2/util/IStateWriter.java index e6b6bed0ff30c26486bfd92e045bd42b0bd63f62..57997266e8eac25cee2be5d43ee074eae6ee1c13 100644 --- a/tlatools/src/tlc2/util/IStateWriter.java +++ b/tlatools/src/tlc2/util/IStateWriter.java @@ -63,4 +63,6 @@ public interface IStateWriter { String getDumpFileName(); boolean isNoop(); + + boolean isDot(); } \ No newline at end of file diff --git a/tlatools/src/tlc2/util/IdThread.java b/tlatools/src/tlc2/util/IdThread.java index 700d713e181b749b4736d1d1c266b86eebc77d3a..6913e2462b6200861446fd4090c27e99c18fb471 100644 --- a/tlatools/src/tlc2/util/IdThread.java +++ b/tlatools/src/tlc2/util/IdThread.java @@ -3,7 +3,7 @@ package tlc2.util; import tlc2.tool.TLCState; -import tlc2.value.Value; +import tlc2.value.IValue; /** An <code>IdThread</code> is a <code>Thread</code> with an integer identifier. */ @@ -24,12 +24,14 @@ public class IdThread extends Thread { public static final void setCurrentState(final TLCState state) { currentState.set(state); } - public static final void resetCurrentState() { + public static final TLCState resetCurrentState() { + final TLCState tlcState = currentState.get(); currentState.remove(); + return tlcState; } private final int id; - private Value[] localValues = new Value[4]; + private IValue[] localValues = new IValue[4]; /** Create a new thread with ID <code>id</code>. */ public IdThread(int id) { @@ -69,16 +71,16 @@ public class IdThread extends Thread { return (th instanceof IdThread) ? ((IdThread)th).id : otherId; } - public Value getLocalValue(int idx) { + public IValue getLocalValue(int idx) { if (idx < this.localValues.length) { return this.localValues[idx]; } return null; } - public void setLocalValue(int idx, Value val) { + public void setLocalValue(int idx, IValue val) { if (idx >= this.localValues.length) { - Value[] vals = new Value[idx + 1]; + IValue[] vals = new IValue[idx + 1]; System.arraycopy(this.localValues, 0, vals, 0, this.localValues.length); this.localValues = vals; } diff --git a/tlatools/src/tlc2/util/IntStack.java b/tlatools/src/tlc2/util/IntStack.java index 4747027378442c9cd7b33eff562a151d2d687d44..17bb23f92eb305f328927c6f241f747b290a2461 100644 --- a/tlatools/src/tlc2/util/IntStack.java +++ b/tlatools/src/tlc2/util/IntStack.java @@ -57,4 +57,13 @@ public interface IntStack { * Removes all elements from the stack */ void reset(); + + // Some implementors support peak operations. + default long peakLong() { + throw new UnsupportedOperationException("Not implemented"); + } + + default int peakInt() { + throw new UnsupportedOperationException("Not implemented"); + } } \ No newline at end of file diff --git a/tlatools/src/tlc2/util/LongVec.java b/tlatools/src/tlc2/util/LongVec.java index 703e71c6367b50ea162b45d526e73767177f7b48..44706322da05c66ff1f53474b3bebbb3bc28bf6c 100644 --- a/tlatools/src/tlc2/util/LongVec.java +++ b/tlatools/src/tlc2/util/LongVec.java @@ -8,14 +8,10 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Arrays; import util.FileUtil; -/** - * - * - * @version $Id$ - */ public class LongVec implements Cloneable, Serializable { private static final long serialVersionUID = 2406899362740899071L; protected long[] elementData; @@ -28,6 +24,11 @@ public class LongVec implements Cloneable, Serializable { this.elementData = new long[initialCapacity]; } + private LongVec(final LongVec other) { + this.elementCount = other.elementCount; + this.elementData = Arrays.copyOfRange(other.elementData, 0, other.elementCount); + } + public final void addElement(long x) { if (this.elementCount == this.elementData.length) { ensureCapacity(this.elementCount + 1); @@ -132,4 +133,26 @@ public class LongVec implements Cloneable, Serializable { System.err.println(vec1.elementAt(2)); } + private LongVec reverse0() { + int left = 0; + int right = elementData.length - 1; + + while (left < right) { + long temp = elementData[left]; + elementData[left] = elementData[right]; + elementData[right] = temp; + + left++; + right--; + } + return this; + } + + public LongVec reverse() { + try { + return new LongVec(this).reverse0(); + } catch (Exception e) { + throw e; + } + } } diff --git a/tlatools/src/tlc2/util/NoopStateWriter.java b/tlatools/src/tlc2/util/NoopStateWriter.java index 4505b16f915c8c326ee4e88abf8051cb02637bff..f3e85e5ec733371abf9c45d33b8f943431bd71fc 100644 --- a/tlatools/src/tlc2/util/NoopStateWriter.java +++ b/tlatools/src/tlc2/util/NoopStateWriter.java @@ -86,6 +86,14 @@ public final class NoopStateWriter implements IStateWriter { public boolean isNoop() { return true; } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isDot() + */ + @Override + public boolean isDot() { + return false; + } /* (non-Javadoc) * @see tlc2.util.IStateWriter#getDumpFileName() @@ -93,4 +101,5 @@ public final class NoopStateWriter implements IStateWriter { public String getDumpFileName() { return ""; } + } diff --git a/tlatools/src/tlc2/util/ObjLongTable.java b/tlatools/src/tlc2/util/ObjLongTable.java index 7001d7893dcc90844fdf1e960feed93cd8cebd67..0b894d096ac6ea0e3116a5fd316e827ee685795e 100644 --- a/tlatools/src/tlc2/util/ObjLongTable.java +++ b/tlatools/src/tlc2/util/ObjLongTable.java @@ -5,38 +5,40 @@ package tlc2.util; -public final class ObjLongTable { +public final class ObjLongTable<T> { private int count; private int length; private int thresh; - private Object[] keys; + private T[] keys; private long[] elems; + @SuppressWarnings("unchecked") public ObjLongTable(int size) { - this.keys = new Object[size]; + this.keys = (T[]) new Object[size]; this.elems = new long[size]; this.count = 0; this.length = size; this.thresh = this.length / 2; } + @SuppressWarnings("unchecked") private final void grow() { Object[] oldKeys = this.keys; long[] oldElems = this.elems; this.count = 0; this.length = 2 * this.length + 1; this.thresh = this.length / 2; - this.keys = new Object[this.length]; + this.keys = (T[]) new Object[this.length]; this.elems = new long[this.length]; for (int i = 0; i < oldKeys.length; i++) { - Object key = oldKeys[i]; + T key = (T) oldKeys[i]; if (key != null) this.put(key, oldElems[i]); } } public final int size() { return this.count; } - public final int put(Object k, long elem) { + public final int put(T k, long elem) { if (count >= thresh) this.grow(); int loc = ((int)k.hashCode() & 0x7FFFFFFF) % this.length; while (true) { @@ -55,7 +57,7 @@ public final class ObjLongTable { } } - public final int add(Object k, long elem) { + public final int add(T k, long elem) { if (count >= thresh) this.grow(); int loc = ((int)k.hashCode() & 0x7FFFFFFF) % this.length; while (true) { @@ -84,41 +86,46 @@ public final class ObjLongTable { } } - public final String[] sortStringKeys() { - String[] res = new String[this.count]; - int idx = -1; - for (int i = 0; i < this.length; i++) { - String key = (String)this.keys[i]; - if (key != null) { - int j = idx; - while (j >= 0) { - if (res[j].compareTo(key) <= 0) break; - res[j+1] = res[j]; - j--; + /** + * Merges the keys and longs of into this instance. If this instance already + * contains an entry with a given key, the long values will be accumulated. + */ + public ObjLongTable<T> mergeInto(final ObjLongTable<T> other) { + T key; + final ObjLongTable<T>.Enumerator<T> keys2 = other.keys(); + while ((key = keys2.nextElement()) != null) { + add(key, other.get(key)); + } + return this; } - res[j+1] = key; - idx++; - } - } - return res; - } - - public final Enumerator keys() { return new Enumerator(); } + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), count); + ObjLongTable<T>.Enumerator<T> keys2 = keys(); + T e = null; + int i = 0; + while((e = keys2.nextElement()) != null) { + a[i++] = e; + } + return a; + } + + public final Enumerator<T> keys() { return new Enumerator<T>(); } - public final class Enumerator { + @SuppressWarnings("hiding") + public final class Enumerator<T> { int index = 0; - public final Object nextElement() { + @SuppressWarnings("unchecked") + public final T nextElement() { while (this.index < keys.length) { if (keys[this.index] != null) { - return keys[this.index++]; + return (T) keys[this.index++]; } this.index++; } return null; } } - - } diff --git a/tlatools/src/tlc2/util/SetOfLong.java b/tlatools/src/tlc2/util/SetOfLong.java index cfc2dd305a8a11086414aa75474d1c5d9714710e..d124389626b9770143ddc01f0c4a780dffa669c1 100644 --- a/tlatools/src/tlc2/util/SetOfLong.java +++ b/tlatools/src/tlc2/util/SetOfLong.java @@ -86,7 +86,7 @@ public final class SetOfLong { public final long sizeof() { return 20 + (8 * this.length); } - public final double checkFPs() { + public final long checkFPs() { int cnt = 0; for (int i = 0; i < this.length; i++) { long x = this.table[i]; @@ -107,7 +107,7 @@ public final class SetOfLong { dis = Math.min(dis, this.table[i]-x); x = this.table[i]; } - return (1.0/dis); + return dis; } public final void beginChkpt(DataOutputStream dos) throws IOException { diff --git a/tlatools/src/tlc2/util/SetOfStates.java b/tlatools/src/tlc2/util/SetOfStates.java index 5c486b5395b3a720b3a1249a3f7b65f3b32401ff..ace08cc903306d11d3c36eb1aeb14da44ebdae77 100644 --- a/tlatools/src/tlc2/util/SetOfStates.java +++ b/tlatools/src/tlc2/util/SetOfStates.java @@ -44,6 +44,10 @@ public final class SetOfStates { private int length; private int thresh; + public SetOfStates() { + this(16); + } + public SetOfStates(final int size) { this.count = 0; this.length = size; @@ -51,7 +55,7 @@ public final class SetOfStates { this.states = new TLCState[length]; } - public void clear() { + public final void clear() { this.count = 0; this.states = new TLCState[length]; } @@ -104,7 +108,7 @@ public final class SetOfStates { /** * @return The current capacity of this set. [](capacity > size) */ - public int capacity() { + public final int capacity() { return this.length; } diff --git a/tlatools/src/tlc2/util/StatePoolReader.java b/tlatools/src/tlc2/util/StatePoolReader.java index fcaefce99a894a7bda210893d72eef75fe38c869..670e3eb1983f22b16f08b9769ff278a4eabc4df6 100644 --- a/tlatools/src/tlc2/util/StatePoolReader.java +++ b/tlatools/src/tlc2/util/StatePoolReader.java @@ -56,7 +56,7 @@ public class StatePoolReader extends Thread { public final synchronized TLCState[] doWork(TLCState[] deqBuf, File file) throws IOException, ClassNotFoundException { if (this.isFull) { - Assert.check(this.poolFile == null, EC.SYSTEM_FILE_NULL); + assert this.poolFile == null : EC.SYSTEM_FILE_NULL; TLCState[] res = this.buf; this.buf = deqBuf; this.poolFile = file; @@ -94,7 +94,7 @@ public class StatePoolReader extends Thread { public final synchronized TLCState[] getCache(TLCState[] deqBuf, File file) throws IOException, ClassNotFoundException { if (this.isFull) { - Assert.check(this.poolFile == null, EC.SYSTEM_FILE_NULL); + assert this.poolFile == null : EC.SYSTEM_FILE_NULL; TLCState[] res = this.buf; this.buf = deqBuf; this.poolFile = file; diff --git a/tlatools/src/tlc2/util/StateWriter.java b/tlatools/src/tlc2/util/StateWriter.java index 3682d65e6840d84323cf8fd31bf37076564943bb..f9fb560e32288207f13f7f3f2acabaa80ff3ace3 100644 --- a/tlatools/src/tlc2/util/StateWriter.java +++ b/tlatools/src/tlc2/util/StateWriter.java @@ -37,6 +37,14 @@ public class StateWriter implements IStateWriter public boolean isNoop() { return false; } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isDot() + */ + @Override + public boolean isDot() { + return false; + } /* (non-Javadoc) * @see tlc2.util.IStateWriter#writeState(tlc2.tool.TLCState) diff --git a/tlatools/src/tlc2/util/Vect.java b/tlatools/src/tlc2/util/Vect.java index 7557aa1bc240af131ab32e8029eb034306f8e1ae..b5852d01a72b431731c67090497a5df35e7c8bee 100644 --- a/tlatools/src/tlc2/util/Vect.java +++ b/tlatools/src/tlc2/util/Vect.java @@ -9,21 +9,20 @@ import java.util.Enumeration; import java.util.NoSuchElementException; import java.util.Vector; -public class Vect implements Cloneable, Serializable { - private Object[] elementData; +@SuppressWarnings("unchecked") +public class Vect<E> implements Cloneable, Serializable { + private E[] elementData; private int elementCount; - static private final Object[] empty = new Object[0]; - - final class Enumerator implements Enumeration { + final class Enumerator<E> implements Enumeration { int index = 0; public final boolean hasMoreElements () { return (this.index < elementCount); } - public final Object nextElement() { - return elementData[index++]; + public final E nextElement() { + return (E) elementData[index++]; } } @@ -32,10 +31,10 @@ public class Vect implements Cloneable, Serializable { public Vect(int initialCapacity) { this.elementCount = 0; if (initialCapacity == 0) { - this.elementData = empty ; + this.elementData = (E[]) new Object[0]; } else { - this.elementData = new Object[initialCapacity]; + this.elementData = (E[]) new Object[initialCapacity]; } } @@ -43,19 +42,19 @@ public class Vect implements Cloneable, Serializable { this(v.size()); int sz = v.size(); for (int i = 0; i < sz; i++) { - this.addElement(v.elementAt(i)); + this.addElement((E) v.elementAt(i)); } } - public final void addElement(Object obj) { + public final void addElement(E obj) { if (this.elementCount == this.elementData.length) { this.ensureCapacity(this.elementCount+1); } this.elementData[this.elementCount++] = obj; } - public final Vect concat(Vect elems) { - Vect v = new Vect(); + public final Vect<E> concat(Vect<E> elems) { + Vect<E> v = new Vect<>(); for (int i = 0; i < this.elementCount; i++) { v.addElement(this.elementData[i]); } @@ -68,7 +67,7 @@ public class Vect implements Cloneable, Serializable { public int capacity() { return this.elementData.length; } public Object clone() { - Vect v = new Vect(this.elementData.length); + Vect<E> v = new Vect<>(this.elementData.length); System.arraycopy(this.elementData, 0, v.elementData, 0, this.elementCount); v.elementCount = this.elementCount; return v; @@ -82,11 +81,12 @@ public class Vect implements Cloneable, Serializable { System.arraycopy(this.elementData, 0, anArray, 0, this.elementCount); } - public final Object elementAt(int index) { + public final E elementAt(int index) { return this.elementData[index]; } - public Enumeration elements() { return new Vect.Enumerator(); } + @SuppressWarnings("rawtypes") + public Enumeration<E> elements() { return new Vect.Enumerator(); } public final void ensureCapacity(int minCapacity) { if (this.elementData.length < minCapacity) { @@ -95,7 +95,7 @@ public class Vect implements Cloneable, Serializable { newCapacity = minCapacity; } Object oldBuffer[] = elementData; - elementData = new Object[newCapacity]; + elementData = (E[]) new Object[newCapacity]; System.arraycopy( oldBuffer, 0, elementData, 0, elementCount); } } @@ -113,7 +113,7 @@ public class Vect implements Cloneable, Serializable { return -1; } - public final void insertElementAt(Object obj, int index) { + public final void insertElementAt(E obj, int index) { if (elementCount == elementData.length) ensureCapacity(elementCount+1); @@ -142,7 +142,7 @@ public class Vect implements Cloneable, Serializable { this.elementData[this.elementCount] = null; } - public final void setElementAt(Object obj, int index) { + public final void setElementAt(E obj, int index) { this.elementData[index] = obj; } @@ -165,7 +165,7 @@ public class Vect implements Cloneable, Serializable { return elem; } - public final void push(Object elem) { + public final void push(E elem) { this.addElement(elem); } @@ -181,7 +181,7 @@ public class Vect implements Cloneable, Serializable { public final boolean equals(Object obj) { if (!(obj instanceof Vect)) return false; - Vect v = (Vect)obj; + Vect<E> v = (Vect<E>)obj; if (v.size() != this.elementCount) return false; for (int i = 0; i < this.elementCount; i++) { if (!this.elementData[i].equals(v.elementAt(i))) return false; diff --git a/tlatools/src/tlc2/util/statistics/CounterStatistic.java b/tlatools/src/tlc2/util/statistics/CounterStatistic.java new file mode 100644 index 0000000000000000000000000000000000000000..39fe31a71138a19d24539c5d09068d7782013b41 --- /dev/null +++ b/tlatools/src/tlc2/util/statistics/CounterStatistic.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.util.statistics; + +import java.util.concurrent.atomic.LongAdder; +import java.util.function.BooleanSupplier; + +public abstract class CounterStatistic { + + public static CounterStatistic getInstance(final BooleanSupplier s) { + if (s.getAsBoolean()) { + return new LongAdderCounterStatistic(); + } else { + return new NoopCounterStatistic(); + } + } + + public abstract void increment(); + + public abstract void add(final long evalCount); + + public abstract long getCount(); + + private CounterStatistic() { + // private ctor + } + + private static class NoopCounterStatistic extends CounterStatistic { + + @Override + public final long getCount() { + return 0; + } + + @Override + public final void increment() { + // noop + } + + @Override + public void add(long evalCount) { + // noop + } + } + + private static class LongAdderCounterStatistic extends CounterStatistic { + + private final LongAdder adder = new LongAdder(); + + @Override + public final long getCount() { + return this.adder.sum(); + } + + @Override + public final void increment() { + adder.increment(); + } + + @Override + public void add(long evalCount) { + adder.add(evalCount); + } + } +} diff --git a/tlatools/src/tlc2/value/IBoolValue.java b/tlatools/src/tlc2/value/IBoolValue.java new file mode 100644 index 0000000000000000000000000000000000000000..f41b70740142350308bb4e8da06db434b50551b1 --- /dev/null +++ b/tlatools/src/tlc2/value/IBoolValue.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +public interface IBoolValue extends IValue { + + public boolean getVal(); +} \ No newline at end of file diff --git a/tlatools/src/tlc2/value/IFcnLambdaValue.java b/tlatools/src/tlc2/value/IFcnLambdaValue.java new file mode 100644 index 0000000000000000000000000000000000000000..25b7bc46bd6c9c989f60d050d97b017896be5798 --- /dev/null +++ b/tlatools/src/tlc2/value/IFcnLambdaValue.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ + +package tlc2.value; + +import tla2sany.semantic.SemanticNode; +import tlc2.util.Context; +import tlc2.value.IFcnParams; +import tlc2.value.IFcnRcdValue; + +public interface IFcnLambdaValue { + + SemanticNode getBody(); + + IFcnRcdValue getRcd(); + + IFcnParams getParams(); + + Context getCon(); + + boolean hasRcd(); + +} diff --git a/tlatools/src/tlc2/value/IFcnParams.java b/tlatools/src/tlc2/value/IFcnParams.java new file mode 100644 index 0000000000000000000000000000000000000000..40082374a6c1e904da86877165fe615bda73895a --- /dev/null +++ b/tlatools/src/tlc2/value/IFcnParams.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import tla2sany.semantic.FormalParamNode; + +public interface IFcnParams { + + int length(); + + FormalParamNode[][] getFormals(); + + IValue[] getDomains(); + + boolean[] isTuples(); + +} diff --git a/tlatools/src/tlc2/value/IFcnRcdValue.java b/tlatools/src/tlc2/value/IFcnRcdValue.java new file mode 100644 index 0000000000000000000000000000000000000000..d2c3b3bdbfe01b16a05daa2b01d0a1d1f0dc2ecd --- /dev/null +++ b/tlatools/src/tlc2/value/IFcnRcdValue.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +public interface IFcnRcdValue { + +} diff --git a/tlatools/src/tlc2/value/IMVPerm.java b/tlatools/src/tlc2/value/IMVPerm.java new file mode 100644 index 0000000000000000000000000000000000000000..63c298db2552278ef4b45cc3a02b5529a7ad50d7 --- /dev/null +++ b/tlatools/src/tlc2/value/IMVPerm.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import tlc2.value.IModelValue; + +public interface IMVPerm { + + IValue get(IValue value); + + void put(IModelValue dval, IModelValue rval); + + int size(); + + IMVPerm compose(IMVPerm elementAt); + +} diff --git a/tlatools/src/tlc2/value/IModelValue.java b/tlatools/src/tlc2/value/IModelValue.java new file mode 100644 index 0000000000000000000000000000000000000000..61d69866eea38a77654936ae087a75342186ef43 --- /dev/null +++ b/tlatools/src/tlc2/value/IModelValue.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +public interface IModelValue { + +} diff --git a/tlatools/src/tlc2/value/ITupleValue.java b/tlatools/src/tlc2/value/ITupleValue.java new file mode 100644 index 0000000000000000000000000000000000000000..a211b7eb1123f3a9db1d7bfba437de2fafb432a2 --- /dev/null +++ b/tlatools/src/tlc2/value/ITupleValue.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +public interface ITupleValue extends IValue { + + IValue getElem(int i); + + IValue[] getElems(); + + int size(); +} \ No newline at end of file diff --git a/tlatools/src/tlc2/value/IValue.java b/tlatools/src/tlc2/value/IValue.java new file mode 100644 index 0000000000000000000000000000000000000000..ec51eace725544c66f935966aef34281d1765de9 --- /dev/null +++ b/tlatools/src/tlc2/value/IValue.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import java.io.IOException; + +import tla2sany.semantic.SemanticNode; +import tlc2.tool.coverage.CostModel; + +public interface IValue extends Comparable<Object> { + + /* This method compares this with val. */ + int compareTo(Object val); + + void write(IValueOutputStream vos) throws IOException; + + IValue setCostModel(CostModel cm); + + CostModel getCostModel(); + + void setSource(SemanticNode semanticNode); + + SemanticNode getSource(); + + boolean hasSource(); + + /** + * This method normalizes (destructively) the representation of + * the value. It is essential for equality comparison. + */ + boolean isNormalized(); + + /* Fully normalize this (composite) value. */ + void deepNormalize(); + + /* This method returns the fingerprint of this value. */ + long fingerPrint(long fp); + + /** + * This method returns the value permuted by the permutation. It + * returns this if nothing is permuted. + */ + IValue permute(IMVPerm perm); + + /* This method returns true iff the value is finite. */ + boolean isFinite(); + + /* This method returns the size of the value. */ + int size(); + + /* This method returns true iff the value is fully defined. */ + boolean isDefined(); + + /* This method makes a real deep copy of this. */ + IValue deepCopy(); + + /** + * This abstract method returns a string representation of this + * value. Each subclass must provide its own implementation. + */ + StringBuffer toString(StringBuffer sb, int offset, boolean swallow); + + /* The string representation of this value */ + String toString(); + + String toString(String delim); + +} \ No newline at end of file diff --git a/tlatools/src/tlc2/value/IValueInputStream.java b/tlatools/src/tlc2/value/IValueInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..3c1413f967bc0700713b2025f32ea8d65e35ec36 --- /dev/null +++ b/tlatools/src/tlc2/value/IValueInputStream.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import java.io.EOFException; +import java.io.IOException; + +import util.IDataInputStream; +import util.UniqueString; + +public interface IValueInputStream { + + IValue read() throws IOException; + + int readShort() throws IOException; + + int readInt() throws IOException; + + long readLong() throws IOException; + + void close() throws IOException; + + int readNat() throws IOException; + + short readShortNat() throws IOException; + + long readLongNat() throws IOException; + + byte readByte() throws EOFException, IOException; + + void assign(Object obj, int idx); + + int getIndex(); + + IDataInputStream getInputStream(); + + UniqueString getValue(int idx); +} \ No newline at end of file diff --git a/tlatools/src/tlc2/value/IValueOutputStream.java b/tlatools/src/tlc2/value/IValueOutputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..cc5cc51cf1f0713ff4101c21b3fe43da817165c6 --- /dev/null +++ b/tlatools/src/tlc2/value/IValueOutputStream.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import java.io.IOException; + +import util.IDataOutputStream; + +public interface IValueOutputStream { + + void writeShort(short x) throws IOException; + + void writeInt(int x) throws IOException; + + void writeLong(long x) throws IOException; + + void close() throws IOException; + + /* Precondition: x is a non-negative short. */ + void writeShortNat(short x) throws IOException; + + /* Precondition: x is a non-negative int. */ + void writeNat(int x) throws IOException; + + /* Precondition: x is a non-negative long. */ + void writeLongNat(long x) throws IOException; + + void writeByte(byte b) throws IOException; + + void writeBoolean(boolean b) throws IOException; + + IDataOutputStream getOutputStream(); + + /** + * Check if another TLCState - which is currently also being serialized to the + * same storage (i.e. disk file) - has/contains an identical Value. If yes, do + * not serialize the Value instance again but make this TLCState point to the + * Value instance previously serialized for the other TLCState. In other words, + * this is a custom-tailored compression/de-duplication mechanism for Value + * instances. + * <p> + * This approach only works because both TLCStates are serialized to the same + * storage and thus de-serialized as part of the same operation (same + * Value*Stream instance). + * <p> + * The purpose of this approach appears to be: + * <ul> + * <li>Reduce serialization efforts and storage size</li> + * <li>Reduce the number of Value instances created during de-serialization</li> + * <li>Allow identity comparison on Value instances (AFAICT not used by Value + * explicitly, just UniqueString) to speed up check. Value#equals internally + * likely uses identity comparison as first check.</li> + * </ul> + * <p> + * A disadvantage is the cost of maintaining the internal HandleTable which can + * grow to thousands of elements during serialization/de-serialization (in + * ValueInputStream). Since serialization suspends the DiskStateQueue and thus + * blocks tlc2.tool.Workers from exploring the state space, this might has + * adverse effects. + */ + int put(Object obj); + +} \ No newline at end of file diff --git a/tlatools/src/tlc2/value/MVPerm.java b/tlatools/src/tlc2/value/MVPerm.java deleted file mode 100644 index 7b1a4b5438c856f372982db84d53b9f37442bf86..0000000000000000000000000000000000000000 --- a/tlatools/src/tlc2/value/MVPerm.java +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Mon 30 Apr 2007 at 13:42:27 PST by lamport -// modified on Thu Nov 16 15:53:30 PST 2000 by yuanyu - -package tlc2.value; - -import java.util.Enumeration; - -import tlc2.util.Vect; -import util.Assert; -import util.Set; - -public final class MVPerm { - private final ModelValue[] elems; - private int count; - - private MVPerm() { - this.elems = new ModelValue[ModelValue.mvs.length]; - this.count = 0; - } - - public final boolean equals(Object obj) { - if (obj instanceof MVPerm) { - MVPerm perm = (MVPerm)obj; - for (int i = 0; i < this.elems.length; i++) { - if (this.elems[i] == null) { - if (perm.elems[i] != null) { - return false; - } - } - else if (!this.elems[i].equals(perm.elems[i])) { - return false; - } - } - return true; - } - return false; - } - - public final int hashCode() { - int res = 0; - for (int i = 0; i < this.elems.length; i++) { - ModelValue mv = this.elems[i]; - if (mv != null) { - res = 31*res + mv.val.hashCode(); - } - } - return res; - } - - private final int size() { return this.count; } - - final ModelValue get(ModelValue k) { - return this.elems[k.index]; - } - - private final void put(ModelValue k, ModelValue elem) { - if (!k.equals(elem) && this.elems[k.index] == null) { - this.elems[k.index] = elem; - this.count++; - } - } - - private final void put(int i, ModelValue elem) { - if (this.elems[i] == null && elem != null) { - this.elems[i] = elem; - this.count++; - } - } - - public final MVPerm compose(MVPerm perm) { - MVPerm res = new MVPerm(); - for (int i = 0; i < this.elems.length; i++) { - ModelValue mv = this.elems[i]; - if (mv == null) { - res.put(i, perm.elems[i]); - } - else { - ModelValue mv1 = perm.elems[mv.index]; - if (mv1 == null) { - res.put(i, mv); - } - else if (!ModelValue.mvs[i].equals(mv1)) { - res.put(i, mv1); - } - } - } - return res; - } - - public static final MVPerm[] permutationSubgroup(final Enumerable enumerable) { - final ValueEnumeration Enum = enumerable.elements(); - final int sz = enumerable.size() - 1; - final Set perms = new Set(sz); - final Vect permVec = new Vect(sz); - // Compute the group generators: - Value elem; - while ((elem = Enum.nextElement()) != null) { - final FcnRcdValue fcn = FcnRcdValue.convert(elem); - if (fcn == null) { - Assert.fail("The symmetry operator must specify a set of functions."); - } - final MVPerm perm = new MVPerm(); - for (int i = 0; i < fcn.domain.length; i++) { - final Value dval = fcn.domain[i]; - final Value rval = fcn.values[i]; - if ((dval instanceof ModelValue) && (rval instanceof ModelValue)) { - perm.put((ModelValue)dval, (ModelValue)rval); - } - else { - Assert.fail("Symmetry function must have model values as domain and range."); - } - } - if (perm.size() > 0 && perms.put(perm) == null) { - permVec.addElement(perm); - } - } - // Compute the group generated by the generators: - final int gsz = permVec.size(); - int sz0 = 0; - while (true) { - final int sz1 = permVec.size(); - for (int i = 0; i < gsz; i++) { - final MVPerm perm1 = (MVPerm)permVec.elementAt(i); - for (int j = sz0; j < sz1; j++) { - MVPerm perm = perm1.compose((MVPerm)permVec.elementAt(j)); - if (perm.size() > 0 && perms.put(perm) == null) { - permVec.addElement(perm); - } - } - } - if (sz1 == permVec.size()) { break; } - sz0 = sz1; - } - // Finally, put all the elements in an array ready for use: - final MVPerm[] res = new MVPerm[permVec.size()]; - final Enumeration permEnum = permVec.elements(); - for (int i = 0; i < res.length; i++) { - res[i] = (MVPerm)permEnum.nextElement(); - } - return res; - } - - public final String toString() { - StringBuffer sb = new StringBuffer("["); - int i = 0; - for (i = 0; i < this.elems.length; i++) { - if (this.elems[i] != null) { - sb.append(ModelValue.mvs[i].toString()); - sb.append(" -> "); - sb.append(this.elems[i].toString()); - break; - } - } - for (int j = i+1; j < this.elems.length; j++) { - if (this.elems[j] != null) { - sb.append(", "); - sb.append(ModelValue.mvs[j].toString()); - sb.append(" -> "); - sb.append(this.elems[j].toString()); - } - } - sb.append("]"); - return sb.toString(); - } - -} diff --git a/tlatools/src/tlc2/value/OpValue.java b/tlatools/src/tlc2/value/OpValue.java deleted file mode 100644 index 1aa0c0a3a31d69e0da656f28e83012e49e4b0e70..0000000000000000000000000000000000000000 --- a/tlatools/src/tlc2/value/OpValue.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Mon 30 Apr 2007 at 13:21:02 PST by lamport -// modified on Fri Sep 22 13:18:45 PDT 2000 by yuanyu - -package tlc2.value; - -public abstract class OpValue extends Value implements Applicable { - -} diff --git a/tlatools/src/tlc2/value/EnumerableValue.java b/tlatools/src/tlc2/value/RandomEnumerableValues.java similarity index 59% rename from tlatools/src/tlc2/value/EnumerableValue.java rename to tlatools/src/tlc2/value/RandomEnumerableValues.java index e158cbf49eb89732d78d34d2966195ca5b533a72..ebd30c2a977d638f3f54713d0597b5329fd9b795 100644 --- a/tlatools/src/tlc2/value/EnumerableValue.java +++ b/tlatools/src/tlc2/value/RandomEnumerableValues.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Microsoft Research. All rights reserved. + * Copyright (c) 2019 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -27,87 +27,39 @@ package tlc2.value; -import java.util.List; import java.util.Random; import tlc2.TLCGlobals; -import tlc2.tool.FingerprintException; import tlc2.tool.ModelChecker; import tlc2.tool.TLCState; import tlc2.util.IdThread; -public abstract class EnumerableValue extends Value implements Enumerable, ValueConstants { - - public Value isSubsetEq(Value other) { - try { - final ValueEnumeration Enum = this.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - if (!other.member(elem)) { - return ValFalse; - } - } - return ValTrue; - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - @Override - public EnumerableValue getRandomSubset(final int kOutOfN) { - // By default, convert all EVs into SetEnumValue and delegate to its - // getRandomSubset. - return SetEnumValue.convert(this).getRandomSubset(kOutOfN); - } - - public ValueEnumeration elements(final int k) { - // The generic implementation collects all n elements of the actual Enumerable - // into the temporary variable values. The SubSetEnumerator then randomly - // returns up to k elements. - // The underlying assuming here is that the size of EnumerableValue (n) is - // very small and this method is not called as part of the next-state relation. - // If it gets called on larger sets or as part of the next-state relation, - // subclasses can provide a more efficient implementation (e.g. see - // IntervalValue and SetEnumValue which return a more efficient subclass - // of SubsetEnumerator). - final List<Value> values = elements().all(); - return new SubsetEnumerator(k) { - @Override - public Value nextElement() { - if (!hasNext()) { - return null; - } - return values.get(nextIndex()); - } - }; - } - +public abstract class RandomEnumerableValues { + /* Randomization for sets */ private static long randomSeed; - public static long getRandomSeed() { + public static long getSeed() { return randomSeed; } /** * Initialize Random with the given seed value. **/ - public static void setRandom(final long seed) { + public static void setSeed(final long seed) { randomSeed = seed; - resetRandom(); + reset(); } /** * Re-Initialize Random with the recorded seed value. **/ - public static void resetRandom() { + public static void reset() { RANDOMS.remove(); } - public static Random getRandom() { + public static Random get() { return RANDOMS.get(); } @@ -202,69 +154,4 @@ public abstract class EnumerableValue extends Value implements Enumerable, Value return this; } } - - abstract class SubsetEnumerator implements ValueEnumeration { - - protected final long x; - protected final int a; - protected final int n; - protected final int k; - protected int i; - - public SubsetEnumerator(final int k) { - this(k, size()); - } - - public SubsetEnumerator(final int k, final int n) { - this.n = n; - - // https://en.wikipedia.org/wiki/Linear_congruential_generator - // - // x has to be co-prime to n. Since n might or might not be a prime number - // - it depends on the actual size of the set - we simply set x to - // be a prime number. The prime x has to be larger than n tough, since n is - // bound by Integer.MAX_VALUE, we simply choose the Mersenne prime - // Integer.MAX_VALUE - // for x and accept that we fail if n = Integer.MAX_VALUE. To minimize - // intermediate results and the rounds of mod in nextIndex, we choose 191 if n - // happens to be smaller (very likely). - assert n < Integer.MAX_VALUE; - this.x = n < 191 ? 191L : 1L * Integer.MAX_VALUE; - - // k out of n elements in the range 0 <= k <= n. - if (n > 0) { - this.k = k; - this.a = getRandom().nextInt(n); - } else { - this.k = 0; - this.a = 0; // RANDOM.nextInt(0) causes IllegalArgumentException. - } - } - - public void reset() { - i = 0; - } - - public boolean hasNext() { - return i < k; - } - - /** - * @return A random (uniformly distributed) index in the range [0,n) where n is - * {@link Enumerable#size()}. - */ - public int nextIndex() { - if (n <= 0) { - i++; - return 0; - } - // long x avoids intermediate overflow, final cast to int safe though because of - // mod n. - final int index = (int) (((x * i++) + a) % n); - assert 0 <= index && index < n; - return index; - } - - public abstract Value nextElement(); - } } diff --git a/tlatools/src/tlc2/value/Value.java b/tlatools/src/tlc2/value/Value.java deleted file mode 100644 index 354211f61216cee3ef2991e84b07ff08aa325298..0000000000000000000000000000000000000000 --- a/tlatools/src/tlc2/value/Value.java +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Wed 12 Jul 2017 at 16:10:00 PST by ian morris nieves -// modified on Mon 30 Apr 2007 at 15:30:13 PST by lamport -// modified on Wed Dec 5 23:18:07 PST 2001 by yuanyu - -package tlc2.value; - -import java.io.Serializable; - -import tla2sany.semantic.SemanticNode; -import tlc2.TLCGlobals; -import tlc2.pprint.PrettyPrint; -import tlc2.tool.FingerprintException; -import tlc2.util.FP64; -import util.Assert; - -public abstract class Value implements ValueConstants, Serializable { - /** - * For each kind of value, we introduce a subclass of Value. - * All the subclasses are given in this value package. - */ - - /** - * This method returns the value kind: an integer that represents - * the kind of this value. See the interface ValueConstants.java. - */ - public abstract byte getKind(); - - public String getKindString() { - try { - return ValueImage[this.getKind()]; - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - /* This method compares this with val. */ - public abstract int compareTo(Object val); - - /* This method returns true iff elem is a member of this. */ - public abstract boolean member(Value elem); - - /* This method returns a new value after taking the except. */ - public abstract Value takeExcept(ValueExcept ex); - - /* This method returns a new value after taking the excepts. */ - public abstract Value takeExcept(ValueExcept[] exs); - - /** - * These methods allow storage and retrieval of the SemanticNode used to create the Value, - * which is helpful for FingerprintException. - */ - private transient SemanticNode source = null; - - public void setSource(final SemanticNode semanticNode) { - source = semanticNode; - } - - public SemanticNode getSource() { - return source; - } - - public boolean hasSource() { - return source != null; - } - - /** - * This method normalizes (destructively) the representation of - * the value. It is essential for equality comparison. - */ - public abstract boolean isNormalized(); - public abstract Value normalize(); - - public final boolean isEmpty() { - try { - - switch (this.getKind()) { - case SETENUMVALUE: - { - SetEnumValue set = (SetEnumValue)this; - return set.elems.size() == 0; - } - case INTERVALVALUE: - { - IntervalValue intv = (IntervalValue)this; - return intv.size() == 0; - } - case SETCAPVALUE: - { - SetCapValue cap = (SetCapValue)this; - return cap.elements().nextElement() == null; - } - case SETCUPVALUE: - { - SetCupValue cup = (SetCupValue)this; - return cup.elements().nextElement() == null; - } - case SETDIFFVALUE: - { - SetDiffValue diff = (SetDiffValue)this; - return diff.elements().nextElement() == null; - } - case SETOFFCNSVALUE: - { - SetOfFcnsValue fcns = (SetOfFcnsValue)this; - return fcns.elements().nextElement() == null; - } - case SETOFRCDSVALUE: - { - SetOfRcdsValue srv = (SetOfRcdsValue)this; - return srv.elements().nextElement() == null; - } - case SETOFTUPLESVALUE: - { - SetOfTuplesValue stv = (SetOfTuplesValue)this; - return stv.elements().nextElement() == null; - } - case SUBSETVALUE: - { - // SUBSET S is never empty. (It always contains {}.) - return false; - } - case UNIONVALUE: - { - UnionValue uv = (UnionValue)this; - return uv.elements().nextElement() == null; - } - case SETPREDVALUE: - { - SetPredValue spv = (SetPredValue)this; - return spv.elements().nextElement() == null; - } - default: - Assert.fail("Shouldn't call isEmpty() on value " + Value.ppr(this.toString())); - return false; - } - - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - /* Fully normalize this (composite) value. */ - public final void deepNormalize() { - try { - - switch (this.getKind()) { - case RECORDVALUE: - { - RecordValue rcd = (RecordValue)this; - for (int i = 0; i < rcd.values.length; i++) { - rcd.values[i].deepNormalize(); - } - rcd.normalize(); - break; - } - case FCNRCDVALUE: - { - FcnRcdValue fcn = (FcnRcdValue)this; - for (int i = 0; i < fcn.values.length; i++) { - fcn.values[i].deepNormalize(); - } - fcn.normalize(); - break; - } - case SETENUMVALUE: - { - SetEnumValue set = (SetEnumValue)this; - for (int i = 0; i < set.elems.size(); i++) { - set.elems.elementAt(i).deepNormalize(); - } - set.normalize(); - break; - } - case TUPLEVALUE: - { - TupleValue tv = (TupleValue)this; - for (int i = 0; i < tv.elems.length; i++) { - tv.elems[i].deepNormalize(); - } - break; - } - case SETCAPVALUE: - { - SetCapValue cap = (SetCapValue)this; - cap.set1.deepNormalize(); - cap.set2.deepNormalize(); - if (cap.capSet == null) { - cap.capSet = DummyEnum; - } - else if (cap.capSet != DummyEnum) { - cap.capSet.deepNormalize(); - } - break; - } - case SETCUPVALUE: - { - SetCupValue cup = (SetCupValue)this; - cup.set1.deepNormalize(); - cup.set2.deepNormalize(); - if (cup.cupSet == null) { - cup.cupSet = DummyEnum; - } - else if (cup.cupSet != DummyEnum) { - cup.cupSet.deepNormalize(); - } - break; - } - case SETDIFFVALUE: - { - SetDiffValue diff = (SetDiffValue)this; - diff.set1.deepNormalize(); - diff.set2.deepNormalize(); - if (diff.diffSet == null) { - diff.diffSet = DummyEnum; - } - else if (diff.diffSet != DummyEnum) { - diff.diffSet.deepNormalize(); - } - break; - } - case SETOFFCNSVALUE: - { - SetOfFcnsValue fcns = (SetOfFcnsValue)this; - fcns.domain.deepNormalize(); - fcns.range.deepNormalize(); - if (fcns.fcnSet == null) { - fcns.fcnSet = DummyEnum; - } - else if (fcns.fcnSet != DummyEnum) { - fcns.fcnSet.deepNormalize(); - } - break; - } - case SETOFRCDSVALUE: - { - SetOfRcdsValue srv = (SetOfRcdsValue)this; - for (int i = 0; i < srv.values.length; i++) { - srv.values[i].deepNormalize(); - } - if (srv.rcdSet == null) { - srv.rcdSet = DummyEnum; - } - else if (srv.rcdSet != DummyEnum) { - srv.rcdSet.deepNormalize(); - } - break; - } - case SETOFTUPLESVALUE: - { - SetOfTuplesValue stv = (SetOfTuplesValue)this; - for (int i = 0; i < stv.sets.length; i++) { - stv.sets[i].deepNormalize(); - } - if (stv.tupleSet == null) { - stv.tupleSet = DummyEnum; - } - else if (stv.tupleSet != DummyEnum) { - stv.tupleSet.deepNormalize(); - } - break; - } - case SUBSETVALUE: - { - SubsetValue pset = (SubsetValue)this; - pset.set.deepNormalize(); - if (pset.pset == null) { - pset.pset = DummyEnum; - } - else if (pset.pset != DummyEnum) { - pset.pset.deepNormalize(); - } - break; - } - case UNIONVALUE: - { - UnionValue uv = (UnionValue)this; - if (uv.realSet == null) { - uv.realSet = DummyEnum; - } - else if (uv.realSet != DummyEnum) { - uv.realSet.deepNormalize(); - } - break; - } - case SETPREDVALUE: - { - SetPredValue spv = (SetPredValue)this; - spv.inVal.deepNormalize(); - break; - } - case FCNLAMBDAVALUE: - { - FcnLambdaValue flv = (FcnLambdaValue)this; - if (flv.fcnRcd == null) { - if (flv.excepts != null) { - for (int i = 0; i < flv.excepts.length; i++) { - flv.excepts[i].value.deepNormalize(); - for (int j = 0; j < flv.excepts[i].path.length; j++) { - flv.excepts[i].path[j].deepNormalize(); - } - } - } - Value[] paramDoms = flv.params.domains; - for (int i = 0; i < paramDoms.length; i++) { - paramDoms[i].deepNormalize(); - } - } - else { - flv.fcnRcd.deepNormalize(); - } - } - default: - break; - } - - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - /* This method returns the fingerprint of this value. */ - public long fingerPrint(long fp) { - try { - Assert.fail("TLC has found a state in which the value of a variable contains " + - Value.ppr(this.toString())); // SZ Feb 24, 2009: changed to static access - return 0; // make compiler happy - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - /** - * This method returns the value permuted by the permutation. It - * returns this if nothing is permuted. - */ - public Value permute(MVPerm perm) { - try { - Assert.fail("TLC has found a state in which the value of a variable contains " + - Value.ppr(this.toString())); // SZ Feb 24, 2009: changed to static access - return null; // make compiler happy - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - /* This method returns true iff the value is finite. */ - public abstract boolean isFinite(); - - /* This method returns the size of the value. */ - public abstract int size(); - - /* This method returns true iff the value is fully defined. */ - public abstract boolean isDefined(); - - /* This method makes a real deep copy of this. */ - public abstract Value deepCopy(); - - /* This method returns true iff val can be assigned to this. */ - public abstract boolean assignable(Value val); - - /* This method returns the hash code of this value. */ - public final int hashCode() { - try { - long fp = this.fingerPrint(FP64.New()); - int high = (int)(fp >> 32); - int low = (int)fp; - return high ^ low; - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - public static boolean expand = true; - - /** - * This method selects the component of this value. The component is - * specified by path. - */ - public final Value select(Value[] path) { - try { - Value result = this; - for (int i = 0; i < path.length; i++) { - if (!(result instanceof Applicable)) { - Assert.fail("Attempted to apply EXCEPT construct to the value " + - ppr(result.toString()) + "."); - } - Value elem = path[i]; - result = ((Applicable)result).select(elem); - if (result == null) return null; - } - return result; - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - - public static Value getValue(SemanticNode expr) { - return (Value)expr.getToolObject(TLCGlobals.ToolId); - } - - /** - * This abstract method returns a string representation of this - * value. Each subclass must provide its own implementation. - */ - public abstract StringBuffer toString(StringBuffer sb, int offset); - - /* The string representation of this value */ - public final String toString() { - try { - StringBuffer sb = new StringBuffer(); - return this.toString(sb, 0).toString(); - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - public final String toString(String delim) { - try { - StringBuffer sb = new StringBuffer(); - sb = this.toString(sb, 0); - sb.append(delim); - return sb.toString(); - } - catch (RuntimeException | OutOfMemoryError e) { - if (hasSource()) { throw FingerprintException.getNewHead(this, e); } - else { throw e; } - } - } - - public static String ppr(String s) { - return PrettyPrint.mypp(s, 80) ; - } - public static String ppr(Value v) { - if (v == null) { - return "null"; - } - return PrettyPrint.mypp(v.toString(), 80) ; - } -} diff --git a/tlatools/src/tlc2/value/ValueConstants.java b/tlatools/src/tlc2/value/ValueConstants.java index e67c6f926b8946e04c27e27239e62094209faec1..8717f41f50e06692cddd41fbaf3da08764aff66e 100644 --- a/tlatools/src/tlc2/value/ValueConstants.java +++ b/tlatools/src/tlc2/value/ValueConstants.java @@ -5,8 +5,6 @@ package tlc2.value; -import util.UniqueString; - public interface ValueConstants { /* Type code for values. */ @@ -36,49 +34,6 @@ public interface ValueConstants { public final byte INTERVALVALUE = USERVALUE + 1; public final byte UNDEFVALUE = INTERVALVALUE + 1; public final byte LAZYVALUE = UNDEFVALUE + 1; - public final byte DUMMYVALUE = LAZYVALUE + 1; - - public final String[] ValueImage = { - "a Boolean value", // "BoolValue", - "an integer", // "IntValue", - "a real", // "RealValue", - "a string", // "StringValue", - "a record", // "RecordValue", - "a set of the form {e1, ... ,eN}", // "SetEnumValue", - "a set of the form {x \\in S : expr}", // "SetPredValue", - "a tuple", // "TupleValue", - "a function of the form [x \\in S |-> expr]", // "FcnLambdaValue", - "a function of the form (d1 :> e1 @@ ... @@ dN :> eN)", // "FcnRcdValue", - "an operator", // "OpLambdaValue", - "a constant operator", // "OpRcdValue", - "a java method", // "MethodValue", - "a set of the form [S -> T]", // "SetOfFcnsValue", - "a set of the form [d1 : S1, ... , dN : SN]", // "SetOfRcdsValue", - "a cartesian product", // "SetOfTuplesValue", - "a set of the form SUBSET S", // "SubsetValue", - "a set of the form S \\ T", // "SetDiffValue", - "a set of the form S \\cap T", // "SetCapValue", - "a set of the form S \\cup T", // "SetCupValue", - "a set of the form UNION S", // "UnionValue", - "a model value", // "ModelValue", - "a special set constant", // "UserValue", - "a set of the form i..j", // "IntervalValue", - "an undefined value", // "UndefValue", - "a value represented in lazy form", // "LazyValue", - "a dummy for not-a-value", // "DummyValue", - }; - - /* Value constants. */ - public final BoolValue ValTrue = new BoolValue(true); - public final BoolValue ValFalse = new BoolValue(false); - public final IntValue ValZero = IntValue.gen(0); - public final IntValue ValOne = IntValue.gen(1); - public final IntValue ValNegOne = IntValue.gen(-1); - public final Value EmptySet = new SetEnumValue(new ValueVec(0), true); - public final Value EmptyFcn = new FcnRcdValue(new Value[0], new Value[0], true); - public final TupleValue EmptyTuple = new TupleValue(new Value[0]); - public final RecordValue EmptyRcd = new RecordValue(new UniqueString[0], new Value[0], true); - public final UndefValue ValUndef = new UndefValue(); - public final SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, true); + public final byte DUMMYVALUE = LAZYVALUE + 1; } diff --git a/tlatools/src/tlc2/value/ValueInputStream.java b/tlatools/src/tlc2/value/ValueInputStream.java index 7a8c91a8f752da2f23a6e18565448b1b0b22e020..2e1c90b2a580defd715bf18f799e87f6f24372d4 100644 --- a/tlatools/src/tlc2/value/ValueInputStream.java +++ b/tlatools/src/tlc2/value/ValueInputStream.java @@ -2,19 +2,30 @@ package tlc2.value; +import java.io.EOFException; import java.io.File; import java.io.IOException; import tlc2.TLCGlobals; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.ModelValue; +import tlc2.value.impl.RecordValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.TupleValue; import util.BufferedDataInputStream; import util.FileUtil; +import util.IDataInputStream; import util.UniqueString; import util.WrongInvocationException; -public final class ValueInputStream implements ValueConstants { +public final class ValueInputStream implements ValueConstants, IValueInputStream { - private BufferedDataInputStream dis; - private HandleTable handles; + private final BufferedDataInputStream dis; + private final HandleTable handles; public ValueInputStream(File file) throws IOException { @@ -27,145 +38,68 @@ public final class ValueInputStream implements ValueConstants { this(new File(fname)); } - public final Value read() throws IOException { - byte kind = this.dis.readByte(); - - switch (kind) { - case BOOLVALUE: - { - boolean b = this.dis.readBoolean(); - return (b) ? ValTrue : ValFalse; - } - case INTVALUE: - { - int x = this.dis.readInt(); - return IntValue.gen(x); - } - case STRINGVALUE: - { - UniqueString str = UniqueString.read(this.dis); - Value res = new StringValue(str); - int index = this.handles.getIndex(); - this.handles.assign(res, index); - return res; - } - case MODELVALUE: - { - int index = this.dis.readShort(); - return ModelValue.mvs[index]; - } - case INTERVALVALUE: - { - int low = this.dis.readInt(); - int hi = this.dis.readInt(); - return new IntervalValue(low, hi); - } - case RECORDVALUE: - { - int index = this.handles.getIndex(); - boolean isNorm = true; - int len = this.dis.readInt(); - if (len < 0) { len = -len; isNorm = false; } - UniqueString[] names = new UniqueString[len]; - Value[] vals = new Value[len]; - for (int i = 0; i < len; i++) { - byte kind1 = this.dis.readByte(); - if (kind1 == DUMMYVALUE) { - int index1 = this.readNat(); - names[i] = (UniqueString)this.handles.getValue(index1); - } - else { - int index1 = this.handles.getIndex(); - names[i] = UniqueString.read(this.dis); - this.handles.assign(names[i], index1); - } - vals[i] = this.read(); - } - Value res = new RecordValue(names, vals, isNorm); - this.handles.assign(res, index); - return res; - } - case FCNRCDVALUE: - { - int index = this.handles.getIndex(); - int len = this.readNat(); - int info = this.dis.readByte(); - Value res; - Value[] rvals = new Value[len]; - if (info == 0) { - int low = this.dis.readInt(); - int high = this.dis.readInt(); - for (int i = 0; i < len; i++) { - rvals[i] = this.read(); - } - IntervalValue intv = new IntervalValue(low, high); - res = new FcnRcdValue(intv, rvals); - } - else { - Value[] dvals = new Value[len]; - for (int i = 0; i < len; i++) { - dvals[i] = this.read(); - rvals[i] = this.read(); - } - res = new FcnRcdValue(dvals, rvals, (info == 1)); - } - this.handles.assign(res, index); - return res; - } - case SETENUMVALUE: - { - int index = this.handles.getIndex(); - boolean isNorm = true; - int len = this.dis.readInt(); - if (len < 0) { len = -len; isNorm = false; } - Value[] elems = new Value[len]; - for (int i = 0; i < len; i++) { - elems[i] = this.read(); + @Override + public final IValue read() throws IOException { + final byte kind = this.dis.readByte(); + + switch (kind) { + case BOOLVALUE: { + return (this.dis.readBoolean()) ? BoolValue.ValTrue : BoolValue.ValFalse; + } + case INTVALUE: { + return IntValue.gen(this.dis.readInt()); + } + case STRINGVALUE: { + return StringValue.createFrom(this); + } + case MODELVALUE: { + return ModelValue.mvs[this.dis.readShort()]; + } + case INTERVALVALUE: { + return new IntervalValue(this.dis.readInt(), this.dis.readInt()); + } + case RECORDVALUE: { + return RecordValue.createFrom(this); + } + case FCNRCDVALUE: { + return FcnRcdValue.createFrom(this); + } + case SETENUMVALUE: { + return SetEnumValue.createFrom(this); + } + case TUPLEVALUE: { + return TupleValue.createFrom(this); + } + case DUMMYVALUE: { + return (IValue) this.handles.getValue(this.readNat()); + } + default: { + throw new WrongInvocationException("ValueInputStream: Can not unpickle a value of kind " + kind); + } + } } - Value res = new SetEnumValue(elems, isNorm); - this.handles.assign(res, index); - return res; - } - case TUPLEVALUE: - { - int index = this.handles.getIndex(); - int len = this.readNat(); - Value[] elems = new Value[len]; - for (int i = 0; i < len; i++) { - elems[i] = this.read(); - } - Value res = new TupleValue(elems); - this.handles.assign(res, index); - return res; - } - case DUMMYVALUE: - { - int index = this.readNat(); - return (Value)this.handles.getValue(index); - } - default: - { - throw new WrongInvocationException("ValueInputStream: Can not unpickle a value of kind " + kind); - } - } - } + @Override public final int readShort() throws IOException { return this.dis.readShort(); } + @Override public final int readInt() throws IOException { return this.dis.readInt(); } + @Override public final long readLong() throws IOException { return this.dis.readLong(); } + @Override public final void close() throws IOException { this.dis.close(); } + @Override public final int readNat() throws IOException { int res = this.dis.readShort(); if (res >= 0) return res; @@ -173,12 +107,14 @@ public final class ValueInputStream implements ValueConstants { return -res; } + @Override public final short readShortNat() throws IOException { short res = this.dis.readByte(); if (res >= 0) return res; return (short) -((res << 8) | (this.dis.readByte() & 0xFF)); } + @Override public final long readLongNat() throws IOException { long res = this.dis.readInt(); if (res >= 0) return res; @@ -186,6 +122,32 @@ public final class ValueInputStream implements ValueConstants { return -res; } + @Override + public final byte readByte() throws EOFException, IOException { + return this.dis.readByte(); + } + + @Override + public final void assign(final Object obj, final int idx) { + this.handles.assign(obj, idx); + } + + @Override + public final int getIndex() { + return handles.getIndex(); + } + + @Override + public final IDataInputStream getInputStream() { + return dis; + } + + @Override + public final UniqueString getValue(int idx) { + return (UniqueString) this.handles.getValue(idx); + } + + // @see ValueOutputStream#put private static class HandleTable { private Object[] values; private int index; @@ -211,5 +173,4 @@ public final class ValueInputStream implements ValueConstants { final Object getValue(int idx) { return this.values[idx]; } } - } diff --git a/tlatools/src/tlc2/value/ValueOutputStream.java b/tlatools/src/tlc2/value/ValueOutputStream.java index 030dcce164627d36c22b192e150a3a47e918d38f..e28c39beb3f59ed8291b01c54ae75fe38506da66 100644 --- a/tlatools/src/tlc2/value/ValueOutputStream.java +++ b/tlatools/src/tlc2/value/ValueOutputStream.java @@ -11,12 +11,11 @@ import java.util.zip.GZIPOutputStream; import tlc2.TLCGlobals; import util.BufferedDataOutputStream; -import util.WrongInvocationException; -public final class ValueOutputStream implements ValueConstants { +public final class ValueOutputStream implements IValueOutputStream { - private BufferedDataOutputStream dos; - private HandleTable handles; + private final BufferedDataOutputStream dos; + private final HandleTable handles; public ValueOutputStream(File file) throws IOException { if (TLCGlobals.useGZIP) { @@ -40,234 +39,28 @@ public final class ValueOutputStream implements ValueConstants { this.handles = new HandleTable(); } - public final void write(Value val) throws IOException { - switch (val.getKind()) { - case BOOLVALUE: - { - this.dos.writeByte(BOOLVALUE); - this.dos.writeBoolean(((BoolValue)val).val); - break; - } - case INTVALUE: - { - this.dos.writeByte(INTVALUE); - dos.writeInt(((IntValue)val).val); - break; - } - case STRINGVALUE: - { - int index = this.handles.put(val); - if (index == -1) { - this.dos.writeByte(STRINGVALUE); - ((StringValue)val).val.write(this.dos); - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index); - } - break; - } - case MODELVALUE: - { - this.dos.writeByte(MODELVALUE); - this.dos.writeShort((short)((ModelValue)val).index); - break; - } - case INTERVALVALUE: - { - this.dos.writeByte(INTERVALVALUE); - this.dos.writeInt(((IntervalValue)val).low); - this.dos.writeInt(((IntervalValue)val).high); - break; - } - case RECORDVALUE: - { - int index = this.handles.put(val); - if (index == -1) { - this.dos.writeByte(RECORDVALUE); - RecordValue rval = (RecordValue)val; - int len = rval.names.length; - this.dos.writeInt((rval.isNormalized()) ? len : -len); - for (int i = 0; i < len; i++) { - int index1 = this.handles.put(rval.names[i]); - if (index1 == -1) { - this.dos.writeByte(STRINGVALUE); - rval.names[i].write(this.dos); - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index1); - } - this.write(rval.values[i]); - } - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index); - } - break; - } - case FCNRCDVALUE: - { - int index = this.handles.put(val); - if (index == -1) { - this.dos.writeByte(FCNRCDVALUE); - FcnRcdValue fval = (FcnRcdValue)val; - int len = fval.values.length; - this.writeNat(len); - if (fval.intv != null) { - this.dos.writeByte((byte)0); - this.dos.writeInt(fval.intv.low); - this.dos.writeInt(fval.intv.high); - for (int i = 0; i < len; i++) { - this.write(fval.values[i]); - } - } - else { - this.dos.writeByte((fval.isNormalized()) ? (byte)1 : (byte)2); - for (int i = 0; i < len; i++) { - this.write(fval.domain[i]); - this.write(fval.values[i]); - } - } - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index); - } - break; - } - case SETENUMVALUE: - { - int index = this.handles.put(val); - if (index == -1) { - this.dos.writeByte(SETENUMVALUE); - SetEnumValue sval = (SetEnumValue)val; - int len = sval.elems.size(); - this.dos.writeInt((sval.isNormalized()) ? len : -len); - for (int i = 0; i < len; i++) { - this.write(sval.elems.elementAt(i)); - } - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index); - } - break; - } - case TUPLEVALUE: - { - int index = this.handles.put(val); - if (index == -1) { - this.dos.writeByte(TUPLEVALUE); - TupleValue tval = (TupleValue)val; - int len = tval.elems.length; - this.writeNat(len); - for (int i = 0; i < len; i++) { - this.write(tval.elems[i]); - } - } - else { - this.dos.writeByte(DUMMYVALUE); - this.writeNat(index); - } - break; - } - case SETCAPVALUE: - { - SetCapValue cap = (SetCapValue)val; - // Assert.check(cap.capSet != null); - this.write(cap.capSet); - break; - } - case SETCUPVALUE: - { - SetCupValue cup = (SetCupValue)val; - // Assert.check(cup.cupSet != null); - this.write(cup.cupSet); - break; - } - case SETDIFFVALUE: - { - SetDiffValue diff = (SetDiffValue)val; - // Assert.check(diff.diffSet != null); - this.write(diff.diffSet); - break; - } - case SUBSETVALUE: - { - SubsetValue pset = (SubsetValue)val; - // Assert.check(pset.pset != null); - this.write(pset.pset); - break; - } - case UNIONVALUE: - { - UnionValue uv = (UnionValue)val; - // Assert.check(uv.realSet != null); - this.write(uv.realSet); - break; - } - case SETOFRCDSVALUE: - { - SetOfRcdsValue rcds = (SetOfRcdsValue)val; - // Assert.check(rcds.rcdSet != null); - this.write(rcds.rcdSet); - break; - } - case SETOFFCNSVALUE: - { - SetOfFcnsValue fcns = (SetOfFcnsValue)val; - // Assert.check(fcns.fcnSet != null); - this.write(fcns.fcnSet); - break; - } - case SETOFTUPLESVALUE: - { - SetOfTuplesValue tuples = (SetOfTuplesValue)val; - // Assert.check(tuples.tupleSet != null); - this.write(tuples.tupleSet); - break; - } - case SETPREDVALUE: - { - SetPredValue spred = (SetPredValue)val; - // Assert.check(spred.tool == null); - this.write(spred.inVal); - break; - } - case FCNLAMBDAVALUE: - { - FcnLambdaValue flambda = (FcnLambdaValue)val; - // Assert.check(flambda.fcnRcd != null); - this.write(flambda.fcnRcd); - break; - } - default: - { - throw new WrongInvocationException("ValueOutputStream: Can not pickle the value\n" + - Value.ppr(val.toString())); - } - } - } - + @Override public final void writeShort(short x) throws IOException { this.dos.writeShort(x); } + @Override public final void writeInt(int x) throws IOException { this.dos.writeInt(x); } + @Override public final void writeLong(long x) throws IOException { this.dos.writeLong(x); } + @Override public final void close() throws IOException { this.dos.close(); } /* Precondition: x is a non-negative short. */ + @Override public final void writeShortNat(short x) throws IOException { if (x > 0x7f) { this.dos.writeShort((short) -x); @@ -278,6 +71,7 @@ public final class ValueOutputStream implements ValueConstants { } /* Precondition: x is a non-negative int. */ + @Override public final void writeNat(int x) throws IOException { if (x > 0x7fff) { this.dos.writeInt(-x); @@ -288,6 +82,7 @@ public final class ValueOutputStream implements ValueConstants { } /* Precondition: x is a non-negative long. */ + @Override public final void writeLongNat(long x) throws IOException { if (x <= 0x7fffffff) { this.dos.writeInt((int)x); @@ -296,6 +91,53 @@ public final class ValueOutputStream implements ValueConstants { this.dos.writeLong(-x); } } + + @Override + public final void writeByte(final byte b) throws IOException { + this.dos.writeByte(b); + } + + @Override + public final void writeBoolean(final boolean b) throws IOException { + this.dos.writeBoolean(b); + } + + @Override + public final BufferedDataOutputStream getOutputStream() { + return dos; + } + + /** + * Check if another TLCState - which is currently also being serialized to the + * same storage (i.e. disk file) - has/contains an identical Value. If yes, do + * not serialize the Value instance again but make this TLCState point to the + * Value instance previously serialized for the other TLCState. In other words, + * this is a custom-tailored compression/de-duplication mechanism for Value + * instances. + * <p> + * This approach only works because both TLCStates are serialized to the same + * storage and thus de-serialized as part of the same operation (same + * Value*Stream instance). + * <p> + * The purpose of this approach appears to be: + * <ul> + * <li>Reduce serialization efforts and storage size</li> + * <li>Reduce the number of Value instances created during de-serialization</li> + * <li>Allow identity comparison on Value instances (AFAICT not used by Value + * explicitly, just UniqueString) to speed up check. Value#equals internally + * likely uses identity comparison as first check.</li> + * </ul> + * <p> + * A disadvantage is the cost of maintaining the internal HandleTable which can + * grow to thousands of elements during serialization/de-serialization (in + * ValueInputStream). Since serialization suspends the DiskStateQueue and thus + * blocks tlc2.tool.Workers from exploring the state space, this might has + * adverse effects. + */ + @Override + public final int put(final Object obj) { + return this.handles.put(obj); + } private static class HandleTable { private int[] spine; @@ -361,62 +203,4 @@ public final class ValueOutputStream implements ValueConstants { } } } - - public static void main(String[] args) { - if (args.length != 1) { - System.err.println("Usage: java tlc2.value.ValueOutputStream filename."); - System.exit(1); - } - - IntValue[] aa = new IntValue[100]; - StringValue[] bb = new StringValue[100]; - - for (int i = 0; i < aa.length; i++) { - aa[i] = IntValue.gen(88); - } - - StringValue sval = new StringValue("ssssssssss"); - for (int i = 0; i < bb.length; i++) { - bb[i] = sval; - } - - try { - /** - BufferedDataOutputStream dos = new BufferedDataOutputStream(args[0]+"_1"); - for (int i = 0; i < aa.length; i++) { - dos.writeInt(88); - } - dos.close(); - - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(args[0]+"_2")); - for (int i = 0; i < bb.length; i++) { - oos.writeObject(bb[i]); - } - oos.close(); - - ValueOutputStream vos = new ValueOutputStream(new File(args[0]+"_3")); - for (int i = 0; i < bb.length; i++) { - vos.write(bb[i]); - } - vos.close(); - **/ - - ValueOutputStream vos = new ValueOutputStream(new File(args[0])); - long x = 1; - for (int i = 0; i < 63; i++) { - System.err.println("write " + x); - vos.writeLongNat(x); - x = x * 2; - } - vos.close(); - - ValueInputStream vis = new ValueInputStream(new File(args[0])); - for (int i = 0; i < 63; i++) { - System.err.println("read " + vis.readLongNat()); - } - vis.close(); - } - catch (Exception e) { } - } - } diff --git a/tlatools/src/tlc2/value/Values.java b/tlatools/src/tlc2/value/Values.java new file mode 100644 index 0000000000000000000000000000000000000000..22c5ba3af1085710be5e5432fa8ba682c14858ec --- /dev/null +++ b/tlatools/src/tlc2/value/Values.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import tlc2.pprint.PrettyPrint; + +public abstract class Values { + + public static String ppr(String s) { + return PrettyPrint.mypp(s, 80) ; + } + + public static String ppr(IValue v) { + if (v == null) { + return "null"; + } + return PrettyPrint.mypp(v.toString(), 80) ; + } +} diff --git a/tlatools/src/tlc2/value/Applicable.java b/tlatools/src/tlc2/value/impl/Applicable.java similarity index 95% rename from tlatools/src/tlc2/value/Applicable.java rename to tlatools/src/tlc2/value/impl/Applicable.java index 2f784f73a99f03b63de9e593e327e27934db3501..1f291877651bc50cf5bf857ed952ac37df7da124 100644 --- a/tlatools/src/tlc2/value/Applicable.java +++ b/tlatools/src/tlc2/value/impl/Applicable.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:20:42 PST by lamport // modified on Wed Jun 2 00:10:22 PDT 1999 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tlc2.tool.EvalException; diff --git a/tlatools/src/tlc2/value/BoolValue.java b/tlatools/src/tlc2/value/impl/BoolValue.java similarity index 74% rename from tlatools/src/tlc2/value/BoolValue.java rename to tlatools/src/tlc2/value/impl/BoolValue.java index 23337bc6de24aab38e779d8e222cd1d3c21f45f9..4b9fdee0ea37ce93617cff77debfd5fe16f9a275 100644 --- a/tlatools/src/tlc2/value/BoolValue.java +++ b/tlatools/src/tlc2/value/impl/BoolValue.java @@ -4,18 +4,33 @@ // modified on Sat 23 February 2008 at 10:01:16 PST by lamport // modified on Fri Aug 10 15:07:07 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.tool.FingerprintException; import tlc2.util.FP64; +import tlc2.value.IBoolValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; -public class BoolValue extends Value { +public class BoolValue extends Value implements IBoolValue { public boolean val; // the boolean + public final static BoolValue ValFalse = new BoolValue(false); + /* Value constants. */ + public final static BoolValue ValTrue = new BoolValue(true); /* Constructor */ public BoolValue(boolean b) { this.val = b; } + @Override + public final boolean getVal() { + return val; + } + public final byte getKind() { return BOOLVALUE; } public final int compareTo(Object obj) { @@ -26,8 +41,8 @@ public class BoolValue extends Value { return x - y; } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to compare boolean " + ppr(this.toString()) + - " with non-boolean:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare boolean " + Values.ppr(this.toString()) + + " with non-boolean:\n" + Values.ppr(obj.toString())); } return 1; } @@ -43,8 +58,8 @@ public class BoolValue extends Value { return this.val == ((BoolValue)obj).val; } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to compare equality of boolean " + ppr(this.toString()) + - " with non-boolean:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare equality of boolean " + Values.ppr(this.toString()) + + " with non-boolean:\n" + Values.ppr(obj.toString())); } return ((ModelValue) obj).modelValueEquals(this) ; } @@ -56,8 +71,8 @@ public class BoolValue extends Value { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the boolean " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the boolean " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -68,7 +83,7 @@ public class BoolValue extends Value { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the boolean " + ppr(this.toString()) + + Assert.fail("Attempted to check if the boolean " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -82,7 +97,7 @@ public class BoolValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the boolean " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -96,7 +111,7 @@ public class BoolValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the boolean " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -109,7 +124,7 @@ public class BoolValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the boolean " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -124,7 +139,7 @@ public class BoolValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -137,6 +152,12 @@ public class BoolValue extends Value { } } + @Override + public void write(IValueOutputStream vos) throws IOException { + vos.writeByte(BOOLVALUE); + vos.writeBoolean(val); + } + /* The fingerprint method */ public final long fingerPrint(long fp) { try { @@ -150,10 +171,15 @@ public class BoolValue extends Value { } } - public final Value permute(MVPerm perm) { return this; } + public final IValue permute(IMVPerm perm) { return this; } /* The string representation */ public final StringBuffer toString(StringBuffer sb, int offset) { + return toString(sb, offset, true); +} + +/* The string representation */ + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { return sb.append((this.val) ? "TRUE" : "FALSE"); } diff --git a/tlatools/src/tlc2/value/Enumerable.java b/tlatools/src/tlc2/value/impl/Enumerable.java similarity index 55% rename from tlatools/src/tlc2/value/Enumerable.java rename to tlatools/src/tlc2/value/impl/Enumerable.java index faeb4a6c1c3b93f0f59d070610be56e8ac79852c..f0bc0029fb607ade5a31729e7129c74117d6b88b 100644 --- a/tlatools/src/tlc2/value/Enumerable.java +++ b/tlatools/src/tlc2/value/impl/Enumerable.java @@ -3,18 +3,33 @@ // Last modified on Mon 30 Apr 2007 at 13:20:54 PST by lamport // modified on Thu Mar 11 21:25:20 PST 1999 by yuanyu -package tlc2.value; +package tlc2.value.impl; -public interface Enumerable { +import tlc2.value.IValue; +public interface Enumerable extends IValue { + + enum Ordering { + UNDEFINED, + /** + * The normalized order is the order of elements when a Value gets + * fingerprinted (@see {@link Value#fingerPrint(long)}. + */ + NORMALIZED; + } + public int size(); public boolean member(Value elem); + /** + * Semantics or Enumerable#elements(Ordering#UNDEFINED) + */ public ValueEnumeration elements(); + public ValueEnumeration elements(final Ordering ordering); /** * Returns a {@link ValueEnumeration} which returns k - * {@link Value}s of all {@link Value}s returned by + * {@link IValue}s of all {@link IValue}s returned by * {@link Enumerable#elements()}. In other words, it returns - * a randomly chosen subset of all {@link Value} members of + * a randomly chosen subset of all {@link IValue} members of * this {@link Enumerable}. */ public ValueEnumeration elements(final int k); diff --git a/tlatools/src/tlc2/value/impl/EnumerableValue.java b/tlatools/src/tlc2/value/impl/EnumerableValue.java new file mode 100644 index 0000000000000000000000000000000000000000..bb4128757858a8ffcb3677b83bbf53ba62aea8a9 --- /dev/null +++ b/tlatools/src/tlc2/value/impl/EnumerableValue.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + * Ian Morris Nieves - added support for fingerprint stack trace + ******************************************************************************/ + +package tlc2.value.impl; + +import java.util.List; + +import tlc2.tool.FingerprintException; +import tlc2.value.RandomEnumerableValues; + +public abstract class EnumerableValue extends Value implements Enumerable { + + public Value isSubsetEq(Value other) { + try { + final ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + if (!other.member(elem)) { + return BoolValue.ValFalse; + } + } + return BoolValue.ValTrue; + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + @Override + public EnumerableValue getRandomSubset(final int kOutOfN) { + // By default, convert all EVs into SetEnumValue and delegate to its + // getRandomSubset. + return ((SetEnumValue) this.toSetEnum()).getRandomSubset(kOutOfN); + } + + @Override + public ValueEnumeration elements(final Ordering ordering) { + if (ordering == Ordering.NORMALIZED) { + // By default, none of the EnumerableValues supports a ValueEnumeration that + // provides normalized ordering. Thus, to traverse the elements in normalized + // ordering, any EV type gets converted into a SetEnumValue - this effectively + // enumerates the EV and normalizes the new SEV. Traversing the normalized + // SEV with a ValueEnumeration returned by Enumerable#elements is guaranteed + // to be in normalized order (@see Ordering.NORMALIZED for what this means). + // In case a subclass provides a more efficient ValueEnumeration that guarantees + // normalized order, the subclass may override this default method. This is + // so far done by SubsetValue. + final Value enumerated = this.toSetEnum(); + if (enumerated != null) { + return ((Enumerable) enumerated.normalize()).elements(); + } + } + return elements(); + } + + public ValueEnumeration elements(final int k) { + // The generic implementation collects all n elements of the actual Enumerable + // into the temporary variable values. The SubSetEnumerator then randomly + // returns up to k elements. + // The underlying assuming here is that the size of Enumerable (n) is + // very small and this method is not called as part of the next-state relation. + // If it gets called on larger sets or as part of the next-state relation, + // subclasses can provide a more efficient implementation (e.g. see + // IntervalValue and SetEnumValue which return a more efficient subclass + // of SubsetEnumerator). + final List<Value> values = elements().all(); + return new SubsetEnumerator(k) { + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return values.get(nextIndex()); + } + }; + } + + abstract class SubsetEnumerator implements ValueEnumeration { + + protected final long x; + protected final int a; + protected final int n; + protected final int k; + protected int i; + + public SubsetEnumerator(final int k) { + this(k, size()); + } + + public SubsetEnumerator(final int k, final int n) { + this.n = n; + + // https://en.wikipedia.org/wiki/Linear_congruential_generator + // + // x has to be co-prime to n. Since n might or might not be a prime number + // - it depends on the actual size of the set - we simply set x to + // be a prime number. The prime x has to be larger than n tough, since n is + // bound by Integer.MAX_VALUE, we simply choose the Mersenne prime + // Integer.MAX_VALUE + // for x and accept that we fail if n = Integer.MAX_VALUE. To minimize + // intermediate results and the rounds of mod in nextIndex, we choose 191 if n + // happens to be smaller (very likely). + assert n < Integer.MAX_VALUE; + this.x = n < 191 ? 191L : 1L * Integer.MAX_VALUE; + + // k out of n elements in the range 0 <= k <= n. + if (n > 0) { + this.k = k; + this.a = RandomEnumerableValues.get().nextInt(n); + } else { + this.k = 0; + this.a = 0; // RANDOM.nextInt(0) causes IllegalArgumentException. + } + } + + public void reset() { + i = 0; + } + + public boolean hasNext() { + return i < k; + } + + /** + * @return A random (uniformly distributed) index in the range [0,n) where n is + * {@link Enumerable#size()}. + */ + public int nextIndex() { + if (n <= 0) { + i++; + return 0; + } + // long x avoids intermediate overflow, final cast to int safe though because of + // mod n. + final int index = (int) (((x * i++) + a) % n); + assert 0 <= index && index < n; + return index; + } + + public abstract Value nextElement(); + } +} diff --git a/tlatools/src/tlc2/value/FcnLambdaValue.java b/tlatools/src/tlc2/value/impl/FcnLambdaValue.java similarity index 69% rename from tlatools/src/tlc2/value/FcnLambdaValue.java rename to tlatools/src/tlc2/value/impl/FcnLambdaValue.java index 3f8d10917352f0b0788782fd40cd1aeb3885fe0e..f943f672b813f619bffdd4e495766a0d23c7955c 100644 --- a/tlatools/src/tlc2/value/FcnLambdaValue.java +++ b/tlatools/src/tlc2/value/impl/FcnLambdaValue.java @@ -4,7 +4,7 @@ // modified on Wed 4 Jul 2007 at 17:31:23 PST by lamport // modified on Thu Dec 6 21:46:34 PST 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.io.IOException; import java.io.ObjectInputStream; @@ -13,27 +13,38 @@ import java.io.ObjectOutputStream; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; +import tlc2.TLCGlobals; import tlc2.tool.EvalControl; import tlc2.tool.EvalException; import tlc2.tool.FingerprintException; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; +import tlc2.value.IFcnLambdaValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; +import util.UniqueString; -public class FcnLambdaValue extends Value implements Applicable { - public FcnParams params; // the function formals - public SemanticNode body; // the function body +public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue { + public final FcnParams params; // the function formals + public final SemanticNode body; // the function body public ValueExcept[] excepts; // the EXCEPTs - public Tool tool; + public final ITool tool; public Context con; - public TLCState state; - public TLCState pstate; + public final TLCState state; + public final TLCState pstate; public int control; public FcnRcdValue fcnRcd; - /* Constructor */ - public FcnLambdaValue(FcnParams params, SemanticNode body, Tool tool, + /* + * Constructor: E.g. [ s \in {"A", "B", "C"} |-> "foo" ] where s \in {"A", "B", + * "C"} is FcnLambdaValue and body is the expression "foo". + */ + public FcnLambdaValue(FcnParams params, SemanticNode body, ITool tool, Context c, TLCState s0, TLCState s1, int control) { this.params = params; this.body = body; @@ -51,6 +62,12 @@ public class FcnLambdaValue extends Value implements Applicable { this.fcnRcd = null; } + public FcnLambdaValue(FcnParams params, SemanticNode body, ITool tool, + Context c, TLCState s0, TLCState s1, int control, CostModel cm) { + this(params, body, tool, c, s0, s1, control); + this.cm = cm; + } + public FcnLambdaValue(FcnLambdaValue fcn) { this.params = fcn.params; this.body = fcn.body; @@ -78,7 +95,7 @@ public class FcnLambdaValue extends Value implements Applicable { public final int compareTo(Object obj) { try { - FcnRcdValue fcn = FcnRcdValue.convert(this); + FcnRcdValue fcn = (FcnRcdValue) this.toFcnRcd(); return fcn.compareTo(obj); } catch (RuntimeException | OutOfMemoryError e) { @@ -89,7 +106,7 @@ public class FcnLambdaValue extends Value implements Applicable { public final boolean equals(Object obj) { try { - FcnRcdValue fcn = FcnRcdValue.convert(this); + FcnRcdValue fcn = (FcnRcdValue) this.toFcnRcd(); return fcn.equals(obj); } catch (RuntimeException | OutOfMemoryError e) { @@ -100,8 +117,8 @@ public class FcnLambdaValue extends Value implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the function " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the function " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -112,7 +129,7 @@ public class FcnLambdaValue extends Value implements Applicable { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the function:\n" + ppr(this.toString()) + + Assert.fail("Attempted to check if the function:\n" + Values.ppr(this.toString()) + "\nis a finite set."); return false; // make compiler happy } @@ -131,14 +148,14 @@ public class FcnLambdaValue extends Value implements Applicable { } // First, find all the excepts that match args. - Value res = null; + Value res = null; int num = 0; ValueExcept[] excepts1 = null; if (this.excepts != null) { int exlen = this.excepts.length; for (int i = exlen-1; i >= 0; i--) { ValueExcept ex = this.excepts[i]; - Value arg = ex.current(); + Value arg = ex.current(); boolean inExcept = true; inExcept = arg.equals(args); if (inExcept) { @@ -153,26 +170,26 @@ public class FcnLambdaValue extends Value implements Applicable { if (res == null) { Context c1 = this.con; FormalParamNode[][] formals = this.params.formals; - Value[] domains = this.params.domains; + Value [] domains = this.params.domains; boolean[] isTuples = this.params.isTuples; int plen = this.params.length(); if (plen == 1) { if (!domains[0].member(args)) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe first argument is:\n" + Value.ppr(args.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe first argument is:\n" + Values.ppr(args.toString()) + "\nwhich is not in its domain.\n"); } if (isTuples[0]) { FormalParamNode[] ids = formals[0]; - TupleValue argVal = TupleValue.convert(args); + TupleValue argVal = (TupleValue) args.toTuple(); if (argVal == null) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe first argument is:\n" + Value.ppr(args.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe first argument is:\n" + Values.ppr(args.toString()) + "\nwhich does not match its formal parameter.\n"); } if (argVal.size() != ids.length) return null; - Value[] elems = argVal.elems; + Value [] elems = argVal.elems; for (int i = 0; i < ids.length; i++) { c1 = c1.cons(ids[i], elems[i]); } @@ -182,32 +199,32 @@ public class FcnLambdaValue extends Value implements Applicable { } } else { - TupleValue tv = TupleValue.convert(args); + TupleValue tv = (TupleValue) args.toTuple(); if (tv == null) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe argument list is:\n" + Value.ppr(args.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe argument list is:\n" + Values.ppr(args.toString()) + "\nwhich does not match its formal parameter.\n"); } Value[] elems = tv.elems; int argn = 0; for (int i = 0; i < formals.length; i++) { FormalParamNode[] ids = formals[i]; - Value domain = domains[i]; + Value domain = domains[i]; if (isTuples[i]) { if (!domain.member(elems[argn])) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + ",\nthe argument number " + (argn+1) + " is:\n" + - Value.ppr(elems[argn].toString()) + + Values.ppr(elems[argn].toString()) + "\nwhich is not in its domain.\n"); } - TupleValue tv1 = TupleValue.convert(elems[argn++]); + TupleValue tv1 = (TupleValue) elems[argn++].toTuple(); if (tv1 == null || tv1.size() != ids.length) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + ",\nthe argument number " + argn + " is:\n" + - Value.ppr(elems[argn-1].toString()) + + Values.ppr(elems[argn-1].toString()) + "\nwhich does not match its formal parameter.\n"); } - Value[] avals = tv1.elems; + Value [] avals = tv1.elems; for (int j = 0; j < ids.length; j++) { c1 = c1.cons(ids[j], avals[j]); } @@ -215,16 +232,16 @@ public class FcnLambdaValue extends Value implements Applicable { else { for (int j = 0; j < ids.length; j++) { if (!domain.member(elems[argn])) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + ",\nthe argument number " + (argn+1) + " is:\n" + - Value.ppr(elems[argn].toString()) + "\nwhich is not in its domain.\n"); + Values.ppr(elems[argn].toString()) + "\nwhich is not in its domain.\n"); } c1 = c1.cons(ids[j], elems[argn++]); } } } } - res = this.tool.eval(this.body, c1, this.state, this.pstate, control); + res = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, control); } // Finally, apply the matching excepts on the result. @@ -290,17 +307,17 @@ public class FcnLambdaValue extends Value implements Applicable { if (!domains[0].member(arg)) return null; if (isTuples[0]) { FormalParamNode[] ids = formals[0]; - TupleValue argVal = TupleValue.convert(arg); + TupleValue argVal = (TupleValue) arg.toTuple(); /* * SZA: Changed from argVal.toString() to arg.toString() to prevent a NullPointerException */ if (argVal == null) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe first argument is:\n" + Value.ppr(arg.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe first argument is:\n" + Values.ppr(arg.toString()) + "\nwhich does not match its formal parameter.\n"); } if (argVal.size() != ids.length) return null; - Value[] elems = argVal.elems; + Value [] elems = argVal.elems; for (int i = 0; i < ids.length; i++) { c1 = c1.cons(ids[i], elems[i]); } @@ -310,10 +327,10 @@ public class FcnLambdaValue extends Value implements Applicable { } } else { - TupleValue tv = TupleValue.convert(arg); + TupleValue tv = (TupleValue) arg.toTuple(); if (tv == null) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + - ",\nthe argument list is:\n" + Value.ppr(arg.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + + ",\nthe argument list is:\n" + Values.ppr(arg.toString()) + "\nwhich does not match its formal parameter.\n"); } Value[] elems = tv.elems; @@ -323,15 +340,15 @@ public class FcnLambdaValue extends Value implements Applicable { Value domain = domains[i]; if (isTuples[i]) { if (!domain.member(elems[argn])) return null; - TupleValue tv1 = TupleValue.convert(elems[argn++]); + TupleValue tv1 = (TupleValue) elems[argn++].toTuple(); if (tv1 == null) { - Assert.fail("In applying the function\n" + Value.ppr(this.toString()) + + Assert.fail("In applying the function\n" + Values.ppr(this.toString()) + ",\nthe argument number " + argn + " is:\n" + - Value.ppr(elems[argn-1].toString()) + + Values.ppr(elems[argn-1].toString()) + "\nwhich does not match its formal parameter.\n"); } if (tv1.size() != ids.length) return null; - Value[] avals = tv1.elems; + Value [] avals = tv1.elems; for (int j = 0; j < ids.length; j++) { c1 = c1.cons(ids[j], avals[j]); } @@ -344,7 +361,7 @@ public class FcnLambdaValue extends Value implements Applicable { } } } - res = this.tool.eval(this.body, c1, this.state, this.pstate, this.control); + res = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, this.control); } // Finally, apply the matching excepts on the result. @@ -442,13 +459,13 @@ public class FcnLambdaValue extends Value implements Applicable { if (len == 1) { return this.params.domains[0]; } - Value[] sets = new Value[len]; + Value [] sets = new Value [len]; int dlen = this.params.domains.length; boolean[] isTuples = this.params.isTuples; int idx = 0; for (int i = 0; i < dlen; i++) { FormalParamNode[] formal = this.params.formals[i]; - Value domain = this.params.domains[i]; + Value domain = this.params.domains[i]; if (isTuples[i]) { sets[idx++] = domain; } @@ -482,7 +499,7 @@ public class FcnLambdaValue extends Value implements Applicable { public final boolean isDefined() { return true; } - public final Value deepCopy() { + public final IValue deepCopy() { try { FcnLambdaValue fcn = new FcnLambdaValue(this); // A bug occured when printing a function whose domain is a Cartesian product because this.fcnRcd @@ -513,7 +530,7 @@ public class FcnLambdaValue extends Value implements Applicable { } private void writeObject(ObjectOutputStream oos) throws IOException { - FcnRcdValue res = this.toFcnRcd(); + FcnRcdValue res = (FcnRcdValue) this.toFcnRcd(); oos.writeObject(res); } @@ -543,7 +560,87 @@ public class FcnLambdaValue extends Value implements Applicable { } } - public final FcnRcdValue toFcnRcd() { + @Override + public final void deepNormalize() { + try { + if (fcnRcd == null) { + if (excepts != null) { + for (int i = 0; i < excepts.length; i++) { + excepts[i].value.deepNormalize(); + for (int j = 0; j < excepts[i].path.length; j++) { + excepts[i].path[j].deepNormalize(); + } + } + } + IValue[] paramDoms = params.domains; + for (int i = 0; i < paramDoms.length; i++) { + paramDoms[i].deepNormalize(); + } + } + else { + fcnRcd.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + @Override + public final Value toTuple() { + if (this.params.length() != 1) return null; + Value dom = this.params.domains[0]; + SymbolNode var = this.params.formals[0][0]; + if (dom instanceof IntervalValue) { + IntervalValue intv = (IntervalValue)dom; + if (intv.low != 1) return null; + Value [] elems = new Value [intv.high]; + for (int i = 1; i <= intv.high; i++) { + Context c1 = this.con.cons(var, IntValue.gen(i)); + elems[i-1] = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, this.control); + } + if (coverage) {cm.incSecondary(elems.length);} + return new TupleValue(elems, cm); + } + else { + SetEnumValue eSet = (SetEnumValue) dom.toSetEnum(); + if (eSet == null) + Assert.fail("To convert a function of form [x \\in S |-> f(x)] " + + "to a tuple, the set S must be enumerable."); + eSet.normalize(); + int len = eSet.size(); + Value [] elems = new Value [len]; + for (int i = 0; i < len; i++) { + Value argVal = eSet.elems.elementAt(i); + if (!(argVal instanceof IntValue)) return null; + if (((IntValue)argVal).val != i + 1) return null; + Context c1 = this.con.cons(var, argVal); + elems[i] = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, this.control); + } + cm.incSecondary(elems.length); + return new TupleValue(elems, cm); + } + } + + @Override + public final Value toRcd() { + FcnRcdValue fcn = (FcnRcdValue) this.toFcnRcd(); + if (fcn == null || fcn.domain == null) { return null; } + fcn.normalize(); + UniqueString[] vars = new UniqueString[fcn.domain.length]; + for (int i = 0; i < fcn.domain.length; i++) { + if (!(fcn.domain[i] instanceof StringValue)) { + return null; + } + vars[i] = ((StringValue)fcn.domain[i]).getVal(); + } + if (coverage) {cm.incSecondary(vars.length);} + return new RecordValue(vars, fcn.values, fcn.isNormalized(), cm); + } + + @Override + public final Value toFcnRcd() { try { if (this.fcnRcd == null) { @@ -551,18 +648,18 @@ public class FcnLambdaValue extends Value implements Applicable { FormalParamNode[][] formals = this.params.formals; boolean[] isTuples = this.params.isTuples; - Value[] domain = new Value[sz]; - Value[] values = new Value[sz]; + Value [] domain = new Value [sz]; + Value [] values = new Value [sz]; int idx = 0; ValueEnumeration Enum = this.params.elements(); - Value arg; + Value arg; if (this.params.length() == 1) { while ((arg = Enum.nextElement()) != null) { domain[idx] = arg; Context c1 = this.con; if (isTuples[0]) { FormalParamNode[] ids = formals[0]; - Value[] avals = ((TupleValue)arg).elems; + Value [] avals = ((TupleValue)arg).elems; for (int j = 0; j < ids.length; j++) { c1 = c1.cons(ids[j], avals[j]); } @@ -570,19 +667,19 @@ public class FcnLambdaValue extends Value implements Applicable { else { c1 = c1.cons(formals[0][0], arg); } - values[idx++] = this.tool.eval(this.body, c1, this.state, this.pstate, this.control); + values[idx++] = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, this.control); } } else { while ((arg = Enum.nextElement()) != null) { domain[idx] = arg; - Value[] argList = ((TupleValue)arg).elems; + Value [] argList = ((TupleValue)arg).elems; int argn = 0; Context c1 = this.con; for (int i = 0; i < formals.length; i++) { FormalParamNode[] ids = formals[i]; if (isTuples[i]) { - Value[] avals = ((TupleValue)argList[argn++]).elems; + Value [] avals = ((TupleValue)argList[argn++]).elems; for (int j = 0; j < ids.length; j++) { c1 = c1.cons(ids[j], avals[j]); } @@ -593,10 +690,11 @@ public class FcnLambdaValue extends Value implements Applicable { } } } - values[idx++] = this.tool.eval(this.body, c1, this.state, this.pstate, this.control); + values[idx++] = (Value) this.tool.eval(this.body, c1, this.state, this.pstate, this.control); } } - this.fcnRcd = new FcnRcdValue(domain, values, false); + if (coverage) {cm.incSecondary(sz);} + this.fcnRcd = new FcnRcdValue(domain, values, false, cm); if (this.excepts != null) { this.fcnRcd = (FcnRcdValue)fcnRcd.takeExcept(this.excepts); } @@ -610,10 +708,15 @@ public class FcnLambdaValue extends Value implements Applicable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + fcnRcd.write(vos); + } + /* The fingerprint methods. */ public final long fingerPrint(long fp) { try { - FcnRcdValue fcn = FcnRcdValue.convert(this); + Value fcn = this.toFcnRcd(); return fcn.fingerPrint(fp); } catch (RuntimeException | OutOfMemoryError e) { @@ -622,9 +725,9 @@ public class FcnLambdaValue extends Value implements Applicable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { - FcnRcdValue fcn = FcnRcdValue.convert(this); + Value fcn = this.toFcnRcd(); return fcn.permute(perm); } catch (RuntimeException | OutOfMemoryError e) { @@ -635,11 +738,16 @@ public class FcnLambdaValue extends Value implements Applicable { /* The string representation of this function. */ public final StringBuffer toString(StringBuffer sb, int offset) { + return toString(sb, offset, true); +} + +/* The string representation of this function. */ + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - if (expand || this.params == null) { + if (TLCGlobals.expand || this.params == null) { try { - Value val = FcnRcdValue.convert(this); - return val.toString(sb, offset); + Value val = this.toFcnRcd(); + return val.toString(sb, offset, true); } catch (Throwable e) { /*SKIP*/ } } @@ -653,4 +761,28 @@ public class FcnLambdaValue extends Value implements Applicable { } } + @Override + public final SemanticNode getBody() { + return body; + } + + @Override + public final FcnRcdValue getRcd() { + return fcnRcd; + } + + @Override + public FcnParams getParams() { + return params; + } + + @Override + public Context getCon() { + return con; + } + + @Override + public boolean hasRcd() { + return fcnRcd != null; + } } diff --git a/tlatools/src/tlc2/value/FcnParams.java b/tlatools/src/tlc2/value/impl/FcnParams.java similarity index 93% rename from tlatools/src/tlc2/value/FcnParams.java rename to tlatools/src/tlc2/value/impl/FcnParams.java index ab089e771116fd7164dc4ca53afdbeb68d27293f..9298fd02c3542b579c65a7f154b54305cb567e65 100644 --- a/tlatools/src/tlc2/value/FcnParams.java +++ b/tlatools/src/tlc2/value/impl/FcnParams.java @@ -3,13 +3,15 @@ // Last modified on Wed 4 Jul 2007 at 17:26:45 PST by lamport // modified on Sat Nov 13 11:14:54 PST 1999 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tla2sany.semantic.FormalParamNode; import tlc2.output.EC; +import tlc2.value.IFcnParams; +import tlc2.value.IValue; import util.Assert; -public class FcnParams { +public class FcnParams implements IFcnParams { public FormalParamNode[][] formals; // array of formal params public boolean[] isTuples; // true iff tuple param public Value[] domains; // the bounds of the formals @@ -164,5 +166,19 @@ public class FcnParams { } } - + + @Override + public FormalParamNode[][] getFormals() { + return formals; + } + + @Override + public IValue[] getDomains() { + return domains; + } + + @Override + public boolean[] isTuples() { + return isTuples; + } } diff --git a/tlatools/src/tlc2/value/FcnRcdValue.java b/tlatools/src/tlc2/value/impl/FcnRcdValue.java similarity index 69% rename from tlatools/src/tlc2/value/FcnRcdValue.java rename to tlatools/src/tlc2/value/impl/FcnRcdValue.java index e4922e037bf28630792966df3621f825db601b04..17fcd1e4020a98e0272a72ce7cb2db96812beb71 100644 --- a/tlatools/src/tlc2/value/FcnRcdValue.java +++ b/tlatools/src/tlc2/value/impl/FcnRcdValue.java @@ -4,21 +4,31 @@ // modified on Sat 23 February 2008 at 10:07:06 PST by lamport // modified on Fri Aug 10 15:07:25 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; import java.util.Arrays; import tlc2.tool.EvalControl; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.FP64; +import tlc2.value.IFcnRcdValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; +import util.UniqueString; -public class FcnRcdValue extends Value implements Applicable { +public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue { public final Value[] domain; public final IntervalValue intv; public final Value[] values; private boolean isNorm; private int[] indexTbl; // speed up function application + public final static Value EmptyFcn = new FcnRcdValue(new Value[0], new Value[0], true); /* Constructor */ public FcnRcdValue(Value[] domain, Value[] values, boolean isNorm) { @@ -37,6 +47,11 @@ public class FcnRcdValue extends Value implements Applicable { this.indexTbl = null; } + public FcnRcdValue(IntervalValue intv, Value[] values, CostModel cm) { + this(intv, values); + this.cm = cm; + } + private FcnRcdValue(FcnRcdValue fcn, Value[] values) { this.domain = fcn.domain; this.intv = fcn.intv; @@ -49,6 +64,16 @@ public class FcnRcdValue extends Value implements Applicable { this(elems.toArray(), values, isNorm); } + public FcnRcdValue(ValueVec elems, Value[] values, boolean isNorm, CostModel cm) { + this(elems, values, isNorm); + this.cm = cm; + } + + public FcnRcdValue(Value[] domain, Value[] values, boolean isNorm, CostModel cm) { + this(domain, values, isNorm); + this.cm = cm; + } + public final byte getKind() { return FCNRCDVALUE; } /* We create an index only when the domain is not very small. */ @@ -79,8 +104,8 @@ public class FcnRcdValue extends Value implements Applicable { while (true) { int idx = this.indexTbl[loc]; if (idx == -1) { - Assert.fail("Attempted to apply function:\n" + ppr(this.toString()) + - "\nto argument " + ppr(arg.toString()) + + Assert.fail("Attempted to apply function:\n" + Values.ppr(this.toString()) + + "\nto argument " + Values.ppr(arg.toString()) + ", which is not in the domain of the function."); } if (this.domain[idx].equals(arg)) { @@ -93,65 +118,26 @@ public class FcnRcdValue extends Value implements Applicable { public final int compareTo(Object obj) { try { - FcnRcdValue fcn = convert(obj); - if (fcn == null) { - if (obj instanceof ModelValue) return 1; - Assert.fail("Attempted to compare the function " + ppr(this.toString()) + - " with the value:\n" + ppr(obj.toString())); - } - this.normalize(); - fcn.normalize(); + final FcnRcdValue fcn = obj instanceof Value ? (FcnRcdValue) ((Value) obj).toFcnRcd() : null; + if (fcn == null) { + if (obj instanceof ModelValue) + return 1; + Assert.fail("Attempted to compare the function " + Values.ppr(this.toString()) + " with the value:\n" + + Values.ppr(obj.toString())); + } + this.normalize(); + fcn.normalize(); - int result = this.values.length - fcn.values.length; - if (result != 0) return result; + final int result = this.values.length - fcn.values.length; + if (result != 0) { + return result; + } - if (this.intv != null) { - if (fcn.intv != null) { - result = this.intv.low - fcn.intv.low; - if (result != 0) return result; - for (int i = 0; i < this.values.length; i++) { - result = this.values[i].compareTo(fcn.values[i]); - if (result != 0) return result; - } - } - else { - for (int i = 0; i < fcn.domain.length; i++) { - Value dElem = fcn.domain[i]; - if (!(dElem instanceof IntValue)) { - Assert.fail("Attempted to compare integer with non-integer:\n" + - ppr(dElem.toString()) + "."); - } - result = this.intv.low + i - ((IntValue)dElem).val; - if (result != 0) return result; - result = this.values[i].compareTo(fcn.values[i]); - if (result != 0) return result; - } - } - } - else { - if (fcn.intv != null) { - for (int i = 0; i < this.domain.length; i++) { - Value dElem = this.domain[i]; - if (!(dElem instanceof IntValue)) { - Assert.fail("Attempted to compare integer with non-integer\n" + - ppr(dElem.toString()) + "."); - } - result = ((IntValue)dElem).val - (fcn.intv.low + i); - if (result != 0) return result; - result = this.values[i].compareTo(fcn.values[i]); - if (result != 0) return result; - } - } - else { - for (int i = 0; i < this.domain.length; i++) { - result = this.domain[i].compareTo(fcn.domain[i]); - if (result != 0) return result; - result = this.values[i].compareTo(fcn.values[i]); - if (result != 0) return result; - } - } - } - return 0; + if (this.intv != null) { + return compareToInterval(fcn); + } else { + return compareOtherInterval(fcn); + } } catch (RuntimeException | OutOfMemoryError e) { @@ -160,15 +146,81 @@ public class FcnRcdValue extends Value implements Applicable { } } + private final int compareOtherInterval(final FcnRcdValue fcn) { + int result; + if (fcn.intv != null) { + for (int i = 0; i < this.domain.length; i++) { + final Value dElem = this.domain[i]; + if (!(dElem instanceof IntValue)) { + Assert.fail( + "Attempted to compare integer with non-integer\n" + Values.ppr(dElem.toString()) + "."); + } + result = ((IntValue) dElem).val - (fcn.intv.low + i); + if (result != 0) { + return result; + } + result = this.values[i].compareTo(fcn.values[i]); + if (result != 0) { + return result; + } + } + } else { + for (int i = 0; i < this.domain.length; i++) { + result = this.domain[i].compareTo(fcn.domain[i]); + if (result != 0) { + return result; + } + result = this.values[i].compareTo(fcn.values[i]); + if (result != 0) { + return result; + } + } + } + return 0; + } + + private final int compareToInterval(final FcnRcdValue fcn) { + int result; + if (fcn.intv != null) { + result = this.intv.low - fcn.intv.low; + if (result != 0) { + return result; + } + for (int i = 0; i < this.values.length; i++) { + result = this.values[i].compareTo(fcn.values[i]); + if (result != 0) { + return result; + } + } + } else { + for (int i = 0; i < fcn.domain.length; i++) { + final Value dElem = fcn.domain[i]; + if (!(dElem instanceof IntValue)) { + Assert.fail( + "Attempted to compare integer with non-integer:\n" + Values.ppr(dElem.toString()) + "."); + } + result = this.intv.low + i - ((IntValue) dElem).val; + if (result != 0) { + return result; + } + result = this.values[i].compareTo(fcn.values[i]); + if (result != 0) { + return result; + } + } + } + return 0; + } + public final boolean equals(Object obj) { try { - FcnRcdValue fcn = convert(obj); + FcnRcdValue fcn = obj instanceof Value ? (FcnRcdValue) ((Value)obj).toFcnRcd() : null; if (fcn == null) { if (obj instanceof ModelValue) return ((ModelValue) obj).modelValueEquals(this) ; - Assert.fail("Attempted to check equality of the function " + ppr(this.toString()) + - " with the value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of the function " + Values.ppr(this.toString()) + + " with the value:\n" + Values.ppr(obj.toString())); } this.normalize(); fcn.normalize(); @@ -187,7 +239,7 @@ public class FcnRcdValue extends Value implements Applicable { Value dElem = fcn.domain[i]; if (!(dElem instanceof IntValue)) { Assert.fail("Attempted to compare an integer with non-integer:\n" + - ppr(dElem.toString()) + "."); + Values.ppr(dElem.toString()) + "."); } if (((IntValue)dElem).val != (this.intv.low + i) || !this.values[i].equals(fcn.values[i])) { @@ -203,7 +255,7 @@ public class FcnRcdValue extends Value implements Applicable { Value dElem = this.domain[i]; if (!(dElem instanceof IntValue)) { Assert.fail("Attempted to compare an integer with non-integer:\n" + - ppr(dElem.toString()) + "."); + Values.ppr(dElem.toString()) + "."); } if (((IntValue)dElem).val != (fcn.intv.low + i) || !this.values[i].equals(fcn.values[i])) { @@ -231,8 +283,8 @@ public class FcnRcdValue extends Value implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the function " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the function " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -245,10 +297,10 @@ public class FcnRcdValue extends Value implements Applicable { public final Value apply(Value arg, int control) { try { - Value result = this.select(arg); + Value result = this.select(arg); if (result == null) { - Assert.fail("Attempted to apply function:\n" + ppr(this.toString()) + - "\nto argument " + ppr(arg.toString()) + ", which is" + + Assert.fail("Attempted to apply function:\n" + Values.ppr(this.toString()) + + "\nto argument " + Values.ppr(arg.toString()) + ", which is" + " not in the domain of the function."); } return result; @@ -277,7 +329,7 @@ public class FcnRcdValue extends Value implements Applicable { // domain is represented as an integer interval: if (!(arg instanceof IntValue)) { Assert.fail("Attempted to apply function with integer domain to" + - " the non-integer argument " + ppr(arg.toString())); + " the non-integer argument " + Values.ppr(arg.toString())); } int idx = ((IntValue)arg).val; if ((idx >= this.intv.low) && (idx <= this.intv.high)) { @@ -324,7 +376,7 @@ public class FcnRcdValue extends Value implements Applicable { int idx = ((IntValue)args[0]).val; if ((idx >= this.intv.low) && (idx <= this.intv.high)) { int vIdx = idx - this.intv.low; - if (this.values[vIdx] == ValUndef || + if (this.values[vIdx] == UndefValue.ValUndef || this.values[vIdx].equals(val)) { this.values[vIdx] = val; return true; @@ -339,7 +391,7 @@ public class FcnRcdValue extends Value implements Applicable { int len = this.domain.length; for (int i = 0; i < len; i++) { if (this.domain[i].equals(argv)) { - if (this.values[i] == ValUndef || + if (this.values[i] == UndefValue.ValUndef || this.values[i].equals(val)) { this.values[i] = val; return true; @@ -440,7 +492,7 @@ public class FcnRcdValue extends Value implements Applicable { * Returns the domain of this FunctionRecordValue regardless of its internal * representation as either Value[] or IntervalValue as Value[]. */ - public Value[] getDomainAsValues() { + public final Value[] getDomainAsValues() { if (this.intv != null) { return this.intv.asValues(); } else { @@ -459,42 +511,49 @@ public class FcnRcdValue extends Value implements Applicable { } } - /* - * This method converts a value to a function value. It returns - * null if the conversion fails. - */ - public static final FcnRcdValue convert(Object val) { - switch (((Value)val).getKind()) { - case FCNRCDVALUE: - { - return (FcnRcdValue)val; - } - case FCNLAMBDAVALUE: - { - return ((FcnLambdaValue)val).toFcnRcd(); + @Override + public final Value toTuple() { + if (this.intv != null) { + if (this.intv.low != 1) return null; + return new TupleValue(this.values); + } + int len = this.values.length; + Value[] elems = new Value[len]; + for (int i = 0; i < len; i++) { + if (!(this.domain[i] instanceof IntValue)) return null; + int idx = ((IntValue)this.domain[i]).val; + if (0 < idx && idx <= len) { + if (elems[idx-1] != null) return null; + elems[idx-1] = this.values[i]; } - case RECORDVALUE: - { - RecordValue rcd = (RecordValue)val; - rcd.normalize(); - Value[] dom = new Value[rcd.names.length]; - for (int i = 0; i < rcd.names.length; i++) { - dom[i] = new StringValue(rcd.names[i]); - } - return new FcnRcdValue(dom, rcd.values, rcd.isNormalized()); + else { + return null; } - case TUPLEVALUE: - { - Value[] elems = ((TupleValue)val).elems; - IntervalValue intv = new IntervalValue(1, elems.length); - return new FcnRcdValue(intv, elems); + } + if (coverage) {cm.incSecondary(elems.length);} + return new TupleValue(elems, cm); + } + + @Override + public final Value toRcd() { + if (this.domain == null) return null; + this.normalize(); + UniqueString[] vars = new UniqueString[this.domain.length]; + for (int i = 0; i < this.domain.length; i++) { + if (!(this.domain[i] instanceof StringValue)) { + return null; } - default: - // return null if not convertable - return null; - } + vars[i] = ((StringValue)this.domain[i]).getVal(); + } + if (coverage) {cm.incSecondary(this.values.length);} + return new RecordValue(vars, this.values, this.isNormalized(), cm); } + @Override + public final Value toFcnRcd() { + return this; + } + /* Return true iff this function is in normal form. */ public final boolean isNormalized() { return this.isNorm; } @@ -512,7 +571,7 @@ public class FcnRcdValue extends Value implements Applicable { "\noccurs multiple times in the function domain."); } else if (cmp > 0) { - Value tv = this.domain[0]; + Value tv = this.domain[0]; this.domain[0] = this.domain[i]; this.domain[i] = tv; tv = this.values[0]; @@ -521,8 +580,8 @@ public class FcnRcdValue extends Value implements Applicable { } } for (int i = 2; i < dlen; i++) { - Value d = this.domain[i]; - Value v = this.values[i]; + Value d = this.domain[i]; + Value v = this.values[i]; int j = i; int cmp; while ((cmp = d.compareTo(this.domain[j-1])) < 0) { @@ -547,6 +606,20 @@ public class FcnRcdValue extends Value implements Applicable { } } + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < values.length; i++) { + values[i].deepNormalize(); + } + normalize(); + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { @@ -568,11 +641,11 @@ public class FcnRcdValue extends Value implements Applicable { } } - public final Value deepCopy() { + public final IValue deepCopy() { try { - Value[] vals = new Value[this.values.length]; + Value[] vals = new Value[this.values.length]; for (int i = 0; i < vals.length; i++) { - vals[i] = this.values[i].deepCopy(); + vals[i] = (Value) this.values[i].deepCopy(); } return new FcnRcdValue(this, vals); } @@ -601,6 +674,33 @@ public class FcnRcdValue extends Value implements Applicable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + final int index = vos.put(this); + if (index == -1) { + vos.writeByte(FCNRCDVALUE); + int len = values.length; + vos.writeNat(len); + if (intv != null) { + vos.writeByte((byte) 0); + vos.writeInt(intv.low); + vos.writeInt(intv.high); + for (int i = 0; i < len; i++) { + values[i].write(vos); + } + } else { + vos.writeByte((isNormalized()) ? (byte) 1 : (byte) 2); + for (int i = 0; i < len; i++) { + domain[i].write(vos); + values[i].write(vos); + } + } + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index); + } + } + /* The fingerprint method. */ public final long fingerPrint(long fp) { try { @@ -629,7 +729,7 @@ public class FcnRcdValue extends Value implements Applicable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.normalize(); @@ -638,15 +738,15 @@ public class FcnRcdValue extends Value implements Applicable { boolean vchanged = false; for (int i = 0; i < flen; i++) { - vals[i] = this.values[i].permute(perm); + vals[i] = (Value) this.values[i].permute(perm); vchanged = vchanged || (vals[i] != this.values[i]); } if (this.intv == null) { - Value[] dom = new Value[flen]; + Value[] dom = new Value[flen]; boolean dchanged = false; for (int i = 0; i < flen; i++) { - dom[i] = this.domain[i].permute(perm); + dom[i] = (Value) this.domain[i].permute(perm); dchanged = dchanged || (dom[i] != this.domain[i]); } @@ -715,7 +815,7 @@ public class FcnRcdValue extends Value implements Applicable { } /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { int len = this.values.length; @@ -725,37 +825,37 @@ public class FcnRcdValue extends Value implements Applicable { else if (this.isRcd()) { sb.append("["); sb.append(((StringValue)this.domain[0]).val + " |-> "); - sb = this.values[0].toString(sb, offset); + sb = this.values[0].toString(sb, offset, swallow); for (int i = 1; i < len; i++) { sb.append(", "); sb.append(((StringValue)this.domain[i]).val + " |-> "); - sb = this.values[i].toString(sb, offset); + sb = this.values[i].toString(sb, offset, swallow); } sb.append("]"); } else if (this.isTuple()) { // It is actually a sequence: sb = sb.append("<<"); - sb = this.values[0].toString(sb, offset); + sb = this.values[0].toString(sb, offset, swallow); for (int i = 1; i < len; i++) { sb.append(", "); - sb = this.values[i].toString(sb, offset); + sb = this.values[i].toString(sb, offset, swallow); } sb.append(">>"); } else { sb = sb.append("("); - sb = this.domain[0].toString(sb, offset); + sb = this.domain[0].toString(sb, offset, swallow); sb.append(" :> "); - sb = this.values[0].toString(sb, offset); + sb = this.values[0].toString(sb, offset, swallow); for (int i = 1; i < len; i++) { sb.append(" @@ "); - sb = this.domain[i].toString(sb, offset); + sb = this.domain[i].toString(sb, offset, swallow); sb.append(" :> "); - sb = this.values[i].toString(sb, offset); + sb = this.values[i].toString(sb, offset, swallow); } sb.append(")"); } @@ -768,4 +868,29 @@ public class FcnRcdValue extends Value implements Applicable { } } + public static IValue createFrom(final IValueInputStream vos) throws IOException { + final int index = vos.getIndex(); + final int len = vos.readNat(); + final int info = vos.readByte(); + Value res; + final Value[] rvals = new Value[len]; + if (info == 0) { + final int low = vos.readInt(); + final int high = vos.readInt(); + for (int i = 0; i < len; i++) { + rvals[i] = (Value) vos.read(); + } + final IntervalValue intv = new IntervalValue(low, high); + res = new FcnRcdValue(intv, rvals); + } else { + final Value[] dvals = new Value[len]; + for (int i = 0; i < len; i++) { + dvals[i] = (Value) vos.read(); + rvals[i] = (Value) vos.read(); + } + res = new FcnRcdValue(dvals, rvals, (info == 1)); + } + vos.assign(res, index); + return res; + } } diff --git a/tlatools/src/tlc2/value/IntValue.java b/tlatools/src/tlc2/value/impl/IntValue.java similarity index 80% rename from tlatools/src/tlc2/value/IntValue.java rename to tlatools/src/tlc2/value/impl/IntValue.java index 38bce557fbe80fd09ea5fd3ba6730e03b6a57691..edfc0f1f7002a0097ff837a9c7a1a83b906c9cab 100644 --- a/tlatools/src/tlc2/value/IntValue.java +++ b/tlatools/src/tlc2/value/impl/IntValue.java @@ -4,19 +4,21 @@ // modified on Sat 23 February 2008 at 10:08:05 PST by lamport // modified on Fri Aug 10 15:07:30 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.tool.FingerprintException; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class IntValue extends Value { private static final IntValue[] cache; - public int val; - - private IntValue(int i) { this.val = i; } - static { cache = new IntValue[10]; for (int i = 0; i < cache.length; i++) { @@ -24,7 +26,11 @@ public class IntValue extends Value { } } - public final byte getKind() { return INTVALUE; } + public final static IntValue ValNegOne = gen(-1); + + public final static IntValue ValOne = gen(1); + + public final static IntValue ValZero = gen(0); public static final int nbits(int tmp) { int nb = 0; @@ -35,6 +41,12 @@ public class IntValue extends Value { return nb + 1; } + public final int val; + + private IntValue(int i) { this.val = i; } + + public final byte getKind() { return INTVALUE; } + // the number of bits needed to encode the value of this int public final int nbits() { try { @@ -59,8 +71,8 @@ public class IntValue extends Value { return this.val - ((IntValue)obj).val; } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to compare integer " + ppr(this.toString()) + - " with non-integer:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare integer " + Values.ppr(this.toString()) + + " with non-integer:\n" + Values.ppr(obj.toString())); } return 1; } @@ -76,8 +88,8 @@ public class IntValue extends Value { return this.val == ((IntValue)obj).val; } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to check equality of integer " + ppr(this.toString()) + - " with non-integer:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of integer " + Values.ppr(this.toString()) + + " with non-integer:\n" + Values.ppr(obj.toString())); } return ((ModelValue) obj).modelValueEquals(this); } @@ -89,8 +101,8 @@ public class IntValue extends Value { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the integer " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the integer " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -101,7 +113,7 @@ public class IntValue extends Value { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the integer " + ppr(this.toString()) + + Assert.fail("Attempted to check if the integer " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -115,7 +127,7 @@ public class IntValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to appy EXCEPT construct to the integer " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -129,7 +141,7 @@ public class IntValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the integer " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -142,7 +154,7 @@ public class IntValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the integer " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -157,7 +169,7 @@ public class IntValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -170,6 +182,12 @@ public class IntValue extends Value { } } + @Override + public void write(IValueOutputStream vos) throws IOException { + vos.writeByte(INTVALUE); + vos.writeInt(val); + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -181,10 +199,10 @@ public class IntValue extends Value { } } - public final Value permute(MVPerm perm) { return this; } + public final IValue permute(IMVPerm perm) { return this; } /* The string representation. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) { try { return sb.append(this.val); } diff --git a/tlatools/src/tlc2/value/IntervalValue.java b/tlatools/src/tlc2/value/impl/IntervalValue.java similarity index 84% rename from tlatools/src/tlc2/value/IntervalValue.java rename to tlatools/src/tlc2/value/impl/IntervalValue.java index fd0de2b18b7b099c15b4919a691d07a5a050ea4d..48198debbfb008bca6224f68fdc4238e480c8209 100644 --- a/tlatools/src/tlc2/value/IntervalValue.java +++ b/tlatools/src/tlc2/value/impl/IntervalValue.java @@ -4,10 +4,16 @@ // modified on Sat 23 February 2008 at 10:12:59 PST by lamport // modified on Fri Aug 10 15:07:36 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.tool.FingerprintException; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class IntervalValue extends EnumerableValue @@ -32,7 +38,7 @@ implements Enumerable, Reducible { return this.low - intv.low; } // Well, we have to convert them to sets and compare. - return SetEnumValue.convert(this).compareTo(obj); + return this.toSetEnum().compareTo(obj); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -48,7 +54,7 @@ implements Enumerable, Reducible { return (this.low == intv.low) && (this.high == intv.high); } // Well, we have to convert them to sets and compare. - return SetEnumValue.convert(this).equals(obj); + return this.toSetEnum().equals(obj); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -65,8 +71,8 @@ implements Enumerable, Reducible { if ( (this.low <= this.high) && ( !(elem instanceof ModelValue) || (((ModelValue) elem).type != 0)) ) { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis in the integer interval " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis in the integer interval " + Values.ppr(this.toString())); } return false; } @@ -81,7 +87,7 @@ implements Enumerable, Reducible { if (other instanceof IntervalValue) { final IntervalValue iv = (IntervalValue) other; if (iv.low <= low && iv.high >= high) { - return ValTrue; + return BoolValue.ValTrue; } } return super.isSubsetEq(other); @@ -123,10 +129,10 @@ implements Enumerable, Reducible { try { ValueVec diffElems = new ValueVec(); for (int i = this.low; i <= this.high; i++) { - Value elem = IntValue.gen(i); + Value elem = IntValue.gen(i); if (!val.member(elem)) diffElems.addElement(elem); } - return new SetEnumValue(diffElems, true); + return new SetEnumValue(diffElems, true, cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -139,10 +145,10 @@ implements Enumerable, Reducible { try { ValueVec capElems = new ValueVec(); for (int i = this.low; i <= this.high; i++) { - Value elem = IntValue.gen(i); + Value elem = IntValue.gen(i); if (val.member(elem)) capElems.addElement(elem); } - return new SetEnumValue(capElems, true); + return new SetEnumValue(capElems, true, cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -165,9 +171,9 @@ implements Enumerable, Reducible { while ((elem = Enum.nextElement()) != null) { if (!this.member(elem)) cupElems.addElement(elem); } - return new SetEnumValue(cupElems, false); + return new SetEnumValue(cupElems, false, cm); } - return new SetCupValue(this, set); + return new SetCupValue(this, set, cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -179,7 +185,7 @@ implements Enumerable, Reducible { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the interval value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -193,7 +199,7 @@ implements Enumerable, Reducible { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the interval value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -209,7 +215,7 @@ implements Enumerable, Reducible { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -223,6 +229,13 @@ implements Enumerable, Reducible { } } + @Override + public void write(final IValueOutputStream vos) throws IOException { + vos.writeByte(INTERVALVALUE); + vos.writeInt(low); + vos.writeInt(high); + } + /* The fingerprint method */ public final long fingerPrint(long fp) { try { @@ -240,12 +253,22 @@ implements Enumerable, Reducible { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { return this; } + @Override + public Value toSetEnum() { + Value[] vals = new Value[size()]; + for (int i = 0; i < vals.length; i++) { + vals[i] = IntValue.gen(i + this.low); + } + if (coverage) {cm.incSecondary(vals.length);} + return new SetEnumValue(vals, true, cm); + } + /* The string representation */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, final boolean ignored) { try { if (this.low <= this.high) { return sb.append(this.low).append("..").append(this.high); @@ -268,7 +291,7 @@ implements Enumerable, Reducible { while ((v = ve.nextElement()) != null) { vec.addElement(v); } - return new SetEnumValue(vec, false); + return new SetEnumValue(vec, false, cm); } public Value elementAt(final int idx) { @@ -276,7 +299,7 @@ implements Enumerable, Reducible { return IntValue.gen(low + idx); } Assert.fail( - "Attempted to retrieve out-of-bounds element from the interval value " + ppr(this.toString()) + "."); + "Attempted to retrieve out-of-bounds element from the interval value " + Values.ppr(this.toString()) + "."); return null; // make compiler happy } @@ -297,6 +320,7 @@ implements Enumerable, Reducible { public final Value nextElement() { if (this.index <= high) { + if (coverage) { cm.incSecondary(); } return IntValue.gen(this.index++); } return null; diff --git a/tlatools/src/tlc2/value/LazyValue.java b/tlatools/src/tlc2/value/impl/LazyValue.java similarity index 82% rename from tlatools/src/tlc2/value/LazyValue.java rename to tlatools/src/tlc2/value/impl/LazyValue.java index 273ca7c510199bfa300e1f0e0e849416f283853a..9c4e3c5a62b1af892c8bcd20ebc6c4b8e01113e1 100644 --- a/tlatools/src/tlc2/value/LazyValue.java +++ b/tlatools/src/tlc2/value/impl/LazyValue.java @@ -4,7 +4,7 @@ // modified on Mon 30 Apr 2007 at 15:30:08 PST by lamport // modified on Thu Feb 8 21:23:55 PST 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.io.IOException; import java.io.ObjectInputStream; @@ -12,7 +12,10 @@ import java.io.ObjectOutputStream; import tla2sany.semantic.SemanticNode; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; import util.Assert; import util.ToolIO; @@ -26,7 +29,7 @@ public class LazyValue extends Value { * bug where TLC generates and incorrect set of states with certain statements. * More details can be found at https://github.com/tlaplus/tlaplus/issues/113. */ - private static final boolean LAZYEVAL_OFF = Boolean.getBoolean(tlc2.value.LazyValue.class.getName() + ".off"); + private static final boolean LAZYEVAL_OFF = Boolean.getBoolean(tlc2.value.impl.LazyValue.class.getName() + ".off"); static { // Indicate if LazyValue will be disabled in this TLC run. @@ -46,22 +49,23 @@ public class LazyValue extends Value { public Context con; private Value val; - public LazyValue(SemanticNode expr, Context con) { - this(expr, con, true); + public LazyValue(SemanticNode expr, Context con, final CostModel cm) { + this(expr, con, true, coverage ? cm.get(expr) : cm); } - public LazyValue(SemanticNode expr, Context con, final boolean cachable) { + public LazyValue(SemanticNode expr, Context con, final boolean cachable, final CostModel cm) { this.expr = expr; this.con = con; + this.cm = coverage ? cm.get(expr) : cm; this.val = null; // See comment on cachable's meager performance in Tool.java on line 1408. // See other note about a bug that surfaced with LazyValue in Tool.java on line ~1385. if (LAZYEVAL_OFF || !cachable) { - this.val = ValUndef; + this.val = UndefValue.ValUndef; } } - public final boolean isUncachable() { return this.val == ValUndef; } + public final boolean isUncachable() { return this.val == UndefValue.ValUndef; } public final void setValue(final Value aValue) { assert !isUncachable(); @@ -78,7 +82,7 @@ public class LazyValue extends Value { public final int compareTo(Object obj) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to compare lazy values."); } return this.val.compareTo(obj); @@ -91,7 +95,7 @@ public class LazyValue extends Value { public final boolean equals(Object obj) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to check equality of lazy values."); } return this.val.equals(obj); @@ -104,7 +108,7 @@ public class LazyValue extends Value { public final boolean member(Value elem) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to check set membership of lazy values."); } return this.val.member(elem); @@ -117,7 +121,7 @@ public class LazyValue extends Value { public final boolean isFinite() { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to check if a lazy value is a finite set."); } return this.val.isFinite(); @@ -130,7 +134,7 @@ public class LazyValue extends Value { public final Value takeExcept(ValueExcept ex) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to apply EXCEPT construct to lazy value."); } return this.val.takeExcept(ex); @@ -143,7 +147,7 @@ public class LazyValue extends Value { public final Value takeExcept(ValueExcept[] exs) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to apply EXCEPT construct to lazy value."); } return this.val.takeExcept(exs); @@ -156,7 +160,7 @@ public class LazyValue extends Value { public final int size() { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to compute size of lazy value."); } return this.val.size(); @@ -172,7 +176,7 @@ public class LazyValue extends Value { } private void writeObject(ObjectOutputStream oos) throws IOException { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to serialize lazy value."); } oos.writeObject(this.val); @@ -181,7 +185,7 @@ public class LazyValue extends Value { /* Nothing to normalize. */ public final boolean isNormalized() { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to normalize lazy value."); } return this.val.isNormalized(); @@ -194,7 +198,7 @@ public class LazyValue extends Value { public final Value normalize() { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to normalize lazy value."); } this.val.normalize(); @@ -208,9 +212,9 @@ public class LazyValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { + public final IValue deepCopy() { try { - if (this.val == null || this.val == ValUndef) return this; + if (this.val == null || this.val == UndefValue.ValUndef) return this; return this.val.deepCopy(); } catch (RuntimeException | OutOfMemoryError e) { @@ -221,7 +225,7 @@ public class LazyValue extends Value { public final boolean assignable(Value val) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to call assignable on lazy value."); } return this.val.assignable(val); @@ -235,7 +239,7 @@ public class LazyValue extends Value { /* The fingerprint method */ public final long fingerPrint(long fp) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to fingerprint a lazy value."); } return this.val.fingerPrint(fp); @@ -246,9 +250,9 @@ public class LazyValue extends Value { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { Assert.fail("Error(TLC): Attempted to apply permutation to lazy value."); } return this.val.permute(perm); @@ -260,12 +264,12 @@ public class LazyValue extends Value { } /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - if (this.val == null || this.val == ValUndef) { + if (this.val == null || this.val == UndefValue.ValUndef) { return sb.append("<LAZY " + this.expr + ">"); } - return this.val.toString(sb, offset); + return this.val.toString(sb, offset, swallow); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/impl/MVPerm.java b/tlatools/src/tlc2/value/impl/MVPerm.java new file mode 100644 index 0000000000000000000000000000000000000000..17ce861766890bc0f15d995f7cd5303b42b181b1 --- /dev/null +++ b/tlatools/src/tlc2/value/impl/MVPerm.java @@ -0,0 +1,117 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 30 Apr 2007 at 13:42:27 PST by lamport +// modified on Thu Nov 16 15:53:30 PST 2000 by yuanyu + +package tlc2.value.impl; + +import tlc2.value.IMVPerm; +import tlc2.value.IModelValue; +import tlc2.value.IValue; + +public final class MVPerm implements IMVPerm { + private final ModelValue[] elems; + private int count; + + MVPerm() { + this.elems = new ModelValue[ModelValue.mvs.length]; + this.count = 0; + } + + public final boolean equals(Object obj) { + if (obj instanceof MVPerm) { + MVPerm perm = (MVPerm)obj; + for (int i = 0; i < this.elems.length; i++) { + if (this.elems[i] == null) { + if (perm.elems[i] != null) { + return false; + } + } + else if (!this.elems[i].equals(perm.elems[i])) { + return false; + } + } + return true; + } + return false; + } + + public final int hashCode() { + int res = 0; + for (int i = 0; i < this.elems.length; i++) { + ModelValue mv = this.elems[i]; + if (mv != null) { + res = 31*res + mv.val.hashCode(); + } + } + return res; + } + + public final int size() { return this.count; } + + public final IValue get(IValue k) { + return this.elems[((ModelValue) k).index]; + } + + @Override + public final void put(IModelValue m1, IModelValue m2) { + ModelValue k = (ModelValue) m1; + ModelValue elem = (ModelValue) m2; + if (!k.equals(elem) && this.elems[k.index] == null) { + this.elems[k.index] = elem; + this.count++; + } + } + + private final void put(int i, ModelValue elem) { + if (this.elems[i] == null && elem != null) { + this.elems[i] = elem; + this.count++; + } + } + + @Override + public final IMVPerm compose(IMVPerm perm) { + MVPerm res = new MVPerm(); + for (int i = 0; i < this.elems.length; i++) { + ModelValue mv = this.elems[i]; + if (mv == null) { + res.put(i, ((MVPerm) perm).elems[i]); + } + else { + ModelValue mv1 = ((MVPerm) perm).elems[mv.index]; + if (mv1 == null) { + res.put(i, mv); + } + else if (!ModelValue.mvs[i].equals(mv1)) { + res.put(i, mv1); + } + } + } + return res; + } + + public final String toString() { + StringBuffer sb = new StringBuffer("["); + int i = 0; + for (i = 0; i < this.elems.length; i++) { + if (this.elems[i] != null) { + sb.append(ModelValue.mvs[i].toString()); + sb.append(" -> "); + sb.append(this.elems[i].toString()); + break; + } + } + for (int j = i+1; j < this.elems.length; j++) { + if (this.elems[j] != null) { + sb.append(", "); + sb.append(ModelValue.mvs[j].toString()); + sb.append(" -> "); + sb.append(this.elems[j].toString()); + } + } + sb.append("]"); + return sb.toString(); + } + +} diff --git a/tlatools/src/tlc2/value/impl/MVPerms.java b/tlatools/src/tlc2/value/impl/MVPerms.java new file mode 100644 index 0000000000000000000000000000000000000000..52b8fa7d30d93aa02f8e52288bea8526e78a0192 --- /dev/null +++ b/tlatools/src/tlc2/value/impl/MVPerms.java @@ -0,0 +1,70 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 30 Apr 2007 at 13:42:27 PST by lamport +// modified on Thu Nov 16 15:53:30 PST 2000 by yuanyu + +package tlc2.value.impl; + +import java.util.Enumeration; + +import tlc2.util.Vect; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import util.Assert; +import util.Set; + +public abstract class MVPerms { + + public static final IMVPerm[] permutationSubgroup(final Enumerable enumerable) { + final ValueEnumeration Enum = enumerable.elements(); + final int sz = enumerable.size() - 1; + final Set perms = new Set(sz); + final Vect<IMVPerm> permVec = new Vect<>(sz); + // Compute the group generators: + Value elem; + while ((elem = Enum.nextElement()) != null) { + final FcnRcdValue fcn = (FcnRcdValue) elem.toFcnRcd(); + if (fcn == null) { + Assert.fail("The symmetry operator must specify a set of functions."); + } + final IMVPerm perm = new MVPerm(); + for (int i = 0; i < fcn.domain.length; i++) { + final IValue dval = fcn.domain[i]; + final IValue rval = fcn.values[i]; + if ((dval instanceof ModelValue) && (rval instanceof ModelValue)) { + perm.put((ModelValue)dval, (ModelValue)rval); + } + else { + Assert.fail("Symmetry function must have model values as domain and range."); + } + } + if (perm.size() > 0 && perms.put(perm) == null) { + permVec.addElement(perm); + } + } + // Compute the group generated by the generators: + final int gsz = permVec.size(); + int sz0 = 0; + while (true) { + final int sz1 = permVec.size(); + for (int i = 0; i < gsz; i++) { + final IMVPerm perm1 = (IMVPerm)permVec.elementAt(i); + for (int j = sz0; j < sz1; j++) { + IMVPerm perm = perm1.compose((IMVPerm)permVec.elementAt(j)); + if (perm.size() > 0 && perms.put(perm) == null) { + permVec.addElement(perm); + } + } + } + if (sz1 == permVec.size()) { break; } + sz0 = sz1; + } + // Finally, put all the elements in an array ready for use: + final IMVPerm[] res = new IMVPerm[permVec.size()]; + final Enumeration<IMVPerm> permEnum = permVec.elements(); + for (int i = 0; i < res.length; i++) { + res[i] = permEnum.nextElement(); + } + return res; + } +} diff --git a/tlatools/src/tlc2/value/MethodValue.java b/tlatools/src/tlc2/value/impl/MethodValue.java similarity index 77% rename from tlatools/src/tlc2/value/MethodValue.java rename to tlatools/src/tlc2/value/impl/MethodValue.java index d0b5548006cf6f89c5f4459f3f8eda4a37ea66ac..bc83114d3c14d14be30720e2c5804cabb209cc6a 100644 --- a/tlatools/src/tlc2/value/MethodValue.java +++ b/tlatools/src/tlc2/value/impl/MethodValue.java @@ -4,30 +4,57 @@ // modified on Mon 30 Apr 2007 at 13:21:00 PST by lamport // modified on Fri Sep 22 13:18:45 PDT 2000 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.EvalControl; import tlc2.tool.EvalException; import tlc2.tool.FingerprintException; +import tlc2.tool.impl.Tool; +import tlc2.value.IValue; +import tlc2.value.Values; import util.Assert; import util.Assert.TLCRuntimeException; import util.WrongInvocationException; public class MethodValue extends OpValue implements Applicable { + + public static MethodValue get(final Method md) { + final MethodValue mv = new MethodValue(md); + // Eagerly evaluate the constant operator if possible (zero arity) to only + // evaluate once at startup and not during state exploration. + final int acnt = md.getParameterTypes().length; + final boolean isConstant = (acnt == 0) && Modifier.isFinal(md.getModifiers()); + return isConstant ? (MethodValue) mv.apply(Tool.EmptyArgs, EvalControl.Clear) : mv; + } + private final MethodHandle mh; private final Method md; /* Constructor */ - public MethodValue(final Method md) { + private MethodValue(final Method md) { this.md = md; try { - this.mh = MethodHandles.publicLookup().unreflect(md); + final int parameterCount = this.md.getParameterCount(); + if (parameterCount > 0) { + // With more than one argument, we want to setup the method handle to use a + // spreader which essentially converts the Value[] into something that is + // accepted by the method handle. Without a spreader, passing a Value[] to + // MethodHandle#invoke does not work. Instead one has to use MethodHandle#invokeWithArguments. + // MethodHandle#invokeWithArguments internally creates a spreader on the fly + // which turns out to be costly (for the spec MongoRepl of the performance + // tests it resulted in a 20% performance drop). + this.mh = MethodHandles.publicLookup().unreflect(md).asSpreader(IValue[].class, parameterCount); + } else { + this.mh = MethodHandles.publicLookup().unreflect(md); + } } catch (IllegalAccessException e) { throw new TLCRuntimeException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, MP.getMessage( EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[] { md.toString(), e.getMessage() })); @@ -39,7 +66,7 @@ public class MethodValue extends OpValue implements Applicable { public final int compareTo(Object obj) { try { Assert.fail("Attempted to compare operator " + this.toString() + - " with value:\n" + obj == null ? "null" : ppr(obj.toString())); + " with value:\n" + obj == null ? "null" : Values.ppr(obj.toString())); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -51,7 +78,7 @@ public class MethodValue extends OpValue implements Applicable { public final boolean equals(Object obj) { try { Assert.fail("Attempted to check equality of operator " + this.toString() + - " with value:\n" + obj == null ? "null" : ppr(obj.toString())); + " with value:\n" + obj == null ? "null" : Values.ppr(obj.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -62,7 +89,7 @@ public class MethodValue extends OpValue implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + elem == null ? "null" : ppr(elem.toString()) + + Assert.fail("Attempted to check if the value:\n" + elem == null ? "null" : Values.ppr(elem.toString()) + "\nis an element of operator " + this.toString()); return false; // make compiler happy } @@ -99,7 +126,11 @@ public class MethodValue extends OpValue implements Applicable { Value res = null; try { - res = (Value) this.mh.invokeWithArguments((Object[]) args); + if (args.length == 0) { + res = (Value) this.mh.invokeExact(); + } else { + res = (Value) this.mh.invoke(args); + } } catch (Throwable e) { if (e instanceof InvocationTargetException) @@ -108,6 +139,9 @@ public class MethodValue extends OpValue implements Applicable { throw new EvalException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), targetException.getMessage()}); } else if (e instanceof NullPointerException) { throw new EvalException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()}); + } else if (e instanceof EvalException) { + // Do not wrap an EvalException below. + throw (EvalException) e; } else { Assert.fail(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()}); @@ -159,7 +193,7 @@ public class MethodValue extends OpValue implements Applicable { try { Assert.fail("Attempted to compute the domain of the operator " + this.toString() + "."); - return EmptySet; // make compiler happy + return SetEnumValue.EmptySet; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -202,7 +236,7 @@ public class MethodValue extends OpValue implements Applicable { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -215,7 +249,7 @@ public class MethodValue extends OpValue implements Applicable { } /* String representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) { try { return sb.append("<Java Method: " + this.md + ">"); } diff --git a/tlatools/src/tlc2/value/ModelValue.java b/tlatools/src/tlc2/value/impl/ModelValue.java similarity index 86% rename from tlatools/src/tlc2/value/ModelValue.java rename to tlatools/src/tlc2/value/impl/ModelValue.java index e32a58c1045b197bbc467edfb1d8ff030e3cb7cb..7c87331751ed43d6578107d45a1e33e07e6f5ef2 100644 --- a/tlatools/src/tlc2/value/ModelValue.java +++ b/tlatools/src/tlc2/value/impl/ModelValue.java @@ -34,17 +34,23 @@ * value/SetEnumValue.java * ***************************************************************************/ -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import tlc2.tool.FingerprintException; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IModelValue; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; import util.UniqueString; -public class ModelValue extends Value { +public class ModelValue extends Value implements IModelValue { /** * A method to reset the model values @@ -87,7 +93,7 @@ public class ModelValue extends Value { } /* Make str a new model value, if it is not one yet. */ - public static ModelValue make(String str) { + public static Value make(String str) { ModelValue mv = (ModelValue)mvTable.get(str); if (mv != null) return mv; mv = new ModelValue(str); @@ -135,13 +141,13 @@ public class ModelValue extends Value { else { Assert.fail("Attempted to check equality " + "of the differently-typed model values " - + ppr(this.toString()) + " and " - + ppr(mobj.toString())); + + Values.ppr(this.toString()) + " and " + + Values.ppr(mobj.toString())); } ; } ; Assert.fail("Attempted to check equality of typed model value " - + ppr(this.toString()) + " and non-model value\n" - + ppr(obj.toString())) ; + + Values.ppr(this.toString()) + " and non-model value\n" + + Values.ppr(obj.toString())) ; return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -159,8 +165,8 @@ public class ModelValue extends Value { try { if (this.type != 0) { Assert.fail("Attempted to check equality of the typed model value " - + ppr(this.toString()) + " and the non-model value\n" - + ppr(obj.toString())) ; + + Values.ppr(this.toString()) + " and the non-model value\n" + + Values.ppr(obj.toString())) ; } ; return false ; @@ -175,9 +181,9 @@ public class ModelValue extends Value { try { if (this.type != 0) { Assert.fail("Attempted to check if the typed model value " - + ppr(this.toString()) + + Values.ppr(this.toString()) + " is an element of\n" - + ppr(obj.toString())) ; + + Values.ppr(obj.toString())) ; } ; return false ; @@ -190,8 +196,8 @@ public class ModelValue extends Value { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the model value " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the model value " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -202,7 +208,7 @@ public class ModelValue extends Value { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the model value " + ppr(this.toString()) + + Assert.fail("Attempted to check if the model value " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -216,7 +222,7 @@ public class ModelValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the model value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -230,7 +236,7 @@ public class ModelValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the model value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -243,7 +249,7 @@ public class ModelValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the model value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -258,7 +264,7 @@ public class ModelValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -271,6 +277,12 @@ public class ModelValue extends Value { } } + @Override + public void write(IValueOutputStream vos) throws IOException { + vos.writeByte(MODELVALUE); + vos.writeShort((short) index); + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -282,9 +294,9 @@ public class ModelValue extends Value { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { - Value res = perm.get(this); + IValue res = perm.get(this); if (res == null) return this; return res; } @@ -295,7 +307,7 @@ public class ModelValue extends Value { } /* The string representation. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) { try { return sb.append(this.val); } diff --git a/tlatools/src/tlc2/value/OpLambdaValue.java b/tlatools/src/tlc2/value/impl/OpLambdaValue.java similarity index 79% rename from tlatools/src/tlc2/value/OpLambdaValue.java rename to tlatools/src/tlc2/value/impl/OpLambdaValue.java index da2c12d03b03b62911640ebed1c6df562c3b3315..a4356f8da11a1b9fd76ff10e18e83b69fadbac70 100644 --- a/tlatools/src/tlc2/value/OpLambdaValue.java +++ b/tlatools/src/tlc2/value/impl/OpLambdaValue.java @@ -4,26 +4,29 @@ // modified on Mon 30 Apr 2007 at 15:30:09 PST by lamport // modified on Fri Sep 22 13:18:45 PDT 2000 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.OpDefNode; import tlc2.tool.FingerprintException; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; +import tlc2.value.IValue; +import tlc2.value.Values; import util.Assert; import util.WrongInvocationException; public class OpLambdaValue extends OpValue implements Applicable { - public OpDefNode opDef; // the operator definition. - public Tool tool; - public Context con; - public TLCState state; - public TLCState pstate; + public final OpDefNode opDef; // the operator definition. + public final ITool tool; + public final Context con; + public final TLCState state; + public final TLCState pstate; /* Constructor */ - public OpLambdaValue(OpDefNode op, Tool tool, Context con, + public OpLambdaValue(OpDefNode op, ITool tool, Context con, TLCState state, TLCState pstate) { this.opDef = op; this.tool = tool; @@ -32,12 +35,18 @@ public class OpLambdaValue extends OpValue implements Applicable { this.pstate = pstate; } + public OpLambdaValue(OpDefNode op, ITool tool, Context con, + TLCState state, TLCState pstate, CostModel cm) { + this(op, tool, con, state, pstate); + this.cm = cm; + } + public final byte getKind() { return OPLAMBDAVALUE; } public final int compareTo(Object obj) { try { - Assert.fail("Attempted to compare operator " + ppr(this.toString()) + - " with value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare operator " + Values.ppr(this.toString()) + + " with value:\n" + Values.ppr(obj.toString())); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -48,8 +57,8 @@ public class OpLambdaValue extends OpValue implements Applicable { public final boolean equals(Object obj) { try { - Assert.fail("Attempted to check equality of operator " + ppr(this.toString()) + - " with value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of operator " + Values.ppr(this.toString()) + + " with value:\n" + Values.ppr(obj.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -60,8 +69,8 @@ public class OpLambdaValue extends OpValue implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of operator " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of operator " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -72,7 +81,7 @@ public class OpLambdaValue extends OpValue implements Applicable { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the operator " + ppr(this.toString()) + + Assert.fail("Attempted to check if the operator " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -96,7 +105,7 @@ public class OpLambdaValue extends OpValue implements Applicable { try { int alen = this.opDef.getArity(); if (alen != args.length) { - Assert.fail("Applying the operator " + ppr(this.toString()) + + Assert.fail("Applying the operator " + Values.ppr(this.toString()) + " with wrong number of arguments."); } Context c1 = this.con; @@ -104,7 +113,7 @@ public class OpLambdaValue extends OpValue implements Applicable { for (int i = 0; i < alen; i++) { c1 = c1.cons(formals[i], args[i]); } - return this.tool.eval(this.opDef.getBody(), c1, this.state, this.pstate, + return (Value) this.tool.eval(this.opDef.getBody(), c1, this.state, this.pstate, control); } catch (RuntimeException | OutOfMemoryError e) { @@ -126,7 +135,7 @@ public class OpLambdaValue extends OpValue implements Applicable { public final Value takeExcept(ValueExcept ex) { try { Assert.fail("Attempted to appy EXCEPT construct to the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return null; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -138,7 +147,7 @@ public class OpLambdaValue extends OpValue implements Applicable { public final Value takeExcept(ValueExcept[] exs) { try { Assert.fail("Attempted to apply EXCEPT construct to the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return null; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -150,8 +159,8 @@ public class OpLambdaValue extends OpValue implements Applicable { public final Value getDomain() { try { Assert.fail("Attempted to compute the domain of the operator " + - ppr(this.toString()) + "."); - return EmptySet; // make compiler happy + Values.ppr(this.toString()) + "."); + return SetEnumValue.EmptySet; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -162,7 +171,7 @@ public class OpLambdaValue extends OpValue implements Applicable { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -194,7 +203,7 @@ public class OpLambdaValue extends OpValue implements Applicable { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -207,7 +216,7 @@ public class OpLambdaValue extends OpValue implements Applicable { } /* String representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) { try { String opName = this.opDef.getName().toString(); return sb.append("<Operator ").append(opName).append(">"); diff --git a/tlatools/src/tlc2/value/OpRcdValue.java b/tlatools/src/tlc2/value/impl/OpRcdValue.java similarity index 86% rename from tlatools/src/tlc2/value/OpRcdValue.java rename to tlatools/src/tlc2/value/impl/OpRcdValue.java index d06d21670b508ca9cb2f4048c2249a9b77ceb9bc..106e60b36a029262e32842f9f0c12e543010d2eb 100644 --- a/tlatools/src/tlc2/value/OpRcdValue.java +++ b/tlatools/src/tlc2/value/impl/OpRcdValue.java @@ -4,10 +4,12 @@ // modified on Mon 30 Apr 2007 at 13:21:01 PST by lamport // modified on Sat Nov 13 12:43:44 PST 1999 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tlc2.tool.FingerprintException; import tlc2.util.Vect; +import tlc2.value.IValue; +import tlc2.value.Values; import util.Assert; import util.WrongInvocationException; @@ -30,8 +32,8 @@ public class OpRcdValue extends OpValue implements Applicable { public final int compareTo(Object obj) { try { - Assert.fail("Attempted to compare operator " + ppr(this.toString()) + - " with value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare operator " + Values.ppr(this.toString()) + + " with value:\n" + Values.ppr(obj.toString())); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -42,8 +44,8 @@ public class OpRcdValue extends OpValue implements Applicable { public final boolean equals(Object obj) { try { - Assert.fail("Attempted to check equality of operator " + ppr(this.toString()) + - " with value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of operator " + Values.ppr(this.toString()) + + " with value:\n" + Values.ppr(obj.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -54,8 +56,8 @@ public class OpRcdValue extends OpValue implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of operator " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of operator " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -66,7 +68,7 @@ public class OpRcdValue extends OpValue implements Applicable { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the operator " + ppr(this.toString()) + + Assert.fail("Attempted to check if the operator " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -108,7 +110,7 @@ public class OpRcdValue extends OpValue implements Applicable { for (int i = 0; i < sz; i++) { Value[] vals = (Value[])this.domain.elementAt(i); if (args.length != vals.length) { - Assert.fail("Attempted to apply the operator " + ppr(this.toString()) + + Assert.fail("Attempted to apply the operator " + Values.ppr(this.toString()) + "\nwith wrong number of arguments."); } boolean matched = true; @@ -121,7 +123,7 @@ public class OpRcdValue extends OpValue implements Applicable { } } // Generate the error message: - String msg = "Attempted to apply operator:\n" + ppr(this.toString()) + + String msg = "Attempted to apply operator:\n" + Values.ppr(this.toString()) + "\nto arguments ("; if (args.length > 0) msg += args[0]; for (int i = 1; i < args.length; i++) { @@ -150,7 +152,7 @@ public class OpRcdValue extends OpValue implements Applicable { public final Value takeExcept(ValueExcept ex) { try { Assert.fail("Attempted to appy EXCEPT construct to the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return null; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -162,7 +164,7 @@ public class OpRcdValue extends OpValue implements Applicable { public final Value takeExcept(ValueExcept[] exs) { try { Assert.fail("Attempted to apply EXCEPT construct to the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return null; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -174,8 +176,8 @@ public class OpRcdValue extends OpValue implements Applicable { public final Value getDomain() { try { Assert.fail("Attempted to compute the domain of the operator " + - ppr(this.toString()) + "."); - return EmptySet; // make compiler happy + Values.ppr(this.toString()) + "."); + return SetEnumValue.EmptySet; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -186,7 +188,7 @@ public class OpRcdValue extends OpValue implements Applicable { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the operator " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -230,7 +232,7 @@ public class OpRcdValue extends OpValue implements Applicable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -243,27 +245,27 @@ public class OpRcdValue extends OpValue implements Applicable { } /* Pretty-printing */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { sb.append("{ "); if (this.values.size() != 0) { sb.append("<"); Value[] args = (Value[])this.domain.elementAt(0); for (int j = 0; j < args.length; j++) { - sb = args[j].toString(sb, offset); + sb = args[j].toString(sb, offset, swallow); sb.append(", "); } - sb = ((Value)this.values.elementAt(0)).toString(sb, offset); + sb = ((Value)this.values.elementAt(0)).toString(sb, offset, swallow); sb.append(">"); } for (int i = 1; i < this.values.size(); i++) { sb.append(", <"); Value[] args = (Value[])this.domain.elementAt(i); for (int j = 0; j < args.length; j++) { - sb = args[j].toString(sb, offset); + sb = args[j].toString(sb, offset, swallow); sb.append(", "); } - sb = ((Value)this.values.elementAt(i)).toString(sb, offset); + sb = ((Value)this.values.elementAt(i)).toString(sb, offset, swallow); sb.append(">"); } return sb.append("}"); diff --git a/tlatools/src/tlc2/value/impl/OpValue.java b/tlatools/src/tlc2/value/impl/OpValue.java new file mode 100644 index 0000000000000000000000000000000000000000..1281b1ae02dfcf0710e500da1fc483871d735e74 --- /dev/null +++ b/tlatools/src/tlc2/value/impl/OpValue.java @@ -0,0 +1,27 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Mon 30 Apr 2007 at 13:21:02 PST by lamport +// modified on Fri Sep 22 13:18:45 PDT 2000 by yuanyu + +package tlc2.value.impl; + +import tla2sany.semantic.ExprOrOpArgNode; +import tlc2.tool.TLCState; +import tlc2.tool.coverage.CostModel; +import tlc2.tool.impl.Tool; +import tlc2.util.Context; + +public abstract class OpValue extends Value implements Applicable { + + // Allow sub-classes to override. + public Value eval(final Tool tool, final ExprOrOpArgNode[] args, final Context c, final TLCState s0, + final TLCState s1, final int control, final CostModel cm) { + final Value[] argVals = new Value[args.length]; + // evaluate the operator's arguments: + for (int i = 0; i < args.length; i++) { + argVals[i] = tool.eval(args[i], c, s0, s1, control, cm); + } + // evaluate the operator: + return this.apply(argVals, control); + } +} diff --git a/tlatools/src/tlc2/value/RecordValue.java b/tlatools/src/tlc2/value/impl/RecordValue.java similarity index 74% rename from tlatools/src/tlc2/value/RecordValue.java rename to tlatools/src/tlc2/value/impl/RecordValue.java index c4cf10f87c41ac944b26f6298012c670f2c854b2..094f312c798022cbda43920724713a2918b50e73 100644 --- a/tlatools/src/tlc2/value/RecordValue.java +++ b/tlatools/src/tlc2/value/impl/RecordValue.java @@ -4,21 +4,30 @@ // modified on Sat 23 February 2008 at 10:15:47 PST by lamport // modified on Fri Aug 10 15:09:07 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.EOFException; +import java.io.IOException; import java.util.Arrays; import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; import util.UniqueString; public class RecordValue extends Value implements Applicable { - public UniqueString[] names; // the field names - public Value[] values; // the field values + public final UniqueString[] names; // the field names + public final Value[] values; // the field values private boolean isNorm; +public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0], new Value[0], true); /* Constructor */ public RecordValue(UniqueString[] names, Value[] values, boolean isNorm) { @@ -27,15 +36,20 @@ public class RecordValue extends Value implements Applicable { this.isNorm = isNorm; } + public RecordValue(UniqueString[] names, Value[] values, boolean isNorm, CostModel cm) { + this(names, values, isNorm); + this.cm = cm; + } + public final byte getKind() { return RECORDVALUE; } public final int compareTo(Object obj) { try { - RecordValue rcd = convert(obj); + RecordValue rcd = obj instanceof Value ? (RecordValue) ((Value)obj).toRcd() : null; if (rcd == null) { if (obj instanceof ModelValue) return 1; - Assert.fail("Attempted to compare record:\n" + ppr(this.toString()) + - "\nwith non-record\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare record:\n" + Values.ppr(this.toString()) + + "\nwith non-record\n" + Values.ppr(obj.toString())); } this.normalize(); rcd.normalize(); @@ -59,12 +73,12 @@ public class RecordValue extends Value implements Applicable { public final boolean equals(Object obj) { try { - RecordValue rcd = convert(obj); + RecordValue rcd = obj instanceof Value ? (RecordValue) ((Value)obj).toRcd() : null; if (rcd == null) { if (obj instanceof ModelValue) return ((ModelValue) obj).modelValueEquals(this) ; - Assert.fail("Attempted to check equality of record:\n" + ppr(this.toString()) + - "\nwith non-record\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of record:\n" + Values.ppr(this.toString()) + + "\nwith non-record\n" + Values.ppr(obj.toString())); } this.normalize(); rcd.normalize(); @@ -85,8 +99,8 @@ public class RecordValue extends Value implements Applicable { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if element:\n" + ppr(elem.toString()) + - "\nis in the record:\n" + ppr(this.toString())); + Assert.fail("Attempted to check if element:\n" + Values.ppr(elem.toString()) + + "\nis in the record:\n" + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -124,7 +138,7 @@ public class RecordValue extends Value implements Applicable { return new RecordValue(newNames, newValues, this.isNorm); } else { - MP.printWarning(EC.TLC_WRONG_RECORD_FIELD_NAME, new String[]{ppr(arcVal.toString())}); + MP.printWarning(EC.TLC_WRONG_RECORD_FIELD_NAME, new String[]{Values.ppr(arcVal.toString())}); } } return ex.value; @@ -149,36 +163,27 @@ public class RecordValue extends Value implements Applicable { } } - /* - * This method converts a value to a function value. It returns - * null if the conversion fails. - */ - public static final RecordValue convert(Object val) { - if (val instanceof RecordValue) { - return (RecordValue)val; - } - else if (val instanceof FcnRcdValue || - val instanceof FcnLambdaValue) { - FcnRcdValue fcn = FcnRcdValue.convert(val); - if (fcn == null || fcn.domain == null) return null; - fcn.normalize(); - UniqueString[] vars = new UniqueString[fcn.domain.length]; - for (int i = 0; i < fcn.domain.length; i++) { - if (!(fcn.domain[i] instanceof StringValue)) { - return null; - } - vars[i] = ((StringValue)fcn.domain[i]).getVal(); - } - return new RecordValue(vars, fcn.values, fcn.isNormalized()); - } - else if ((val instanceof TupleValue) && - ((TupleValue)val).size() == 0) { - return EmptyRcd; - } - // return null if not convertable - return null; + @Override + public final Value toRcd() { + return this; + } + + @Override + public final Value toTuple() { + return size() == 0 ? TupleValue.EmptyTuple : super.toTuple(); } + @Override + public final Value toFcnRcd() { + this.normalize(); + Value[] dom = new Value[this.names.length]; + for (int i = 0; i < this.names.length; i++) { + dom[i] = new StringValue(this.names[i], cm); + } + if (coverage) {cm.incSecondary(dom.length);} + return new FcnRcdValue(dom, this.values, this.isNormalized(), cm); + } + public final int size() { try { return this.names.length; @@ -193,7 +198,7 @@ public class RecordValue extends Value implements Applicable { try { if (!(arg instanceof StringValue)) { Assert.fail("Attempted to apply record to a non-string value " + - ppr(arg.toString()) + "."); + Values.ppr(arg.toString()) + "."); } UniqueString name = ((StringValue)arg).getVal(); int rlen = this.names.length; @@ -202,7 +207,7 @@ public class RecordValue extends Value implements Applicable { return this.values[i]; } } - Assert.fail("Attempted to apply the record\n" + ppr(this.toString()) + + Assert.fail("Attempted to apply the record\n" + Values.ppr(this.toString()) + "\nto nonexistent record field " + name + "."); return null; // make compiler happy } @@ -230,7 +235,7 @@ public class RecordValue extends Value implements Applicable { try { if (!(arg instanceof StringValue)) { Assert.fail("Attempted to apply record to a non-string argument " + - ppr(arg.toString()) + "."); + Values.ppr(arg.toString()) + "."); } UniqueString name = ((StringValue)arg).getVal(); int rlen = this.names.length; @@ -249,7 +254,7 @@ public class RecordValue extends Value implements Applicable { public final Value getDomain() { try { - Value[] dElems = new Value[this.names.length]; + Value[] dElems = new Value[this.names.length]; for (int i = 0; i < this.names.length; i++) { dElems[i] = new StringValue(this.names[i]); } @@ -265,7 +270,7 @@ public class RecordValue extends Value implements Applicable { try { for (int i = 0; i < this.names.length; i++) { if (name.equals(this.names[i])) { - if (this.values[i] == ValUndef || + if (this.values[i] == UndefValue.ValUndef || this.values[i].equals(val)) { this.values[i] = val; return true; @@ -328,6 +333,20 @@ public class RecordValue extends Value implements Applicable { } } + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < values.length; i++) { + values[i].deepNormalize(); + } + normalize(); + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { boolean defined = true; @@ -342,11 +361,11 @@ public class RecordValue extends Value implements Applicable { } } - public final Value deepCopy() { + public final IValue deepCopy() { try { - Value[] vals = new Value[this.values.length]; + Value[] vals = new Value[this.values.length]; for (int i = 0; i < this.values.length; i++) { - vals[i] = this.values[i].deepCopy(); + vals[i] = (Value) this.values[i].deepCopy(); } // Following code modified 16 June 2015 by adding Arrays.copyOf to fix // the following bug that seems to have manifested itself only in TLC.Print and @@ -381,6 +400,30 @@ public class RecordValue extends Value implements Applicable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + final int index = vos.put(this); + if (index == -1) { + vos.writeByte(RECORDVALUE); + final int len = names.length; + vos.writeInt((isNormalized()) ? len : -len); + for (int i = 0; i < len; i++) { + final int index1 = vos.put(names[i]); + if (index1 == -1) { + vos.writeByte(STRINGVALUE); + names[i].write(vos.getOutputStream()); + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index1); + } + values[i].write(vos); + } + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index); + } + } + /* The fingerprint methods. */ public final long fingerPrint(long fp) { try { @@ -403,14 +446,14 @@ public class RecordValue extends Value implements Applicable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.normalize(); int rlen = this.names.length; Value[] vals = new Value[rlen]; boolean changed = false; for (int i = 0; i < rlen; i++) { - vals[i] = this.values[i].permute(perm); + vals[i] = (Value) this.values[i].permute(perm); changed = changed || (vals[i] != this.values[i]); } if (changed) { @@ -425,19 +468,19 @@ public class RecordValue extends Value implements Applicable { } /* The string representation */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { int len = this.names.length; sb.append("["); if (len > 0) { sb.append(this.names[0] + " |-> "); - sb = this.values[0].toString(sb, offset); + sb = this.values[0].toString(sb, offset, swallow); } for (int i = 1; i < len; i++) { sb.append(", "); sb.append(this.names[i] + " |-> "); - sb = this.values[i].toString(sb, offset); + sb = this.values[i].toString(sb, offset, swallow); } return sb.append("]"); } @@ -447,4 +490,30 @@ public class RecordValue extends Value implements Applicable { } } + public static IValue createFrom(final IValueInputStream vos) throws EOFException, IOException { + final int index = vos.getIndex(); + boolean isNorm = true; + int len = vos.readInt(); + if (len < 0) { + len = -len; + isNorm = false; + } + final UniqueString[] names = new UniqueString[len]; + final Value[] vals = new Value[len]; + for (int i = 0; i < len; i++) { + final byte kind1 = vos.readByte(); + if (kind1 == DUMMYVALUE) { + final int index1 = vos.readNat(); + names[i] = vos.getValue(index1); + } else { + final int index1 = vos.getIndex(); + names[i] = UniqueString.read(vos.getInputStream()); + vos.assign(names[i], index1); + } + vals[i] = (Value) vos.read(); + } + final Value res = new RecordValue(names, vals, isNorm); + vos.assign(res, index); + return res; + } } diff --git a/tlatools/src/tlc2/value/Reducible.java b/tlatools/src/tlc2/value/impl/Reducible.java similarity index 95% rename from tlatools/src/tlc2/value/Reducible.java rename to tlatools/src/tlc2/value/impl/Reducible.java index 492894ca289fa4b5fdde0204c8a5a0eda936a2be..c44a2d1a5a2c59aa58420edd6522a4d4fd760d65 100644 --- a/tlatools/src/tlc2/value/Reducible.java +++ b/tlatools/src/tlc2/value/impl/Reducible.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:21:02 PST by lamport // modified on Tue Mar 23 00:37:35 PST 1999 by yuanyu -package tlc2.value; +package tlc2.value.impl; public interface Reducible { diff --git a/tlatools/src/tlc2/value/SetCapValue.java b/tlatools/src/tlc2/value/impl/SetCapValue.java similarity index 69% rename from tlatools/src/tlc2/value/SetCapValue.java rename to tlatools/src/tlc2/value/impl/SetCapValue.java index 821cd4f3d22d5b2425572e903575ce111a6143d9..df1dc81c35c726627c4b87e59dcb3bef714a37f9 100644 --- a/tlatools/src/tlc2/value/SetCapValue.java +++ b/tlatools/src/tlc2/value/impl/SetCapValue.java @@ -4,14 +4,21 @@ // modified on Mon 30 Apr 2007 at 13:21:03 PST by lamport // modified on Fri Aug 10 15:09:21 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; + +import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetCapValue extends EnumerableValue implements Enumerable { - public Value set1; - public Value set2; + public final Value set1; + public final Value set2; protected SetEnumValue capSet; /* Constructor */ @@ -58,7 +65,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final boolean isFinite() { try { if (!this.set1.isFinite() && !this.set2.isFinite()) { - Assert.fail("Attempted to check if the set " + ppr(this.toString()) + "is finite."); + Assert.fail("Attempted to check if the set " + Values.ppr(this.toString()) + "is finite."); } return true; } @@ -71,7 +78,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -84,7 +91,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -107,7 +114,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { - if (this.capSet == null || this.capSet == DummyEnum) { + if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) { return (this.set1.isNormalized() && this.set2.isNormalized()); } return this.capSet.isNormalized(); @@ -120,7 +127,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.capSet == null || this.capSet == DummyEnum) { + if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) { this.set1.normalize(); this.set2.normalize(); } @@ -145,7 +152,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -157,6 +164,11 @@ public class SetCapValue extends EnumerableValue implements Enumerable { } } + @Override + public void write(final IValueOutputStream vos) throws IOException { + capSet.write(vos); + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -169,7 +181,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.capSet.permute(perm); @@ -182,36 +194,69 @@ public class SetCapValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.capSet == null) { - this.capSet = SetEnumValue.convert(this); + this.capSet = (SetEnumValue) this.toSetEnum(); } - else if (this.capSet == DummyEnum) { + else if (this.capSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.capSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.capSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.capSet == DummyEnum) { this.capSet = val; } + if (this.capSet == SetEnumValue.DummyEnum) { this.capSet = val; } } } } + + @Override + public final void deepNormalize() { + try { + set1.deepNormalize(); + set2.deepNormalize(); + if (capSet == null) { + capSet = SetEnumValue.DummyEnum; + } + else if (capSet != SetEnumValue.DummyEnum) { + capSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + @Override + public final Value toSetEnum() { + if (this.capSet != null && this.capSet != SetEnumValue.DummyEnum) { + return this.capSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.isNormalized(), cm); + } /* String representation of this value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { try { - if (expand) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + if (TLCGlobals.expand) { + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } } - catch (Throwable e) { /*SKIP*/ } + catch (Throwable e) { if (!swallow) throw e; } - sb = this.set1.toString(sb, offset); + sb = this.set1.toString(sb, offset, swallow); sb = sb.append(" \\cap "); - sb = this.set2.toString(sb, offset); + sb = this.set2.toString(sb, offset, swallow); return sb; } catch (RuntimeException | OutOfMemoryError e) { @@ -222,7 +267,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.capSet == null || this.capSet == DummyEnum) { + if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.capSet.elements(); @@ -248,7 +293,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { } else { Assert.fail("Attempted to enumerate S \\cap T when neither S:\n" + - ppr(set1.toString()) + "\nnor T:\n" + ppr(set2.toString()) + + Values.ppr(set1.toString()) + "\nnor T:\n" + Values.ppr(set2.toString()) + "\nis enumerable"); } } @@ -256,8 +301,9 @@ public class SetCapValue extends EnumerableValue implements Enumerable { public final void reset() { this.enum1.reset(); } public final Value nextElement() { - Value elem = this.enum1.nextElement(); + Value elem = this.enum1.nextElement(); while (elem != null) { + if (coverage) { cm.incSecondary(); } if (this.set.member(elem)) return elem; elem = this.enum1.nextElement(); } diff --git a/tlatools/src/tlc2/value/SetCupValue.java b/tlatools/src/tlc2/value/impl/SetCupValue.java similarity index 69% rename from tlatools/src/tlc2/value/SetCupValue.java rename to tlatools/src/tlc2/value/impl/SetCupValue.java index 2a69d8c69fd4d6ae5aa90ebf19cca8111b6f7ab5..265140102d21593fb24a221d535386def7143f52 100644 --- a/tlatools/src/tlc2/value/SetCupValue.java +++ b/tlatools/src/tlc2/value/impl/SetCupValue.java @@ -4,14 +4,22 @@ // modified on Mon 30 Apr 2007 at 13:21:03 PST by lamport // modified on Fri Aug 10 15:09:28 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; + +import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetCupValue extends EnumerableValue implements Enumerable { - public Value set1; - public Value set2; + public final Value set1; + public final Value set2; protected SetEnumValue cupSet; /* Constructor */ @@ -21,6 +29,11 @@ public class SetCupValue extends EnumerableValue implements Enumerable { this.cupSet = null; } + public SetCupValue(Value set1, Value set2, CostModel cm) { + this(set1, set2); + this.cm = cm; + } + public final byte getKind() { return SETCUPVALUE; } public final int compareTo(Object obj) { @@ -68,7 +81,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -81,7 +94,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -105,7 +118,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { return (this.cupSet != null && - this.cupSet != DummyEnum && + this.cupSet != SetEnumValue.DummyEnum && this.cupSet.isNormalized()); } catch (RuntimeException | OutOfMemoryError e) { @@ -116,7 +129,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.cupSet != null && this.cupSet != DummyEnum) { + if (this.cupSet != null && this.cupSet != SetEnumValue.DummyEnum) { this.cupSet.normalize(); } return this; @@ -127,6 +140,24 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + set1.deepNormalize(); + set2.deepNormalize(); + if (cupSet == null) { + cupSet = SetEnumValue.DummyEnum; + } + else if (cupSet != SetEnumValue.DummyEnum) { + cupSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { return this.set1.isDefined() && this.set2.isDefined(); @@ -137,7 +168,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -149,6 +180,11 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + cupSet.write(vos); + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -161,7 +197,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.cupSet.permute(perm); @@ -174,36 +210,51 @@ public class SetCupValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.cupSet == null) { - this.cupSet = SetEnumValue.convert(this); + this.cupSet = (SetEnumValue) this.toSetEnum(); } - else if (this.cupSet == DummyEnum) { + else if (this.cupSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.cupSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.cupSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.cupSet == DummyEnum) { this.cupSet = val; } + if (this.cupSet == SetEnumValue.DummyEnum) { this.cupSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.cupSet != null && this.cupSet != SetEnumValue.DummyEnum) { + return this.cupSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, false, cm); + } + /* String representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { try { - if (expand) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + if (TLCGlobals.expand) { + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } } - catch (Throwable e) { /*SKIP*/ } + catch (Throwable e) { if (!swallow) throw e; } - sb = this.set1.toString(sb, offset); + sb = this.set1.toString(sb, offset, swallow); sb = sb.append(" \\cup "); - sb = this.set2.toString(sb, offset); + sb = this.set2.toString(sb, offset, swallow); return sb; } catch (RuntimeException | OutOfMemoryError e) { @@ -214,7 +265,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.cupSet == null || this.cupSet == DummyEnum) { + if (this.cupSet == null || this.cupSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.cupSet.elements(); @@ -238,7 +289,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } else { Assert.fail("Attempted to enumerate S \\cup T when S:\n" + - ppr(set1.toString()) + "\nand T:\n" + ppr(set2.toString()) + + Values.ppr(set1.toString()) + "\nand T:\n" + Values.ppr(set2.toString()) + "\nare not both enumerable"); } } @@ -249,7 +300,8 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } public final Value nextElement() { - Value elem = this.enum1.nextElement(); + if (coverage) { cm.incSecondary(); } + Value elem = this.enum1.nextElement(); if (elem != null) return elem; elem = this.enum2.nextElement(); return elem; diff --git a/tlatools/src/tlc2/value/SetDiffValue.java b/tlatools/src/tlc2/value/impl/SetDiffValue.java similarity index 69% rename from tlatools/src/tlc2/value/SetDiffValue.java rename to tlatools/src/tlc2/value/impl/SetDiffValue.java index 4ba3e0758d07b93e82249b13636c0e626900130e..89698c2b9fed1a53a49707b0170c196ccf522595 100644 --- a/tlatools/src/tlc2/value/SetDiffValue.java +++ b/tlatools/src/tlc2/value/impl/SetDiffValue.java @@ -4,14 +4,21 @@ // modified on Mon 30 Apr 2007 at 13:21:03 PST by lamport // modified on Fri Aug 10 15:09:34 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; + +import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetDiffValue extends EnumerableValue implements Enumerable { - public Value set1; - public Value set2; + public final Value set1; + public final Value set2; protected SetEnumValue diffSet; /* Constructor */ @@ -61,7 +68,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { return true; } if (!this.set2.isFinite()) { - Assert.fail("Attempted to check if the set " + ppr(this.toString()) + "is finite."); + Assert.fail("Attempted to check if the set " + Values.ppr(this.toString()) + "is finite."); } return false; } @@ -74,7 +81,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -87,7 +94,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -110,7 +117,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { - if (this.diffSet == null || this.diffSet == DummyEnum) { + if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) { return this.set1.isNormalized(); } return this.diffSet.isNormalized(); @@ -123,7 +130,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.diffSet == null || this.diffSet == DummyEnum) { + if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) { this.set1.normalize(); this.set2.normalize(); } @@ -138,6 +145,24 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + set1.deepNormalize(); + set2.deepNormalize(); + if (diffSet == null) { + diffSet = SetEnumValue.DummyEnum; + } + else if (diffSet != SetEnumValue.DummyEnum) { + diffSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { return this.set1.isDefined() && this.set2.isDefined(); @@ -148,7 +173,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -160,6 +185,11 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + diffSet.write(vos); + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -172,7 +202,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.diffSet.permute(perm); @@ -185,36 +215,51 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.diffSet == null) { - this.diffSet = SetEnumValue.convert(this); + this.diffSet = (SetEnumValue) this.toSetEnum(); } - else if (this.diffSet == DummyEnum) { + else if (this.diffSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.diffSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.diffSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.diffSet == DummyEnum) { this.diffSet = val; } + if (this.diffSet == SetEnumValue.DummyEnum) { this.diffSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.diffSet != null && this.diffSet != SetEnumValue.DummyEnum) { + return this.diffSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.set1.isNormalized(), cm); + } + /* The string representation */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { try { - if (expand) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + if (TLCGlobals.expand) { + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } } - catch (Throwable e) { /*SKIP*/ } + catch (Throwable e) { if (!swallow) throw e; } - sb = this.set1.toString(sb, offset); + sb = this.set1.toString(sb, offset, swallow); sb = sb.append(" \\ "); - sb = this.set2.toString(sb, offset); + sb = this.set2.toString(sb, offset, swallow); return sb; } catch (RuntimeException | OutOfMemoryError e) { @@ -225,7 +270,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.diffSet == null || this.diffSet == DummyEnum) { + if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.diffSet.elements(); @@ -246,15 +291,16 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } else { Assert.fail("Attempted to enumerate S \\ T when S:\n" + - ppr(set1.toString()) + "\nis not enumerable."); + Values.ppr(set1.toString()) + "\nis not enumerable."); } } public final void reset() { this.enum1.reset(); } public final Value nextElement() { - Value elem = this.enum1.nextElement(); + Value elem = this.enum1.nextElement(); while (elem != null) { + if (coverage) { cm.incSecondary(); } if (!set2.member(elem)) return elem; elem = this.enum1.nextElement(); } diff --git a/tlatools/src/tlc2/value/SetEnumValue.java b/tlatools/src/tlc2/value/impl/SetEnumValue.java similarity index 61% rename from tlatools/src/tlc2/value/SetEnumValue.java rename to tlatools/src/tlc2/value/impl/SetEnumValue.java index 601f28a1621a32244a844084cbbfa73d0770ec35..213199f2526b1f0996c53d8d24bfcf15190104a0 100644 --- a/tlatools/src/tlc2/value/SetEnumValue.java +++ b/tlatools/src/tlc2/value/impl/SetEnumValue.java @@ -4,42 +4,66 @@ // modified on Sat 23 February 2008 at 10:16:24 PST by lamport // modified on Mon Aug 20 10:54:08 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.Values; import util.Assert; public class SetEnumValue extends EnumerableValue implements Enumerable, Reducible { public ValueVec elems; // the elements of the set private boolean isNorm; // normalized? +public final static SetEnumValue EmptySet = new SetEnumValue(new ValueVec(0), true); +public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, true); /* Constructor */ public SetEnumValue(Value[] elems, boolean isNorm) { - this.elems = new ValueVec(elems); - this.isNorm = isNorm; + this(new ValueVec(elems), isNorm); + } + + public SetEnumValue(Value[] vals, boolean isNorm, CostModel cm) { + this(vals, isNorm); + this.cm = cm; } public SetEnumValue(ValueVec elems, boolean isNorm) { this.elems = elems; this.isNorm = isNorm; } - + + public SetEnumValue(ValueVec elems, boolean isNorm, final CostModel cm) { + this(elems, isNorm); + this.cm = cm; + } + public SetEnumValue() { - this.elems = new ValueVec(0); - this.isNorm = true; + this(new ValueVec(0), true); + } + + public SetEnumValue(CostModel cm) { + this(); + this.cm = cm; } public final byte getKind() { return SETENUMVALUE; } public final int compareTo(Object obj) { try { - SetEnumValue set = convert(obj); + SetEnumValue set = obj instanceof Value ? (SetEnumValue) ((Value)obj).toSetEnum() : null; if (set == null) { if (obj instanceof ModelValue) return 1; - Assert.fail("Attempted to compare the set " + ppr(this.toString()) + - " with the value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare the set " + Values.ppr(this.toString()) + + " with the value:\n" + Values.ppr(obj.toString())); } this.normalize(); set.normalize(); @@ -60,12 +84,12 @@ implements Enumerable, Reducible { public final boolean equals(Object obj) { try { - SetEnumValue set = convert(obj); + SetEnumValue set = obj instanceof Value ? (SetEnumValue) ((Value)obj).toSetEnum() : null; if (set == null) { if (obj instanceof ModelValue) return ((ModelValue) obj).modelValueEquals(this) ; - Assert.fail("Attempted to check equality of the set " + ppr(this.toString()) + - " with the value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of the set " + Values.ppr(this.toString()) + + " with the value:\n" + Values.ppr(obj.toString())); } this.normalize(); set.normalize(); @@ -103,12 +127,12 @@ implements Enumerable, Reducible { int sz = this.elems.size(); ValueVec diffElems = new ValueVec(); for (int i = 0; i < sz; i++) { - Value elem = this.elems.elementAt(i); + Value elem = this.elems.elementAt(i); if (!val.member(elem)) { diffElems.addElement(elem); } } - return new SetEnumValue(diffElems, this.isNormalized()); + return new SetEnumValue(diffElems, this.isNormalized(), cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -121,12 +145,12 @@ implements Enumerable, Reducible { int sz = this.elems.size(); ValueVec capElems = new ValueVec(); for (int i = 0; i < sz; i++) { - Value elem = this.elems.elementAt(i); + Value elem = this.elems.elementAt(i); if (val.member(elem)) { capElems.addElement(elem); } } - return new SetEnumValue(capElems, this.isNormalized()); + return new SetEnumValue(capElems, this.isNormalized(), cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -142,7 +166,7 @@ implements Enumerable, Reducible { if (set instanceof Reducible) { ValueVec cupElems = new ValueVec(); for (int i = 0; i < sz; i++) { - Value elem = this.elems.elementAt(i); + Value elem = this.elems.elementAt(i); cupElems.addElement(elem); } ValueEnumeration Enum = ((Enumerable)set).elements(); @@ -152,7 +176,7 @@ implements Enumerable, Reducible { } return new SetEnumValue(cupElems, false); } - return new SetCupValue(this, set); + return new SetCupValue(this, set, cm); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -163,7 +187,7 @@ implements Enumerable, Reducible { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -176,7 +200,7 @@ implements Enumerable, Reducible { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -213,149 +237,24 @@ implements Enumerable, Reducible { else { throw e; } } } - - /* Convert val into a SetEnumValue. Returns null if not possible. */ - public static final SetEnumValue convert(Object val) { - switch (((Value)val).getKind()) { - case SETENUMVALUE: - return (SetEnumValue)val; - case INTERVALVALUE: - { - IntervalValue intv = (IntervalValue)val; - Value[] vals = new Value[intv.size()]; - for (int i = 0; i < vals.length; i++) { - vals[i] = IntValue.gen(i + intv.low); - } - return new SetEnumValue(vals, true); - } - case SETCAPVALUE: - { - SetCapValue cap = (SetCapValue)val; - if (cap.capSet != null && cap.capSet != DummyEnum) { - return cap.capSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = cap.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, cap.isNormalized()); - } - case SETCUPVALUE: - { - SetCupValue cup = (SetCupValue)val; - if (cup.cupSet != null && cup.cupSet != DummyEnum) { - return cup.cupSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = cup.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, false); - } - case SETDIFFVALUE: - { - SetDiffValue diff = (SetDiffValue)val; - if (diff.diffSet != null && diff.diffSet != DummyEnum) { - return diff.diffSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = diff.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, diff.set1.isNormalized()); - } - case UNIONVALUE: - { - UnionValue uv = (UnionValue)val; - if (uv.realSet != null && uv.realSet != DummyEnum) { - return uv.realSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = uv.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, false); - } - case SUBSETVALUE: - { - SubsetValue pset = (SubsetValue)val; - if (pset.pset != null && pset.pset != DummyEnum) { - return pset.pset; - } - ValueVec vals = new ValueVec(pset.size()); - ValueEnumeration Enum = pset.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, false); - } - case SETOFRCDSVALUE: - { - SetOfRcdsValue rcds = (SetOfRcdsValue)val; - if (rcds.rcdSet != null && rcds.rcdSet != DummyEnum) { - return rcds.rcdSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = rcds.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, rcds.isNormalized()); - } - case SETOFFCNSVALUE: - { - SetOfFcnsValue fcns = (SetOfFcnsValue)val; - if (fcns.fcnSet != null && fcns.fcnSet != DummyEnum) { - return fcns.fcnSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = fcns.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, fcns.isNormalized()); - } - case SETOFTUPLESVALUE: - { - SetOfTuplesValue tvs = (SetOfTuplesValue)val; - if (tvs.tupleSet != null && tvs.tupleSet != DummyEnum) { - return tvs.tupleSet; - } - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = tvs.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, tvs.isNormalized()); - } - case SETPREDVALUE: - { - SetPredValue sPred = (SetPredValue)val; - if (sPred.tool == null) return (SetEnumValue)sPred.inVal; - ValueVec vals = new ValueVec(); - ValueEnumeration Enum = sPred.elements(); - Value elem; - while ((elem = Enum.nextElement()) != null) { - vals.addElement(elem); - } - return new SetEnumValue(vals, sPred.isNormalized()); + + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < elems.size(); i++) { + elems.elementAt(i).deepNormalize(); } - default: - // null if val can not be converted. - return null; - } + normalize(); + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + @Override + public final Value toSetEnum() { + return this; } public final boolean isDefined() { @@ -373,7 +272,7 @@ implements Enumerable, Reducible { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -385,6 +284,22 @@ implements Enumerable, Reducible { } } + @Override + public final void write(IValueOutputStream vos) throws IOException { + final int index = vos.put(this); + if (index == -1) { + vos.writeByte(SETENUMVALUE); + final int len = elems.size(); + vos.writeInt((isNormalized()) ? len : -len); + for (int i = 0; i < len; i++) { + elems.elementAt(i).write(vos); + } + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index); + } + } + /* The fingerprint methods */ public final long fingerPrint(long fp) { try { @@ -404,13 +319,13 @@ implements Enumerable, Reducible { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { int sz = this.elems.size(); Value[] vals = new Value[sz]; boolean changed = false; for (int i = 0; i < sz; i++) { - vals[i] = this.elems.elementAt(i).permute(perm); + vals[i] = (Value) this.elems.elementAt(i).permute(perm); changed = (changed || vals[i] != this.elems.elementAt(i)); } if (changed) { @@ -425,7 +340,7 @@ implements Enumerable, Reducible { } /* The string representation */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { // If this SetEnumValue object is created by a union, at least one of // whose elements is a Cartesian product, then this can be an unnormalized @@ -448,11 +363,11 @@ implements Enumerable, Reducible { int len = this.elems.size(); sb = sb.append("{"); if (len > 0) { - this.elems.elementAt(0).toString(sb, offset); + this.elems.elementAt(0).toString(sb, offset, swallow); } for (int i = 1; i < len; i++) { sb.append(", "); - this.elems.elementAt(i).toString(sb, offset); + this.elems.elementAt(i).toString(sb, offset, swallow); } sb.append("}"); return sb; @@ -463,9 +378,9 @@ implements Enumerable, Reducible { } } - public Value randomElement() { + public final Value randomElement() { int sz = size(); - int index = (int) Math.floor(getRandom().nextDouble() * sz); + int index = (int) Math.floor(RandomEnumerableValues.get().nextDouble() * sz); return this.elems.elementAt(index); } @@ -489,6 +404,7 @@ implements Enumerable, Reducible { public final void reset() { this.index = 0; } public final Value nextElement() { + if (coverage) { cm.incSecondary(); } if (this.index < elems.size()) { return elems.elementAt(this.index++); } @@ -506,7 +422,7 @@ implements Enumerable, Reducible { while ((v = ve.nextElement()) != null) { vec.addElement(v); } - return new SetEnumValue(vec, false); + return new SetEnumValue(vec, false, cm); } @Override @@ -522,4 +438,21 @@ implements Enumerable, Reducible { } }; } + + public static IValue createFrom(final IValueInputStream vos) throws IOException { + final int index = vos.getIndex(); + boolean isNorm = true; + int len = vos.readInt(); + if (len < 0) { + len = -len; + isNorm = false; + } + final Value[] elems = new Value[len]; + for (int i = 0; i < len; i++) { + elems[i] = (Value) vos.read(); + } + final Value res = new SetEnumValue(elems, isNorm); + vos.assign(res, index); + return res; + } } diff --git a/tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java b/tlatools/src/tlc2/value/impl/SetOfFcnsOrRcdsValue.java similarity index 93% rename from tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java rename to tlatools/src/tlc2/value/impl/SetOfFcnsOrRcdsValue.java index 7dd8f63582f2e5295ca5bac68d8ce9620bcbb8ab..3a04b08e989a43bf17988f3ab4e42b1b7cf7d7f0 100644 --- a/tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java +++ b/tlatools/src/tlc2/value/impl/SetOfFcnsOrRcdsValue.java @@ -23,10 +23,12 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import java.math.BigInteger; +import tlc2.value.RandomEnumerableValues; + public abstract class SetOfFcnsOrRcdsValue extends EnumerableValue { @Override @@ -45,7 +47,8 @@ public abstract class SetOfFcnsOrRcdsValue extends EnumerableValue { assert (needBigInteger() ? vec.sort(true).size() == kOutOfN : vec.sort(true).size() == Math.min(kOutOfN, size())); - return new SetEnumValue(vec, false); + if (coverage) {cm.incSecondary(vec.size());} + return new SetEnumValue(vec, false, cm); } @Override @@ -93,7 +96,7 @@ public abstract class SetOfFcnsOrRcdsValue extends EnumerableValue { this.k = k; this.i = 0; - this.a = BigInteger.valueOf(Math.abs(getRandom().nextLong())); + this.a = BigInteger.valueOf(Math.abs(RandomEnumerableValues.get().nextLong())); // http://primes.utm.edu/lists/2small/0bit.html // (2^63 - 25) diff --git a/tlatools/src/tlc2/value/SetOfFcnsValue.java b/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java similarity index 77% rename from tlatools/src/tlc2/value/SetOfFcnsValue.java rename to tlatools/src/tlc2/value/impl/SetOfFcnsValue.java index 1f5f00e68de0d72e54780fadf5652c343a55ad3a..b407c9599565e3f8cd567369eae1a5ccea2a7cd6 100644 --- a/tlatools/src/tlc2/value/SetOfFcnsValue.java +++ b/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java @@ -4,17 +4,23 @@ // modified on Sat 23 February 2008 at 10:17:11 PST by lamport // modified on Fri Aug 10 15:09:46 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; import java.math.BigInteger; import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { - public Value domain; /* Function domain */ - public Value range; /* Function range */ + public final Value domain; /* Function domain */ + public final Value range; /* Function range */ protected SetEnumValue fcnSet; /* Constructor */ @@ -24,6 +30,11 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { this.fcnSet = null; } + public SetOfFcnsValue(Value domain, Value range, CostModel cm) { + this(domain, range); + this.cm = cm; + } + public final byte getKind() { return SETOFFCNSVALUE; } public final int compareTo(Object obj) { @@ -55,12 +66,12 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final boolean member(Value elem) { try { - FcnRcdValue fcn = FcnRcdValue.convert(elem); + FcnRcdValue fcn = (FcnRcdValue) elem.toFcnRcd(); if (fcn == null) { if (elem instanceof ModelValue) return ((ModelValue) elem).modelValueMember(this) ; Assert.fail("Attempted to check if \n" + elem + "\nwhich is not a TLC function" + - " value, is in the set of functions:\n" + ppr(this.toString())); + " value, is in the set of functions:\n" + Values.ppr(this.toString())); } if (fcn.intv == null) { fcn.normalize(); @@ -104,7 +115,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT to the set of functions:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return ex.value; } @@ -118,7 +129,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT to the set of functions:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return this; } @@ -137,7 +148,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { sz *= rsz; if (sz < -2147483648 || sz > 2147483647) { Assert.fail("Overflow when computing the number of elements in:\n" + - ppr(toString())); + Values.ppr(toString())); } } return (int)sz; @@ -164,7 +175,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final boolean isNormalized() { try { - if (this.fcnSet == null || this.fcnSet == DummyEnum) { + if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) { return this.domain.isNormalized() && this.range.isNormalized(); } return this.fcnSet.isNormalized(); @@ -177,7 +188,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final Value normalize() { try { - if (this.fcnSet == null || this.fcnSet == DummyEnum) { + if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) { this.domain.normalize(); this.range.normalize(); } @@ -192,6 +203,24 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + domain.deepNormalize(); + range.deepNormalize(); + if (fcnSet == null) { + fcnSet = SetEnumValue.DummyEnum; + } + else if (fcnSet != SetEnumValue.DummyEnum) { + fcnSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { return this.domain.isDefined() && this.range.isDefined(); @@ -202,7 +231,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -226,7 +255,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.fcnSet.permute(perm); @@ -239,26 +268,46 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { private final void convertAndCache() { if (this.fcnSet == null) { - this.fcnSet = SetEnumValue.convert(this); + this.fcnSet = (SetEnumValue) this.toSetEnum(); } - else if (this.fcnSet == DummyEnum) { + else if (this.fcnSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.fcnSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.fcnSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.fcnSet == DummyEnum) { this.fcnSet = val; } + if (this.fcnSet == SetEnumValue.DummyEnum) { this.fcnSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.fcnSet != null && this.fcnSet != SetEnumValue.DummyEnum) { + return this.fcnSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.isNormalized(), cm); + } + + @Override + public final void write(final IValueOutputStream vos) throws IOException { + fcnSet.write(vos); + } + /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - boolean unlazy = expand; + boolean unlazy = TLCGlobals.expand; try { if (unlazy) { int dsz = this.domain.size(); @@ -274,17 +323,17 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { unlazy = sz < TLCGlobals.enumBound; } } - catch (Throwable e) { unlazy = false; } + catch (Throwable e) { if (swallow) unlazy = false; else throw e; } if (unlazy) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } else { sb.append("["); - this.domain.toString(sb, offset); + this.domain.toString(sb, offset, swallow); sb.append(" -> "); - this.range.toString(sb, offset); + this.range.toString(sb, offset, swallow); sb.append("]"); return sb; } @@ -297,7 +346,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.fcnSet == null || this.fcnSet == DummyEnum) { + if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.fcnSet.elements(); @@ -316,10 +365,10 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public Enumerator() { this.isDone = false; - SetEnumValue domSet = SetEnumValue.convert(domain); + SetEnumValue domSet = (SetEnumValue) domain.toSetEnum(); if (domSet == null) Assert.fail("Attempted to enumerate a set of the form [D -> R]," + - "but the domain D:\n" + ppr(domain.toString()) + + "but the domain D:\n" + Values.ppr(domain.toString()) + "\ncannot be enumerated."); domSet.normalize(); ValueVec elems = domSet.elems; @@ -343,7 +392,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } else { Assert.fail("Attempted to enumerate a set of the form [D -> R]," + - "but the range R:\n" + ppr(range.toString()) + + "but the range R:\n" + Values.ppr(range.toString()) + "\ncannot be enumerated."); } } @@ -363,8 +412,9 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { return null; } if (this.currentElems.length == 0) { + if (coverage) { cm.incSecondary(); } this.isDone = true; - return new FcnRcdValue(this.dom, new Value[this.currentElems.length], true); + return new FcnRcdValue(this.dom, new Value[this.currentElems.length], true, cm); } else { // Take and store a snapshot of currentElems as the element to return for // this invocation of nextElement(). @@ -373,6 +423,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { // Eagerly generate the next element which is going to be returned the upon next // invocation of nextElement(). + if (coverage) { cm.incSecondary(this.currentElems.length); } for (int i = this.currentElems.length - 1; i >= 0; i--) { this.currentElems[i] = this.enums[i].nextElement(); if (this.currentElems[i] != null) { @@ -386,14 +437,14 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { this.currentElems[i] = this.enums[i].nextElement(); } - return new FcnRcdValue(this.dom, elems, true); + return new FcnRcdValue(this.dom, elems, true, cm); } } } @Override - protected tlc2.value.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { + protected tlc2.value.impl.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { return new SubsetEnumerator(k, n); } @@ -404,10 +455,10 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { SubsetEnumerator(final int k, final int n) { super(k, n); - domSet = SetEnumValue.convert(domain); + domSet = (SetEnumValue) domain.toSetEnum(); domSet.normalize(); - rangeSet = SetEnumValue.convert(range); + rangeSet = (SetEnumValue) range.toSetEnum(); mod = range.size(); } @@ -428,7 +479,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } @Override - protected tlc2.value.SetOfFcnsOrRcdsValue.BigIntegerSubsetEnumerator getBigSubsetEnumerator(int k) { + protected tlc2.value.impl.SetOfFcnsOrRcdsValue.BigIntegerSubsetEnumerator getBigSubsetEnumerator(int k) { return new BigIntegerSubsetEnumerator(k); } @@ -441,10 +492,10 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public BigIntegerSubsetEnumerator(final int k) { super(k); - this.domSet = SetEnumValue.convert(domain); + this.domSet = (SetEnumValue) domain.toSetEnum(); this.domSet.normalize(); - this.rangeSet = SetEnumValue.convert(range); + this.rangeSet = (SetEnumValue) range.toSetEnum(); this.mod = range.size(); this.bMod = BigInteger.valueOf(mod); diff --git a/tlatools/src/tlc2/value/SetOfRcdsValue.java b/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java similarity index 79% rename from tlatools/src/tlc2/value/SetOfRcdsValue.java rename to tlatools/src/tlc2/value/impl/SetOfRcdsValue.java index 999c474c6034173bb1666bcd2e326a1da024503b..9990059038dbb648758386785c61e2a60c1a2c8e 100644 --- a/tlatools/src/tlc2/value/SetOfRcdsValue.java +++ b/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java @@ -4,19 +4,25 @@ // modified on Sat 23 February 2008 at 10:18:01 PST by lamport // modified on Fri Aug 10 15:09:53 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; import java.math.BigInteger; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; import util.UniqueString; public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { - public UniqueString[] names; // The names of the fields. - public Value[] values; // The values of the fields. + public final UniqueString[] names; // The names of the fields. + public final Value[] values; // The values of the fields. protected SetEnumValue rcdSet; /* Constructor */ @@ -30,6 +36,11 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } + public SetOfRcdsValue(UniqueString[] names, Value[] values, boolean isNorm, CostModel cm) { + this(names, values, isNorm); + this.cm = cm; + } + public final byte getKind() { return SETOFRCDSVALUE; } public final int compareTo(Object obj) { @@ -49,8 +60,8 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { SetOfRcdsValue rcds = (SetOfRcdsValue)obj; boolean isEmpty1 = this.isEmpty(); - if (isEmpty1) return rcds.isEmpty(); - if (rcds.isEmpty()) return isEmpty1; + if (isEmpty1) { return rcds.isEmpty(); } + if (rcds.isEmpty()) { return isEmpty1; } if (this.names.length != rcds.names.length) { return false; @@ -74,12 +85,12 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final boolean member(Value elem) { try { - RecordValue rcd = RecordValue.convert(elem); + RecordValue rcd = (RecordValue) elem.toRcd(); if (rcd == null) { if (elem instanceof ModelValue) return ((ModelValue) elem).modelValueMember(this) ; Assert.fail("Attempted to check if non-record\n" + elem + "\nis in the" + - " set of records:\n" + ppr(this.toString())); + " set of records:\n" + Values.ppr(this.toString())); } rcd.normalize(); if (this.names.length != rcd.names.length) { @@ -116,7 +127,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT to the set of records:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return ex.value; } @@ -130,7 +141,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT to the set of records:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return this; } @@ -147,7 +158,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { sz *= this.values[i].size(); if (sz < -2147483648 || sz > 2147483647) { Assert.fail(EC.TLC_MODULE_OVERFLOW, "the number of elements in:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } } return (int)sz; @@ -172,7 +183,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final boolean isNormalized() { try { - if (this.rcdSet == null || this.rcdSet == DummyEnum) { + if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) { for (int i = 0; i < this.names.length; i++) { if (!this.values[i].isNormalized()) { return false; @@ -190,7 +201,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final Value normalize() { try { - if (this.rcdSet == null || this.rcdSet == DummyEnum) { + if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) { for (int i = 0; i < this.names.length; i++) { this.values[i].normalize(); } @@ -206,6 +217,25 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < values.length; i++) { + values[i].deepNormalize(); + } + if (rcdSet == null) { + rcdSet = SetEnumValue.DummyEnum; + } + else if (rcdSet != SetEnumValue.DummyEnum) { + rcdSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + private final void sortByNames() { for (int i = 1; i < this.names.length; i++) { int cmp = this.names[0].compareTo(this.names[i]); @@ -255,7 +285,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -279,7 +309,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.rcdSet.permute(perm); @@ -292,26 +322,46 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { private final void convertAndCache() { if (this.rcdSet == null) { - this.rcdSet = SetEnumValue.convert(this); + this.rcdSet = (SetEnumValue) this.toSetEnum(); } - else if (this.rcdSet == DummyEnum) { + else if (this.rcdSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.rcdSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.rcdSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.rcdSet == DummyEnum) { this.rcdSet = val; } + if (this.rcdSet == SetEnumValue.DummyEnum) { this.rcdSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.rcdSet != null && this.rcdSet != SetEnumValue.DummyEnum) { + return this.rcdSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.isNormalized(), cm); + } + + @Override + public final void write(final IValueOutputStream vos) throws IOException { + rcdSet.write(vos); + } + /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - boolean unlazy = expand; + boolean unlazy = TLCGlobals.expand; try { if (unlazy) { long sz = 1; @@ -325,23 +375,23 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { unlazy = sz < TLCGlobals.enumBound; } } - catch (Throwable e) { unlazy = false; } + catch (Throwable e) { if (swallow) unlazy = false; else throw e; } if (unlazy) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } else { sb.append("["); int len = this.names.length; if (len != 0) { sb.append(names[0] + ": "); - this.values[0].toString(sb, offset); + this.values[0].toString(sb, offset, swallow); } for (int i = 1; i < len; i++) { sb.append(", "); sb.append(names[i] + ": "); - this.values[i].toString(sb, offset); + this.values[i].toString(sb, offset, swallow); } sb.append("]"); return sb; @@ -355,7 +405,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.rcdSet == null || this.rcdSet == DummyEnum) { + if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.rcdSet.elements(); @@ -388,7 +438,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { else { Assert.fail("Attempted to enumerate a set of the form [l1 : v1, ..., ln : vn]," + "\nbut can't enumerate the value of the `" + names[i] + "' field:\n" + - ppr(values[i].toString())); + Values.ppr(values[i].toString())); } } } @@ -406,6 +456,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public final Value nextElement() { if (this.isDone) return null; Value[] elems = new Value[this.currentElems.length]; + if (coverage) { cm.incSecondary(elems.length); } for (int i = 0; i < elems.length; i++) { elems[i] = this.currentElems[i]; } @@ -419,13 +470,13 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { this.enums[i].reset(); this.currentElems[i] = this.enums[i].nextElement(); } - return new RecordValue(names, elems, true); + return new RecordValue(names, elems, true, cm); } } @Override - protected tlc2.value.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { + protected tlc2.value.impl.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { return new SubsetEnumerator(k, n); } @@ -442,7 +493,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { int numElems = 1; // 1 to avoid div by zero in elementAt for (int i = values.length - 1; i >= 0; i--) { - convert[i] = SetEnumValue.convert(values[i]); + convert[i] = (SetEnumValue) values[i].toSetEnum(); rescaleBy[i] = numElems; numElems *= convert[i].elems.size(); } @@ -461,7 +512,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { val[i] = sev.elems.elementAt(elementAt); } - return new RecordValue(names, val, false); + return new RecordValue(names, val, false, cm); } } @@ -483,7 +534,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { BigInteger numElems = BigInteger.ONE; // 1 to avoid div by zero in elementAt for (int i = values.length - 1; i >= 0; i--) { - convert[i] = SetEnumValue.convert(values[i]); + convert[i] = (SetEnumValue) values[i].toSetEnum(); rescaleBy[i] = numElems; numElems = numElems.multiply(BigInteger.valueOf(convert[i].elems.size())); } @@ -505,7 +556,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { val[i] = sev.elems.elementAt(elementAt); } - return new RecordValue(names, val, false); + return new RecordValue(names, val, false, cm); } } } diff --git a/tlatools/src/tlc2/value/SetOfTuplesValue.java b/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java similarity index 75% rename from tlatools/src/tlc2/value/SetOfTuplesValue.java rename to tlatools/src/tlc2/value/impl/SetOfTuplesValue.java index a7ab439fd8e7f73b3a6a9a15660f36b474d2f2d7..11a1a40e3d67be108bce416c9007633ce4d1b6ac 100644 --- a/tlatools/src/tlc2/value/SetOfTuplesValue.java +++ b/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java @@ -4,14 +4,21 @@ // modified on Sat 23 February 2008 at 10:18:39 PST by lamport // modified on Fri Aug 10 15:09:59 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetOfTuplesValue extends EnumerableValue implements Enumerable { - public Value[] sets; + public final Value[] sets; protected SetEnumValue tupleSet; /* Constructor */ @@ -19,18 +26,20 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { this.sets = sets; this.tupleSet = null; } + public SetOfTuplesValue(Value[] set, CostModel cm) { + this(set); + this.cm = cm; + } public SetOfTuplesValue(Value val) { - this.sets = new Value[1]; + this(new Value[1]); this.sets[0] = val; - this.tupleSet = null; } public SetOfTuplesValue(Value v1, Value v2) { - this.sets = new Value[2]; + this(new Value[2]); this.sets[0] = v1; this.sets[1] = v2; - this.tupleSet = null; } public final byte getKind() { return SETOFTUPLESVALUE; } @@ -76,20 +85,20 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { public final boolean member(Value elem) { try { - TupleValue tv = TupleValue.convert(elem); + TupleValue tv = (TupleValue) elem.toTuple(); if (tv == null) { - FcnRcdValue fcn = FcnRcdValue.convert(elem); + FcnRcdValue fcn = (FcnRcdValue) elem.toFcnRcd(); if (fcn == null) { if (elem instanceof ModelValue) return ((ModelValue) elem).modelValueMember(this) ; - Assert.fail("Attempted to check if non-tuple\n" + ppr(elem.toString()) + - "\nis in the set of tuples:\n" + ppr(this.toString())); + Assert.fail("Attempted to check if non-tuple\n" + Values.ppr(elem.toString()) + + "\nis in the set of tuples:\n" + Values.ppr(this.toString())); } if (fcn.intv != null) return false; for (int i = 0; i < fcn.domain.length; i++) { if (!(fcn.domain[i] instanceof IntValue)) { - Assert.fail("Attempted to check if non-tuple\n" + ppr(elem.toString()) + - "\nis in the set of tuples:\n" + ppr(this.toString())); + Assert.fail("Attempted to check if non-tuple\n" + Values.ppr(elem.toString()) + + "\nis in the set of tuples:\n" + Values.ppr(this.toString())); } } return false; @@ -128,7 +137,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the set of tuples:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return ex.value; } @@ -142,7 +151,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the set of tuples:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return this; } @@ -159,7 +168,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { sz *= this.sets[i].size(); if (sz < -2147483648 || sz > 2147483647) { Assert.fail("Overflow when computing the number of elements in " + - ppr(this.toString())); + Values.ppr(this.toString())); } } return (int)sz; @@ -172,7 +181,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { - if (this.tupleSet == null || this.tupleSet == DummyEnum) { + if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) { for (int i = 0; i < this.sets.length; i++) { if (!this.sets[i].isNormalized()) { return false; @@ -190,7 +199,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.tupleSet == null || this.tupleSet == DummyEnum) { + if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) { for (int i = 0; i < this.sets.length; i++) { this.sets[i].normalize(); } @@ -206,6 +215,25 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < sets.length; i++) { + sets[i].deepNormalize(); + } + if (tupleSet == null) { + tupleSet = SetEnumValue.DummyEnum; + } + else if (tupleSet != SetEnumValue.DummyEnum) { + tupleSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { boolean defined = true; @@ -220,7 +248,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -244,7 +272,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.tupleSet.permute(perm); @@ -257,26 +285,46 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.tupleSet == null) { - this.tupleSet = SetEnumValue.convert(this); + this.tupleSet = (SetEnumValue) this.toSetEnum(); } - else if (this.tupleSet == DummyEnum) { + else if (this.tupleSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.tupleSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.tupleSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.tupleSet == DummyEnum) { this.tupleSet = val; } + if (this.tupleSet == SetEnumValue.DummyEnum) { this.tupleSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.tupleSet != null && this.tupleSet != SetEnumValue.DummyEnum) { + return this.tupleSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.isNormalized(), cm); + } + + @Override + public final void write(final IValueOutputStream vos) throws IOException { + tupleSet.write(vos); + } + /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - boolean unlazy = expand; + boolean unlazy = TLCGlobals.expand; try { if (unlazy) { long sz = 1; @@ -290,20 +338,20 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { unlazy = sz < TLCGlobals.enumBound; } } - catch (Throwable e) { unlazy = false; } + catch (Throwable e) { if (swallow) unlazy = false; else throw e; } if (unlazy) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } else { if (this.sets.length > 0) { sb.append("("); - this.sets[0].toString(sb, offset); + this.sets[0].toString(sb, offset, swallow); } for (int i = 1; i < this.sets.length; i++) { sb.append(" \\X "); - this.sets[i].toString(sb, offset); + this.sets[i].toString(sb, offset, swallow); } if (this.sets.length > 0) { sb.append(")"); @@ -319,7 +367,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.tupleSet == null || this.tupleSet == DummyEnum) { + if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.tupleSet.elements(); @@ -351,7 +399,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { } else { Assert.fail("Attempted to enumerate a set of the form s1 \\X s2 ... \\X sn," + - "\nbut can't enumerate s" + i + ":\n" + ppr(sets[i].toString())); + "\nbut can't enumerate s" + i + ":\n" + Values.ppr(sets[i].toString())); } } } @@ -369,6 +417,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { public final Value nextElement() { if (this.isDone) return null; Value[] elems = new Value[this.currentElems.length]; + if (coverage) { cm.incSecondary(elems.length); } for (int i = 0; i < elems.length; i++) { elems[i] = this.currentElems[i]; } @@ -382,7 +431,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { this.enums[i].reset(); this.currentElems[i] = this.enums[i].nextElement(); } - return new TupleValue(elems); + return new TupleValue(elems, cm); } } diff --git a/tlatools/src/tlc2/value/SetPredValue.java b/tlatools/src/tlc2/value/impl/SetPredValue.java similarity index 72% rename from tlatools/src/tlc2/value/SetPredValue.java rename to tlatools/src/tlc2/value/impl/SetPredValue.java index 832cdebc19a194a2a4d3c36b57230fe9304ce000..e6a686e3191eb2ba150822bfa8cf22ad201e7c59 100644 --- a/tlatools/src/tlc2/value/SetPredValue.java +++ b/tlatools/src/tlc2/value/impl/SetPredValue.java @@ -4,7 +4,7 @@ // modified on Thu 5 Jul 2007 at 4:44:23 PST by lamport // modified on Fri Aug 10 15:10:04 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.io.IOException; import java.io.ObjectInputStream; @@ -12,28 +12,35 @@ import java.io.ObjectOutputStream; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.SemanticNode; +import tlc2.TLCGlobals; import tlc2.tool.EvalException; import tlc2.tool.FingerprintException; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; +import tlc2.tool.coverage.CostModel; import tlc2.util.Context; +import tlc2.value.IBoolValue; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class SetPredValue extends EnumerableValue implements Enumerable { - public Object vars; // FormalParamNode or FormalParamNode[] + public final Object vars; // FormalParamNode or FormalParamNode[] /*********************************************************************** * Was OpDeclNode or OpDeclNode[]. * ***********************************************************************/ public Value inVal; // the in value or the real set - public SemanticNode pred; // the predicate - public Tool tool; // null iff inVal is the real set - public Context con; - public TLCState state; - public TLCState pstate; - public int control; + public final SemanticNode pred; // the predicate + public ITool tool; // null iff inVal is the real set + public final Context con; + public final TLCState state; + public final TLCState pstate; + public final int control; /* Constructor */ - public SetPredValue(Object vars, Value inVal, SemanticNode pred, Tool tool, + public SetPredValue(Object vars, Value inVal, SemanticNode pred, ITool tool, Context con, TLCState s0, TLCState s1, int control) { this.vars = vars; this.inVal = inVal; @@ -56,11 +63,17 @@ public class SetPredValue extends EnumerableValue implements Enumerable { this.control = control; } + public SetPredValue(Object vars, Value inVal, SemanticNode pred, ITool tool, + Context con, TLCState s0, TLCState s1, int control, CostModel cm) { + this(vars, inVal, pred, tool, con, s0, s1, control); + this.cm = cm; + } + public final byte getKind() { return SETPREDVALUE; } public final int compareTo(Object obj) { try { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; return this.inVal.compareTo(obj); } @@ -72,7 +85,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public final boolean equals(Object obj) { try { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; return this.inVal.equals(obj); } @@ -95,20 +108,20 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } else { FormalParamNode[] ids = (FormalParamNode[])this.vars; - TupleValue tv = TupleValue.convert(elem); + TupleValue tv = (TupleValue) elem.toTuple(); if ((tv != null) && (tv.elems.length == ids.length)) { - Value[] vals = ((TupleValue)tv).elems; + Value [] vals = ((TupleValue)tv).elems; for (int i = 0; i < ids.length; i++) { con1 = con1.cons(ids[i], vals[i]); } } else { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + "\nis an element of a set of " + ids.length + "-tuples."); } } - Value res = this.tool.eval(this.pred, con1, this.state, this.pstate, this.control); - if (!(res instanceof BoolValue)) { + Value res = (Value) this.tool.eval(this.pred, con1, this.state, this.pstate, this.control); + if (!(res instanceof IBoolValue)) { Assert.fail("The evaluation of predicate " + this.pred + " yielded non-Boolean value."); } @@ -116,8 +129,8 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } } catch (EvalException e) { - Assert.fail("Cannot decide if element:\n" + ppr(elem.toString()) + - "\n is element of:\n" + ppr(this.inVal.toString()) + + Assert.fail("Cannot decide if element:\n" + Values.ppr(elem.toString()) + + "\n is element of:\n" + Values.ppr(this.inVal.toString()) + "\nand satisfies the predicate " + this.pred); } return false; @@ -132,7 +145,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { try { if (!(this.inVal.isFinite())) { Assert.fail("Attempted to check if expression of form {x \\in S : p(x)} is a " + - "finite set, but cannot check if S:\n" + ppr(this.inVal.toString()) + + "finite set, but cannot check if S:\n" + Values.ppr(this.inVal.toString()) + "\nis finite."); } return true; @@ -146,7 +159,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -159,7 +172,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -171,7 +184,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public final int size() { try { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; return this.inVal.size(); } @@ -182,13 +195,13 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } private final void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - this.inVal = (Value)ois.readObject(); + this.inVal = (Value )ois.readObject(); this.tool = null; } private final void writeObject(ObjectOutputStream oos) throws IOException { if (this.tool != null) { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; } oos.writeObject(this.inVal); @@ -216,9 +229,20 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + inVal.deepNormalize(); + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -233,7 +257,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { /* The fingerprint method */ public final long fingerPrint(long fp) { try { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; return this.inVal.fingerPrint(fp); } @@ -243,9 +267,9 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { - this.inVal = SetEnumValue.convert(this); + this.inVal = this.toSetEnum(); this.tool = null; return this.inVal.permute(perm); } @@ -255,16 +279,36 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } } + @Override + public Value toSetEnum() { + if (this.tool == null) { + return (SetEnumValue) this.inVal; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, this.isNormalized(), cm); + } + + @Override + public void write(final IValueOutputStream vos) throws IOException { + inVal.write(vos); + } + /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { try { - if (expand) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + if (TLCGlobals.expand) { + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } } - catch (Throwable e) { /*SKIP*/ } + catch (Throwable e) { if (!swallow) throw e; } sb.append("{"); if (this.vars instanceof FormalParamNode) { @@ -306,7 +350,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public Enumerator() { if (!(inVal instanceof Enumerable)) { Assert.fail("Attempted to enumerate { x \\in S : p(x) } when S:\n" + - ppr(inVal.toString()) + "\nis not enumerable"); + Values.ppr(inVal.toString()) + "\nis not enumerable"); } this.Enum = ((Enumerable)inVal).elements(); } @@ -314,29 +358,30 @@ public class SetPredValue extends EnumerableValue implements Enumerable { public final void reset() { this.Enum.reset(); } public final Value nextElement() { - Value elem; + Value elem; while ((elem = this.Enum.nextElement()) != null) { + if (coverage) { cm.incSecondary(); } Context con1 = con; if (vars instanceof FormalParamNode) { con1 = con1.cons((FormalParamNode)vars, elem); } else { FormalParamNode[] ids = (FormalParamNode[])vars; - TupleValue tv = TupleValue.convert(elem); + TupleValue tv = (TupleValue) elem.toTuple(); if ((tv != null) && (((TupleValue)tv).elems.length == ids.length)) { - Value[] vals = ((TupleValue)tv).elems; + Value [] vals = ((TupleValue)tv).elems; for (int i = 0; i < ids.length; i++) { con1 = con1.cons(ids[i], vals[i]); } } else { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + "\nis an element of a set of " + ids.length + "-tuples."); } } - Value res = tool.eval(pred, con1, state, pstate, control); - if (!(res instanceof BoolValue)) { + Value res = (Value) tool.eval(pred, con1, state, pstate, control, cm); + if (!(res instanceof IBoolValue)) { Assert.fail("Evaluating predicate " + pred + " yielded non-Boolean value."); } if (((BoolValue)res).val) return elem; diff --git a/tlatools/src/tlc2/value/StringValue.java b/tlatools/src/tlc2/value/impl/StringValue.java similarity index 77% rename from tlatools/src/tlc2/value/StringValue.java rename to tlatools/src/tlc2/value/impl/StringValue.java index a9c07c5b56f7ba2f3e3600020f7bb3e5ad42ca01..1ca046936acc6311d82737134375c2993d13c01f 100644 --- a/tlatools/src/tlc2/value/StringValue.java +++ b/tlatools/src/tlc2/value/impl/StringValue.java @@ -4,15 +4,23 @@ // modified on Sat 23 February 2008 at 10:19:41 PST by lamport // modified on Fri Aug 10 15:06:37 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; import util.UniqueString; public class StringValue extends Value { - public UniqueString val; + public final UniqueString val; /* Constructor */ public StringValue(String str) { @@ -24,6 +32,11 @@ public class StringValue extends Value { this.val = var; } + public StringValue(UniqueString var, CostModel cm) { + this(var); + this.cm = cm; + } + public final byte getKind() { return STRINGVALUE; } public final UniqueString getVal() { return this.val; } @@ -34,8 +47,8 @@ public class StringValue extends Value { return this.val.compareTo(((StringValue)obj).val); } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to compare string " + ppr(this.toString()) + - " with non-string:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare string " + Values.ppr(this.toString()) + + " with non-string:\n" + Values.ppr(obj.toString())); } return 1; } @@ -51,8 +64,8 @@ public class StringValue extends Value { return this.val.equals(((StringValue)obj).getVal()); } if (!(obj instanceof ModelValue)) { - Assert.fail("Attempted to check equality of string " + ppr(this.toString()) + - " with non-string:\n" + ppr(obj.toString())); + Assert.fail("Attempted to check equality of string " + Values.ppr(this.toString()) + + " with non-string:\n" + Values.ppr(obj.toString())); } return ((ModelValue) obj).modelValueEquals(this) ; } @@ -64,8 +77,8 @@ public class StringValue extends Value { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element of the string " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element of the string " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -76,7 +89,7 @@ public class StringValue extends Value { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the string " + ppr(this.toString()) + + Assert.fail("Attempted to check if the string " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -90,7 +103,7 @@ public class StringValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the string " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -104,7 +117,7 @@ public class StringValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the string " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -117,7 +130,7 @@ public class StringValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the string " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -132,7 +145,7 @@ public class StringValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -155,6 +168,18 @@ public class StringValue extends Value { } } + @Override + public void write(IValueOutputStream vos) throws IOException { + final int index = vos.put(this); + if (index == -1) { + vos.writeByte(STRINGVALUE); + val.write(vos.getOutputStream()); + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index); + } + } + /* The fingerprint method */ public final long fingerPrint(long fp) { try { @@ -169,7 +194,7 @@ public class StringValue extends Value { } } - public final Value permute(MVPerm perm) { return this; } + public final IValue permute(IMVPerm perm) { return this; } /************************************************************************* * toString() modified 23 Aug 2007 by LL to call PrintVersion so strings * @@ -213,7 +238,7 @@ public class StringValue extends Value { /* The string representation of the value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { return sb.append("\"" + PrintVersion(this.val.toString()) + "\""); } @@ -223,4 +248,12 @@ public class StringValue extends Value { } } + public static IValue createFrom(final IValueInputStream vos) throws IOException { + final UniqueString str = UniqueString.read(vos.getInputStream()); + final IValue res = new StringValue(str); + final int index = vos.getIndex(); + vos.assign(res, index); + return res; + } + } diff --git a/tlatools/src/tlc2/value/SubsetValue.java b/tlatools/src/tlc2/value/impl/SubsetValue.java similarity index 69% rename from tlatools/src/tlc2/value/SubsetValue.java rename to tlatools/src/tlc2/value/impl/SubsetValue.java index 3e78e3dde49b0a3ee3112a40056fb680d21e04ae..21137a7611be318fa6bbb0f9fab69fd29014324e 100644 --- a/tlatools/src/tlc2/value/SubsetValue.java +++ b/tlatools/src/tlc2/value/impl/SubsetValue.java @@ -4,8 +4,9 @@ // modified on Mon 30 Apr 2007 at 13:46:07 PST by lamport // modified on Fri Aug 10 15:10:16 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.BitSet; @@ -14,21 +15,33 @@ import java.util.HashSet; import java.util.Random; import java.util.TreeMap; +import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.Combinatorics; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.Values; import util.Assert; public class SubsetValue extends EnumerableValue implements Enumerable { - public Value set; // SUBSET set + public Value set; // SUBSET set protected SetEnumValue pset; /* Constructor */ - public SubsetValue(Value set) { + public SubsetValue(Value set) { this.set = set; this.pset = null; } + public SubsetValue(Value set, CostModel cm) { + this(set); + this.cm = cm; + } + public final byte getKind() { return SUBSETVALUE; } public final int compareTo(Object obj) { @@ -63,14 +76,16 @@ public class SubsetValue extends EnumerableValue implements Enumerable { try { if (val instanceof Enumerable) { ValueEnumeration Enum = ((Enumerable)val).elements(); - Value elem; + Value elem; while ((elem = Enum.nextElement()) != null) { - if (!this.set.member(elem)) return false; + if (!this.set.member(elem)) { + return false; + } } } else { Assert.fail("Attempted to check if the non-enumerable value\n" + - ppr(val.toString()) + "\nis element of\n" + ppr(this.toString())); + Values.ppr(val.toString()) + "\nis element of\n" + Values.ppr(this.toString())); } return true; } @@ -84,9 +99,9 @@ public class SubsetValue extends EnumerableValue implements Enumerable { try { // Reduce (SUBSET A \subseteq SUBSET B) to (A \subseteq B) to avoid // exponential blowup inherent in generating the power set. - if (other instanceof SubsetValue && this.set instanceof EnumerableValue) { + if (other instanceof SubsetValue && this.set instanceof Enumerable) { final SubsetValue sv = (SubsetValue) other; - return ((EnumerableValue) this.set).isSubsetEq(sv.set); + return ((Enumerable) this.set).isSubsetEq(sv.set); } return super.isSubsetEq(other); } @@ -109,7 +124,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -122,7 +137,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set " + Values.ppr(this.toString()) + "."); } return this; } @@ -137,7 +152,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { int sz = this.set.size(); if (sz >= 31) { Assert.fail(EC.TLC_MODULE_OVERFLOW, "the number of elements in:\n" + - ppr(this.toString())); + Values.ppr(this.toString())); } return (1 << sz); } @@ -150,7 +165,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { return (this.pset != null && - this.pset != DummyEnum && + this.pset != SetEnumValue.DummyEnum && this.pset.isNormalized()); } catch (RuntimeException | OutOfMemoryError e) { @@ -161,7 +176,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.pset == null || this.pset == DummyEnum) { + if (this.pset == null || this.pset == SetEnumValue.DummyEnum) { this.set.normalize(); } else { @@ -175,6 +190,23 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + set.deepNormalize(); + if (pset == null) { + pset = SetEnumValue.DummyEnum; + } + else if (pset != SetEnumValue.DummyEnum) { + pset.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { return this.set.isDefined(); @@ -185,7 +217,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -197,6 +229,11 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } } + @Override + public final void write(final IValueOutputStream vos) throws IOException { + pset.write(vos); + } + /* The fingerprint */ public final long fingerPrint(long fp) { try { @@ -209,7 +246,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.pset.permute(perm); @@ -222,40 +259,58 @@ public class SubsetValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.pset == null) { - this.pset = SetEnumValue.convert(this); + this.pset = (SetEnumValue) this.toSetEnum(); } - else if (this.pset == DummyEnum) { + else if (this.pset == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.pset == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.pset == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.pset == DummyEnum) { this.pset = val; } + if (this.pset == SetEnumValue.DummyEnum) { this.pset = val; } } } } + @Override + public final Value toSetEnum() { + if (this.pset != null && this.pset != SetEnumValue.DummyEnum) { + return this.pset; + } + ValueVec vals = new ValueVec(this.size()); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + // For as long as pset.elements() (SubsetValue#elements) + // internally calls SubsetValue#elementsNormalized, the + // result SetEnumValue here is indeed normalized. + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, true, cm); + } + /* The string representation */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - boolean unlazy = expand; + boolean unlazy = TLCGlobals.expand; try { if (unlazy) { unlazy = this.set.size() < 7; } } - catch (Throwable e) { unlazy = false; } + catch (Throwable e) { if (swallow) unlazy = false; else throw e; } if (unlazy) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } else { sb = sb.append("SUBSET "); - sb = this.set.toString(sb, offset); + sb = this.set.toString(sb, offset, swallow); return sb; } } @@ -267,7 +322,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public Unrank getUnrank(final int kSubset) { // Convert outer set only once. - final SetEnumValue convert = SetEnumValue.convert(set); + final SetEnumValue convert = (SetEnumValue) set.toSetEnum(); convert.normalize(); final ValueVec elems = convert.elems; @@ -275,9 +330,9 @@ public class SubsetValue extends EnumerableValue implements Enumerable { Combinatorics.pascalTableUpTo(elems.size(), kSubset), elems, kSubset); } - public EnumerableValue getRandomSetOfSubsets(final int numOfSubsetsRequested, final int maxLengthOfSubsets) { + public Enumerable getRandomSetOfSubsets(final int numOfSubsetsRequested, final int maxLengthOfSubsets) { // Convert outer set only once. - final SetEnumValue convert = SetEnumValue.convert(set); + final SetEnumValue convert = (SetEnumValue) set.toSetEnum(); convert.normalize(); final ValueVec elems = convert.elems; final int size = elems.size(); @@ -312,15 +367,15 @@ public class SubsetValue extends EnumerableValue implements Enumerable { // number of subsets (will be close to its calculated n anyway). final RandomUnrank unrank = new RandomUnrank(rank, rank == kss.length - 1 ? numOfSubsetsRequested - vec.size() : n, ppt, elems, maxLengthOfSubsets, - EnumerableValue.getRandom()); + RandomEnumerableValues.get()); - Value subset; + Value subset; while ((subset = unrank.randomSubset()) != null && vec.size() < numOfSubsetsRequested) { vec.addElement(subset); } } assert vec.size() == numOfSubsetsRequested; - return new SetEnumValue(vec, false); + return new SetEnumValue(vec, false, cm); } public class Unrank { @@ -361,7 +416,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { vec.addElement(this.elems.elementAt(choice)); } } - return new SetEnumValue(vec, false); + return new SetEnumValue(vec, false, cm); } protected long memoizedBinomial(final int n, final int k) { @@ -399,7 +454,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { this.a = Math.abs(random.nextLong()) % n; } - public Value randomSubset() { + public Value randomSubset() { if (i < n) { return subsetAt(((x * i++) + a) % n); } @@ -414,13 +469,106 @@ public class SubsetValue extends EnumerableValue implements Enumerable { // duplicates). The alternative - a ValueVec which gets sorted to remove // duplicates after the while loops is slower. final int estimated = (int) (numOfPicks * probability); - final Collection<Value> sets = new HashSet<>(estimated); - Value val; + final Collection<Value > sets = new HashSet<>(estimated); + Value val; while ((val = enumerator.nextElement()) != null) { sets.add(val); } - return new SetEnumValue(new ValueVec(sets), false); + return new SetEnumValue(new ValueVec(sets), false, cm); + } + + private final ValueEnumeration emptyEnumeration = new ValueEnumeration() { + private boolean done = false; + + @Override + public void reset() { + done = false; + } + + @Override + public Value nextElement() { + if (done) { return null; } + done = true; + return new SetEnumValue(cm); + } + }; + + /** + * @see file SubsetValue.tla. + * <p> + * In addition, this generates all subsets of this SubsetValue instance which extends + * the order definition given in SubsetValue.tla such that a subset s is considered + * lower than t (s < t) if Cardinality(s) < Cardinality(t) \/ Definition in SubsetValue.tla. + * <p> + * The most noteworthy difference between bElements and + */ + final ValueEnumeration elementsNormalized() { + final int n = set.size(); + if (n == 0) { + emptyEnumeration.reset(); + return emptyEnumeration; + } + // Only normalized inputs will yield a normalized output. Note that SEV#convert + // (unfortunately) enumerates the input. Thus "SUBSET SUBSET 1..10" will result + // in the nested/right SUBSET to be fully enumerated (1..10 obviously too). + final ValueVec elems = ((SetEnumValue) set.toSetEnum().normalize()).elems; + return new ValueEnumeration() { + + private int k = 0; + private final int[] indices = new int[n]; + + @Override + public void reset() { + reset(0); + } + + private void reset(final int k) { + this.k = k; + if (k > n) { + return; + } + for (int i = 0; i < k; i++) { + indices[i] = i; + } + } + + @Override + public Value nextElement() { + if (k > n) { + return null; + } else if (k == 0) { + reset(k + 1); + return new SetEnumValue(cm); + } + + final ValueVec vals = new ValueVec(k); + int i = k - 1; + for (int j = i; j >= 0; j--) { + vals.addElementAt(elems.elementAt(indices[j]), j); + if (indices[j] + k - j == n) { + i = j - 1; + } + } + final SetEnumValue result = new SetEnumValue(vals, true, cm); + + if (indices[0] == n - k) { + // Increment k to generate the set of k-subset for this k. + reset(k + 1); + return result; + } + + // Increment the right element r by one and remember its old value. + indices[i]++; + + // Adjust all the elements right to the right element r. For all indices j > i, + // the element at j is set to p[i] + j. + for (i++; i < k; i++) { + indices[i] = indices[i - 1] + 1; + } + return result; + } + }; } /** @@ -447,21 +595,8 @@ public class SubsetValue extends EnumerableValue implements Enumerable { throw new IllegalArgumentException(); } if (k == 0) { - return new ValueEnumeration() { - private boolean done = false; - - @Override - public void reset() { - done = false; - } - - @Override - public Value nextElement() { - if (done) { return null; } - done = true; - return new SetEnumValue(); - } - }; + emptyEnumeration.reset(); + return emptyEnumeration; } return new KElementEnumerator(k); @@ -483,7 +618,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { throw new IllegalArgumentException("Subset too large."); } - final SetEnumValue convert = SetEnumValue.convert(set); + final SetEnumValue convert = (SetEnumValue) set.toSetEnum(); convert.normalize(); elems = convert.elems; @@ -525,7 +660,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { // ...right-shift zero-fill bits by one afterwards. bits = bits >>> 1; } - return new SetEnumValue(vals, false); + return new SetEnumValue(vals, false, cm); } public KElementEnumerator sort() { @@ -533,11 +668,20 @@ public class SubsetValue extends EnumerableValue implements Enumerable { return this; } } + + @Override + public ValueEnumeration elements(final Ordering ordering) { + // Use elementsNormalized regardless of requested ordering. Even for ordering + // UNDEFINED, elementsNormalized is fastest. + return elements(); + } public final ValueEnumeration elements() { try { - if (this.pset == null || this.pset == DummyEnum) { - return new Enumerator(); + if (this.pset == null || this.pset == SetEnumValue.DummyEnum) { + // See note on SetEnumValue#convert for SubsetValue wrt + // the normalized SetEnumValue result. + return elementsNormalized(); } return this.pset.elements(); } @@ -546,6 +690,10 @@ public class SubsetValue extends EnumerableValue implements Enumerable { else { throw e; } } } + + final ValueEnumeration elementsLexicographic() { + return new Enumerator(); + } final class Enumerator implements ValueEnumeration { private ValueVec elems; @@ -553,7 +701,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { public Enumerator() { //WARNING! Mutates the outer instance!? - set = SetEnumValue.convert(set); + set = set.toSetEnum(); set.normalize(); this.elems = ((SetEnumValue)set).elems; this.descriptor = new BitSet(this.elems.size()); @@ -564,34 +712,36 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } public final Value nextElement() { - if (this.descriptor == null) return null; - ValueVec vals = new ValueVec(); - int sz = this.elems.size(); - if (sz == 0) { - this.descriptor = null; - } - else { - for (int i = 0; i < sz; i++) { - if (this.descriptor.get(i)) { - vals.addElement(this.elems.elementAt(i)); - } - } - for (int i = 0; i < sz; i++) { - if (this.descriptor.get(i)) { - this.descriptor.clear(i); - if (i >= sz - 1) { - this.descriptor = null; - break; - } - } - else { - this.descriptor.set(i); - break; - } - } - } - return new SetEnumValue(vals, true); - } + if (this.descriptor == null) + return null; + ValueVec vals; + int sz = this.elems.size(); + if (sz == 0) { + vals = new ValueVec(0); + this.descriptor = null; + } else { + vals = new ValueVec(this.descriptor.cardinality()); + for (int i = 0; i < sz; i++) { + if (this.descriptor.get(i)) { + vals.addElement(this.elems.elementAt(i)); + } + } + for (int i = 0; i < sz; i++) { + if (this.descriptor.get(i)) { + this.descriptor.clear(i); + if (i >= sz - 1) { + this.descriptor = null; + break; + } + } else { + this.descriptor.set(i); + break; + } + } + } + if (coverage) { cm.incSecondary(vals.size()); } + return new SetEnumValue(vals, true, cm); + } } @@ -613,7 +763,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { SubsetEnumerator(final int k) { super(k, 1 << set.size()); - final SetEnumValue convert = SetEnumValue.convert(set); + final SetEnumValue convert = (SetEnumValue) set.toSetEnum(); convert.normalize(); this.elems = convert.elems; } @@ -634,7 +784,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { // ...right-shift zero-fill bits by one afterwards. bits = bits >>> 1; } - return new SetEnumValue(vals, false); + return new SetEnumValue(vals, false, cm); } } @@ -662,7 +812,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { this.numOfPicks = numOfPicks; this.probability = probability; - final SetEnumValue convert = SetEnumValue.convert(set); + final SetEnumValue convert = (SetEnumValue) set.toSetEnum(); convert.normalize(); this.elems = convert.elems; } @@ -675,12 +825,12 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } final ValueVec vals = new ValueVec(elems.size()); for (int i = 0; i < elems.size(); i++) { - if (EnumerableValue.getRandom().nextDouble() < probability) { + if (RandomEnumerableValues.get().nextDouble() < probability) { vals.addElement(elems.elementAt(i)); } } this.i++; - return new SetEnumValue(vals, false); + return new SetEnumValue(vals, false, cm); } private boolean hasNext() { diff --git a/tlatools/src/tlc2/value/impl/SubsetValue.tla b/tlatools/src/tlc2/value/impl/SubsetValue.tla new file mode 100644 index 0000000000000000000000000000000000000000..62e8d00ba8d90a49f024d167dc32e0217d48f4bb --- /dev/null +++ b/tlatools/src/tlc2/value/impl/SubsetValue.tla @@ -0,0 +1,124 @@ +-------------------------- MODULE SubsetValue -------------------------- +EXTENDS Sequences, FiniteSets, Integers + +(* + ASSUME Len(u) = Len(v) + + There exists a prefix p of u with length 0..Len(u)-1 s.t. + /\ \A i \in 1..p: u[i] <= v[i] + /\ u[p+1] < v[p+1] + In other words, if u < v then there exists a prefix of u of length 0..(Len(u)-1) + s.t. for all elements in the prefix of u are lower than the corresponding elements + in the prefix of v. +*) +Sorted(u, v) == \E p \in 0..(Len(u) - 1) : /\ \A q \in 1..p : u[q] <= v[q] + /\ (u[p+1] + 1) = v[p+1] + +----------------------------------------------------------------------------- + +CONSTANT N, + K + +ASSUME /\ \A nn \in N: nn \in Nat + /\ \A kk \in K: kk \in (Nat \ {0}) + \* n >= k \* Via a state constraint, to not explicitly handle this case in the + \* algorithm. It makes no sense to draw subsets of cardinality k + \* out of n elements if k > n. + +(* See Kunth's Volume 4 Fascicle 3, Generating All Combinations and Partitions (2005), + vi+150pp. ISBN 0-201-85394-9, http://www-cs-faculty.stanford.edu/~knuth/taocp.html + (also http://www.cs.utsa.edu/~wagner/knuth/). + "Efficiently Enumerating the Subsets of a Set" 2000 by Loughry, van Hemmert, and Schoofs + found at http://www.applied-math.org/subset.pdf describe the same idea from a different + perspective (providing a recursive algorithm). + + The purpuse of this algorithm is to generate the k-Subsets + { t \in SUBSET S : Cardinality(t) = k } out of the input set 0..(n-1) in a predefined + order. Even though sets have no notion of order, the technical representation of a set + in TLC has an order. This is e.g. important to efficiently determine equality of two + or more sets. If all sets adhere to a predefined order, equality can be determined + in O(n) time by a single pass over both sets. + Let u and v be to k-Subsets for a given k. The (total) order defined by this algorithm + is such that there exists a prefix p of u with length 0..Len(u)-1 s.t. + \A i \in 1..p: u[i] <= v[i] /\ u[p+1] < v[p+1] (see Sorted operator above). +--algorithm EnumerateSubsets { + variables n \in N; k \in K; + (* Represent sets as sequences because we are interested in order. *) + s = <<>>; r = <<>>; + i = 0; j = 0; + (* A strictly monotonically increasing sequence from 0 to k-1 used to + maintain the state of the algorithm. + Let k = 4 and n = 5. Initially, idx is [0,1,2,3] which corresponds to the + first k-Subset with the first, second, third, fourth element of the + original input set (which does not appear in this spec because it is + irrelevant for the actual algorithm). Next idx will change to [0,1,2,4], + followed by [0,1,2,5], [0,1,3,4], [0,1,3,5], ... *) + idx = [ii \in 0..(k - 1) |-> ii ]; + { + (* The while below first generates the current k-subset determined by the state + of idx and then mutates the state of idx to be ready to generate the next + k-subset in the subsequent iteration. *) + start: + while (TRUE) { + j := k - 1; i := k - 1; s := <<>>; + + (* The l1 loop serves two purposes: + 1) Generate the next k-Subset (depending on the state of idx) + by doing a full pass over idx from end to front. + 2) As a byproduct, determine the next index i of idx which + has to be incremented. + *) + l1: + while (j >= 0) { + \* 2) Determine next i. + if (idx[j] + k - j = n) { + i := j - 1; + }; + \* 1) Prepend idx[j] to seq s. + s := <<idx[j]>> \o s; j := j - 1; + }; + \* Add s to the set r of k-Subsets. + r := Append(r, s); + + l2: + if (idx[0] = n - k) { + goto Done; + } else { + (* Increment the i-th idx (by one) and for all higher indices + h of i set idx[h] to idx[i] + (h - i). *) + idx[i] := idx[i] + 1; i := i + 1; + + l3: + while (i < k) { + idx[i] := idx[i - 1] + 1; i := i + 1; + }; + }; + }; + } +} +*) +\* BEGIN TRANSLATION +\* omitted +\* END TRANSLATION + +----------------------------------------------------------------------------- +\* Invariant and helpers: + +SeqOfSeqsToSetOfSets(seq) == LET (* The image of function f with Op applied to each element f[x]. *) + ImageApply(f, Op(_)) == { Op(f[x]) : x \in DOMAIN f } + Image(f) == ImageApply(f, LAMBDA x : x) \* Lambda is just identy + IN ImageApply(seq, Image) + +(* The set S of all k-subsets ks (Cardinality(ks) = k) for the range 0 to n - 1. + In other words, this is the expected set of subsets to be generated by the + EnumerateSubsets above. *) +Expected == {ss \in SUBSET (0..(n-1)) : Cardinality(ss) = k } + +Inv == (pc = "Done") => \* When terminated... + \* ... the correct subsets have been generated... + /\ Expected = SeqOfSeqsToSetOfSets(r) + \* ... in the predefined order. + /\ \A ii \in 1..Len(r) - 1: Sorted(r[ii], r[ii+1]) + +============================================================================= + diff --git a/tlatools/src/tlc2/value/TupleValue.java b/tlatools/src/tlc2/value/impl/TupleValue.java similarity index 70% rename from tlatools/src/tlc2/value/TupleValue.java rename to tlatools/src/tlc2/value/impl/TupleValue.java index 7137f184247094f45d1cabc5e5737b75290d1448..b35bed3544e1dd6d737b754bb505154714e4d86a 100644 --- a/tlatools/src/tlc2/value/TupleValue.java +++ b/tlatools/src/tlc2/value/impl/TupleValue.java @@ -4,42 +4,63 @@ // modified on Mon 30 Apr 2007 at 15:30:09 PST by lamport // modified on Fri Aug 10 15:10:22 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; + +import java.io.IOException; -import tla2sany.semantic.SymbolNode; -import tlc2.tool.FingerprintException; import tlc2.output.EC; import tlc2.output.MP; import tlc2.tool.EvalControl; -import tlc2.util.Context; +import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.ITupleValue; +import tlc2.value.IValue; +import tlc2.value.IValueInputStream; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; -public class TupleValue extends Value implements Applicable { +public class TupleValue extends Value implements Applicable, ITupleValue { public final Value[] elems; // the elements of this tuple. + public final static TupleValue EmptyTuple = new TupleValue(new Value[0]); /* Constructor */ public TupleValue(Value[] elems) { this.elems = elems; } public TupleValue(Value v) { - this.elems = new Value[1]; + this(new Value[1]); this.elems[0] = v; } public TupleValue(Value v1, Value v2) { - this.elems = new Value[2]; + this(new Value[2]); this.elems[0] = v1; this.elems[1] = v2; } + public TupleValue(Value[] elems, CostModel cm) { + this(elems); + this.cm = cm; + } + + public IValue getElem(int idx) { + return elems[idx]; + } + + public IValue[] getElems() { + return elems; + } + public final byte getKind() { return TUPLEVALUE; } public final int compareTo(Object obj) { try { - TupleValue tv = convert(obj); + TupleValue tv = obj instanceof Value ? (TupleValue) ((Value)obj).toTuple() : null; if (tv == null) { // Well, we have to convert this to function and compare. - return FcnRcdValue.convert(this).compareTo(obj); + return this.toFcnRcd().compareTo(obj); } int len = this.elems.length; int cmp = len - tv.elems.length; @@ -59,10 +80,10 @@ public class TupleValue extends Value implements Applicable { public final boolean equals(Object obj) { try { - TupleValue tv = convert(obj); + TupleValue tv = obj instanceof Value ? (TupleValue) ((Value)obj).toTuple() : null; if (tv == null) { // Well, we have to convert this to function and compare. - return FcnRcdValue.convert(this).equals(obj); + return this.toFcnRcd().equals(obj); } int len = this.elems.length; if (len != tv.elems.length) @@ -99,10 +120,10 @@ public class TupleValue extends Value implements Applicable { } int idx = ((IntValue)arg).val; if (idx <= 0 || idx > this.elems.length) { - Assert.fail("Attempted to apply tuple\n" + ppr(this.toString()) + + Assert.fail("Attempted to apply tuple\n" + Values.ppr(this.toString()) + "\nto integer " + idx + " which is out of domain."); } - return this.elems[idx-1]; + return (Value) this.elems[idx-1]; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -127,11 +148,11 @@ public class TupleValue extends Value implements Applicable { try { if (!(arg instanceof IntValue)) { Assert.fail("Attempted to apply tuple to a non-integer argument " + - ppr(arg.toString()) + "."); + Values.ppr(arg.toString()) + "."); } int idx = ((IntValue)arg).val; if (idx > 0 && idx <= this.elems.length) { - return this.elems[idx-1]; + return (Value) this.elems[idx-1]; } return null; } @@ -158,7 +179,7 @@ public class TupleValue extends Value implements Applicable { } return new TupleValue(newElems); } - MP.printWarning(EC.TLC_WRONG_TUPLE_FIELD_NAME, new String[]{ppr(arcVal.toString())}); + MP.printWarning(EC.TLC_WRONG_TUPLE_FIELD_NAME, new String[]{Values.ppr(arcVal.toString())}); } return ex.value; } @@ -194,74 +215,35 @@ public class TupleValue extends Value implements Applicable { public final int size() { return this.elems.length; } - /* - * This method converts a value to a tuple value. It returns - * null if the conversion fails. - */ - public static TupleValue convert(Object val) { - if (val instanceof TupleValue) { - return (TupleValue)val; - } - else if (val instanceof FcnRcdValue) { - FcnRcdValue fcn = (FcnRcdValue)val; - if (fcn.intv != null) { - if (fcn.intv.low != 1) return null; - return new TupleValue(fcn.values); - } - int len = fcn.values.length; - Value[] elems = new Value[len]; - for (int i = 0; i < len; i++) { - if (!(fcn.domain[i] instanceof IntValue)) return null; - int idx = ((IntValue)fcn.domain[i]).val; - if (0 < idx && idx <= len) { - if (elems[idx-1] != null) return null; - elems[idx-1] = fcn.values[i]; + @Override + public final void deepNormalize() { + try { + for (int i = 0; i < elems.length; i++) { + elems[i].deepNormalize(); } - else { - return null; - } - } - return new TupleValue(elems); - } - else if (val instanceof FcnLambdaValue) { - FcnLambdaValue fcn = (FcnLambdaValue)val; - if (fcn.params.length() != 1) return null; - Value dom = fcn.params.domains[0]; - SymbolNode var = fcn.params.formals[0][0]; - if (dom instanceof IntervalValue) { - IntervalValue intv = (IntervalValue)dom; - if (intv.low != 1) return null; - Value[] elems = new Value[intv.high]; - for (int i = 1; i <= intv.high; i++) { - Context c1 = fcn.con.cons(var, IntValue.gen(i)); - elems[i-1] = fcn.tool.eval(fcn.body, c1, fcn.state, fcn.pstate, fcn.control); - } - return new TupleValue(elems); - } - else { - SetEnumValue eSet = SetEnumValue.convert(dom); - if (eSet == null) - Assert.fail("To convert a function of form [x \\in S |-> f(x)] " + - "to a tuple, the set S must be enumerable."); - eSet.normalize(); - int len = eSet.size(); - Value[] elems = new Value[len]; - for (int i = 0; i < len; i++) { - Value argVal = eSet.elems.elementAt(i); - if (!(argVal instanceof IntValue)) return null; - if (((IntValue)argVal).val != i + 1) return null; - Context c1 = fcn.con.cons(var, argVal); - elems[i] = fcn.tool.eval(fcn.body, c1, fcn.state, fcn.pstate, fcn.control); - } - return new TupleValue(elems); - } - } - else if ((val instanceof RecordValue) && - ((RecordValue)val).size() == 0) { - return EmptyTuple; - } - return null; + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + @Override + public final Value toTuple() { + return this; } + + @Override + public final Value toRcd() { + return size() == 0 ? RecordValue.EmptyRcd : super.toRcd(); + } + + @Override + public final Value toFcnRcd() { + final IntervalValue intv = new IntervalValue(1, this.elems.length); + if (coverage) {cm.incSecondary(this.elems.length);} + return new FcnRcdValue(intv, this.elems, cm); + } /* The normalization of the value. */ public final boolean isNormalized() { return true; } @@ -282,11 +264,11 @@ public class TupleValue extends Value implements Applicable { } } - public final Value deepCopy() { + public final IValue deepCopy() { try { - Value[] vals = new Value[this.elems.length]; + Value[] vals = new Value[this.elems.length]; for (int i = 0; i < this.elems.length; i++) { - vals[i] = this.elems[i].deepCopy(); + vals[i] = (Value) this.elems[i].deepCopy(); } return new TupleValue(vals); } @@ -312,6 +294,22 @@ public class TupleValue extends Value implements Applicable { } } + @Override + public final void write(IValueOutputStream vos) throws IOException { + final int index = vos.put(this); + if (index == -1) { + vos.writeByte(TUPLEVALUE); + final int len = elems.length; + vos.writeNat(len); + for (int i = 0; i < len; i++) { + elems[i].write(vos); + } + } else { + vos.writeByte(DUMMYVALUE); + vos.writeNat(index); + } + } + /* The fingerprint method: tuples are functions. */ public final long fingerPrint(long fp) { try { @@ -331,12 +329,12 @@ public class TupleValue extends Value implements Applicable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { - Value[] vals = new Value[this.elems.length]; + Value[] vals = new Value[this.elems.length]; boolean changed = false; for (int i = 0; i < vals.length; i++) { - vals[i] = this.elems[i].permute(perm); + vals[i] = (Value) this.elems[i].permute(perm); changed = changed || (vals[i] != this.elems[i]); } if (changed) { @@ -351,16 +349,16 @@ public class TupleValue extends Value implements Applicable { } /* The string representation of this value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { sb.append("<<"); int len = this.elems.length; if (len > 0) { - sb = this.elems[0].toString(sb, offset); + sb = this.elems[0].toString(sb, offset, swallow); } for (int i = 1; i < len; i++) { sb = sb.append(", "); - sb = this.elems[i].toString(sb, offset); + sb = this.elems[i].toString(sb, offset, swallow); } sb.append(">>"); return sb; @@ -371,4 +369,15 @@ public class TupleValue extends Value implements Applicable { } } + public static IValue createFrom(final IValueInputStream vos) throws IOException { + final int index = vos.getIndex(); + final int len = vos.readNat(); + final Value[] elems = new Value[len]; + for (int i = 0; i < len; i++) { + elems[i] = (Value) vos.read(); + } + final Value res = new TupleValue(elems); + vos.assign(res, index); + return res; + } } diff --git a/tlatools/src/tlc2/value/UndefValue.java b/tlatools/src/tlc2/value/impl/UndefValue.java similarity index 84% rename from tlatools/src/tlc2/value/UndefValue.java rename to tlatools/src/tlc2/value/impl/UndefValue.java index 01fbbc9f837c9dd431e706b071850436ffa5be08..a7ff40a913495b6b2f1938661adb0dd702cb2b1e 100644 --- a/tlatools/src/tlc2/value/UndefValue.java +++ b/tlatools/src/tlc2/value/impl/UndefValue.java @@ -4,13 +4,17 @@ // modified on Mon 30 Apr 2007 at 13:21:06 PST by lamport // modified on Tue Aug 15 23:08:23 PDT 2000 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tlc2.tool.FingerprintException; +import tlc2.value.IValue; +import tlc2.value.Values; import util.Assert; public class UndefValue extends Value { + public final static UndefValue ValUndef = new UndefValue(); + public UndefValue() { /*SKIP*/ } public byte getKind() { return UNDEFVALUE; } @@ -37,8 +41,8 @@ public class UndefValue extends Value { public final boolean member(Value elem) { try { - Assert.fail("Attempted to check if the value:\n" + ppr(elem.toString()) + - "\nis an element " + ppr(this.toString())); + Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) + + "\nis an element " + Values.ppr(this.toString())); return false; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -49,7 +53,7 @@ public class UndefValue extends Value { public final boolean isFinite() { try { - Assert.fail("Attempted to check if the value " + ppr(this.toString()) + + Assert.fail("Attempted to check if the value " + Values.ppr(this.toString()) + " is a finite set."); return false; // make compiler happy } @@ -63,7 +67,7 @@ public class UndefValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT construct to the value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -77,7 +81,7 @@ public class UndefValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT construct to the value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -90,7 +94,7 @@ public class UndefValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -105,12 +109,12 @@ public class UndefValue extends Value { public final boolean isDefined() { return false; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { return true; } /* The string representation. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { return sb.append("UNDEF"); } diff --git a/tlatools/src/tlc2/value/UnionValue.java b/tlatools/src/tlc2/value/impl/UnionValue.java similarity index 73% rename from tlatools/src/tlc2/value/UnionValue.java rename to tlatools/src/tlc2/value/impl/UnionValue.java index 534206c9fda80eb252b251f55a91c1e307e9d104..f694bf0a26fd481dd65b74c853dc7254bc2f885a 100644 --- a/tlatools/src/tlc2/value/UnionValue.java +++ b/tlatools/src/tlc2/value/impl/UnionValue.java @@ -4,13 +4,21 @@ // modified on Mon 30 Apr 2007 at 13:46:50 PST by lamport // modified on Fri Aug 10 15:10:39 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; +import java.io.IOException; + +import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.Values; import util.Assert; public class UnionValue extends EnumerableValue implements Enumerable { - public Value set; + public final Value set; protected SetEnumValue realSet; /* Constructor */ @@ -19,6 +27,11 @@ public class UnionValue extends EnumerableValue implements Enumerable { this.realSet = null; } + public UnionValue(Value val, CostModel cm) { + this(val); + this.cm = cm; + } + public byte getKind() { return UNIONVALUE; } public final int compareTo(Object obj) { @@ -46,9 +59,9 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final boolean member(Value elem) { try { if (!(this.set instanceof Enumerable)) { - Assert.fail("Attempted to check if:\n " + ppr(elem.toString()) + + Assert.fail("Attempted to check if:\n " + Values.ppr(elem.toString()) + "\nis an element of the non-enumerable set:\n " + - ppr(this.toString())); + Values.ppr(this.toString())); } ValueEnumeration Enum = ((Enumerable)this.set).elements(); Value val; @@ -66,7 +79,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final boolean isFinite() { try { if (!(this.set instanceof Enumerable)) { - Assert.fail("Attempted to check if the nonenumerable set:\n" + ppr(this.toString()) + + Assert.fail("Attempted to check if the nonenumerable set:\n" + Values.ppr(this.toString()) + "\nis a finite set."); } ValueEnumeration Enum = ((Enumerable)this.set).elements(); @@ -85,7 +98,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept ex) { try { if (ex.idx < ex.path.length) { - Assert.fail("Attempted to apply EXCEPT to the set:\n" + ppr(this.toString())); + Assert.fail("Attempted to apply EXCEPT to the set:\n" + Values.ppr(this.toString())); } return ex.value; } @@ -98,7 +111,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final Value takeExcept(ValueExcept[] exs) { try { if (exs.length != 0) { - Assert.fail("Attempted to apply EXCEPT to the set:\n " + ppr(this.toString()) + "."); + Assert.fail("Attempted to apply EXCEPT to the set:\n " + Values.ppr(this.toString()) + "."); } return this; } @@ -122,7 +135,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final boolean isNormalized() { try { return (this.realSet != null && - this.realSet != DummyEnum && + this.realSet != SetEnumValue.DummyEnum && this.realSet.isNormalized()); } catch (RuntimeException | OutOfMemoryError e) { @@ -133,7 +146,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final Value normalize() { try { - if (this.realSet != null && this.realSet != DummyEnum) { + if (this.realSet != null && this.realSet != SetEnumValue.DummyEnum) { this.realSet.normalize(); } return this; @@ -144,6 +157,22 @@ public class UnionValue extends EnumerableValue implements Enumerable { } } + @Override + public final void deepNormalize() { + try { + if (realSet == null) { + realSet = SetEnumValue.DummyEnum; + } + else if (realSet != SetEnumValue.DummyEnum) { + realSet.deepNormalize(); + } + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + public final boolean isDefined() { try { return this.set.isDefined(); @@ -154,7 +183,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { } } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -176,20 +205,27 @@ public class UnionValue extends EnumerableValue implements Enumerable { } if (canCombine) { ValueVec resElems = new ValueVec(); - Value result = new SetEnumValue(resElems, false); + Value result = new SetEnumValue(resElems, false, val.getCostModel()); for (int i = 0; i < elems.size(); i++) { ValueVec elems1 = ((SetEnumValue)elems.elementAt(i)).elems; for (int j = 0; j < elems1.size(); j++) { - Value elem = elems1.elementAt(j); - if (!result.member(elem)) resElems.addElement(elem); + Value elem = elems1.elementAt(j); + if (!result.member(elem)) { + resElems.addElement(elem); + } } } return result; } } - return new UnionValue(val); + return new UnionValue(val, val.getCostModel()); } + @Override + public void write(final IValueOutputStream vos) throws IOException { + realSet.write(vos); + } + /* The fingerprint */ public final long fingerPrint(long fp) { try { @@ -202,7 +238,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { } } - public final Value permute(MVPerm perm) { + public final IValue permute(IMVPerm perm) { try { this.convertAndCache(); return this.realSet.permute(perm); @@ -215,32 +251,47 @@ public class UnionValue extends EnumerableValue implements Enumerable { private final void convertAndCache() { if (this.realSet == null) { - this.realSet = SetEnumValue.convert(this); + this.realSet = (SetEnumValue) this.toSetEnum(); } - else if (this.realSet == DummyEnum) { + else if (this.realSet == SetEnumValue.DummyEnum) { SetEnumValue val = null; synchronized(this) { - if (this.realSet == DummyEnum) { - val = SetEnumValue.convert(this); + if (this.realSet == SetEnumValue.DummyEnum) { + val = (SetEnumValue) this.toSetEnum(); val.deepNormalize(); } } synchronized(this) { - if (this.realSet == DummyEnum) { this.realSet = val; } + if (this.realSet == SetEnumValue.DummyEnum) { this.realSet = val; } } } } + @Override + public final Value toSetEnum() { + if (this.realSet != null && this.realSet != SetEnumValue.DummyEnum) { + return this.realSet; + } + ValueVec vals = new ValueVec(); + ValueEnumeration Enum = this.elements(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + if (coverage) {cm.incSecondary(vals.size());} + return new SetEnumValue(vals, false, cm); + } + /* String representation of this value. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - if (expand) { - Value val = SetEnumValue.convert(this); - return val.toString(sb, offset); + if (TLCGlobals.expand) { + Value val = this.toSetEnum(); + return val.toString(sb, offset, swallow); } else { sb = sb.append("UNION("); - sb = this.set.toString(sb, offset); + sb = this.set.toString(sb, offset, swallow); sb.append(")"); return sb; } @@ -253,7 +304,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public final ValueEnumeration elements() { try { - if (this.realSet == null || this.realSet == DummyEnum) { + if (this.realSet == null || this.realSet == SetEnumValue.DummyEnum) { return new Enumerator(); } return this.realSet.elements(); @@ -272,7 +323,7 @@ public class UnionValue extends EnumerableValue implements Enumerable { public Enumerator() { if (!(set instanceof Enumerable)) { Assert.fail("Attempted to enumerate the nonenumerable set:\n"+ - ppr(this.toString())); + Values.ppr(this.toString())); } this.Enum = ((Enumerable)set).elements(); this.elemSet = this.Enum.nextElement(); @@ -298,12 +349,13 @@ public class UnionValue extends EnumerableValue implements Enumerable { if (this.elemSet == null) return null; if (!(this.elemSet instanceof Enumerable)) { Assert.fail("Attempted to enumerate the nonenumerable set:\n" + - ppr(this.elemSet.toString()) + - "\nwhen enumerating:\n" + ppr(this.toString())); + Values.ppr(this.elemSet.toString()) + + "\nwhen enumerating:\n" + Values.ppr(this.toString())); } this.elemSetEnum = ((Enumerable)this.elemSet).elements(); val = this.nextElement(); } + if (coverage) { cm.incSecondary(); } return val; } diff --git a/tlatools/src/tlc2/value/UserObj.java b/tlatools/src/tlc2/value/impl/UserObj.java similarity index 90% rename from tlatools/src/tlc2/value/UserObj.java rename to tlatools/src/tlc2/value/impl/UserObj.java index 63f5c81d63e8a6e86f3a902f0f59eec51e850b10..a12baa077ea76693db032a66c21484fd82ad9e4c 100644 --- a/tlatools/src/tlc2/value/UserObj.java +++ b/tlatools/src/tlc2/value/impl/UserObj.java @@ -3,8 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:21:09 PST by lamport // modified on Mon Aug 20 10:53:55 PDT 2001 by yuanyu -package tlc2.value; - +package tlc2.value.impl; public abstract class UserObj { @@ -17,11 +16,11 @@ public abstract class UserObj { public abstract boolean isFinite(); /* The String representation. */ - public abstract StringBuffer toString(StringBuffer sb, int offset); + public abstract StringBuffer toString(StringBuffer sb, int offset, boolean swallow); public final String toString() { StringBuffer sb = new StringBuffer(); - sb = this.toString(sb, 0); + sb = this.toString(sb, 0, true); return sb.toString(); } diff --git a/tlatools/src/tlc2/value/UserValue.java b/tlatools/src/tlc2/value/impl/UserValue.java similarity index 87% rename from tlatools/src/tlc2/value/UserValue.java rename to tlatools/src/tlc2/value/impl/UserValue.java index 2c9416413700a70c9449819485367286234445f1..0b9e14a98cf877ea6b5b7b1d31f87480f5a03da5 100644 --- a/tlatools/src/tlc2/value/UserValue.java +++ b/tlatools/src/tlc2/value/impl/UserValue.java @@ -4,9 +4,11 @@ // modified on Mon 30 Apr 2007 at 13:21:09 PST by lamport // modified on Fri May 11 15:14:04 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tlc2.tool.FingerprintException; +import tlc2.value.IValue; +import tlc2.value.Values; import util.Assert; public class UserValue extends Value { @@ -22,8 +24,8 @@ public class UserValue extends Value { return this.userObj.compareTo((Value)obj); } if (!(obj instanceof ModelValue)) - Assert.fail("Attempted to compare overridden value " + ppr(this.toString()) + - " with non-overridden value:\n" + ppr(obj.toString())); + Assert.fail("Attempted to compare overridden value " + Values.ppr(this.toString()) + + " with non-overridden value:\n" + Values.ppr(obj.toString())); return 1; } catch (RuntimeException | OutOfMemoryError e) { @@ -66,7 +68,7 @@ public class UserValue extends Value { try { if (ex.idx < ex.path.length) { Assert.fail("Attempted to apply EXCEPT to the overridden value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return ex.value; } @@ -80,7 +82,7 @@ public class UserValue extends Value { try { if (exs.length != 0) { Assert.fail("Attempted to apply EXCEPT to the overridden value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); } return this; } @@ -93,7 +95,7 @@ public class UserValue extends Value { public final int size() { try { Assert.fail("Attempted to compute the number of elements in the overridden value " + - ppr(this.toString()) + "."); + Values.ppr(this.toString()) + "."); return 0; // make compiler happy } catch (RuntimeException | OutOfMemoryError e) { @@ -109,7 +111,7 @@ public class UserValue extends Value { public final boolean isDefined() { return true; } - public final Value deepCopy() { return this; } + public final IValue deepCopy() { return this; } public final boolean assignable(Value val) { try { @@ -122,9 +124,9 @@ public class UserValue extends Value { } /* The string representation. */ - public final StringBuffer toString(StringBuffer sb, int offset) { + public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { try { - return this.userObj.toString(sb, offset); + return this.userObj.toString(sb, offset, swallow); } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/impl/Value.java b/tlatools/src/tlc2/value/impl/Value.java new file mode 100644 index 0000000000000000000000000000000000000000..ab6741f63b9cc6efb5c81381f5556c906d6473af --- /dev/null +++ b/tlatools/src/tlc2/value/impl/Value.java @@ -0,0 +1,339 @@ +// Copyright (c) 2003 Compaq Corporation. All rights reserved. +// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. +// Last modified on Wed 12 Jul 2017 at 16:10:00 PST by ian morris nieves +// modified on Mon 30 Apr 2007 at 15:30:13 PST by lamport +// modified on Wed Dec 5 23:18:07 PST 2001 by yuanyu + +package tlc2.value.impl; + +import java.io.IOException; +import java.io.Serializable; + +import tla2sany.semantic.SemanticNode; +import tlc2.TLCGlobals; +import tlc2.tool.FingerprintException; +import tlc2.tool.coverage.CostModel; +import tlc2.util.FP64; +import tlc2.value.IMVPerm; +import tlc2.value.IValue; +import tlc2.value.IValueOutputStream; +import tlc2.value.ValueConstants; +import tlc2.value.Values; +import util.Assert; +import util.WrongInvocationException; + +public abstract class Value implements ValueConstants, Serializable, IValue { + + private static final String[] ValueImage = { + "a Boolean value", // "BoolValue", + "an integer", // "IntValue", + "a real", // "RealValue", + "a string", // "StringValue", + "a record", // "RecordValue", + "a set of the form {e1, ... ,eN}", // "SetEnumValue", + "a set of the form {x \\in S : expr}", // "SetPredValue", + "a tuple", // "TupleValue", + "a function of the form [x \\in S |-> expr]", // "FcnLambdaValue", + "a function of the form (d1 :> e1 @@ ... @@ dN :> eN)", // "FcnRcdValue", + "an operator", // "OpLambdaValue", + "a constant operator", // "OpRcdValue", + "a java method", // "MethodValue", + "a set of the form [S -> T]", // "SetOfFcnsValue", + "a set of the form [d1 : S1, ... , dN : SN]", // "SetOfRcdsValue", + "a cartesian product", // "SetOfTuplesValue", + "a set of the form SUBSET S", // "SubsetValue", + "a set of the form S \\ T", // "SetDiffValue", + "a set of the form S \\cap T", // "SetCapValue", + "a set of the form S \\cup T", // "SetCupValue", + "a set of the form UNION S", // "UnionValue", + "a model value", // "ModelValue", + "a special set constant", // "UserValue", + "a set of the form i..j", // "IntervalValue", + "an undefined value", // "UndefValue", + "a value represented in lazy form", // "LazyValue", + "a dummy for not-a-value", // "DummyValue", + }; + + /** + * @see See note on performance in CostModelCreator. + */ + protected static final boolean coverage = TLCGlobals.isCoverageEnabled(); + /** + * For each kind of value, we introduce a subclass of Value. + * All the subclasses are given in this value package. + * This method returns the value kind: an integer that represents + * the kind of this value. See the interface ValueConstants.java. + */ + public abstract byte getKind(); + + public String getKindString() { + try { + return ValueImage[this.getKind()]; + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /* This method returns true iff elem is a member of this. */ + public abstract boolean member(Value elem); + + /* This method returns a new value after taking the except. */ + public abstract Value takeExcept(ValueExcept ex); + + /* This method returns a new value after taking the excepts. */ + public abstract Value takeExcept(ValueExcept[] exs); + + /* This method returns true iff val can be assigned to this. */ + abstract boolean assignable(Value val); + + public abstract Value normalize(); + + @Override + public void write(IValueOutputStream vos) throws IOException { + throw new WrongInvocationException("ValueOutputStream: Can not pickle the value\n" + + Values.ppr(toString())); + } + + public transient CostModel cm = CostModel.DO_NOT_RECORD; + + @Override + public IValue setCostModel(CostModel cm) { + this.cm = cm; + return this; + } + + @Override + public CostModel getCostModel() { + return this.cm; + } + + /** + * These methods allow storage and retrieval of the SemanticNode used to create the Value, + * which is helpful for FingerprintException. + */ + private transient SemanticNode source = null; + + @Override + public void setSource(final SemanticNode semanticNode) { + source = semanticNode; + } + + @Override + public SemanticNode getSource() { + return source; + } + + @Override + public boolean hasSource() { + return source != null; + } + + public final boolean isEmpty() { + try { + + switch (this.getKind()) { + case SETENUMVALUE: + { + SetEnumValue set = (SetEnumValue)this; + return set.elems.size() == 0; + } + case INTERVALVALUE: + { + IntervalValue intv = (IntervalValue)this; + return intv.size() == 0; + } + case SETCAPVALUE: + { + SetCapValue cap = (SetCapValue)this; + return cap.elements().nextElement() == null; + } + case SETCUPVALUE: + { + SetCupValue cup = (SetCupValue)this; + return cup.elements().nextElement() == null; + } + case SETDIFFVALUE: + { + SetDiffValue diff = (SetDiffValue)this; + return diff.elements().nextElement() == null; + } + case SETOFFCNSVALUE: + { + SetOfFcnsValue fcns = (SetOfFcnsValue)this; + return fcns.elements().nextElement() == null; + } + case SETOFRCDSVALUE: + { + SetOfRcdsValue srv = (SetOfRcdsValue)this; + return srv.elements().nextElement() == null; + } + case SETOFTUPLESVALUE: + { + SetOfTuplesValue stv = (SetOfTuplesValue)this; + return stv.elements().nextElement() == null; + } + case SUBSETVALUE: + { + // SUBSET S is never empty. (It always contains {}.) + return false; + } + case UNIONVALUE: + { + UnionValue uv = (UnionValue)this; + return uv.elements().nextElement() == null; + } + case SETPREDVALUE: + { + SetPredValue spv = (SetPredValue)this; + return spv.elements().nextElement() == null; + } + default: + Assert.fail("Shouldn't call isEmpty() on value " + Values.ppr(this.toString())); + return false; + } + + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /* Fully normalize this (composite) value. */ + @Override + public void deepNormalize() { + } + + /* This method returns the fingerprint of this value. */ + @Override + public long fingerPrint(long fp) { + try { + Assert.fail("TLC has found a state in which the value of a variable contains " + + Values.ppr(this.toString())); // SZ Feb 24, 2009: changed to static access + return 0; // make compiler happy + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /** + * This method returns the value permuted by the permutation. It + * returns this if nothing is permuted. + */ + @Override + public IValue permute(IMVPerm perm) { + try { + Assert.fail("TLC has found a state in which the value of a variable contains " + + Values.ppr(this.toString())); // SZ Feb 24, 2009: changed to static access + return null; // make compiler happy + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /* This method returns the hash code of this value. */ + @Override + public final int hashCode() { + try { + long fp = this.fingerPrint(FP64.New()); + int high = (int)(fp >> 32); + int low = (int)fp; + return high ^ low; + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /** + * This method selects the component of this value. The component is + * specified by path. + */ + public final Value select(Value[] path) { + try { + Value result = this; + for (int i = 0; i < path.length; i++) { + if (!(result instanceof Applicable)) { + Assert.fail("Attempted to apply EXCEPT construct to the value " + + Values.ppr(result.toString()) + "."); + } + Value elem = path[i]; + result = ((Applicable)result).select(elem); + if (result == null) return null; + } + return result; + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } + + /* Convert val into a SetEnumValue. Returns null if not possible. */ + public Value toSetEnum() { + return null; + } + + /* + * This method converts a value to a function value. It returns + * null if the conversion fails. + */ + public Value toFcnRcd() { + return null; + } + + /* + * This method converts a value to a function value. It returns + * null if the conversion fails. + */ + public Value toRcd() { + return null; + } + + /* + * This method converts a value to a tuple value. It returns + * null if the conversion fails. + */ + public Value toTuple() { + return null; + } + + /* The string representation of this value */ + @Override + public final String toString() { + return toStringImpl("", true); + } + + /* Same as toString except that nested exceptions won't be silently discarded */ + public final String toStringUnchecked() { + return toStringImpl("", false); + } + + @Override + public final String toString(final String delim) { + return toStringImpl(delim, true); + } + + public final String toStringUnchecked(final String delim) { + return toStringImpl(delim, false); + } + + private final String toStringImpl(final String delim, final boolean checked) { + try { + final StringBuffer sb = this.toString(new StringBuffer(), 0, checked); + sb.append(delim); + return sb.toString(); + } + catch (RuntimeException | OutOfMemoryError e) { + if (hasSource()) { throw FingerprintException.getNewHead(this, e); } + else { throw e; } + } + } +} diff --git a/tlatools/src/tlc2/value/ValueEnumeration.java b/tlatools/src/tlc2/value/impl/ValueEnumeration.java similarity index 97% rename from tlatools/src/tlc2/value/ValueEnumeration.java rename to tlatools/src/tlc2/value/impl/ValueEnumeration.java index b213f0ecc6b5fe0f1fe5a55d066833a5b4e1f336..4e8037fb21e3ab647c7eadd34993a9d1d0ad787f 100644 --- a/tlatools/src/tlc2/value/ValueEnumeration.java +++ b/tlatools/src/tlc2/value/impl/ValueEnumeration.java @@ -3,7 +3,7 @@ // Last modified on Mon 30 Apr 2007 at 13:21:10 PST by lamport // modified on Tue Aug 22 11:56:52 PDT 2000 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.util.ArrayList; import java.util.List; diff --git a/tlatools/src/tlc2/value/ValueExcept.java b/tlatools/src/tlc2/value/impl/ValueExcept.java similarity index 72% rename from tlatools/src/tlc2/value/ValueExcept.java rename to tlatools/src/tlc2/value/impl/ValueExcept.java index 8f4e67aad7a54fd8953c07912ecc1f5e62f77665..6dcdf261e15e16b3b5f884c1da6b76e534a18355 100644 --- a/tlatools/src/tlc2/value/ValueExcept.java +++ b/tlatools/src/tlc2/value/impl/ValueExcept.java @@ -3,7 +3,7 @@ // Last modified on Wed 4 Jul 2007 at 17:31:51 PST by lamport // modified on Wed Jul 25 11:04:30 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import tla2sany.semantic.FormalParamNode; @@ -12,7 +12,7 @@ public class ValueExcept { public Value value; public int idx; - public ValueExcept(Value[] lhs, Value rhs) { + public ValueExcept(Value [] lhs, Value rhs) { this.path = lhs; this.value = rhs; this.idx = 0; @@ -25,17 +25,17 @@ public class ValueExcept { } public final ValueExcept checkArg(FcnLambdaValue fcn) { - Value argv = this.path[idx]; - if (fcn.params.length() == 1) { - if (!fcn.params.domains[0].member(argv)) return null; + Value argv = this.path[idx]; + if (fcn.getParams().length() == 1) { + if (!fcn.getParams().domains[0].member(argv)) return null; } else { TupleValue tval = (TupleValue)argv; - Value[] argList = tval.elems; - FormalParamNode[][] formals = fcn.params.formals; - Value[] domains = fcn.params.domains; + Value [] argList = tval.elems; + FormalParamNode[][] formals = fcn.getParams().formals; + Value [] domains = fcn.getParams().domains; int argn = 0; - for (int i = 0; i < fcn.params.formals.length; i++) { + for (int i = 0; i < fcn.getParams().formals.length; i++) { FormalParamNode[] formal = formals[i]; for (int j = 0; j < formal.length; j++) { if (!domains[i].member(argList[argn++])) return null; @@ -45,7 +45,7 @@ public class ValueExcept { return this; } - public final Value current() { return this.path[this.idx]; } + public final Value current() { return this.path[this.idx]; } public final boolean isLast() { return this.idx == (this.path.length - 1); diff --git a/tlatools/src/tlc2/value/ValueVec.java b/tlatools/src/tlc2/value/impl/ValueVec.java similarity index 79% rename from tlatools/src/tlc2/value/ValueVec.java rename to tlatools/src/tlc2/value/impl/ValueVec.java index a5446377b5d19fdf0ab0064af2dc6b877ae124ac..8e0edc89d4956a823e5f16c1210d206f519390a4 100644 --- a/tlatools/src/tlc2/value/ValueVec.java +++ b/tlatools/src/tlc2/value/impl/ValueVec.java @@ -3,7 +3,7 @@ // Last modified on Tue 1 May 2007 at 13:40:06 PST by lamport // modified on Tue Aug 21 17:02:26 PDT 2001 by yuanyu -package tlc2.value; +package tlc2.value.impl; import java.io.Serializable; import java.util.Collection; @@ -12,10 +12,10 @@ import tlc2.TLCGlobals; import util.WrongInvocationException; public class ValueVec implements Cloneable, Serializable { - private Value[] elementData; + private Value [] elementData; private int elementCount; - static private final Value[] empty = new Value[0]; + static private final Value [] empty = new Value [0]; public ValueVec() { this(10); } @@ -25,21 +25,25 @@ public class ValueVec implements Cloneable, Serializable { this.elementData = empty; } else { - this.elementData = new Value[initialCapacity]; + this.elementData = new Value [initialCapacity]; } } - public ValueVec(Value[] elems) { + public ValueVec(Value [] elems) { this.elementData = elems; this.elementCount = elems.length; } - public ValueVec(Collection<Value> elems) { + public ValueVec(Collection<Value > elems) { this(elems.size()); - for (Value value : elems) { + for (Value value : elems) { addElement(value); } } + public final void addElementAt(Value val, int index) { + this.elementData[index] = val; + this.elementCount++; + } public final void addElement(Value val) { if (this.elementCount == this.elementData.length) { @@ -48,7 +52,7 @@ public class ValueVec implements Cloneable, Serializable { this.elementData[this.elementCount++] = val; } - public final void addElement1(Value val) { + public final void addElement1(Value val) { if (this.elementCount == this.elementData.length) { ensureCapacity(this.elementCount+1); } @@ -77,15 +81,15 @@ public class ValueVec implements Cloneable, Serializable { return v; } - public final boolean contains(Value elem) { + public final boolean contains(Value elem) { return (indexOf(elem) != -1); } - public final void copyInto(Value anArray[]) { + public final void copyInto(Value anArray[]) { System.arraycopy(elementData, 0, anArray, 0, elementCount); } - public final Value elementAt(int index) { + public final Value elementAt(int index) { // Assert.check(index < this.elementCount); return this.elementData[index]; } @@ -103,25 +107,25 @@ public class ValueVec implements Cloneable, Serializable { if (newCapacity > TLCGlobals.setBound) { newCapacity = TLCGlobals.setBound; } - Value oldData[] = this.elementData; - this.elementData = new Value[newCapacity]; + Value oldData[] = this.elementData; + this.elementData = new Value [newCapacity]; System.arraycopy(oldData, 0, elementData, 0, elementCount); } } - public final Value firstElement() { return this.elementData[0]; } + public final Value firstElement() { return this.elementData[0]; } - public final int indexOf(Value elem) { return indexOf(elem, 0); } + public final int indexOf(Value elem) { return indexOf(elem, 0); } - public final int indexOf(Value elem, int index) { + public final int indexOf(Value elem, int index) { for (int pos = index; pos < elementCount; pos++) { if (elem.equals(elementData[pos])) return pos; } return -1; } - public final void insertElementAt(Value obj, int index) { + public final void insertElementAt(Value obj, int index) { if (elementCount == elementData.length) { this.ensureCapacity(elementCount+1); } @@ -132,18 +136,18 @@ public class ValueVec implements Cloneable, Serializable { public final boolean isEmpty() { return (elementCount == 0); } - public final Value lastElement() { + public final Value lastElement() { return this.elementData[this.elementCount-1]; } - public final void setElementAt(Value obj, int index) { + public final void setElementAt(Value obj, int index) { this.elementData[index] = obj; } public final int size() { return this.elementCount; } /* Assume that the elements are sorted. */ - public final boolean search(Value elem, boolean sorted) { + public final boolean search(Value elem, boolean sorted) { if (sorted) { int cmp = 0, mid = 0, low = 0, high = this.elementCount; while (low < high) { @@ -171,7 +175,7 @@ public class ValueVec implements Cloneable, Serializable { public final ValueVec sort(boolean noDup) { int newCount = (this.elementCount == 0) ? 0 : 1; for (int i = 1; i < this.elementCount; i++) { - Value elem = this.elementData[i]; + Value elem = this.elementData[i]; int cmp = 0, idx = 0, low = 0, high = newCount; while (low < high) { idx = (low + high) >> 1; @@ -212,8 +216,8 @@ public class ValueVec implements Cloneable, Serializable { return sb.toString(); } - public Value[] toArray() { - final Value[] copy = new Value[elementCount]; + public Value [] toArray() { + final Value [] copy = new Value [elementCount]; System.arraycopy(elementData, 0, copy, 0, elementCount); return copy; } diff --git a/tlatools/src/util/Assert.java b/tlatools/src/util/Assert.java index 90fae76922d60fc2e2f951e8e447b79d3f6da51d..3cb19484effaab388ec095bbd92ed3663fe750da 100644 --- a/tlatools/src/util/Assert.java +++ b/tlatools/src/util/Assert.java @@ -4,7 +4,6 @@ package util; -import tlc2.output.EC; import tlc2.output.MP; /** @@ -17,7 +16,6 @@ public class Assert /** * Unconditioned way to throw an exception * @param reason the explaining message to be enclosed into the exception - * @deprecated Use {@link EC} constants instead */ public static void fail(String reason) throws RuntimeException { @@ -31,7 +29,7 @@ public class Assert */ public static void fail(int errorCode, String[] parameters) { - throw new TLCRuntimeException(errorCode, MP.getMessage(errorCode, parameters)); + throw new TLCRuntimeException(errorCode, parameters, MP.getMessage(errorCode, parameters)); } /** @@ -41,7 +39,7 @@ public class Assert */ public static void fail(int errorCode, String parameter) { - throw new TLCRuntimeException(errorCode, MP.getMessage(errorCode, parameter)); + throw new TLCRuntimeException(errorCode, new String[] {parameter}, MP.getMessage(errorCode, parameter)); } /** @@ -74,7 +72,7 @@ public class Assert { if (!condition) { - throw new TLCRuntimeException(errorCode, MP.getMessage(errorCode, parameters)); + throw new TLCRuntimeException(errorCode, parameters, MP.getMessage(errorCode, parameters)); } } @@ -89,7 +87,7 @@ public class Assert { if (!condition) { - throw new TLCRuntimeException(errorCode, MP.getMessage(errorCode, parameter)); + throw new TLCRuntimeException(errorCode, new String[] {parameter}, MP.getMessage(errorCode, parameter)); } } @@ -129,9 +127,11 @@ public class Assert } } - public static class TLCRuntimeException extends RuntimeException { + @SuppressWarnings("serial") + public static class TLCRuntimeException extends RuntimeException { public final int errorCode; + public String[] parameters = null; public TLCRuntimeException(String errorMsg) { super(errorMsg); @@ -147,5 +147,10 @@ public class Assert super(message, cause); this.errorCode = errorCode; } + + public TLCRuntimeException(int errorCode, String[] parameters, String message) { + this(errorCode, message); + this.parameters = parameters; + } } } diff --git a/tlatools/src/util/BufferedDataInputStream.java b/tlatools/src/util/BufferedDataInputStream.java index 713deed933787a00b84edabd11c1bf181d33584f..c9c53cac9da192f514f45c85d91552679961e8a9 100644 --- a/tlatools/src/util/BufferedDataInputStream.java +++ b/tlatools/src/util/BufferedDataInputStream.java @@ -22,7 +22,7 @@ import tlc2.output.EC; the comments of this class by the specification <TT>REQUIRES LL = SELF</TT>. */ -public class BufferedDataInputStream extends FilterInputStream { +public final class BufferedDataInputStream extends FilterInputStream implements IDataInputStream { /* protected by SELF */ private byte[] buff; /* buffer of bytes to read */ private int len; /* number of valid bytes in "buff" */ @@ -99,7 +99,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** REQUIRES LL = SELF */ /** Returns <code>true</code> iff the stream is exhausted. */ - public boolean atEOF() { + public final boolean atEOF() { return (this.len < 0); } @@ -107,7 +107,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** Reads up to <code>b.length</code> bytes into <code>b</code>, and returns the number of bytes read, or -1 if the stream is exhausted on entry. */ - public int read(byte[] b) throws IOException { + public final int read(byte[] b) throws IOException { return this.read(b, 0, b.length); } @@ -115,7 +115,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** Reads up to <code>n</code> bytes into <code>b</code> starting at position <code>off</code>, and returns the number of bytes read, or -1 if the stream is exhausted on entry. */ - public int read(byte[] b, int off, int n) throws IOException { + public final int read(byte[] b, int off, int n) throws IOException { if (this.len < 0) return -1; int offInit = off; while (n > 0 && this.len > 0) { @@ -136,7 +136,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** Reads <code>b.length</code> bytes into <code>b</code>, or throws <code>EOFException</code> if the stream contains fewer than <code>b.length</code> bytes. */ - public void readFully(byte[] b) throws IOException, EOFException { + public final void readFully(byte[] b) throws IOException, EOFException { this.readFully(b, 0, b.length); } @@ -144,7 +144,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** Reads <code>n</code> bytes into <code>b</code> starting at position <code>off</code>, or throws <code>EOFException</code> if the stream contains fewer than <code>n</code> bytes. */ - public void readFully(byte[] b, int off, int n) + public final void readFully(byte[] b, int off, int n) throws IOException, EOFException { while (n > 0) { int numRead = this.read(b, off, n); @@ -156,7 +156,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** REQUIRES LL = SELF */ /** Reads and returns the next byte of this stream, or throws <code>EOFException</code> if the stream is exhausted. */ - public byte readByte() throws IOException, EOFException { + public final byte readByte() throws IOException, EOFException { if (this.len < 0) throw new EOFException(); byte res = this.buff[this.curr++]; if (this.curr == this.len) { @@ -173,7 +173,7 @@ public class BufferedDataInputStream extends FilterInputStream { encoded in the next byte of this stream, or throws <code>EOFException</code> if the stream is exhausted. */ - public boolean readBoolean() throws IOException, EOFException { + public final boolean readBoolean() throws IOException, EOFException { return (this.readByte() != 0); } @@ -182,7 +182,7 @@ public class BufferedDataInputStream extends FilterInputStream { encoded in the next two bytes of this stream, or throw <code>EOFException</code> if the stream contains fewer than two bytes. */ - public short readShort() throws IOException, EOFException { + public final short readShort() throws IOException, EOFException { this.readFully(this.temp, 0, 2); return (short) ((temp[0] << 8) | (temp[1] & 0xff)); } @@ -192,7 +192,7 @@ public class BufferedDataInputStream extends FilterInputStream { encoded in the next four bytes of this stream, or throws <code>EOFException</code> if the stream contains fewer than four bytes. */ - public int readInt() throws IOException, EOFException { + public final int readInt() throws IOException, EOFException { this.readFully(this.temp, 0, 4); int res = temp[0]; res <<= 8; res |= (temp[1] & 0xff); @@ -206,7 +206,7 @@ public class BufferedDataInputStream extends FilterInputStream { encoded in the next eight bytes of this stream, or throws <code>EOFException</code> if the stream contains fewer than eight bytes. */ - public long readLong() throws IOException, EOFException { + public final long readLong() throws IOException, EOFException { this.readFully(this.temp, 0, 8); long res = temp[0]; res <<= 8; res |= (temp[1] & 0xff); @@ -226,7 +226,7 @@ public class BufferedDataInputStream extends FilterInputStream { by a carriage return character (<code>'\r'</code>), a newline character (<code>'\n'</code>), a carriage return immediately followed by a newline, or by the end of the stream. */ - public String readLine() throws IOException { + public final String readLine() throws IOException { String res = null; while (this.len > 0) { for (int i = this.curr; i < this.len; i++) { @@ -262,7 +262,7 @@ public class BufferedDataInputStream extends FilterInputStream { return res; } - public String readString(int n) throws IOException { + public final String readString(int n) throws IOException { char[] b = new char[n]; int off = 0; while (n > 0) { @@ -291,7 +291,7 @@ public class BufferedDataInputStream extends FilterInputStream { /** Skips over the next <code>n</code> bytes in this stream, or throws <code>EOFException</code> if it contains fewer than <code>n</code> bytes. */ - public void skip(int n) throws IOException, EOFException { + public final void skip(int n) throws IOException, EOFException { while (this.len > 0 && this.curr + n >= this.len) { n -= (this.len - this.curr); // refill buffer from underlying input stream diff --git a/tlatools/src/util/BufferedDataOutputStream.java b/tlatools/src/util/BufferedDataOutputStream.java index fc136e422abd4343727f2e8ea039b68cc3c92901..fa2dd63602ce578c68c3987facf9b89fb67926d3 100644 --- a/tlatools/src/util/BufferedDataOutputStream.java +++ b/tlatools/src/util/BufferedDataOutputStream.java @@ -16,7 +16,7 @@ import java.io.OutputStream; unmonitored. Hence, it is the client's responsibility to lock the stream before using it. */ -public class BufferedDataOutputStream extends FilterOutputStream { +public final class BufferedDataOutputStream extends FilterOutputStream implements IDataOutputStream { private byte[] buff; /* buffer of bytes to write */ private int len; /* number of valid bytes in "buff" */ private byte[] temp; /* temporary array used by various methods */ @@ -83,7 +83,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Flush all bytes written to this stream to the underlying output stream. */ - public void flush() throws IOException { + public final void flush() throws IOException { this.out.write(this.buff, 0, this.len); this.out.flush(); this.len = 0; @@ -91,26 +91,26 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Closes this stream and its underlying stream, after first flushing any buffered data. */ - public void close() throws IOException { + public final void close() throws IOException { this.flush(); this.out.close(); this.out = null; } /** Write <code>b</code> to this stream. */ - public void write(byte b) throws IOException { + public final void write(byte b) throws IOException { this.writeByte(b); } /** Write the <code>b.length</code> bytes of <code>b</code> to this stream. */ - public void write(byte[] b) throws IOException { + public final void write(byte[] b) throws IOException { this.write(b, 0, b.length); } /** Write <code>n</code> bytes of <code>b</code> starting - at possition <code>off</code> to this stream. */ - public void write(byte[] b, int off, int n) throws IOException { + at position <code>off</code> to this stream. */ + public final void write(byte[] b, int off, int n) throws IOException { while (n > 0) { int toCopy = Math.min(n, this.buff.length - this.len); System.arraycopy(b, off, this.buff, this.len, toCopy); @@ -124,7 +124,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { } /** Write the byte <code>b</code> to this stream. */ - public void writeByte(byte b) throws IOException { + public final void writeByte(byte b) throws IOException { this.buff[this.len++] = b; if (this.buff.length == this.len) { // write buffer to underlying stream @@ -135,14 +135,14 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write the boolean value <code>b</code> to this stream as a single byte. */ - public void writeBoolean(boolean bool) throws IOException { + public final void writeBoolean(boolean bool) throws IOException { byte b = (bool ? (byte)1 : (byte)0); this.writeByte(b); } /** Write the short value <code>s</code> to this stream as two bytes. */ - public void writeShort(short s) throws IOException { + public final void writeShort(short s) throws IOException { this.temp[0] = (byte) ((s >>> 8) & 0xff); this.temp[1] = (byte) (s & 0xff); this.write(this.temp, 0, 2); @@ -150,7 +150,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write the integer value <code>i</code> to this stream as four bytes. */ - public void writeInt(int i) throws IOException { + public final void writeInt(int i) throws IOException { this.temp[0] = (byte) ((i >>> 24) & 0xff); this.temp[1] = (byte) ((i >>> 16) & 0xff); this.temp[2] = (byte) ((i >>> 8) & 0xff); @@ -160,7 +160,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write the long value <code>l</code> to this stream as eight bytes. */ - public void writeLong(long l) throws IOException { + public final void writeLong(long l) throws IOException { this.temp[0] = (byte) ((l >>> 56) & 0xff); this.temp[1] = (byte) ((l >>> 48) & 0xff); this.temp[2] = (byte) ((l >>> 40) & 0xff); @@ -174,19 +174,19 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write the float value <code>f</code> to this stream as four bytes. */ - public void writeFloat(float f) throws IOException { + public final void writeFloat(float f) throws IOException { this.writeInt(Float.floatToIntBits(f)); } /** Write the double value <code>d</code> to this stream as eight bytes. */ - public void writeDouble(double d) throws IOException { + public final void writeDouble(double d) throws IOException { this.writeLong(Double.doubleToLongBits(d)); } /** Write the characters of the string <code>s</code> to this stream as a sequence of bytes. */ - public void writeString(String s) throws IOException { + public final void writeString(String s) throws IOException { int n = s.length(); int off = 0; while (n > 0) { @@ -203,7 +203,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write <code>n</code> characters of <code>chars</code> starting at offset <code>off</code> to this stream as a sequence of bytes. */ - public void writeChars(char[] chars, int off, int n) throws IOException { + public final void writeChars(char[] chars, int off, int n) throws IOException { int finOff = off + n; while (off < finOff) { // Copy (part of) chars to this.buff @@ -223,7 +223,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { can be read back by <code>BufferedDataInputStream.readAnyString</code>, even if <code>s</code> is <code>null</code> or if it contains newline characters. */ - public void writeAnyString(String s) throws IOException { + public final void writeAnyString(String s) throws IOException { if (s == null) { this.writeInt(-1); } @@ -235,7 +235,7 @@ public class BufferedDataOutputStream extends FilterOutputStream { /** Write the characters of the string <code>s</code> to this stream as a sequence of bytes, followed by a newline. */ - public void writeLine(String s) throws IOException { + public final void writeLine(String s) throws IOException { this.writeString(s); this.writeByte((byte) '\n'); } diff --git a/tlatools/src/util/ByteArrayInputStream.java b/tlatools/src/util/ByteArrayInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tlatools/src/util/ExecutionStatisticsCollector.java b/tlatools/src/util/ExecutionStatisticsCollector.java new file mode 100644 index 0000000000000000000000000000000000000000..e9393ae3392fb286a39040e503a69aa16c8e08f6 --- /dev/null +++ b/tlatools/src/util/ExecutionStatisticsCollector.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class ExecutionStatisticsCollector { + + static final String RND_ID_STR = "RANDOM_IDENTIFIER"; + static final String NO_ESC_STR = "NO_STATISTICS"; + + public enum Selection { + ON, RANDOM_IDENTIFIER, NO_ESC; + + @Override + public String toString() { + if (this == ON) { + return getRandomIdentifier(); + } else if (this == RANDOM_IDENTIFIER) { + return RND_ID_STR; + } else { + return NO_ESC_STR; + } + } + } + + private static final String PATH = System.getProperty("user.home", "") + File.separator + ".tlaplus" + File.separator + "esc.txt"; + + public static final String PROP = ExecutionStatisticsCollector.class.getName() + ".id"; + + private final boolean isOptOut; + private final String pathname; + + public ExecutionStatisticsCollector() { + this(isOptOut(), PATH); + } + + ExecutionStatisticsCollector(String path) { + this(false, path); + } + + ExecutionStatisticsCollector(final boolean optOut, final String path) { + this.isOptOut = optOut; + this.pathname = path; + } + + public void collect(final Map<String, String> parameters) { + collect(parameters, true); + } + + private void collect(final Map<String, String> parameters, final boolean dontWaitForCompletion) { + // Do not block TLC startup but send this to the background immediately. If + // dontWaitForCompletion is true, the VM will terminate this thread regardless + // of its state if the VM decides to shutdown (e.g. because TLC is done). + final Thread thread = new Thread(new Runnable() { + @Override + public void run() { + if (isEnabled()) { + // Include identifier to track individual installations (not users!). + parameters.put("id", getIdentifier()); + submit(parameters, dontWaitForCompletion); + } + } + }, "TLC Execution Statistics Collector"); + thread.setDaemon(dontWaitForCompletion); + thread.start(); + } + + /* + * file == ~/.tlaplus/esc.txt + * fl == first line of file interpreted as a string without terminal chars + * in/out == opt-in & opt-out + * y/r/n == data collected with constant id/data collected with random id/data not collected + * + * | No file | fl unreadable | fl empty | fl = "NO_UDC" | fl = "RANDOM_IDENTIFIER" | fl any other string + * ========================================================================================================== + * | out | y | n | n | n | r | y | + * ---------------------------------------------------------------------------------------------------------- + * | in | n | n | n | n | r | y | + * ---------------------------------------------------------------------------------------------------------- + */ + public String getIdentifier() { + if (System.getProperty(PROP) != null) { + return System.getProperty(PROP); + } + String identifier; + + final File udcFile = new File(pathname); + if (!udcFile.exists() && isOptOut) { + try (BufferedWriter br = new BufferedWriter(new FileWriter(udcFile))) { + br.write(getRandomIdentifier()); + } catch (Exception e) { + // Something went wrong writing to file ~/.tlaplus/esc.txt. Consider ESC failed. + return null; + } + } + if (!udcFile.exists()) { + // No file ~/.tlaplus/esc.txt. + return null; + } + try (BufferedReader br = new BufferedReader(new FileReader(udcFile))) { + identifier = br.readLine(); + } catch (Exception e) { + // Something went wrong reading file ~/.tlaplus/esc.txt + return null; + } + if (identifier == null || NO_ESC_STR.equals(identifier.trim())) { + // File is empty or its first line is "NO_STATISTICS". + return null; + } else if (identifier == null || RND_ID_STR.equals(identifier.trim())) { + identifier = getRandomIdentifier(); + } + + // truncate the identifier no matter what, but first remove leading and trailing whitespaces. + return identifier.trim().substring(0, 32); + } + + private boolean escFileExists() { + return new File(pathname).exists(); + } + + public boolean isEnabled() { + return getIdentifier() != null; + } + + public void set(final Selection c) throws IOException { + final File udcFile = new File(PATH); + udcFile.createNewFile(); + + try (BufferedWriter br = new BufferedWriter(new FileWriter(udcFile))) { + br.write(c.toString() + "\n"); + } catch (IOException e) { + throw e; + } + } + + public Selection get() { + if (isEnabled()) { + try (BufferedReader br = new BufferedReader(new FileReader(new File(pathname)))) { + String line = br.readLine(); + if (RND_ID_STR.equals(line)) { + return Selection.RANDOM_IDENTIFIER; + } else { + return Selection.ON; + } + } catch (Exception e) { + } + } + return Selection.NO_ESC; + } + + public static boolean promptUser() { + return !(new ExecutionStatisticsCollector().escFileExists()); + } + + private static String getRandomIdentifier() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + private static boolean isOptOut() { + return false; // Nobody is opt-out right now + + // Below is a way how we could detect Microsoft corpnet machines: This check is + // conservative because we don't identify Microsoft employees but corporate + // Microsoft computers. We don't set ESC to opt-out for Microsoft machines yet + // but might in the future. +// final String userDNSDomain = System.getenv("USERDNSDOMAIN"); +// return userDNSDomain != null && userDNSDomain.toUpperCase().endsWith(".CORP.MICROSOFT.COM"); + } + + // Send the request. + private static void submit(final Map<String, String> parameters, final boolean dontWaitForCompletion) { + // Include a timestamp to cause HEAD to be un-cachable. + parameters.put("ts", Long.toString(System.currentTimeMillis())); + parameters.put("optout", Boolean.toString(isOptOut())); + + try { + // Opt-out data doesn't report to the opt-in endpoint. The opt-in endpoint is + // public data, the opt-out endpoint doesn't get shared with the public. + final URL url = new URL( + "https://" + (isOptOut() ? "esc02" : "esc01") + ".tlapl.us/?" + encode(parameters)); + + final HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("HEAD"); + con.getResponseMessage(); + con.disconnect(); + } catch (Exception ignoreCompletely) { + // A TLC user doesn't care if execution statistics collection doesn't work. + } + } + + private static String encode(final Map<String, String> parameters) throws UnsupportedEncodingException { + final StringBuffer buf = new StringBuffer(); + + for (String key : parameters.keySet()) { + String value = parameters.get(key); + buf.append(URLEncoder.encode(key, "UTF-8")); + buf.append("="); + buf.append(URLEncoder.encode(value, "UTF-8")); + buf.append(","); + } + + return buf.toString().replaceFirst(",$", ""); + } + + // for manual testing // + + public static void main(String[] args) { + new ExecutionStatisticsCollector().collect(new HashMap<>(), false); + } +} diff --git a/tlatools/src/util/FileUtil.java b/tlatools/src/util/FileUtil.java index c5dfa1164af91cd24b4889c7d65777e1c1367dfb..c1c22d9585b41c143de8ab4291f069096dd20122 100644 --- a/tlatools/src/util/FileUtil.java +++ b/tlatools/src/util/FileUtil.java @@ -39,6 +39,19 @@ public class FileUtil public static final String separator = File.separator; public static final String pathSeparator = File.pathSeparator; + /** + * Parses the directory path from a filename. If the filename + * is already a basename, returns the empty string. + */ + public static String parseDirname(String filename) { + int lastSep = filename.lastIndexOf(separatorChar); + if (lastSep == -1) { + // No parent directory. + return ""; + } + return filename.substring(0, lastSep + 1); + } + /** * Deletes the file or directory. Returns true iff the deletion * succeeds. The argument recurse forces the deletion of non-empty diff --git a/tlatools/src/util/FilenameToStream.java b/tlatools/src/util/FilenameToStream.java index 11dc64cb397173c415de83de4632c3f7c67e1086..e026e9e5ead6403c966dc0fe138db0db298d546c 100644 --- a/tlatools/src/util/FilenameToStream.java +++ b/tlatools/src/util/FilenameToStream.java @@ -41,4 +41,14 @@ public interface FilenameToStream * @return */ public boolean isStandardModule(String moduleName) ; + + static final String TMPDIR = System.getProperty("java.io.tmpdir"); + + static boolean isInJar(final String aString) { + return aString.startsWith("jar:") || aString.endsWith(".jar"); + } + + static boolean isArchive(String aString) { + return isInJar(aString) || aString.endsWith(".zip"); + } } diff --git a/tlatools/src/util/IDataInputStream.java b/tlatools/src/util/IDataInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..90d944f5f94f6dc055bddb176246bd83b9540bd7 --- /dev/null +++ b/tlatools/src/util/IDataInputStream.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import java.io.EOFException; +import java.io.IOException; + +public interface IDataInputStream { + + int readInt() throws IOException, EOFException; + + String readString(int slen) throws IOException; + +} diff --git a/tlatools/src/util/IDataOutputStream.java b/tlatools/src/util/IDataOutputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..d4ac8bb7c36e2c9f4bcb36766bd8893e8385ab8c --- /dev/null +++ b/tlatools/src/util/IDataOutputStream.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import java.io.IOException; + +public interface IDataOutputStream { + + void writeInt(int varLoc) throws IOException; + + void writeString(String s) throws IOException; + +} diff --git a/tlatools/src/util/MailSender.java b/tlatools/src/util/MailSender.java index 122fbac897f62288e0e28410672f4d029ee0dcd1..bcec703dd1fa661fbd7cf66f754282ca608f8743 100644 --- a/tlatools/src/util/MailSender.java +++ b/tlatools/src/util/MailSender.java @@ -3,6 +3,7 @@ package util; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintStream; import java.net.InetAddress; import java.net.UnknownHostException; @@ -13,8 +14,6 @@ import java.util.List; import java.util.Properties; import java.util.Scanner; -import javax.activation.DataHandler; -import javax.activation.FileDataSource; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; @@ -23,7 +22,6 @@ import javax.naming.directory.InitialDirContext; import model.ModelInJar; import tlc2.output.MP; -// Requires Java >=6 due to javax.activation only part starting with 6 public class MailSender { public static final String MODEL_NAME = "modelName"; diff --git a/tlatools/src/util/SimpleFilenameToStream.java b/tlatools/src/util/SimpleFilenameToStream.java index 62a5ce87528532291efbb9ead56883e07566664b..3a8f22efc334c2e14380a49eb1392eb597543c77 100644 --- a/tlatools/src/util/SimpleFilenameToStream.java +++ b/tlatools/src/util/SimpleFilenameToStream.java @@ -36,7 +36,6 @@ public class SimpleFilenameToStream implements FilenameToStream { private static final ClassLoader cl = SimpleFilenameToStream.class.getClassLoader(); - private static final String TMPDIR = System.getProperty("java.io.tmpdir"); private static final String STANDARD_MODULES = "tla2sany" + '/' + STANDARD_MODULES_FOLDER + '/'; @@ -51,6 +50,10 @@ public class SimpleFilenameToStream implements FilenameToStream { libraryPaths = getLibraryPaths(getInstallationBasePath(), null); } + public SimpleFilenameToStream(final String libraryPath) { + this(new String[] {libraryPath}); + } + /** * August 2014 - TL * This constructor was on the interface but was not implemented. @@ -75,7 +78,7 @@ public class SimpleFilenameToStream implements FilenameToStream { final String path = url.toString(); try { // convert to URI which handles paths correctly (even OS dependently) - if(!isInJar(path)) { + if(!FilenameToStream.isInJar(path)) { final URI uri = new URI(path); return new File(uri).getAbsolutePath(); } @@ -91,10 +94,6 @@ public class SimpleFilenameToStream implements FilenameToStream { return path; } - private static boolean isInJar(String aString) { - return aString.startsWith("jar:"); - } - /** * August 2014 - TL * added an informative method for returning the actual path used by this resolver @@ -189,6 +188,7 @@ public class SimpleFilenameToStream implements FilenameToStream { * field in util/ToolIO. * ***********************************************************************/ int idx = 0; + InputStream is; while (true) { if ((idx == 0) && (ToolIO.getUserDir() != null)) { @@ -202,29 +202,10 @@ public class SimpleFilenameToStream implements FilenameToStream { // // This would be a lot simpler if TLC would not depend on // File but on InputStream instead - if(isInJar(prefix)) { - InputStream is = cl - .getResourceAsStream(STANDARD_MODULES - + name); - + if(FilenameToStream.isInJar(prefix)) { + is = cl.getResourceAsStream(STANDARD_MODULES + name); if(is != null) { - try { - sourceFile = new File(TMPDIR + File.separator + name); - sourceFile.deleteOnExit(); - - FileOutputStream fos = new FileOutputStream(sourceFile); - - byte buf[] = new byte[1024]; - int len; - while ((len = is.read(buf)) > 0) { - fos.write(buf, 0, len); - } - fos.close(); - is.close(); - } catch (IOException e) { - // must not happen - e.printStackTrace(); - } + sourceFile = read(name, is); } } else { sourceFile = new File( prefix + name ); @@ -233,7 +214,19 @@ public class SimpleFilenameToStream implements FilenameToStream { // Debug // System.out.println("Looking for file " + sourceFile); if ( sourceFile.exists() ) break; - if (idx >= libraryPaths.length) break; + if (idx >= libraryPaths.length) { + // As a last resort, try to load resource from the Java classpath. Give up, if it + // fails. + // The use case for this strategy is to load additional TLA+ module collections + // - e.g. community-driven ones - which ship a single jar containing the .tla + // operator definitions as well as Java module overwrites as .class files. + is = cl.getResourceAsStream(name); + if(is != null) { + return read(name, is); + } else { + break; + } + } prefix = libraryPaths[idx++]; } // end while @@ -241,6 +234,27 @@ public class SimpleFilenameToStream implements FilenameToStream { } // end locate() + private File read(String name, InputStream is) { + final File sourceFile = new File(TMPDIR + File.separator + name); + sourceFile.deleteOnExit(); + try { + + final FileOutputStream fos = new FileOutputStream(sourceFile); + + byte buf[] = new byte[1024]; + int len; + while ((len = is.read(buf)) > 0) { + fos.write(buf, 0, len); + } + fos.close(); + is.close(); + } catch (IOException e) { + // must not happen + e.printStackTrace(); + } + return sourceFile; + } + /** * Returns a file * obtained by some standard method from the string name. For example, diff --git a/tlatools/src/util/TLCRuntime.java b/tlatools/src/util/TLCRuntime.java index eac53fc36b05fffcdc098d33449f4ef62b176b6f..93e9354e1ff0263e8315f98078f0b4d2bc8b6867 100644 --- a/tlatools/src/util/TLCRuntime.java +++ b/tlatools/src/util/TLCRuntime.java @@ -2,6 +2,7 @@ package util; +import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.List; @@ -165,4 +166,33 @@ public class TLCRuntime { } return ARCH.x86; } + + // See java.lang.ProcessHandle.current().pid() or -1 when Java version -lt 9. + @SuppressWarnings({ "unchecked", "rawtypes" }) + public long pid() { + // Once Java9 is minimum BREE, change to: + // return java.lang.ProcessHandle.current().pid(); + try { + // Get class. + final ClassLoader classLoader = getClass().getClassLoader(); + final Class aClass = classLoader.loadClass("java.lang.ProcessHandle"); + // Execute static current() + final Object o = aClass.getMethod("current").invoke(null, (Object[]) null); + // Execute instance method pid() + return (long) aClass.getMethod("pid").invoke(o, (Object[]) null); + } catch (Exception e) { + return -1; + } + } + + public boolean isThroughputOptimizedGC() { + final List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans(); + for (GarbageCollectorMXBean gc : gcs) { + // This might not be a reliable way to identify the currently active GC. + if ("PS Scavenge".equals(gc.getName())) { + return true; + } + } + return false; + } } diff --git a/tlatools/src/util/ToolIO.java b/tlatools/src/util/ToolIO.java index 5738bcdd9b3734456da29a9c6a44b45808abd0c5..6be583f9f3b7a859635899d1ddf0970b5a886aed 100644 --- a/tlatools/src/util/ToolIO.java +++ b/tlatools/src/util/ToolIO.java @@ -2,13 +2,8 @@ package util; import java.io.PipedOutputStream; import java.io.PrintStream; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; import java.util.Locale; -import tla2sany.semantic.SemanticNode; - /*************************************************************************** * SANY and TLC were written to communicate only by calling the * * System.out or System.err println() or print() methods. The GUI needs * @@ -84,12 +79,6 @@ public class ToolIO // = 1 for testing. Should be set to reasonable value like 1000. private static final int InitialMaxLength = 1; - /** - * List of semantic nodes which are used by tools - * @see ToolIO#registerSemanticNode() - */ - private static List<SemanticNode> semanticNodes = new LinkedList<>(); - /** * The current sequence of messages is messages[0] ... * messages[length-1] A single message may contain \n characters. @@ -230,46 +219,6 @@ public class ToolIO ToolIO.defaultResolver = resolver; } - /** - * Registers the semantic node - * @param node the node containing tool specific information - * @param toolId the id of the tool (currently not used) - * - * <br><b>Note:</b><br> - * This method is called from {@link SemanticNode#setToolObject(int, Object)} - * and identifies the semantic node that carries tool specific information. - * This information can be deleted using {@link ToolIO#cleanToolObjects(int)} - */ - public static void registerSemanticNode(SemanticNode node, int toolId) - { - if (!semanticNodes.contains(node)) - { - semanticNodes.add(node); - } - } - - /** - * Sets the tool-specific object for all listed semantic nodes to <code>null</code> - * @param toolId the Id of the tool to reset the tool specific information - */ - public static void cleanToolObjects(int toolId) - { - Iterator<SemanticNode> iter = semanticNodes.iterator(); - while(iter.hasNext()) - { - SemanticNode node = iter.next(); - node.setToolObject(toolId, null); - } - } - - /** - * Deletes the information about semantic nodes used with tool-specific information - */ - public static void unregisterSemanticNodes() - { - semanticNodes = new LinkedList<SemanticNode>(); - } - } // class ToolIO class ToolPrintStream extends PrintStream diff --git a/tlatools/src/util/UniqueString.java b/tlatools/src/util/UniqueString.java index d550b446a5d46a79a4d3608548746d92e373e7a8..f9b06ea0365d4b3489e57a3ef4bca04509cccd43 100644 --- a/tlatools/src/util/UniqueString.java +++ b/tlatools/src/util/UniqueString.java @@ -279,7 +279,7 @@ public final class UniqueString implements Serializable * @return * @throws IOException */ - public final void write(BufferedDataOutputStream dos) throws IOException + public final void write(IDataOutputStream dos) throws IOException { dos.writeInt(this.tok); dos.writeInt(this. getVarLoc()); @@ -296,7 +296,7 @@ public final class UniqueString implements Serializable * * The method does not change member/class variables */ - public static UniqueString read(BufferedDataInputStream dis) throws IOException + public static UniqueString read(IDataInputStream dis) throws IOException { int tok1 = dis.readInt(); int loc1 = dis.readInt(); diff --git a/tlatools/test-benchmark/ModuleOverwrites.java b/tlatools/test-benchmark/ModuleOverwrites.java index 293322daa0e78dd5f4d62fa0750f8305209ccbc1..b1f922db66bbacfebdc3a407fe169e85ace5e495 100644 --- a/tlatools/test-benchmark/ModuleOverwrites.java +++ b/tlatools/test-benchmark/ModuleOverwrites.java @@ -3,17 +3,17 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import tlc2.value.BoolValue; -import tlc2.value.FcnRcdValue; -import tlc2.value.IntValue; -import tlc2.value.Value; +import tlc2.value.IValue; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; public class ModuleOverwrites { - public static Value noDupesOverwrite(final FcnRcdValue frv, final IntValue exclude) { + public static IValue noDupesOverwrite(final FcnRcdValue frv, final IntValue exclude) { // LET sub == SelectSeq(t, LAMBDA e: e # emp) // IN ... - final List<Value> filtered = Arrays.asList(frv.values).stream().filter(e -> e != exclude).collect(Collectors.toList()); + final List<IValue> filtered = Arrays.asList(frv.values).stream().filter(e -> e != exclude).collect(Collectors.toList()); // IF Len(sub) < 2 THEN TRUE ... if (filtered.size() < 2) { diff --git a/tlatools/test-benchmark/README.txt b/tlatools/test-benchmark/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8a9061c62999338033248ad375fb31143b6c6d8 --- /dev/null +++ b/tlatools/test-benchmark/README.txt @@ -0,0 +1,18 @@ +Run JMH benchmarks from inside Eclipse: +--------------------------------------- + +a) Activate Annotation Processing in the project preferences of the tlatools project under "Java Compiler" > "Annotation Processing" +b) Add the two jars from lib/jmh/jmh-*.jar as annotation processors to "Java Compiler" > "Annotation Processing" > "Factory Path" +c) Add lib/jmh/commons-math3-*.jar to the launch configs classpath +d) Add a main to the benchmark as shown in the various JMH examples (https://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/) + +Run JMH benchmarks from ant (customBuilds.xml): +----------------------------------------------- + +ant -f customBuild.xml compile compile-test benchmark && +java -jar target/benchmarks.jar -wi 1 -i1 -f1 \ +-rf json \ +-rff DiskQueueBenachmark-$(date +%s)-$(git rev-parse --short HEAD).json \ +-jvmArgsPrepend "-ea -Xms8192m -Xmx8192m" \ +-jvmArgsAppend "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" \ +tlc2.tool.queue.DiskQueueBenachmark diff --git a/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java index f5f1a393fc6398149aa7cb59cfdca8b3e67bb858..63cdafccd933b37374ac106c91349f1ecf544e8b 100644 --- a/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java +++ b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java @@ -34,8 +34,9 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import tlc2.value.FcnRcdValue; -import tlc2.value.Value; +import tlc2.tool.impl.Tool; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.Value; import util.SimpleFilenameToStream; import util.ToolIO; import util.UniqueString; @@ -53,7 +54,7 @@ public class ModuleOverwritesBenchmark { private static final String BASE_PATH = System .getProperty(ModuleOverwritesBenchmark.class.getName() + ".base"); - private static final Tool tool; + private static final ITool tool; private static final TLCStateMut state; static { @@ -62,7 +63,6 @@ public class ModuleOverwritesBenchmark { ToolIO.setUserDir(dir); tool = new Tool("", "ModuleOverwrites", "ModuleOverwrites", new SimpleFilenameToStream()); - tool.init(true, null); state = (TLCStateMut) tool.getInitStates().elementAt(0); } diff --git a/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark-1535138934-548ce71f5.json b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark-1535138934-548ce71f5.json new file mode 100644 index 0000000000000000000000000000000000000000..e3705ddc5063cac5811bbe0b9c1740ad76958e22 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark-1535138934-548ce71f5.json @@ -0,0 +1,128 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayBenchmark.AswapWithCopy", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-11-openjdk-amd64/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "10.0.2", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "10.0.2+13-Ubuntu-1ubuntu0.18.04.1", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.9284288211942446E8, + "scoreError" : 1.2894808885787597E7, + "scoreConfidence" : [ + 1.7994807323363686E8, + 2.0573769100521207E8 + ], + "scorePercentiles" : { + "0.0" : 1.8376569492012057E8, + "50.0" : 1.9164345746308792E8, + "90.0" : 2.0265063750222045E8, + "95.0" : 2.0265063750222045E8, + "99.0" : 2.0265063750222045E8, + "99.9" : 2.0265063750222045E8, + "99.99" : 2.0265063750222045E8, + "99.999" : 2.0265063750222045E8, + "99.9999" : 2.0265063750222045E8, + "100.0" : 2.0265063750222045E8 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2.0265063750222045E8, + 2.0163514267585754E8, + 2.0146764720797616E8 + ], + [ + 1.8787724608521232E8, + 1.8376569492012057E8, + 1.8502766664432153E8 + ], + [ + 1.9164345746308792E8, + 1.860197486552854E8, + 1.9549869792073822E8 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayBenchmark.BswapGetSet", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-11-openjdk-amd64/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "10.0.2", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "10.0.2+13-Ubuntu-1ubuntu0.18.04.1", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 6.087182668510927E8, + "scoreError" : 1.2923203076996244E7, + "scoreConfidence" : [ + 5.957950637740965E8, + 6.216414699280889E8 + ], + "scorePercentiles" : { + "0.0" : 5.959914922634013E8, + "50.0" : 6.098126314774866E8, + "90.0" : 6.174645254898823E8, + "95.0" : 6.174645254898823E8, + "99.0" : 6.174645254898823E8, + "99.9" : 6.174645254898823E8, + "99.99" : 6.174645254898823E8, + "99.999" : 6.174645254898823E8, + "99.9999" : 6.174645254898823E8, + "100.0" : 6.174645254898823E8 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.970025135703455E8, + 5.959914922634013E8, + 6.090513375990788E8 + ], + [ + 6.098126314774866E8, + 6.123331210694003E8, + 6.067840687850246E8 + ], + [ + 6.148359838927962E8, + 6.151887275124179E8, + 6.174645254898823E8 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark.java b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..dc345c51099aa67ff7e6e8e5085bc25a5db5a806 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayBenchmark.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.fp; + +import java.io.IOException; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +@State(Scope.Benchmark) +public class LongArrayBenchmark { + private LongArray array; + + @Setup + public void up() throws IOException { + final long elements = 1L << 10; + array = new LongArray(elements); + array.zeroMemory(1); + for (long i = 0L; i < elements; i++) { + array.set(i, Long.MAX_VALUE - i); + } + } + + @Benchmark + public void AswapWithCopy() { + array.swapCopy(0, array.size() - 1); + } + + @Benchmark + public void BswapGetSet() { + array.swap(0, array.size() - 1); + } +} diff --git a/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark-1540420474-5f451e67c.json b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark-1540420474-5f451e67c.json new file mode 100644 index 0000000000000000000000000000000000000000..527d1818cc98683b02f88d0cd6afa765698c5adc --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark-1540420474-5f451e67c.json @@ -0,0 +1,829 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.AputAddressSingle", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "8" + }, + "primaryMetric" : { + "score" : 15691.037304952166, + "scoreError" : 3227.6738320727072, + "scoreConfidence" : [ + 12463.363472879459, + 18918.711137024875 + ], + "scorePercentiles" : { + "0.0" : 15149.456337242189, + "50.0" : 15709.295867528572, + "90.0" : 16196.101147509331, + "95.0" : 16196.101147509331, + "99.0" : 16196.101147509331, + "99.9" : 16196.101147509331, + "99.99" : 16196.101147509331, + "99.999" : 16196.101147509331, + "99.9999" : 16196.101147509331, + "100.0" : 16196.101147509331 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 16025.043319946451, + 15393.548415110692 + ], + [ + 16196.101147509331, + 15149.456337242189 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.AputAddressSingle", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "16" + }, + "primaryMetric" : { + "score" : 10257.952132803022, + "scoreError" : 1609.8651787441936, + "scoreConfidence" : [ + 8648.086954058828, + 11867.817311547216 + ], + "scorePercentiles" : { + "0.0" : 10002.640123830502, + "50.0" : 10219.707935833161, + "90.0" : 10589.752535715264, + "95.0" : 10589.752535715264, + "99.0" : 10589.752535715264, + "99.9" : 10589.752535715264, + "99.99" : 10589.752535715264, + "99.999" : 10589.752535715264, + "99.9999" : 10589.752535715264, + "100.0" : 10589.752535715264 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 10589.752535715264, + 10156.48634104379 + ], + [ + 10282.929530622534, + 10002.640123830502 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.AputAddressSingle", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "24" + }, + "primaryMetric" : { + "score" : 76.898812891649, + "scoreError" : 2.7474408988974544, + "scoreConfidence" : [ + 74.15137199275155, + 79.64625379054645 + ], + "scorePercentiles" : { + "0.0" : 76.48035969067071, + "50.0" : 76.8971373633593, + "90.0" : 77.32061714920668, + "95.0" : 77.32061714920668, + "99.0" : 77.32061714920668, + "99.9" : 77.32061714920668, + "99.99" : 77.32061714920668, + "99.999" : 77.32061714920668, + "99.9999" : 77.32061714920668, + "100.0" : 77.32061714920668 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 77.32061714920668, + 76.48035969067071 + ], + [ + 77.20477337813603, + 76.58950134858259 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.AputAddressSingle", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "28" + }, + "primaryMetric" : { + "score" : 4.8919062820566035, + "scoreError" : 0.13982428649979478, + "scoreConfidence" : [ + 4.752081995556809, + 5.031730568556398 + ], + "scorePercentiles" : { + "0.0" : 4.869023032502967, + "50.0" : 4.892757182572337, + "90.0" : 4.913087730578771, + "95.0" : 4.913087730578771, + "99.0" : 4.913087730578771, + "99.9" : 4.913087730578771, + "99.99" : 4.913087730578771, + "99.999" : 4.913087730578771, + "99.9999" : 4.913087730578771, + "100.0" : 4.913087730578771 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.913087730578771, + 4.869023032502967 + ], + [ + 4.907434706339786, + 4.8780796588048885 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.AputAddressSingle", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "31" + }, + "primaryMetric" : { + "score" : 0.6054237172952491, + "scoreError" : 0.057545101881470405, + "scoreConfidence" : [ + 0.5478786154137787, + 0.6629688191767196 + ], + "scorePercentiles" : { + "0.0" : 0.5920856333767331, + "50.0" : 0.6095564484306197, + "90.0" : 0.6104963389430239, + "95.0" : 0.6104963389430239, + "99.0" : 0.6104963389430239, + "99.9" : 0.6104963389430239, + "99.99" : 0.6104963389430239, + "99.999" : 0.6104963389430239, + "99.9999" : 0.6104963389430239, + "100.0" : 0.6104963389430239 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.6093206980085581, + 0.5920856333767331 + ], + [ + 0.6097921988526813, + 0.6104963389430239 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.BputAddressConcurrent", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "8" + }, + "primaryMetric" : { + "score" : 5823.508981235277, + "scoreError" : 331.24359175202756, + "scoreConfidence" : [ + 5492.265389483249, + 6154.752572987305 + ], + "scorePercentiles" : { + "0.0" : 5753.76878817967, + "50.0" : 5838.788951447104, + "90.0" : 5862.689233867229, + "95.0" : 5862.689233867229, + "99.0" : 5862.689233867229, + "99.9" : 5862.689233867229, + "99.99" : 5862.689233867229, + "99.999" : 5862.689233867229, + "99.9999" : 5862.689233867229, + "100.0" : 5862.689233867229 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5861.34019538168, + 5816.237707512529 + ], + [ + 5862.689233867229, + 5753.76878817967 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.BputAddressConcurrent", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "16" + }, + "primaryMetric" : { + "score" : 5123.978800612953, + "scoreError" : 106.38946063324629, + "scoreConfidence" : [ + 5017.589339979707, + 5230.368261246199 + ], + "scorePercentiles" : { + "0.0" : 5100.830231354179, + "50.0" : 5128.5271012328085, + "90.0" : 5138.030768632014, + "95.0" : 5138.030768632014, + "99.0" : 5138.030768632014, + "99.9" : 5138.030768632014, + "99.99" : 5138.030768632014, + "99.999" : 5138.030768632014, + "99.9999" : 5138.030768632014, + "100.0" : 5138.030768632014 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5138.030768632014, + 5132.914045761264 + ], + [ + 5100.830231354179, + 5124.140156704352 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.BputAddressConcurrent", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "24" + }, + "primaryMetric" : { + "score" : 68.97129891399425, + "scoreError" : 2.413345681248791, + "scoreConfidence" : [ + 66.55795323274546, + 71.38464459524303 + ], + "scorePercentiles" : { + "0.0" : 68.58880458551265, + "50.0" : 68.91555687043092, + "90.0" : 69.4652773296025, + "95.0" : 69.4652773296025, + "99.0" : 69.4652773296025, + "99.9" : 69.4652773296025, + "99.99" : 69.4652773296025, + "99.999" : 69.4652773296025, + "99.9999" : 69.4652773296025, + "100.0" : 69.4652773296025 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 68.81090527067398, + 69.02020847018787 + ], + [ + 68.58880458551265, + 69.4652773296025 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.BputAddressConcurrent", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "28" + }, + "primaryMetric" : { + "score" : 4.295134928414715, + "scoreError" : 0.107034811914763, + "scoreConfidence" : [ + 4.188100116499952, + 4.4021697403294775 + ], + "scorePercentiles" : { + "0.0" : 4.278376300240857, + "50.0" : 4.295239726791536, + "90.0" : 4.311683959834933, + "95.0" : 4.311683959834933, + "99.0" : 4.311683959834933, + "99.9" : 4.311683959834933, + "99.99" : 4.311683959834933, + "99.999" : 4.311683959834933, + "99.9999" : 4.311683959834933, + "100.0" : 4.311683959834933 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.278376300240857, + 4.311683959834933 + ], + [ + 4.2836567656737925, + 4.30682268790928 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.BputAddressConcurrent", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "31" + }, + "primaryMetric" : { + "score" : 0.5397866544024822, + "scoreError" : 0.0015897046802224838, + "scoreConfidence" : [ + 0.5381969497222597, + 0.5413763590827047 + ], + "scorePercentiles" : { + "0.0" : 0.5394561862215702, + "50.0" : 0.539844153558601, + "90.0" : 0.5400021242711565, + "95.0" : 0.5400021242711565, + "99.0" : 0.5400021242711565, + "99.9" : 0.5400021242711565, + "99.99" : 0.5400021242711565, + "99.999" : 0.5400021242711565, + "99.9999" : 0.5400021242711565, + "100.0" : 0.5400021242711565 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.5400021242711565, + 0.5399424181107918 + ], + [ + 0.5397458890064103, + 0.5394561862215702 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.CsetMemory", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "8" + }, + "primaryMetric" : { + "score" : 1.7117812650403537E7, + "scoreError" : 1858981.951784521, + "scoreConfidence" : [ + 1.5258830698619016E7, + 1.897679460218806E7 + ], + "scorePercentiles" : { + "0.0" : 1.6809496813037805E7, + "50.0" : 1.7132330412883125E7, + "90.0" : 1.7397092962810084E7, + "95.0" : 1.7397092962810084E7, + "99.0" : 1.7397092962810084E7, + "99.9" : 1.7397092962810084E7, + "99.99" : 1.7397092962810084E7, + "99.999" : 1.7397092962810084E7, + "99.9999" : 1.7397092962810084E7, + "100.0" : 1.7397092962810084E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6809496813037805E7, + 1.6938938543361507E7 + ], + [ + 1.7325722282404747E7, + 1.7397092962810084E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.CsetMemory", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "16" + }, + "primaryMetric" : { + "score" : 79289.53265336789, + "scoreError" : 4239.252439267255, + "scoreConfidence" : [ + 75050.28021410064, + 83528.78509263514 + ], + "scorePercentiles" : { + "0.0" : 78885.94805588268, + "50.0" : 79001.56006617282, + "90.0" : 80269.06242524325, + "95.0" : 80269.06242524325, + "99.0" : 80269.06242524325, + "99.9" : 80269.06242524325, + "99.99" : 80269.06242524325, + "99.999" : 80269.06242524325, + "99.9999" : 80269.06242524325, + "100.0" : 80269.06242524325 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 79039.68258539782, + 80269.06242524325 + ], + [ + 78885.94805588268, + 78963.43754694781 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.CsetMemory", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "24" + }, + "primaryMetric" : { + "score" : 81.08833107753068, + "scoreError" : 2.958405915843286, + "scoreConfidence" : [ + 78.1299251616874, + 84.04673699337397 + ], + "scorePercentiles" : { + "0.0" : 80.60014890852541, + "50.0" : 81.07172218289426, + "90.0" : 81.60973103580875, + "95.0" : 81.60973103580875, + "99.0" : 81.60973103580875, + "99.9" : 81.60973103580875, + "99.99" : 81.60973103580875, + "99.999" : 81.60973103580875, + "99.9999" : 81.60973103580875, + "100.0" : 81.60973103580875 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 80.82876474476265, + 81.60973103580875 + ], + [ + 80.60014890852541, + 81.31467962102589 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.CsetMemory", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "28" + }, + "primaryMetric" : { + "score" : 5.073907234951268, + "scoreError" : 0.14121152721716443, + "scoreConfidence" : [ + 4.932695707734104, + 5.215118762168433 + ], + "scorePercentiles" : { + "0.0" : 5.054526541541467, + "50.0" : 5.074118390666934, + "90.0" : 5.092865616929739, + "95.0" : 5.092865616929739, + "99.0" : 5.092865616929739, + "99.9" : 5.092865616929739, + "99.99" : 5.092865616929739, + "99.999" : 5.092865616929739, + "99.9999" : 5.092865616929739, + "100.0" : 5.092865616929739 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.055443635693725, + 5.092793145640142 + ], + [ + 5.054526541541467, + 5.092865616929739 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.fp.LongArrayInitializeBenchmark.CsetMemory", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_191", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.191-b12", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "31" + }, + "primaryMetric" : { + "score" : 0.6308208674513708, + "scoreError" : 0.0021647577060876096, + "scoreConfidence" : [ + 0.6286561097452832, + 0.6329856251574584 + ], + "scorePercentiles" : { + "0.0" : 0.6303389225544128, + "50.0" : 0.6309177899582723, + "90.0" : 0.6311089673345258, + "95.0" : 0.6311089673345258, + "99.0" : 0.6311089673345258, + "99.9" : 0.6311089673345258, + "99.99" : 0.6311089673345258, + "99.999" : 0.6311089673345258, + "99.9999" : 0.6311089673345258, + "100.0" : 0.6311089673345258 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.6308816519037619, + 0.6311089673345258 + ], + [ + 0.6303389225544128, + 0.6309539280127826 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark.java b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..de8b2876f46024a0edae589b2a49ce066d82259c --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/fp/LongArrayInitializeBenchmark.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.fp; + +import java.io.IOException; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +@State(Scope.Benchmark) +public class LongArrayInitializeBenchmark { + + private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors(); + private LongArray array; + + @Param({"8", "16", "24", "28", "31"}) + public int size; + + @Setup + public void up() throws IOException { + final long elements = 1L << size; + array = new LongArray(elements); + } + + @Benchmark + public void AputAddressSingle() throws IOException { + array.zeroMemory(1); + } + + @Benchmark + public void BputAddressConcurrent() throws IOException { + array.zeroMemory(AVAILABLE_PROCESSORS); + } + + @Benchmark + public void CsetMemory() throws IOException { + array.zeroMemory(); + } +} diff --git a/tlatools/test-benchmark/tlc2/tool/queue/DiskQueueBenachmark.java b/tlatools/test-benchmark/tlc2/tool/queue/DiskQueueBenachmark.java new file mode 100644 index 0000000000000000000000000000000000000000..3f07157a42fd8a003cebbe221c4cc7568f95e133 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/queue/DiskQueueBenachmark.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.queue; + +import java.io.IOException; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Group; +import org.openjdk.jmh.annotations.GroupThreads; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import tlc2.tool.TLCState; +import tlc2.tool.TLCStates; +import tlc2.util.FlightRecorderProfiler; + +@State(Scope.Group) +@BenchmarkMode(Mode.Throughput) +public class DiskQueueBenachmark { + + @Param({"1", "2", "4", "8", "16", "32", "64"}) + public int vars; + + @Param({"DiskByteArrayQueue", "DiskStateQueue"}) + public String impl; + + private IStateQueue dsq; + + private TLCState state; + + @Setup + public void up() throws IOException { + if (impl.equals("DiskByteArrayQueue")) { + this.dsq = new DiskByteArrayQueue(); + } else { + this.dsq = new DiskStateQueue(); + } + + this.state = TLCStates.createDummyState(vars); + } + + @TearDown + public void down() throws IOException { + this.dsq.delete(); + } + + @Benchmark + @Group("g02") + @GroupThreads(1) + public TLCState consumer1() { + return this.dsq.sDequeue(); + } + + @Benchmark + @Group("g02") + @GroupThreads(1) + public void producer1() { + this.dsq.sEnqueue(this.state); + } + + + @Benchmark + @Group("g04") + @GroupThreads(2) + public TLCState consumer2() { + return this.dsq.sDequeue(); + } + + @Benchmark + @Group("g04") + @GroupThreads(2) + public void producer2() { + this.dsq.sEnqueue(this.state); + } + + + @Benchmark + @Group("g08") + @GroupThreads(4) + public TLCState consumer4() { + return this.dsq.sDequeue(); + } + + @Benchmark + @Group("g08") + @GroupThreads(4) + public void producer4() { + this.dsq.sEnqueue(this.state); + } + + + @Benchmark + @Group("g16") + @GroupThreads(8) + public TLCState consumer8() { + return this.dsq.sDequeue(); + } + + @Benchmark + @Group("g16") + @GroupThreads(8) + public void producer8() { + this.dsq.sEnqueue(this.state); + } + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(DiskQueueBenachmark.class.getSimpleName()) + .addProfiler(FlightRecorderProfiler.class) + .build(); + + new Runner(opt).run(); + } +} diff --git a/tlatools/test-benchmark/tlc2/tool/queue/StateQueueBenachmark.java b/tlatools/test-benchmark/tlc2/tool/queue/StateQueueBenachmark.java new file mode 100644 index 0000000000000000000000000000000000000000..b8221bab3a15a03748d31e4cc4e6cb0ab71f97ca --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/queue/StateQueueBenachmark.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.queue; + +import java.io.IOException; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Group; +import org.openjdk.jmh.annotations.GroupThreads; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; + +import tlc2.tool.TLCState; +import tlc2.tool.TLCStates; + +@State(Scope.Group) +public class StateQueueBenachmark { + + @Param({"1", "2", "4", "8", "16", "32", "64"}) + public int size; + + private IStateQueue s; + + private TLCState[] batch; + + @Setup + public void up() throws IOException { + s = new DiskStateQueue(); + + // balance off the costs for creating the TLCState[]. + this.batch = new TLCState[size]; + for (int i = 0; i < batch.length; i++) { + batch[i] = TLCStates.createDummyState(); + } + } + + @TearDown + public void down() throws IOException { + this.s.delete(); + } + + @Benchmark + @Group("single") + @GroupThreads(2) + public TLCState[] consumerSingle() { + final TLCState[] res = new TLCState[batch.length]; + for (int i = 0; i < batch.length; i++) { + res[i] = this.s.sDequeue(); + } + return res; + } + + @Benchmark + @Group("single") + @GroupThreads(2) + public void producerSingle() { + for (int i = 0; i < batch.length; i++) { + this.s.sEnqueue(batch[i]); + } + } + + + /* Batches of enqueue only */ + + @Benchmark + @Group("batchasym") + @GroupThreads(2) + public TLCState[] consumerBatch() { + final TLCState[] res = new TLCState[batch.length]; + for (int i = 0; i < batch.length; i++) { + res[i] = this.s.sDequeue(); + } + return res; + } + + @Benchmark + @Group("batchasym") + @GroupThreads(2) + public void producerBatch() { + this.s.sEnqueue(batch); + } + + + /* Batches of dequeue & enqueue */ + + @Benchmark + @Group("batchsym") + @GroupThreads(2) + public TLCState[] consumerBatchSym() { + return this.s.sDequeue(size); + } + + @Benchmark + @Group("batchsym") + @GroupThreads(2) + public void producerBatchSym() { + this.s.sEnqueue(batch); + } +} diff --git a/tlatools/test-benchmark/tlc2/tool/simulation/SimulatorBenchmark.java b/tlatools/test-benchmark/tlc2/tool/simulation/SimulatorBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..6c2c2176d850fae3d40fa19f1e404eeed6ab3079 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/simulation/SimulatorBenchmark.java @@ -0,0 +1,74 @@ +package tlc2.tool.simulation; + +import java.io.File; +import java.io.IOException; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import tla2sany.modanalyzer.SpecObj; +import tlc2.tool.Simulator; +import tlc2.util.RandomGenerator; +import util.SimpleFilenameToStream; +import util.ToolIO; + +/** + * A benchmark to measure multi-threaded simulation performance. + */ +@State(Scope.Benchmark) +public class SimulatorBenchmark { + + @Param({ "1", "2", "3", "4", "5", "6"}) + public int nWorkers; + + Simulator simulator; + SpecObj specObj; + RandomGenerator rng = new RandomGenerator(0); + long seed = 0; + + @Setup + public void up() throws IOException { + ToolIO.setUserDir("test-model" + File.separator + "simulation" + File.separator + "BenchmarkSpec"); + } + + @Setup(Level.Iteration) + public void reseedIter() { + // For each iteration of a benchmark, we set the seed to a known value, so that each + // benchmark fork starts a particular iteration with the same seed. + seed += 1; + rng.setSeed(seed); + } + + @Setup(Level.Trial) + public void reseed() { + // We reset the random number generator to a fixed seed before benchmarking a specific worker count. + // This should help to make these benchmarks more deterministic for a fixed set of benchmark parameters. The initial + // seed of this random number generator should effectively determine what traces are explored in what order by the simulation + // workers, so a particular seed should correspond to a fixed exploration order of the behavior space. + rng.setSeed(0); + seed = 0; + } + + public void simulatorBenchmark(int nWorkers) { + try { + int maxTraceDepth = 20; + Simulator simulator = new Simulator("BenchmarkSpec", "MCInv", null, false, maxTraceDepth, Long.MAX_VALUE, rng, 0, + new SimpleFilenameToStream(), nWorkers); + simulator.simulate(); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + public void SimulatorWorkers() { + simulatorBenchmark(nWorkers); + } +} diff --git a/tlatools/test-benchmark/tlc2/util/FlightRecorderProfiler.java b/tlatools/test-benchmark/tlc2/util/FlightRecorderProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..b001afb8464d2ebdcd1b85a3ce236691f4d53e84 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/util/FlightRecorderProfiler.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.util; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.openjdk.jmh.infra.BenchmarkParams; +import org.openjdk.jmh.profile.ExternalProfiler; +import org.openjdk.jmh.results.BenchmarkResult; +import org.openjdk.jmh.results.Result; + +public class FlightRecorderProfiler implements ExternalProfiler { + + // Inspired by https://github.com/nicoulaj/jmh-utils + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.Profiler#getDescription() + */ + @Override + public String getDescription() { + return FlightRecorderProfiler.class.getSimpleName(); + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#addJVMInvokeOptions(org.openjdk.jmh.infra.BenchmarkParams) + */ + @Override + public Collection<String> addJVMInvokeOptions(BenchmarkParams arg0) { + return new ArrayList<String>(); + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#allowPrintErr() + */ + @Override + public boolean allowPrintErr() { + return true; + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#allowPrintOut() + */ + @Override + public boolean allowPrintOut() { + return true; + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#beforeTrial(org.openjdk.jmh.infra.BenchmarkParams) + */ + @Override + public void beforeTrial(BenchmarkParams arg0) { + //noop + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#afterTrial(org.openjdk.jmh.results.BenchmarkResult, long, java.io.File, java.io.File) + */ + @Override + public Collection<? extends Result> afterTrial(BenchmarkResult arg0, long arg1, File arg2, File arg3) { + return new ArrayList<>(); + } + + /* (non-Javadoc) + * @see org.openjdk.jmh.profile.ExternalProfiler#addJVMOptions(org.openjdk.jmh.infra.BenchmarkParams) + */ + @Override + public Collection<String> addJVMOptions(BenchmarkParams bp) { + // Create the jfr file in the current directory named after the benchmark. + return Arrays.asList("-XX:StartFlightRecording=settings=default,disk=true,dumponexit=true,filename=./" + bp.id() + ".jfr"); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/EnumerateSubsetBenchmark-1537381744-b7b00550b.json b/tlatools/test-benchmark/tlc2/value/EnumerateSubsetBenchmark-1537381744-b7b00550b.json new file mode 100644 index 0000000000000000000000000000000000000000..3fda8d484f95b10a241a2c2e08fdc0899402f417 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/EnumerateSubsetBenchmark-1537381744-b7b00550b.json @@ -0,0 +1,3184 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "0" + }, + "primaryMetric" : { + "score" : 3.611267082827124E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3.611267082827124E7, + "50.0" : 3.611267082827124E7, + "90.0" : 3.611267082827124E7, + "95.0" : 3.611267082827124E7, + "99.0" : 3.611267082827124E7, + "99.9" : 3.611267082827124E7, + "99.99" : 3.611267082827124E7, + "99.999" : 3.611267082827124E7, + "99.9999" : 3.611267082827124E7, + "100.0" : 3.611267082827124E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.611267082827124E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "1" + }, + "primaryMetric" : { + "score" : 1.0354789744882155E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.0354789744882155E7, + "50.0" : 1.0354789744882155E7, + "90.0" : 1.0354789744882155E7, + "95.0" : 1.0354789744882155E7, + "99.0" : 1.0354789744882155E7, + "99.9" : 1.0354789744882155E7, + "99.99" : 1.0354789744882155E7, + "99.999" : 1.0354789744882155E7, + "99.9999" : 1.0354789744882155E7, + "100.0" : 1.0354789744882155E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.0354789744882155E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "2" + }, + "primaryMetric" : { + "score" : 7424758.104352328, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 7424758.104352328, + "50.0" : 7424758.104352328, + "90.0" : 7424758.104352328, + "95.0" : 7424758.104352328, + "99.0" : 7424758.104352328, + "99.9" : 7424758.104352328, + "99.99" : 7424758.104352328, + "99.999" : 7424758.104352328, + "99.9999" : 7424758.104352328, + "100.0" : 7424758.104352328 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7424758.104352328 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "3" + }, + "primaryMetric" : { + "score" : 4520093.423989947, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 4520093.423989947, + "50.0" : 4520093.423989947, + "90.0" : 4520093.423989947, + "95.0" : 4520093.423989947, + "99.0" : 4520093.423989947, + "99.9" : 4520093.423989947, + "99.99" : 4520093.423989947, + "99.999" : 4520093.423989947, + "99.9999" : 4520093.423989947, + "100.0" : 4520093.423989947 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4520093.423989947 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "4" + }, + "primaryMetric" : { + "score" : 1925178.7174611264, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1925178.7174611264, + "50.0" : 1925178.7174611264, + "90.0" : 1925178.7174611264, + "95.0" : 1925178.7174611264, + "99.0" : 1925178.7174611264, + "99.9" : 1925178.7174611264, + "99.99" : 1925178.7174611264, + "99.999" : 1925178.7174611264, + "99.9999" : 1925178.7174611264, + "100.0" : 1925178.7174611264 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1925178.7174611264 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "8" + }, + "primaryMetric" : { + "score" : 133009.5244991998, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 133009.5244991998, + "50.0" : 133009.5244991998, + "90.0" : 133009.5244991998, + "95.0" : 133009.5244991998, + "99.0" : 133009.5244991998, + "99.9" : 133009.5244991998, + "99.99" : 133009.5244991998, + "99.999" : 133009.5244991998, + "99.9999" : 133009.5244991998, + "100.0" : 133009.5244991998 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 133009.5244991998 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10" + }, + "primaryMetric" : { + "score" : 29226.867534242203, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 29226.867534242203, + "50.0" : 29226.867534242203, + "90.0" : 29226.867534242203, + "95.0" : 29226.867534242203, + "99.0" : 29226.867534242203, + "99.9" : 29226.867534242203, + "99.99" : 29226.867534242203, + "99.999" : 29226.867534242203, + "99.9999" : 29226.867534242203, + "100.0" : 29226.867534242203 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29226.867534242203 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12" + }, + "primaryMetric" : { + "score" : 6081.382406132828, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 6081.382406132828, + "50.0" : 6081.382406132828, + "90.0" : 6081.382406132828, + "95.0" : 6081.382406132828, + "99.0" : 6081.382406132828, + "99.9" : 6081.382406132828, + "99.99" : 6081.382406132828, + "99.999" : 6081.382406132828, + "99.9999" : 6081.382406132828, + "100.0" : 6081.382406132828 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6081.382406132828 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14" + }, + "primaryMetric" : { + "score" : 1390.845676349573, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1390.845676349573, + "50.0" : 1390.845676349573, + "90.0" : 1390.845676349573, + "95.0" : 1390.845676349573, + "99.0" : 1390.845676349573, + "99.9" : 1390.845676349573, + "99.99" : 1390.845676349573, + "99.999" : 1390.845676349573, + "99.9999" : 1390.845676349573, + "100.0" : 1390.845676349573 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1390.845676349573 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16" + }, + "primaryMetric" : { + "score" : 330.27592509790907, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 330.27592509790907, + "50.0" : 330.27592509790907, + "90.0" : 330.27592509790907, + "95.0" : 330.27592509790907, + "99.0" : 330.27592509790907, + "99.9" : 330.27592509790907, + "99.99" : 330.27592509790907, + "99.999" : 330.27592509790907, + "99.9999" : 330.27592509790907, + "100.0" : 330.27592509790907 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 330.27592509790907 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "18" + }, + "primaryMetric" : { + "score" : 73.27729464188555, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 73.27729464188555, + "50.0" : 73.27729464188555, + "90.0" : 73.27729464188555, + "95.0" : 73.27729464188555, + "99.0" : 73.27729464188555, + "99.9" : 73.27729464188555, + "99.99" : 73.27729464188555, + "99.999" : 73.27729464188555, + "99.9999" : 73.27729464188555, + "100.0" : 73.27729464188555 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 73.27729464188555 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsAlwaysNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "19" + }, + "primaryMetric" : { + "score" : 27.9553224857132, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 27.9553224857132, + "50.0" : 27.9553224857132, + "90.0" : 27.9553224857132, + "95.0" : 27.9553224857132, + "99.0" : 27.9553224857132, + "99.9" : 27.9553224857132, + "99.99" : 27.9553224857132, + "99.999" : 27.9553224857132, + "99.9999" : 27.9553224857132, + "100.0" : 27.9553224857132 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 27.9553224857132 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "0" + }, + "primaryMetric" : { + "score" : 1.3197374943346184E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.3197374943346184E7, + "50.0" : 1.3197374943346184E7, + "90.0" : 1.3197374943346184E7, + "95.0" : 1.3197374943346184E7, + "99.0" : 1.3197374943346184E7, + "99.9" : 1.3197374943346184E7, + "99.99" : 1.3197374943346184E7, + "99.999" : 1.3197374943346184E7, + "99.9999" : 1.3197374943346184E7, + "100.0" : 1.3197374943346184E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.3197374943346184E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "1" + }, + "primaryMetric" : { + "score" : 6123381.900721031, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 6123381.900721031, + "50.0" : 6123381.900721031, + "90.0" : 6123381.900721031, + "95.0" : 6123381.900721031, + "99.0" : 6123381.900721031, + "99.9" : 6123381.900721031, + "99.99" : 6123381.900721031, + "99.999" : 6123381.900721031, + "99.9999" : 6123381.900721031, + "100.0" : 6123381.900721031 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6123381.900721031 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "2" + }, + "primaryMetric" : { + "score" : 4565321.513276472, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 4565321.513276472, + "50.0" : 4565321.513276472, + "90.0" : 4565321.513276472, + "95.0" : 4565321.513276472, + "99.0" : 4565321.513276472, + "99.9" : 4565321.513276472, + "99.99" : 4565321.513276472, + "99.999" : 4565321.513276472, + "99.9999" : 4565321.513276472, + "100.0" : 4565321.513276472 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4565321.513276472 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "3" + }, + "primaryMetric" : { + "score" : 2608382.546140382, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 2608382.546140382, + "50.0" : 2608382.546140382, + "90.0" : 2608382.546140382, + "95.0" : 2608382.546140382, + "99.0" : 2608382.546140382, + "99.9" : 2608382.546140382, + "99.99" : 2608382.546140382, + "99.999" : 2608382.546140382, + "99.9999" : 2608382.546140382, + "100.0" : 2608382.546140382 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2608382.546140382 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "4" + }, + "primaryMetric" : { + "score" : 1122145.0197631393, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1122145.0197631393, + "50.0" : 1122145.0197631393, + "90.0" : 1122145.0197631393, + "95.0" : 1122145.0197631393, + "99.0" : 1122145.0197631393, + "99.9" : 1122145.0197631393, + "99.99" : 1122145.0197631393, + "99.999" : 1122145.0197631393, + "99.9999" : 1122145.0197631393, + "100.0" : 1122145.0197631393 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1122145.0197631393 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "8" + }, + "primaryMetric" : { + "score" : 25729.526497328603, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 25729.526497328603, + "50.0" : 25729.526497328603, + "90.0" : 25729.526497328603, + "95.0" : 25729.526497328603, + "99.0" : 25729.526497328603, + "99.9" : 25729.526497328603, + "99.99" : 25729.526497328603, + "99.999" : 25729.526497328603, + "99.9999" : 25729.526497328603, + "100.0" : 25729.526497328603 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 25729.526497328603 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10" + }, + "primaryMetric" : { + "score" : 2847.859944849876, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 2847.859944849876, + "50.0" : 2847.859944849876, + "90.0" : 2847.859944849876, + "95.0" : 2847.859944849876, + "99.0" : 2847.859944849876, + "99.9" : 2847.859944849876, + "99.99" : 2847.859944849876, + "99.999" : 2847.859944849876, + "99.9999" : 2847.859944849876, + "100.0" : 2847.859944849876 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2847.859944849876 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12" + }, + "primaryMetric" : { + "score" : 324.61093701658825, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 324.61093701658825, + "50.0" : 324.61093701658825, + "90.0" : 324.61093701658825, + "95.0" : 324.61093701658825, + "99.0" : 324.61093701658825, + "99.9" : 324.61093701658825, + "99.99" : 324.61093701658825, + "99.999" : 324.61093701658825, + "99.9999" : 324.61093701658825, + "100.0" : 324.61093701658825 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 324.61093701658825 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14" + }, + "primaryMetric" : { + "score" : 29.229042769052267, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 29.229042769052267, + "50.0" : 29.229042769052267, + "90.0" : 29.229042769052267, + "95.0" : 29.229042769052267, + "99.0" : 29.229042769052267, + "99.9" : 29.229042769052267, + "99.99" : 29.229042769052267, + "99.999" : 29.229042769052267, + "99.9999" : 29.229042769052267, + "100.0" : 29.229042769052267 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29.229042769052267 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16" + }, + "primaryMetric" : { + "score" : 1.9081657766508895, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.9081657766508895, + "50.0" : 1.9081657766508895, + "90.0" : 1.9081657766508895, + "95.0" : 1.9081657766508895, + "99.0" : 1.9081657766508895, + "99.9" : 1.9081657766508895, + "99.99" : 1.9081657766508895, + "99.999" : 1.9081657766508895, + "99.9999" : 1.9081657766508895, + "100.0" : 1.9081657766508895 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.9081657766508895 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "18" + }, + "primaryMetric" : { + "score" : 0.128569060485454, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 0.128569060485454, + "50.0" : 0.128569060485454, + "90.0" : 0.128569060485454, + "95.0" : 0.128569060485454, + "99.0" : 0.128569060485454, + "99.9" : 0.128569060485454, + "99.99" : 0.128569060485454, + "99.999" : 0.128569060485454, + "99.9999" : 0.128569060485454, + "100.0" : 0.128569060485454 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.128569060485454 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "19" + }, + "primaryMetric" : { + "score" : 0.031828143851718595, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 0.031828143851718595, + "50.0" : 0.031828143851718595, + "90.0" : 0.031828143851718595, + "95.0" : 0.031828143851718595, + "99.0" : 0.031828143851718595, + "99.9" : 0.031828143851718595, + "99.99" : 0.031828143851718595, + "99.999" : 0.031828143851718595, + "99.9999" : 0.031828143851718595, + "100.0" : 0.031828143851718595 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.031828143851718595 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "0" + }, + "primaryMetric" : { + "score" : 1.700831123275485E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.700831123275485E7, + "50.0" : 1.700831123275485E7, + "90.0" : 1.700831123275485E7, + "95.0" : 1.700831123275485E7, + "99.0" : 1.700831123275485E7, + "99.9" : 1.700831123275485E7, + "99.99" : 1.700831123275485E7, + "99.999" : 1.700831123275485E7, + "99.9999" : 1.700831123275485E7, + "100.0" : 1.700831123275485E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.700831123275485E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "1" + }, + "primaryMetric" : { + "score" : 1.1138688178715378E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.1138688178715378E7, + "50.0" : 1.1138688178715378E7, + "90.0" : 1.1138688178715378E7, + "95.0" : 1.1138688178715378E7, + "99.0" : 1.1138688178715378E7, + "99.9" : 1.1138688178715378E7, + "99.99" : 1.1138688178715378E7, + "99.999" : 1.1138688178715378E7, + "99.9999" : 1.1138688178715378E7, + "100.0" : 1.1138688178715378E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.1138688178715378E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "2" + }, + "primaryMetric" : { + "score" : 7759027.958066327, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 7759027.958066327, + "50.0" : 7759027.958066327, + "90.0" : 7759027.958066327, + "95.0" : 7759027.958066327, + "99.0" : 7759027.958066327, + "99.9" : 7759027.958066327, + "99.99" : 7759027.958066327, + "99.999" : 7759027.958066327, + "99.9999" : 7759027.958066327, + "100.0" : 7759027.958066327 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7759027.958066327 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "3" + }, + "primaryMetric" : { + "score" : 4547334.765941614, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 4547334.765941614, + "50.0" : 4547334.765941614, + "90.0" : 4547334.765941614, + "95.0" : 4547334.765941614, + "99.0" : 4547334.765941614, + "99.9" : 4547334.765941614, + "99.99" : 4547334.765941614, + "99.999" : 4547334.765941614, + "99.9999" : 4547334.765941614, + "100.0" : 4547334.765941614 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4547334.765941614 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "4" + }, + "primaryMetric" : { + "score" : 2563987.258485594, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 2563987.258485594, + "50.0" : 2563987.258485594, + "90.0" : 2563987.258485594, + "95.0" : 2563987.258485594, + "99.0" : 2563987.258485594, + "99.9" : 2563987.258485594, + "99.99" : 2563987.258485594, + "99.999" : 2563987.258485594, + "99.9999" : 2563987.258485594, + "100.0" : 2563987.258485594 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2563987.258485594 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "8" + }, + "primaryMetric" : { + "score" : 131149.70918675946, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 131149.70918675946, + "50.0" : 131149.70918675946, + "90.0" : 131149.70918675946, + "95.0" : 131149.70918675946, + "99.0" : 131149.70918675946, + "99.9" : 131149.70918675946, + "99.99" : 131149.70918675946, + "99.999" : 131149.70918675946, + "99.9999" : 131149.70918675946, + "100.0" : 131149.70918675946 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 131149.70918675946 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10" + }, + "primaryMetric" : { + "score" : 12308.28613737422, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 12308.28613737422, + "50.0" : 12308.28613737422, + "90.0" : 12308.28613737422, + "95.0" : 12308.28613737422, + "99.0" : 12308.28613737422, + "99.9" : 12308.28613737422, + "99.99" : 12308.28613737422, + "99.999" : 12308.28613737422, + "99.9999" : 12308.28613737422, + "100.0" : 12308.28613737422 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 12308.28613737422 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12" + }, + "primaryMetric" : { + "score" : 2598.9041516352163, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 2598.9041516352163, + "50.0" : 2598.9041516352163, + "90.0" : 2598.9041516352163, + "95.0" : 2598.9041516352163, + "99.0" : 2598.9041516352163, + "99.9" : 2598.9041516352163, + "99.99" : 2598.9041516352163, + "99.999" : 2598.9041516352163, + "99.9999" : 2598.9041516352163, + "100.0" : 2598.9041516352163 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2598.9041516352163 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14" + }, + "primaryMetric" : { + "score" : 621.0476255011224, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 621.0476255011224, + "50.0" : 621.0476255011224, + "90.0" : 621.0476255011224, + "95.0" : 621.0476255011224, + "99.0" : 621.0476255011224, + "99.9" : 621.0476255011224, + "99.99" : 621.0476255011224, + "99.999" : 621.0476255011224, + "99.9999" : 621.0476255011224, + "100.0" : 621.0476255011224 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 621.0476255011224 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16" + }, + "primaryMetric" : { + "score" : 139.82630658657763, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 139.82630658657763, + "50.0" : 139.82630658657763, + "90.0" : 139.82630658657763, + "95.0" : 139.82630658657763, + "99.0" : 139.82630658657763, + "99.9" : 139.82630658657763, + "99.99" : 139.82630658657763, + "99.999" : 139.82630658657763, + "99.9999" : 139.82630658657763, + "100.0" : 139.82630658657763 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 139.82630658657763 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "18" + }, + "primaryMetric" : { + "score" : 32.359718767696705, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 32.359718767696705, + "50.0" : 32.359718767696705, + "90.0" : 32.359718767696705, + "95.0" : 32.359718767696705, + "99.0" : 32.359718767696705, + "99.9" : 32.359718767696705, + "99.99" : 32.359718767696705, + "99.999" : 32.359718767696705, + "99.9999" : 32.359718767696705, + "100.0" : 32.359718767696705 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 32.359718767696705 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.elementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "19" + }, + "primaryMetric" : { + "score" : 15.903491038693316, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 15.903491038693316, + "50.0" : 15.903491038693316, + "90.0" : 15.903491038693316, + "95.0" : 15.903491038693316, + "99.0" : 15.903491038693316, + "99.9" : 15.903491038693316, + "99.99" : 15.903491038693316, + "99.999" : 15.903491038693316, + "99.9999" : 15.903491038693316, + "100.0" : 15.903491038693316 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 15.903491038693316 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "0" + }, + "primaryMetric" : { + "score" : 3.0952316339848503E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3.0952316339848503E7, + "50.0" : 3.0952316339848503E7, + "90.0" : 3.0952316339848503E7, + "95.0" : 3.0952316339848503E7, + "99.0" : 3.0952316339848503E7, + "99.9" : 3.0952316339848503E7, + "99.99" : 3.0952316339848503E7, + "99.999" : 3.0952316339848503E7, + "99.9999" : 3.0952316339848503E7, + "100.0" : 3.0952316339848503E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.0952316339848503E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "1" + }, + "primaryMetric" : { + "score" : 7560521.642894856, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 7560521.642894856, + "50.0" : 7560521.642894856, + "90.0" : 7560521.642894856, + "95.0" : 7560521.642894856, + "99.0" : 7560521.642894856, + "99.9" : 7560521.642894856, + "99.99" : 7560521.642894856, + "99.999" : 7560521.642894856, + "99.9999" : 7560521.642894856, + "100.0" : 7560521.642894856 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7560521.642894856 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "2" + }, + "primaryMetric" : { + "score" : 3557526.180877572, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3557526.180877572, + "50.0" : 3557526.180877572, + "90.0" : 3557526.180877572, + "95.0" : 3557526.180877572, + "99.0" : 3557526.180877572, + "99.9" : 3557526.180877572, + "99.99" : 3557526.180877572, + "99.999" : 3557526.180877572, + "99.9999" : 3557526.180877572, + "100.0" : 3557526.180877572 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3557526.180877572 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "3" + }, + "primaryMetric" : { + "score" : 1721980.583759659, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1721980.583759659, + "50.0" : 1721980.583759659, + "90.0" : 1721980.583759659, + "95.0" : 1721980.583759659, + "99.0" : 1721980.583759659, + "99.9" : 1721980.583759659, + "99.99" : 1721980.583759659, + "99.999" : 1721980.583759659, + "99.9999" : 1721980.583759659, + "100.0" : 1721980.583759659 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1721980.583759659 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "4" + }, + "primaryMetric" : { + "score" : 737795.2258201947, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 737795.2258201947, + "50.0" : 737795.2258201947, + "90.0" : 737795.2258201947, + "95.0" : 737795.2258201947, + "99.0" : 737795.2258201947, + "99.9" : 737795.2258201947, + "99.99" : 737795.2258201947, + "99.999" : 737795.2258201947, + "99.9999" : 737795.2258201947, + "100.0" : 737795.2258201947 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 737795.2258201947 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "8" + }, + "primaryMetric" : { + "score" : 14470.141135737491, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 14470.141135737491, + "50.0" : 14470.141135737491, + "90.0" : 14470.141135737491, + "95.0" : 14470.141135737491, + "99.0" : 14470.141135737491, + "99.9" : 14470.141135737491, + "99.99" : 14470.141135737491, + "99.999" : 14470.141135737491, + "99.9999" : 14470.141135737491, + "100.0" : 14470.141135737491 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 14470.141135737491 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10" + }, + "primaryMetric" : { + "score" : 3409.1535618738417, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3409.1535618738417, + "50.0" : 3409.1535618738417, + "90.0" : 3409.1535618738417, + "95.0" : 3409.1535618738417, + "99.0" : 3409.1535618738417, + "99.9" : 3409.1535618738417, + "99.99" : 3409.1535618738417, + "99.999" : 3409.1535618738417, + "99.9999" : 3409.1535618738417, + "100.0" : 3409.1535618738417 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3409.1535618738417 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12" + }, + "primaryMetric" : { + "score" : 662.9793727227765, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 662.9793727227765, + "50.0" : 662.9793727227765, + "90.0" : 662.9793727227765, + "95.0" : 662.9793727227765, + "99.0" : 662.9793727227765, + "99.9" : 662.9793727227765, + "99.99" : 662.9793727227765, + "99.999" : 662.9793727227765, + "99.9999" : 662.9793727227765, + "100.0" : 662.9793727227765 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 662.9793727227765 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14" + }, + "primaryMetric" : { + "score" : 89.74606370164268, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 89.74606370164268, + "50.0" : 89.74606370164268, + "90.0" : 89.74606370164268, + "95.0" : 89.74606370164268, + "99.0" : 89.74606370164268, + "99.9" : 89.74606370164268, + "99.99" : 89.74606370164268, + "99.999" : 89.74606370164268, + "99.9999" : 89.74606370164268, + "100.0" : 89.74606370164268 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 89.74606370164268 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16" + }, + "primaryMetric" : { + "score" : 9.497863578110545, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 9.497863578110545, + "50.0" : 9.497863578110545, + "90.0" : 9.497863578110545, + "95.0" : 9.497863578110545, + "99.0" : 9.497863578110545, + "99.9" : 9.497863578110545, + "99.99" : 9.497863578110545, + "99.999" : 9.497863578110545, + "99.9999" : 9.497863578110545, + "100.0" : 9.497863578110545 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 9.497863578110545 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "18" + }, + "primaryMetric" : { + "score" : 0.7630303029631332, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 0.7630303029631332, + "50.0" : 0.7630303029631332, + "90.0" : 0.7630303029631332, + "95.0" : 0.7630303029631332, + "99.0" : 0.7630303029631332, + "99.9" : 0.7630303029631332, + "99.99" : 0.7630303029631332, + "99.999" : 0.7630303029631332, + "99.9999" : 0.7630303029631332, + "100.0" : 0.7630303029631332 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.7630303029631332 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "19" + }, + "primaryMetric" : { + "score" : 0.18791317607485522, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 0.18791317607485522, + "50.0" : 0.18791317607485522, + "90.0" : 0.18791317607485522, + "95.0" : 0.18791317607485522, + "99.0" : 0.18791317607485522, + "99.9" : 0.18791317607485522, + "99.99" : 0.18791317607485522, + "99.999" : 0.18791317607485522, + "99.9999" : 0.18791317607485522, + "100.0" : 0.18791317607485522 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.18791317607485522 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "0" + }, + "primaryMetric" : { + "score" : 3.916296940504498E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3.916296940504498E7, + "50.0" : 3.916296940504498E7, + "90.0" : 3.916296940504498E7, + "95.0" : 3.916296940504498E7, + "99.0" : 3.916296940504498E7, + "99.9" : 3.916296940504498E7, + "99.99" : 3.916296940504498E7, + "99.999" : 3.916296940504498E7, + "99.9999" : 3.916296940504498E7, + "100.0" : 3.916296940504498E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.916296940504498E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "1" + }, + "primaryMetric" : { + "score" : 1.0229672606085628E7, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1.0229672606085628E7, + "50.0" : 1.0229672606085628E7, + "90.0" : 1.0229672606085628E7, + "95.0" : 1.0229672606085628E7, + "99.0" : 1.0229672606085628E7, + "99.9" : 1.0229672606085628E7, + "99.99" : 1.0229672606085628E7, + "99.999" : 1.0229672606085628E7, + "99.9999" : 1.0229672606085628E7, + "100.0" : 1.0229672606085628E7 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.0229672606085628E7 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "2" + }, + "primaryMetric" : { + "score" : 5187949.167063834, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 5187949.167063834, + "50.0" : 5187949.167063834, + "90.0" : 5187949.167063834, + "95.0" : 5187949.167063834, + "99.0" : 5187949.167063834, + "99.9" : 5187949.167063834, + "99.99" : 5187949.167063834, + "99.999" : 5187949.167063834, + "99.9999" : 5187949.167063834, + "100.0" : 5187949.167063834 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5187949.167063834 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "3" + }, + "primaryMetric" : { + "score" : 2615973.0534431874, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 2615973.0534431874, + "50.0" : 2615973.0534431874, + "90.0" : 2615973.0534431874, + "95.0" : 2615973.0534431874, + "99.0" : 2615973.0534431874, + "99.9" : 2615973.0534431874, + "99.99" : 2615973.0534431874, + "99.999" : 2615973.0534431874, + "99.9999" : 2615973.0534431874, + "100.0" : 2615973.0534431874 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2615973.0534431874 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "4" + }, + "primaryMetric" : { + "score" : 1488347.4408349597, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 1488347.4408349597, + "50.0" : 1488347.4408349597, + "90.0" : 1488347.4408349597, + "95.0" : 1488347.4408349597, + "99.0" : 1488347.4408349597, + "99.9" : 1488347.4408349597, + "99.99" : 1488347.4408349597, + "99.999" : 1488347.4408349597, + "99.9999" : 1488347.4408349597, + "100.0" : 1488347.4408349597 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1488347.4408349597 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "8" + }, + "primaryMetric" : { + "score" : 88358.67738981682, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 88358.67738981682, + "50.0" : 88358.67738981682, + "90.0" : 88358.67738981682, + "95.0" : 88358.67738981682, + "99.0" : 88358.67738981682, + "99.9" : 88358.67738981682, + "99.99" : 88358.67738981682, + "99.999" : 88358.67738981682, + "99.9999" : 88358.67738981682, + "100.0" : 88358.67738981682 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 88358.67738981682 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10" + }, + "primaryMetric" : { + "score" : 16036.52761637113, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 16036.52761637113, + "50.0" : 16036.52761637113, + "90.0" : 16036.52761637113, + "95.0" : 16036.52761637113, + "99.0" : 16036.52761637113, + "99.9" : 16036.52761637113, + "99.99" : 16036.52761637113, + "99.999" : 16036.52761637113, + "99.9999" : 16036.52761637113, + "100.0" : 16036.52761637113 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 16036.52761637113 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12" + }, + "primaryMetric" : { + "score" : 3750.424490260002, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 3750.424490260002, + "50.0" : 3750.424490260002, + "90.0" : 3750.424490260002, + "95.0" : 3750.424490260002, + "99.0" : 3750.424490260002, + "99.9" : 3750.424490260002, + "99.99" : 3750.424490260002, + "99.999" : 3750.424490260002, + "99.9999" : 3750.424490260002, + "100.0" : 3750.424490260002 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3750.424490260002 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14" + }, + "primaryMetric" : { + "score" : 825.1117433250652, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 825.1117433250652, + "50.0" : 825.1117433250652, + "90.0" : 825.1117433250652, + "95.0" : 825.1117433250652, + "99.0" : 825.1117433250652, + "99.9" : 825.1117433250652, + "99.99" : 825.1117433250652, + "99.999" : 825.1117433250652, + "99.9999" : 825.1117433250652, + "100.0" : 825.1117433250652 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 825.1117433250652 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16" + }, + "primaryMetric" : { + "score" : 212.8694242448053, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 212.8694242448053, + "50.0" : 212.8694242448053, + "90.0" : 212.8694242448053, + "95.0" : 212.8694242448053, + "99.0" : 212.8694242448053, + "99.9" : 212.8694242448053, + "99.99" : 212.8694242448053, + "99.999" : 212.8694242448053, + "99.9999" : 212.8694242448053, + "100.0" : 212.8694242448053 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 212.8694242448053 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "18" + }, + "primaryMetric" : { + "score" : 51.088303317628935, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 51.088303317628935, + "50.0" : 51.088303317628935, + "90.0" : 51.088303317628935, + "95.0" : 51.088303317628935, + "99.0" : 51.088303317628935, + "99.9" : 51.088303317628935, + "99.99" : 51.088303317628935, + "99.999" : 51.088303317628935, + "99.9999" : 51.088303317628935, + "100.0" : 51.088303317628935 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 51.088303317628935 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.EnumerateSubsetBenchmark.kElementsNotNormalized", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "1.8.0_181", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.181-b13", + "warmupIterations" : 1, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 1, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "19" + }, + "primaryMetric" : { + "score" : 24.809251093862, + "scoreError" : "NaN", + "scoreConfidence" : [ + "NaN", + "NaN" + ], + "scorePercentiles" : { + "0.0" : 24.809251093862, + "50.0" : 24.809251093862, + "90.0" : 24.809251093862, + "95.0" : 24.809251093862, + "99.0" : 24.809251093862, + "99.9" : 24.809251093862, + "99.99" : 24.809251093862, + "99.999" : 24.809251093862, + "99.9999" : 24.809251093862, + "100.0" : 24.809251093862 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 24.809251093862 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/value/impl/EnumerateSubsetBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/EnumerateSubsetBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..78995d3d950b6a33e8337988fe9ed0826a662003 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/impl/EnumerateSubsetBenchmark.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value.impl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; + +@State(Scope.Benchmark) +public class EnumerateSubsetBenchmark { + + static { + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); + + FP64.Init(); + } + + @Param({"0", "1", "2", "3", "4", "8", "10", "12", "14", "16", "18", "19"}) + public int numOfElements; + + @Benchmark + public Enumerable elementsAlwaysNormalized() { + final IntervalValue inner = new IntervalValue(1, numOfElements); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vals = new ValueVec(subset.size()); + final ValueEnumeration Enum = subset.elementsNormalized(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + return (Enumerable) new SetEnumValue(vals, true).normalize(); + } + + @Benchmark + public Enumerable kElementsNotNormalized() { + final IntervalValue inner = new IntervalValue(1, numOfElements); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vec = new ValueVec(subset.size()); + for (int i = 0; i <= inner.size(); i++) { + final ValueEnumeration Enum = subset.kElements(i); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vec.addElement(elem); + } + } + return (Enumerable) new SetEnumValue(vec, false); + } + + @Benchmark + public Enumerable kElementsNormalized() { + final IntervalValue inner = new IntervalValue(1, numOfElements); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vec = new ValueVec(subset.size()); + for (int i = 0; i <= inner.size(); i++) { + final ValueEnumeration Enum = subset.kElements(i); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vec.addElement(elem); + } + } + return (Enumerable) new SetEnumValue(vec, false).normalize(); + } + + @Benchmark + public Enumerable elementsNotNormalized() { + final IntervalValue inner = new IntervalValue(1, numOfElements); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vals = new ValueVec(subset.size()); + final ValueEnumeration Enum = subset.elementsLexicographic(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + return (Enumerable) new SetEnumValue(vals, false); + } + + @Benchmark + public Enumerable elementsNormalized() { + final IntervalValue inner = new IntervalValue(1, numOfElements); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vals = new ValueVec(subset.size()); + final ValueEnumeration Enum = subset.elementsLexicographic(); + Value elem; + while ((elem = Enum.nextElement()) != null) { + vals.addElement(elem); + } + return (Enumerable) new SetEnumValue(vals, false).normalize(); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/IntervalValueBenchmark.java similarity index 90% rename from tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/IntervalValueBenchmark.java index c07719467ea42f3bd7119bd21fc67c7fd6113753..6f7bd8f2de99ededd742fbef27ce3597228b80f0 100644 --- a/tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/IntervalValueBenchmark.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; @@ -33,13 +33,16 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntervalValue; @State(Scope.Benchmark) public class IntervalValueBenchmark { static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); } diff --git a/tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/RandomizationBenchmark.java similarity index 73% rename from tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/RandomizationBenchmark.java index e26006915c068281ceeb529b3d1db3abe59577c0..5e168f4d590469ef0494387aef4148f409225c07 100644 --- a/tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/RandomizationBenchmark.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Scope; @@ -31,6 +31,13 @@ import org.openjdk.jmh.annotations.State; import tlc2.TLCGlobals; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.SetOfFcnsValue; +import tlc2.value.impl.SubsetValue; @State(Scope.Benchmark) public class RandomizationBenchmark { @@ -81,8 +88,8 @@ public class RandomizationBenchmark { } static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); @@ -131,385 +138,385 @@ public class RandomizationBenchmark { /* exact */ @Benchmark - public EnumerableValue randomSetOfSubsetExact024k008() { + public Enumerable randomSetOfSubsetExact024k008() { return subset2pow24.getRandomSetOfSubsets(twoPow08, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact024k012() { + public Enumerable randomSetOfSubsetExact024k012() { return subset2pow24.getRandomSetOfSubsets(twoPow12, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact024k016() { + public Enumerable randomSetOfSubsetExact024k016() { return subset2pow24.getRandomSetOfSubsets(twoPow16, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact031k008() { + public Enumerable randomSetOfSubsetExact031k008() { return subset2pow31.getRandomSetOfSubsets(twoPow08, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact031k012() { + public Enumerable randomSetOfSubsetExact031k012() { return subset2pow31.getRandomSetOfSubsets(twoPow12, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact031k016() { + public Enumerable randomSetOfSubsetExact031k016() { return subset2pow31.getRandomSetOfSubsets(twoPow16, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact65k008() { + public Enumerable randomSetOfSubsetExact65k008() { return subset2pow65.getRandomSetOfSubsets(twoPow08, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact065k012() { + public Enumerable randomSetOfSubsetExact065k012() { return subset2pow65.getRandomSetOfSubsets(twoPow12, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact065k016() { + public Enumerable randomSetOfSubsetExact065k016() { return subset2pow65.getRandomSetOfSubsets(twoPow16, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact150k008() { + public Enumerable randomSetOfSubsetExact150k008() { return subset2pow150.getRandomSetOfSubsets(twoPow08, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact150k012() { + public Enumerable randomSetOfSubsetExact150k012() { return subset2pow150.getRandomSetOfSubsets(twoPow12, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact150k016() { + public Enumerable randomSetOfSubsetExact150k016() { return subset2pow150.getRandomSetOfSubsets(twoPow16, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact268k008() { + public Enumerable randomSetOfSubsetExact268k008() { return subset2pow268.getRandomSetOfSubsets(twoPow08, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact268k012() { + public Enumerable randomSetOfSubsetExact268k012() { return subset2pow268.getRandomSetOfSubsets(twoPow12, 10); } @Benchmark - public EnumerableValue randomSetOfSubsetExact268k016() { + public Enumerable randomSetOfSubsetExact268k016() { return subset2pow268.getRandomSetOfSubsets(twoPow16, 10); } /* probabilistic */ @Benchmark - public EnumerableValue randomSetOfSubset024k008() { + public Enumerable randomSetOfSubset024k008() { return subset2pow24.getRandomSetOfSubsets(twoPow08, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset024k012() { + public Enumerable randomSetOfSubset024k012() { return subset2pow24.getRandomSetOfSubsets(twoPow12, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset024k016() { + public Enumerable randomSetOfSubset024k016() { return subset2pow24.getRandomSetOfSubsets(twoPow16, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset031k008() { + public Enumerable randomSetOfSubset031k008() { return subset2pow31.getRandomSetOfSubsets(twoPow08, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset031k012() { + public Enumerable randomSetOfSubset031k012() { return subset2pow31.getRandomSetOfSubsets(twoPow12, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset031k016() { + public Enumerable randomSetOfSubset031k016() { return subset2pow31.getRandomSetOfSubsets(twoPow16, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset065k008() { + public Enumerable randomSetOfSubset065k008() { return subset2pow65.getRandomSetOfSubsets(twoPow08, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset065k012() { + public Enumerable randomSetOfSubset065k012() { return subset2pow65.getRandomSetOfSubsets(twoPow12, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset065k016() { + public Enumerable randomSetOfSubset065k016() { return subset2pow65.getRandomSetOfSubsets(twoPow16, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset150k008() { + public Enumerable randomSetOfSubset150k008() { return subset2pow150.getRandomSetOfSubsets(twoPow08, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset150k012() { + public Enumerable randomSetOfSubset150k012() { return subset2pow150.getRandomSetOfSubsets(twoPow12, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset150k016() { + public Enumerable randomSetOfSubset150k016() { return subset2pow150.getRandomSetOfSubsets(twoPow16, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset268k008() { + public Enumerable randomSetOfSubset268k008() { return subset2pow268.getRandomSetOfSubsets(twoPow08, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset268k012() { + public Enumerable randomSetOfSubset268k012() { return subset2pow268.getRandomSetOfSubsets(twoPow12, .1d); } @Benchmark - public EnumerableValue randomSetOfSubset268k016() { + public Enumerable randomSetOfSubset268k016() { return subset2pow268.getRandomSetOfSubsets(twoPow16, .1d); } /* IntervalValue */ @Benchmark - public EnumerableValue randomInterval016setBound() { + public Enumerable randomInterval016setBound() { return interval16.getRandomSubset(TLCGlobals.setBound); } @Benchmark - public EnumerableValue randomInterval020setBound() { + public Enumerable randomInterval020setBound() { return interval20.getRandomSubset(TLCGlobals.setBound); } @Benchmark - public EnumerableValue randomInterval024setBound() { + public Enumerable randomInterval024setBound() { return interval24.getRandomSubset(TLCGlobals.setBound); } @Benchmark - public EnumerableValue randomInterval028setBound() { + public Enumerable randomInterval028setBound() { return interval28.getRandomSubset(TLCGlobals.setBound); } @Benchmark - public EnumerableValue randomInterval031setBound() { + public Enumerable randomInterval031setBound() { return interval31.getRandomSubset(TLCGlobals.setBound); } @Benchmark - public EnumerableValue randomIntervalt016all() { + public Enumerable randomIntervalt016all() { return interval16.getRandomSubset(interval16.size() - 1); } @Benchmark - public EnumerableValue randomInterval020all() { + public Enumerable randomInterval020all() { return interval20.getRandomSubset(interval20.size() - 1); } @Benchmark - public EnumerableValue randomInterval024all() { + public Enumerable randomInterval024all() { return interval24.getRandomSubset(interval24.size() - 1); } @Benchmark - public EnumerableValue randomIntervalt016half() { + public Enumerable randomIntervalt016half() { return interval16.getRandomSubset(interval16.size() / 2); } @Benchmark - public EnumerableValue randomInterval020half() { + public Enumerable randomInterval020half() { return interval20.getRandomSubset(interval20.size() / 2); } @Benchmark - public EnumerableValue randomInterval024half() { + public Enumerable randomInterval024half() { return interval24.getRandomSubset(interval24.size() / 2); } /* SetEnumValue */ @Benchmark - public EnumerableValue randomSubset016() { + public Enumerable randomSubset016() { return enum016.getRandomSubset(enum016.size() - 1); } @Benchmark - public EnumerableValue randomSubset032() { + public Enumerable randomSubset032() { return enum032.getRandomSubset(enum032.size() - 1); } @Benchmark - public EnumerableValue randomSubset064() { + public Enumerable randomSubset064() { return enum064.getRandomSubset(enum064.size() - 1); } @Benchmark - public EnumerableValue randomSubset128() { + public Enumerable randomSubset128() { return enum128.getRandomSubset(enum128.size() - 1); } @Benchmark - public EnumerableValue randomSubset256() { + public Enumerable randomSubset256() { return enum256.getRandomSubset(enum256.size() - 1); } @Benchmark - public EnumerableValue randomSubset512() { + public Enumerable randomSubset512() { return enum512.getRandomSubset(enum512.size() - 1); } @Benchmark - public EnumerableValue randomSubset1024() { + public Enumerable randomSubset1024() { return enum1024.getRandomSubset(enum1024.size() - 1); } @Benchmark - public EnumerableValue randomSubset2048() { + public Enumerable randomSubset2048() { return enum2048.getRandomSubset(enum2048.size() - 1); } @Benchmark - public EnumerableValue randomSubset4096() { + public Enumerable randomSubset4096() { return enum4096.getRandomSubset(enum4096.size() - 1); } @Benchmark - public EnumerableValue randomSubset8192() { + public Enumerable randomSubset8192() { return enum8192.getRandomSubset(enum8192.size() - 1); } @Benchmark - public EnumerableValue randomSubset16384() { + public Enumerable randomSubset16384() { return enum16384.getRandomSubset(enum16384.size() - 1); } @Benchmark - public EnumerableValue randomSubset32768() { + public Enumerable randomSubset32768() { return enum32768.getRandomSubset(enum32768.size() - 1); } @Benchmark - public EnumerableValue randomSubsetTLCBound() { + public Enumerable randomSubsetTLCBound() { return enumTLCBound.getRandomSubset(enumTLCBound.size() - 1); } /* randomSubset with SetOfFcns */ @Benchmark - public EnumerableValue randomSubsetFcns008x008p16() { + public Enumerable randomSubsetFcns008x008p16() { return fcns008x008.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns008x008p08() { + public Enumerable randomSubsetFcns008x008p08() { return fcns008x008.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns008x008p12() { + public Enumerable randomSubsetFcns008x008p12() { return fcns008x008.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns011x011p16() { + public Enumerable randomSubsetFcns011x011p16() { return fcns008x008.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns011x011p08() { + public Enumerable randomSubsetFcns011x011p08() { return fcns011x011.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns011x011p12() { + public Enumerable randomSubsetFcns011x011p12() { return fcns011x011.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns016x008p16() { + public Enumerable randomSubsetFcns016x008p16() { return fcns011x011.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns016x008p08() { + public Enumerable randomSubsetFcns016x008p08() { return fcns016x008.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns016x008p12() { + public Enumerable randomSubsetFcns016x008p12() { return fcns016x008.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns016x016p16() { + public Enumerable randomSubsetFcns016x016p16() { return fcns016x016.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns016x016p08() { + public Enumerable randomSubsetFcns016x016p08() { return fcns016x016.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns016x016p12() { + public Enumerable randomSubsetFcns016x016p12() { return fcns016x016.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns032x016p16() { + public Enumerable randomSubsetFcns032x016p16() { return fcns032x016.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns032x016p08() { + public Enumerable randomSubsetFcns032x016p08() { return fcns032x016.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns032x016p12() { + public Enumerable randomSubsetFcns032x016p12() { return fcns032x016.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns032x032p16() { + public Enumerable randomSubsetFcns032x032p16() { return fcns032x032.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns032x032p08() { + public Enumerable randomSubsetFcns032x032p08() { return fcns032x032.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns032x032p12() { + public Enumerable randomSubsetFcns032x032p12() { return fcns032x032.getRandomSubset(twoPow12); } @Benchmark - public EnumerableValue randomSubsetFcns048x048p16() { + public Enumerable randomSubsetFcns048x048p16() { return fcns048x048.getRandomSubset(twoPow16); } @Benchmark - public EnumerableValue randomSubsetFcns048x048p08() { + public Enumerable randomSubsetFcns048x048p08() { return fcns048x048.getRandomSubset(twoPow08); } @Benchmark - public EnumerableValue randomSubsetFcns048x048p12() { + public Enumerable randomSubsetFcns048x048p12() { return fcns048x048.getRandomSubset(twoPow12); } } diff --git a/tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/SetEnumValueBenchmark.java similarity index 89% rename from tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/SetEnumValueBenchmark.java index 91707427532edde57d05ddbb1993a2ae2fece837..e0b853c4585f1fe58ec2e8e0b373a635bb1933be 100644 --- a/tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/SetEnumValueBenchmark.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; @@ -33,13 +33,17 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.SetEnumValue; @State(Scope.Benchmark) public class SetEnumValueBenchmark { static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); } @@ -66,7 +70,7 @@ public class SetEnumValueBenchmark { } @Benchmark - public EnumerableValue randomSubset() { + public Enumerable randomSubset() { return setEnumValue.getRandomSubset(1 << numOfElements); } } diff --git a/tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/SetOfFcnsBenchmark.java similarity index 93% rename from tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/SetOfFcnsBenchmark.java index 4e558e0501100679f955518b77a6257729bcfb47..09ef16cd5b415dce356bf724bb3c8ed7d81a04ff 100644 --- a/tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/SetOfFcnsBenchmark.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; @@ -33,13 +33,14 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; @State(Scope.Benchmark) public class SetOfFcnsBenchmark { static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); } @@ -77,7 +78,7 @@ public class SetOfFcnsBenchmark { } @Benchmark - public EnumerableValue randomSubset() { + public Enumerable randomSubset() { return setOfFcns.getRandomSubset(1 << numOfElements); } } diff --git a/tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/SubsetBenchmark.java similarity index 87% rename from tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/SubsetBenchmark.java index 63e05bff52979d853dfbd55c3f11839ba6262313..54aa0060ae703eacdb29f86141dd141cf80b9abf 100644 --- a/tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/SubsetBenchmark.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; @@ -33,13 +33,17 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SubsetValue; @State(Scope.Benchmark) public class SubsetBenchmark { static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); } @@ -65,12 +69,12 @@ public class SubsetBenchmark { } @Benchmark - public EnumerableValue randomSetOfSubsets() { + public Enumerable randomSetOfSubsets() { return subset.getRandomSetOfSubsets(1 << numOfElements, .1d); } @Benchmark - public EnumerableValue randomSetOfSubsetsExact() { + public Enumerable randomSetOfSubsetsExact() { return subset.getRandomSetOfSubsets(1 << numOfElements, 10); } } diff --git a/tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/impl/SubsetValueBenchmark.java similarity index 74% rename from tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java rename to tlatools/test-benchmark/tlc2/value/impl/SubsetValueBenchmark.java index 10edca6895059679cf198737359346e9140f8eda..c2aecd266ce7a24a607468ffa8007b69adf12d40 100644 --- a/tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java +++ b/tlatools/test-benchmark/tlc2/value/impl/SubsetValueBenchmark.java @@ -23,13 +23,17 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import tlc2.util.FP64; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SubsetValue; @State(Scope.Benchmark) public class SubsetValueBenchmark { @@ -47,8 +51,8 @@ public class SubsetValueBenchmark { private static final double d2 = 0.2d; static { - EnumerableValue.setRandom(15041980L); - EnumerableValue.resetRandom(); + RandomEnumerableValues.setSeed(15041980L); + RandomEnumerableValues.reset(); FP64.Init(); @@ -67,73 +71,73 @@ public class SubsetValueBenchmark { } @Benchmark - public EnumerableValue probabilisticN035k80d01() { + public Enumerable probabilisticN035k80d01() { // ~49k subsets return subset35.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN060k80d01() { + public Enumerable probabilisticN060k80d01() { // ~76500 subsets return subset60.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN100k80d01() { + public Enumerable probabilisticN100k80d01() { // ~79900 return subset100.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN200k80d01() { + public Enumerable probabilisticN200k80d01() { // ~80k return subset200.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN300k80d01() { + public Enumerable probabilisticN300k80d01() { // ~80k return subset300.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN400k80d01() { + public Enumerable probabilisticN400k80d01() { // ~80k return subset400.getRandomSetOfSubsets(k, d); } @Benchmark - public EnumerableValue probabilisticN035k16d01() { + public Enumerable probabilisticN035k16d01() { // ~73500 return subset35.getRandomSetOfSubsets(k2, d); } @Benchmark - public EnumerableValue probabilisticN060k16d01() { + public Enumerable probabilisticN060k16d01() { // ~150k return subset60.getRandomSetOfSubsets(k2, d); } @Benchmark - public EnumerableValue probabilisticN100k16d01() { + public Enumerable probabilisticN100k16d01() { // ~160k return subset100.getRandomSetOfSubsets(k2, d); } @Benchmark - public EnumerableValue probabilisticN200k16d01() { + public Enumerable probabilisticN200k16d01() { // 160k return subset200.getRandomSetOfSubsets(k2, d); } @Benchmark - public EnumerableValue probabilisticN300k16d01() { + public Enumerable probabilisticN300k16d01() { // 160k return subset300.getRandomSetOfSubsets(k2, d); } @Benchmark - public EnumerableValue probabilisticN400k16d01() { + public Enumerable probabilisticN400k16d01() { // 160k return subset400.getRandomSetOfSubsets(k2, d); } @@ -141,73 +145,73 @@ public class SubsetValueBenchmark { /* d2 */ @Benchmark - public EnumerableValue probabilisticN035k80d02() { + public Enumerable probabilisticN035k80d02() { // ~77600 return subset35.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN060k80d02() { + public Enumerable probabilisticN060k80d02() { // 80k return subset60.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN100k80d02() { + public Enumerable probabilisticN100k80d02() { // 80k return subset100.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN200k80d02() { + public Enumerable probabilisticN200k80d02() { // 80k return subset200.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN300k80d02() { + public Enumerable probabilisticN300k80d02() { // 80k return subset300.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN400k80d02() { + public Enumerable probabilisticN400k80d02() { // 80k return subset400.getRandomSetOfSubsets(k, d2); } @Benchmark - public EnumerableValue probabilisticN035k16d02() { + public Enumerable probabilisticN035k16d02() { // ~15200 return subset35.getRandomSetOfSubsets(k2, d2); } @Benchmark - public EnumerableValue probabilisticN060k16d02() { + public Enumerable probabilisticN060k16d02() { // 160k return subset60.getRandomSetOfSubsets(k2, d2); } @Benchmark - public EnumerableValue probabilisticN100k16d02() { + public Enumerable probabilisticN100k16d02() { // 160k return subset100.getRandomSetOfSubsets(k2, d2); } @Benchmark - public EnumerableValue probabilisticN200k16d02() { + public Enumerable probabilisticN200k16d02() { // 160k return subset200.getRandomSetOfSubsets(k2, d2); } @Benchmark - public EnumerableValue probabilisticN300k16d02() { + public Enumerable probabilisticN300k16d02() { // 160k return subset300.getRandomSetOfSubsets(k2, d2); } @Benchmark - public EnumerableValue probabilisticN400k16d02() { + public Enumerable probabilisticN400k16d02() { // 160k return subset400.getRandomSetOfSubsets(k2, d2); } @@ -215,84 +219,84 @@ public class SubsetValueBenchmark { /* Exact getRandomSetOfSubsets */ @Benchmark - public EnumerableValue exactN035K08() { + public Enumerable exactN035K08() { return subset35.getRandomSetOfSubsets(k, 8); } @Benchmark - public EnumerableValue exactN035K13() { + public Enumerable exactN035K13() { return subset35.getRandomSetOfSubsets(k, 13); } @Benchmark - public EnumerableValue exactN060K08() { + public Enumerable exactN060K08() { return subset60.getRandomSetOfSubsets(k, 8); } @Benchmark - public EnumerableValue exactN100K08() { + public Enumerable exactN100K08() { return subset100.getRandomSetOfSubsets(k, 8); } @Benchmark - public EnumerableValue exactN100K10() { + public Enumerable exactN100K10() { return subset100.getRandomSetOfSubsets(k, 10); } @Benchmark - public EnumerableValue exactN200K10() { + public Enumerable exactN200K10() { return subset200.getRandomSetOfSubsets(k, 10); } @Benchmark - public EnumerableValue exactN300K09() { + public Enumerable exactN300K09() { return subset300.getRandomSetOfSubsets(k, 9); } @Benchmark - public EnumerableValue exactN400K09() { + public Enumerable exactN400K09() { return subset400.getRandomSetOfSubsets(k, 9); } /* k2 */ @Benchmark - public EnumerableValue exactN035K208() { + public Enumerable exactN035K208() { return subset35.getRandomSetOfSubsets(k2, 8); } @Benchmark - public EnumerableValue exactN035K213() { + public Enumerable exactN035K213() { return subset35.getRandomSetOfSubsets(k2, 13); } @Benchmark - public EnumerableValue exactN060K208() { + public Enumerable exactN060K208() { return subset60.getRandomSetOfSubsets(k2, 8); } @Benchmark - public EnumerableValue exactN100K208() { + public Enumerable exactN100K208() { return subset100.getRandomSetOfSubsets(k2, 8); } @Benchmark - public EnumerableValue exactN100K210() { + public Enumerable exactN100K210() { return subset100.getRandomSetOfSubsets(k2, 10); } @Benchmark - public EnumerableValue exactN200K210() { + public Enumerable exactN200K210() { return subset200.getRandomSetOfSubsets(k2, 10); } @Benchmark - public EnumerableValue exactN300K209() { + public Enumerable exactN300K209() { return subset300.getRandomSetOfSubsets(k2, 9); } @Benchmark - public EnumerableValue exactN400K209() { + public Enumerable exactN400K209() { return subset400.getRandomSetOfSubsets(k2, 9); } } @@ -303,9 +307,9 @@ public class SubsetValueBenchmark { * better) Mode.SampleTime: Calculate how long does it take for a method to run * (including percentiles). Mode.SingleShotTime: Just run a method once (useful * for cold-testing mode). Or more than once if you have specified a batch size - * for your iterations (see @Measurement annotation below) – in this case JMH + * for your iterations (see @Measurement annotation below) - in this case JMH * will calculate the batch running time (total time for all invocations in a - * batch). Any set of these modes You can specify any set of these modes – the + * batch). Any set of these modes You can specify any set of these modes - the * test will be run several times (depending on number of requested modes). * Mode.All: All these modes one after another. */ \ No newline at end of file diff --git a/tlatools/test-long/tlc2/tool/fp/FPSetTest.java b/tlatools/test-long/tlc2/tool/fp/FPSetTest.java index 5adadc05b830d75818eeb21b1f6229dbae9532b0..fd48e05b5e8da50d417c38f75f7b5a1ee0d89cf5 100644 --- a/tlatools/test-long/tlc2/tool/fp/FPSetTest.java +++ b/tlatools/test-long/tlc2/tool/fp/FPSetTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Date; import java.util.Random; + import org.junit.Test; public abstract class FPSetTest extends AbstractFPSetTest { diff --git a/tlatools/test-long/tlc2/tool/fp/OffHeapDiskFPSetLongTest.java b/tlatools/test-long/tlc2/tool/fp/OffHeapDiskFPSetLongTest.java index 079f81f4e313437c6447a77b7ad6289cb277589f..dd0667435682a0e3152c7069c833c537e7a432aa 100644 --- a/tlatools/test-long/tlc2/tool/fp/OffHeapDiskFPSetLongTest.java +++ b/tlatools/test-long/tlc2/tool/fp/OffHeapDiskFPSetLongTest.java @@ -6,7 +6,9 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Random; + import org.junit.Test; + import util.TLCRuntime; public class OffHeapDiskFPSetLongTest extends FPSetTest { diff --git a/tlatools/test-long/tlc2/tool/liveness/MultiThreadedSpecTest.java b/tlatools/test-long/tlc2/tool/liveness/MultiThreadedSpecTest.java index caedceda530ae0769488c6adb955b8386f3e2c9f..095bd66b36d783f62f48b6e41ba0eb30a17bed65 100644 --- a/tlatools/test-long/tlc2/tool/liveness/MultiThreadedSpecTest.java +++ b/tlatools/test-long/tlc2/tool/liveness/MultiThreadedSpecTest.java @@ -38,8 +38,10 @@ import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + import org.junit.Before; import org.junit.Test; + import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.tool.WorkerMonitor; diff --git a/tlatools/test-long/tlc2/tool/queue/DiskStateQueueTest.java b/tlatools/test-long/tlc2/tool/queue/DiskStateQueueTest.java index b093369427fea8a3e111f49f4cee7376dc1585e8..7722fccb64b69d5b5a05044514d0b8dcd223602c 100644 --- a/tlatools/test-long/tlc2/tool/queue/DiskStateQueueTest.java +++ b/tlatools/test-long/tlc2/tool/queue/DiskStateQueueTest.java @@ -3,9 +3,11 @@ package tlc2.tool.queue; import static org.junit.Assert.assertTrue; import java.io.File; + import org.junit.After; import org.junit.Before; import org.junit.Test; + import tlc2.tool.TLCState; public class DiskStateQueueTest extends StateQueueTest { diff --git a/tlatools/test-model/.gitattributes b/tlatools/test-model/.gitattributes index fcadb2cf97913f58a2523f535336e725c6b59d1f..8b8a4987707a99a70444d60d1bd5911155574261 100644 --- a/tlatools/test-model/.gitattributes +++ b/tlatools/test-model/.gitattributes @@ -1 +1,2 @@ * text eol=lf +*.zip -text \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions.tla b/tlatools/test-model/BidirectionalTransitions.tla new file mode 100644 index 0000000000000000000000000000000000000000..13692344091ab32bb16f8c9eddfa4340e1837986 --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions.tla @@ -0,0 +1,28 @@ +-------- MODULE BidirectionalTransitions -------- +EXTENDS Naturals +VARIABLE x + +------------------------------------------------- + +A == \/ x' = (x + 1) % 3 +B == x' \in 0..2 +Spec1A == (x=0) /\ [][A \/ B]_x/\ WF_x(A) +Prop1A == Spec1A /\ WF_x(A) /\ []<><<A>>_x + +Fair1B == WF_x(B) +Spec1B == (x=0) /\ [][A \/ B]_x/\ Fair1B +Prop1Bx == WF_x(A) +Prop1By == []<><<A>>_x + +------------------------------------------------- + +C == x' = (x + 1) % 4 +D == IF x = 0 THEN x' = 3 ELSE x' = x - 1 +Spec2 == (x=0) /\ [][C \/ D]_x/\ WF_x(D) +Prop2 == Spec2 /\ WF_x(D) /\ []<><<D>>_x + +Fair2C == WF_x(C) +Spec2C == (x=0) /\ [][C \/ D]_x/\ Fair2C +Prop2Cx == WF_x(D) +Prop2Cy == []<><<D>>_x +================================================= diff --git a/tlatools/test-model/BidirectionalTransitions1.cfg b/tlatools/test-model/BidirectionalTransitions1.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4dfeb6f715ebb0c65e5dc6ea88e7e21bb111121c --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions1.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec1A +PROPERTY Prop1A \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions1Bx.cfg b/tlatools/test-model/BidirectionalTransitions1Bx.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e367efe8156a93bef21e9f069e2762959c275273 --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions1Bx.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec1B +PROPERTY Prop1Bx \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions1By.cfg b/tlatools/test-model/BidirectionalTransitions1By.cfg new file mode 100644 index 0000000000000000000000000000000000000000..5ea4ab4b101fc5cbd4f3e4960ce7762fae4793a8 --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions1By.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec1B +PROPERTY Prop1By \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions2.cfg b/tlatools/test-model/BidirectionalTransitions2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..cf19795244dfcd43754275e2226f72f98622b353 --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions2.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec2 +PROPERTY Prop2 \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions2Cx.cfg b/tlatools/test-model/BidirectionalTransitions2Cx.cfg new file mode 100644 index 0000000000000000000000000000000000000000..89d65691a97406e4ea87144e83ee11f266b746b0 --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions2Cx.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec2C +PROPERTY Prop2Cx \ No newline at end of file diff --git a/tlatools/test-model/BidirectionalTransitions2Cy.cfg b/tlatools/test-model/BidirectionalTransitions2Cy.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8fdea573a4265780e569292ab97742c5b3b99a7a --- /dev/null +++ b/tlatools/test-model/BidirectionalTransitions2Cy.cfg @@ -0,0 +1,2 @@ +SPECIFICATION Spec2C +PROPERTY Prop2Cy \ No newline at end of file diff --git a/tlatools/test-model/Bug279/InitStateBug.cfg b/tlatools/test-model/Bug279/InitStateBug.cfg new file mode 100644 index 0000000000000000000000000000000000000000..5db1b74d8239cc161ffbc357c088cdbc8f41f02c --- /dev/null +++ b/tlatools/test-model/Bug279/InitStateBug.cfg @@ -0,0 +1,4 @@ +\* INIT definition +INIT Init +NEXT Next +\* Generated on Wed Mar 07 12:58:05 PST 2012 \ No newline at end of file diff --git a/tlatools/test-model/Bug279/InitStateBug.tla b/tlatools/test-model/Bug279/InitStateBug.tla new file mode 100644 index 0000000000000000000000000000000000000000..53c2c4226d146f1163a7f8b4ea6948b6215d6ed7 --- /dev/null +++ b/tlatools/test-model/Bug279/InitStateBug.tla @@ -0,0 +1,39 @@ +---------------------------- MODULE InitStateBug ---------------------------- +EXTENDS Naturals + +RECURSIVE AllSubs(_) +AllSubs(S) == + IF S = {} THEN {{}} ELSE + LET + c == CHOOSE c \in S : TRUE + T == S \ {c} + TT == AllSubs(T) + IN + TT \cup { t \cup {c} : t \in TT } + +RECURSIVE Sum(_) +Sum(S) == + IF S = {} THEN 0 ELSE + LET c == CHOOSE c \in S : TRUE + IN c + Sum(S \ {c}) + +Ch(S) == CHOOSE v \in S : Sum(v) > 4 + +S1 == SUBSET (1..20) \* Increased from 1..8 to 1..20 to also test performance with this spec. +S2 == AllSubs(1..8) + +VARIABLE pc, set, fun + +Init == pc = 0 /\ set = {} /\ fun = {} + +Next == + CASE + pc = 0 -> pc' = 1 /\ set' = S1 /\ fun' = Ch(set') + [] + pc = 1 -> pc' = 2 /\ set' = S2 /\ fun' = Ch(set') + [] + OTHER -> FALSE +============================================================================= +\* Modification History +\* Last modified Wed Mar 07 10:27:18 PST 2012 by tomr +\* Created Wed Mar 07 10:24:35 PST 2012 by tomr diff --git a/tlatools/test-model/CallGotoUnlabeledTest.tla b/tlatools/test-model/CallGotoUnlabeledTest.tla index 23c92f7c48b07b63c3e2bdf3a354982bb9aab125..f8eb948eef286115e24c5a588c3af372948a8e80 100644 --- a/tlatools/test-model/CallGotoUnlabeledTest.tla +++ b/tlatools/test-model/CallGotoUnlabeledTest.tla @@ -56,9 +56,11 @@ C == /\ pc = "C" /\ pc' = "A" /\ stack' = stack +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Foo \/ A \/ Lbl_2 \/ C - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/CodePlexBug08/checkpoint.zip b/tlatools/test-model/CodePlexBug08/checkpoint.zip index 7ec0a6bf7e431bf80d098a17cf312261a8fb3bae..b9c9d7d520634a13a9fe457bddf49cb78247b532 100644 Binary files a/tlatools/test-model/CodePlexBug08/checkpoint.zip and b/tlatools/test-model/CodePlexBug08/checkpoint.zip differ diff --git a/tlatools/test-model/DistributedTrace.cfg b/tlatools/test-model/DistributedTrace.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/DistributedTrace.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/DistributedTrace.tla b/tlatools/test-model/DistributedTrace.tla new file mode 100644 index 0000000000000000000000000000000000000000..6149b74a924ac27de52a3461e0124a21b13eabf5 --- /dev/null +++ b/tlatools/test-model/DistributedTrace.tla @@ -0,0 +1,14 @@ +-------------------------- MODULE DistributedTrace -------------------------- +EXTENDS Integers, Sequences + +VARIABLES x +vars == <<x>> + +Init == x \in 1..10 + +Next == x' = x + 1 + +Spec == /\ Init /\ [][Next]_vars + +Inv == x < 20 +============================================================================= diff --git a/tlatools/test-model/EmptyOrderOfSolutions.cfg b/tlatools/test-model/EmptyOrderOfSolutions.cfg new file mode 100644 index 0000000000000000000000000000000000000000..20524345c8bb1355485ae7282e49cd9a44301eca --- /dev/null +++ b/tlatools/test-model/EmptyOrderOfSolutions.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +PROPERTY +Prop diff --git a/tlatools/test-model/EmptyOrderOfSolutions.tla b/tlatools/test-model/EmptyOrderOfSolutions.tla new file mode 100644 index 0000000000000000000000000000000000000000..96d3acd32389749608f70073e1fcf0132d6d3291 --- /dev/null +++ b/tlatools/test-model/EmptyOrderOfSolutions.tla @@ -0,0 +1,11 @@ +----- MODULE EmptyOrderOfSolutions ----- +VARIABLES x + +Init == x = 0 + +Next == x' = 1 + +Spec == Init /\ [][Next]_x + +Prop == <>[]TRUE => TRUE +===== diff --git a/tlatools/test-model/EvalOrder/Base.tla b/tlatools/test-model/EvalOrder/Base.tla new file mode 100644 index 0000000000000000000000000000000000000000..28ae14504aa4588c69bd526ba3bb137a6418bcc6 --- /dev/null +++ b/tlatools/test-model/EvalOrder/Base.tla @@ -0,0 +1,9 @@ +-------------------------------- MODULE Base -------------------------------- +VARIABLES clk +vars == <<clk>> + +Init == clk = 0 + +Spec == Init /\ [][UNCHANGED vars]_vars + +============================================================================= diff --git a/tlatools/test-model/EvalOrder/InitEvalOrder.tla b/tlatools/test-model/EvalOrder/InitEvalOrder.tla new file mode 100644 index 0000000000000000000000000000000000000000..098bc1a98d2ceb693bb9edd3e7cd7f408cdb8bf1 --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrder.tla @@ -0,0 +1,23 @@ +--------------------------- MODULE InitEvalOrder --------------------------- +VARIABLE Clk1 +S1 == INSTANCE Base WITH clk <- Clk1 + +VARIABLE Clk2 +S2 == INSTANCE Base WITH clk <- Clk2 + +Spec1 == + /\ S1!Init /\ S2!Init /\ (Clk2 = Clk1) + /\ [][UNCHANGED <<Clk1, Clk2>>]_<<S1!vars, S2!vars>> + +Spec2 == + /\ S2!Init /\ S1!Init /\ (Clk1 = Clk2) + /\ [][UNCHANGED <<Clk1, Clk2>>]_<<S1!vars, S2!vars>> + +Spec3 == + /\ S1!Init /\ S2!Init /\ (Clk1 = Clk2) + /\ [][UNCHANGED <<Clk1, Clk2>>]_<<S1!vars, S2!vars>> + +Spec4 == + /\ S2!Init /\ S1!Init /\ (Clk2 = Clk1) + /\ [][UNCHANGED <<Clk1, Clk2>>]_<<S1!vars, S2!vars>> +============================================================================= diff --git a/tlatools/test-model/EvalOrder/InitEvalOrder1.cfg b/tlatools/test-model/EvalOrder/InitEvalOrder1.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d1f34ad6b4d496bb2024748004055359877a09ef --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrder1.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec1 diff --git a/tlatools/test-model/EvalOrder/InitEvalOrder2.cfg b/tlatools/test-model/EvalOrder/InitEvalOrder2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e041393416d454a2bdd87c66b69feebaf31ddbd9 --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrder2.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec2 diff --git a/tlatools/test-model/EvalOrder/InitEvalOrder3.cfg b/tlatools/test-model/EvalOrder/InitEvalOrder3.cfg new file mode 100644 index 0000000000000000000000000000000000000000..da6984d2a15785661ab45dfbce82aefb482c1c8a --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrder3.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec3 diff --git a/tlatools/test-model/EvalOrder/InitEvalOrder4.cfg b/tlatools/test-model/EvalOrder/InitEvalOrder4.cfg new file mode 100644 index 0000000000000000000000000000000000000000..789c3de3bc109d466cec77824bda13ad9b4b1da8 --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrder4.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec4 diff --git a/tlatools/test-model/EvalOrder/InitEvalOrderBasic.cfg b/tlatools/test-model/EvalOrder/InitEvalOrderBasic.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrderBasic.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec diff --git a/tlatools/test-model/EvalOrder/InitEvalOrderBasic.tla b/tlatools/test-model/EvalOrder/InitEvalOrderBasic.tla new file mode 100644 index 0000000000000000000000000000000000000000..9e70f772e449733b9a29de075dd99c9dd36a9c82 --- /dev/null +++ b/tlatools/test-model/EvalOrder/InitEvalOrderBasic.tla @@ -0,0 +1,6 @@ +--------------------------- MODULE InitEvalOrderBasic --------------------------- +VARIABLES x, y + +Spec == /\ (y=0) /\ (x=0) /\ (y = x) + /\ [][UNCHANGED <<x,y>>]_<<x,y>> +============================================================================= diff --git a/tlatools/test-model/Github179a.cfg b/tlatools/test-model/Github179a.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3662e06f049e7c9069b5137ddfc038d9eb799c36 --- /dev/null +++ b/tlatools/test-model/Github179a.cfg @@ -0,0 +1,4 @@ +INIT +Init +NEXT +Next \ No newline at end of file diff --git a/tlatools/test-model/Github179a.tla b/tlatools/test-model/Github179a.tla new file mode 100644 index 0000000000000000000000000000000000000000..fd046e45a32ead359ea53c1cf490f8db1303aa0f --- /dev/null +++ b/tlatools/test-model/Github179a.tla @@ -0,0 +1,25 @@ +---- MODULE Github179a ---- +EXTENDS TLC, Naturals + +VARIABLE v + +Max(s) == { x \in s : \A y \in s : x >= y} + +(* Attempted to check equality of integer 1 with non-integer: {1} *) +sillyExpr == + {s \in SUBSET {1,2,3} : + \A x \in s : IF x = Max(s) + THEN TRUE + ELSE (x+1) \in s} +---- + +ASSUME PrintT(<<"$!@$!@$!@$!@$!", sillyExpr>>) +---- + +Init == +FALSE/\v = 0 +---- +Next == +FALSE/\ v'= v +---- +============================================================================= diff --git a/tlatools/test-model/Github179b.cfg b/tlatools/test-model/Github179b.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3662e06f049e7c9069b5137ddfc038d9eb799c36 --- /dev/null +++ b/tlatools/test-model/Github179b.cfg @@ -0,0 +1,4 @@ +INIT +Init +NEXT +Next \ No newline at end of file diff --git a/tlatools/test-model/Github179b.tla b/tlatools/test-model/Github179b.tla new file mode 100644 index 0000000000000000000000000000000000000000..adcd7ea71a7ad30334038fe0fe6dab8f5b1b9c3c --- /dev/null +++ b/tlatools/test-model/Github179b.tla @@ -0,0 +1,18 @@ +---- MODULE Github179b ---- +EXTENDS TLC, Naturals + +VARIABLE v + +Max(s) == { x \in s : \A y \in s : x >= y} + +sillyExpr == +{s \in SUBSET {1,2,3,4} : \A x \in s : IF x = Max(s) THEN TRUE ELSE (x+1) \in s} +---- + +Init == +Print(sillyExpr, FALSE)/\v = 0 +---- +Next == +FALSE/\ v'= v +---- +============================================================================= diff --git a/tlatools/test-model/Github179c.cfg b/tlatools/test-model/Github179c.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3662e06f049e7c9069b5137ddfc038d9eb799c36 --- /dev/null +++ b/tlatools/test-model/Github179c.cfg @@ -0,0 +1,4 @@ +INIT +Init +NEXT +Next \ No newline at end of file diff --git a/tlatools/test-model/Github179c.tla b/tlatools/test-model/Github179c.tla new file mode 100644 index 0000000000000000000000000000000000000000..37a89a6e2d0c1a9f51725b77fb7d768c7c8b1d7a --- /dev/null +++ b/tlatools/test-model/Github179c.tla @@ -0,0 +1,17 @@ +---- MODULE Github179c ---- +EXTENDS TLC, Naturals + +VARIABLE v + +Max(s) == { x \in s : \A y \in s : x >= y} + +sillyExpr == +{s \in SUBSET {1,2,3,4} : + \A x \in s : IF x = Max(s) + THEN TRUE + ELSE (x+1) \in s} + +Init == v = 0 + +Next == PrintT(sillyExpr) = FALSE /\ v'= v +===== diff --git a/tlatools/test-model/MinimumDiameter.cfg b/tlatools/test-model/MinimumDiameter.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b --- /dev/null +++ b/tlatools/test-model/MinimumDiameter.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec diff --git a/tlatools/test-model/MinimumDiameter.tla b/tlatools/test-model/MinimumDiameter.tla new file mode 100644 index 0000000000000000000000000000000000000000..470e11f3c8194fdfb3dd450a9de3f58773009471 --- /dev/null +++ b/tlatools/test-model/MinimumDiameter.tla @@ -0,0 +1,5 @@ +--------------------------- MODULE MinimumDiameter --------------------------- +VARIABLES x + +Spec == (x = 0) /\ [][UNCHANGED x]_x +============================================================================= diff --git a/tlatools/test-model/MissingBodyInWhile.tla b/tlatools/test-model/MissingBodyInWhile.tla new file mode 100644 index 0000000000000000000000000000000000000000..12427132e914c5a82ba8057f220f3eb0af5b9dd8 --- /dev/null +++ b/tlatools/test-model/MissingBodyInWhile.tla @@ -0,0 +1,10 @@ +------------------------------ MODULE MissingBodyInWhile ------------------------------ +(*************************************************************************** +--algorithm MissingBodyInWhile +begin + while TRUE do + end while; +end algorithm + ***************************************************************************) + +============================================================================= diff --git a/tlatools/test-model/TLCGetLevel.cfg b/tlatools/test-model/TLCGetLevel.cfg new file mode 100644 index 0000000000000000000000000000000000000000..774452b7125ec39c1e777f0bb0bb59fa54527b34 --- /dev/null +++ b/tlatools/test-model/TLCGetLevel.cfg @@ -0,0 +1,6 @@ +INIT +Init +NEXT +Next +PROPERTY +Prop diff --git a/tlatools/test-model/TLCGetLevel.tla b/tlatools/test-model/TLCGetLevel.tla new file mode 100644 index 0000000000000000000000000000000000000000..e2522d3c6d17fb40bf8d27a81b8c4f276f171292 --- /dev/null +++ b/tlatools/test-model/TLCGetLevel.tla @@ -0,0 +1,16 @@ +--------------------------- MODULE TLCGetLevel ---------------------------- +EXTENDS Integers, TLC + +VARIABLES x, y + +ASSUME(TLCGet("level") = 0) + +Init == /\ x = 0 + /\ y = TLCGet("level") + +Next == /\ x < 3 + /\ x' = x + 1 + /\ y' = TLCGet("level") + +Prop == <>[](x = 2) +============================================================================= diff --git a/tlatools/test-model/TLCGetNamedUndefined.cfg b/tlatools/test-model/TLCGetNamedUndefined.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d4ca8dc341ceb40f8d5582f9bc0e52ff7ef99ce3 --- /dev/null +++ b/tlatools/test-model/TLCGetNamedUndefined.cfg @@ -0,0 +1,5 @@ +CONSTANTS +A <- diameter +B <- distinct +C <- queue +D <- level diff --git a/tlatools/test-model/TLCGetNamedUndefined.tla b/tlatools/test-model/TLCGetNamedUndefined.tla new file mode 100644 index 0000000000000000000000000000000000000000..854da116c482dac2e94ac6d2cf9f7c340963c4be --- /dev/null +++ b/tlatools/test-model/TLCGetNamedUndefined.tla @@ -0,0 +1,13 @@ +------------------------ MODULE TLCGetNamedUndefined ------------------------ +EXTENDS TLC + +diameter == TLCGet("diameter") +distinct == TLCGet("distinct") +queue == TLCGet("queue") +level == TLCGet("level") + +CONSTANT A,B,C,D + +ASSUME(TRUE) + +============================================================================= diff --git a/tlatools/test-model/TLCGetNonDeterminism.cfg b/tlatools/test-model/TLCGetNonDeterminism.cfg new file mode 100644 index 0000000000000000000000000000000000000000..774452b7125ec39c1e777f0bb0bb59fa54527b34 --- /dev/null +++ b/tlatools/test-model/TLCGetNonDeterminism.cfg @@ -0,0 +1,6 @@ +INIT +Init +NEXT +Next +PROPERTY +Prop diff --git a/tlatools/test-model/TLCGetNonDeterminism.tla b/tlatools/test-model/TLCGetNonDeterminism.tla new file mode 100644 index 0000000000000000000000000000000000000000..5dcd2adcd3e17249022b33e045120fb64648e206 --- /dev/null +++ b/tlatools/test-model/TLCGetNonDeterminism.tla @@ -0,0 +1,48 @@ +--------------------------- MODULE TLCGetNonDeterminism ---------------------------- +EXTENDS Integers, TLC + +\* A monotonic counter: + +VARIABLES x,y + +Init == /\ TLCSet(1, 0) + /\ x = 0 + /\ y = TLCGet(1) + +\* Replacing "TLCGet(1) + 1" with "x'" does not trigger the TLC bug. +\* "x'" is clearly defined but TLCGet(1) returns the local value of +\* a non-deterministically chosen worker from the set of TLC workers +\* (the local values are inconsistent and depend on worker threading). +\* +\* In other words, this next-state relation does not correspond to a +\* single behavior <x=1,y=1>, <x=2,y=2>, <x=3,y=3> but to a set of +\* behaviors where the value of y \in 1..3 depends on the actual +\* worker schedule. E.g. with three workers, the behavior might be: +\* <x=1,y=1-a>, <x=2,y=1-b>, <x=3,y=1-c> with 1-a being the local value +\* of worker a, 1-b the local value of worker b, ... +Next == /\ x < 3 + /\ TLCSet(1, TLCGet(1) + 1) + /\ x' = x + 1 + /\ y' = TLCGet(1) + +\* This bug surfaces at a later stage, when TLC re-creates the error +\* trace for the violation of Prop below: +\* Error: TLC threw an unexpected exception. +\* This was probably caused by an error in the spec or model. +\* The error occurred when TLC was checking liveness. +\* The exception was a tlc2.tool.EvalException +\* : Failed to recover the next state from its fingerprint. +\* +\* During error trace re-creation (where TLC re-creates the actual states +\* from a path in the fingerprint graph, TLC always runs with a single worker. +\* Consequently, it always create the expected <x=1,y=1>, <x=2,y=2>, <x=3,y=3> +\* behavior. This behavior however gets rejected because the fingerprints +\* in the path do not match the fingerprint of the re-created states. + +------------------------------------------------------------------------------ + +\* Force an arbitrary liveness violation by allowing +\* x to go up to 3 but expect x to remain -lt 3 forever. +Prop == <>[](x < 3) + +============================================================================= diff --git a/tlatools/test-model/TLCSet.tla b/tlatools/test-model/TLCSet.tla index a40245ee617860d02ac40866fccf7ab3eebe18d9..f9008c735ddf4dbe5ac5c7fc397f89b82722035f 100644 --- a/tlatools/test-model/TLCSet.tla +++ b/tlatools/test-model/TLCSet.tla @@ -1,5 +1,20 @@ --------------------------- MODULE TLCSet --------------------------- EXTENDS Integers, TLC -Spec == TLCSet(1, {}) +VARIABLES x + +Init == /\ x = 0 + /\ TLCGet("diameter") = 1 + /\ TLCGet("queue") = 0 + /\ TLCGet("distinct") = 0 + /\ TLCGet("duration") >= 0 \* Init might take more than a seconds since startup. + +Next == /\ x' = x + 1 + /\ TLCGet("distinct") = x + 1 + /\ TLCGet("diameter") = x + 1 \* As byproduct check that trace is strictly monotonically increasing. + /\ TLCGet("queue") = 0 \* queue is always empty because spec is a single behavior. + /\ TLCGet("duration") >= 0 \* Next might evaluate within the first second of model checking. + /\ TLCSet("exit", x = 4223) + +Spec == Init /\ [][Next]_x ============================================================================= diff --git a/tlatools/test-model/UserModuleOverride.class b/tlatools/test-model/UserModuleOverride.class index dd08da0f10e3f4aaca43e8957876100ac0d1f4bf..64e8fae620e506c2d8b882ee131ce78afcf729c1 100644 Binary files a/tlatools/test-model/UserModuleOverride.class and b/tlatools/test-model/UserModuleOverride.class differ diff --git a/tlatools/test-model/UserModuleOverride.java b/tlatools/test-model/UserModuleOverride.java index 3d10b44e29aaac079fc9c6dfd46546048599cf0b..6cbac2ff78480e399a26c0b66c2ddb937ef74ea3 100644 --- a/tlatools/test-model/UserModuleOverride.java +++ b/tlatools/test-model/UserModuleOverride.java @@ -1,7 +1,18 @@ -import tlc2.value.BoolValue; -// manually compiled with Java 1.6 +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.Value; + +// manually compiled with Java 1.8 public class UserModuleOverride { - public static BoolValue Get() { - return new BoolValue(true); + public static Value Get() { + return BoolValue.ValTrue; + } + + public static Value Get2(Value v1) { + return BoolValue.ValFalse; + } + + + public static Value Get3() { + return BoolValue.ValFalse; } } diff --git a/tlatools/test-model/UserModuleOverride.tla b/tlatools/test-model/UserModuleOverride.tla index d221d1a25a159a2af349076e206eb6c6e1f4635a..258e5c7efc6a204aa5dc5f861cbfef0baed1d08f 100644 --- a/tlatools/test-model/UserModuleOverride.tla +++ b/tlatools/test-model/UserModuleOverride.tla @@ -4,9 +4,11 @@ VARIABLES x Get == FALSE +Get2 == TRUE + Init == x = Get -Next == x' = TRUE +Next == x' = Get2 Spec == Init /\ [][Next]_<<x>> diff --git a/tlatools/test-model/UserModuleOverrideBase.cfg b/tlatools/test-model/UserModuleOverrideBase.cfg new file mode 100644 index 0000000000000000000000000000000000000000..20524345c8bb1355485ae7282e49cd9a44301eca --- /dev/null +++ b/tlatools/test-model/UserModuleOverrideBase.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +PROPERTY +Prop diff --git a/tlatools/test-model/UserModuleOverrideBase.tla b/tlatools/test-model/UserModuleOverrideBase.tla new file mode 100644 index 0000000000000000000000000000000000000000..77b33caa16d9017b53e11b7bf81204f32d8b0bde --- /dev/null +++ b/tlatools/test-model/UserModuleOverrideBase.tla @@ -0,0 +1,12 @@ +--------------------------- MODULE UserModuleOverrideBase ----------------------- +EXTENDS Naturals, UserModuleOverrideFromJar +VARIABLES x + +Init == x = Get + +Next == x' = Get2 + +Spec == Init /\ [][Next]_<<x>> + +Prop == [](x = TRUE) +============================================================================= diff --git a/tlatools/test-model/UserModuleOverrideFromJar.jar b/tlatools/test-model/UserModuleOverrideFromJar.jar new file mode 100644 index 0000000000000000000000000000000000000000..a410365e01d820d76a0065a5898975dc24712403 Binary files /dev/null and b/tlatools/test-model/UserModuleOverrideFromJar.jar differ diff --git a/tlatools/test-model/checkpoint/InfiniteStateSpace.cfg b/tlatools/test-model/checkpoint/InfiniteStateSpace.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b --- /dev/null +++ b/tlatools/test-model/checkpoint/InfiniteStateSpace.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec diff --git a/tlatools/test-model/checkpoint/InfiniteStateSpace.tla b/tlatools/test-model/checkpoint/InfiniteStateSpace.tla new file mode 100644 index 0000000000000000000000000000000000000000..89ae5a5ca869a16f69470d257748f81ae17643dc --- /dev/null +++ b/tlatools/test-model/checkpoint/InfiniteStateSpace.tla @@ -0,0 +1,7 @@ +------------------------------ MODULE InfiniteStateSpace ------------------------------ +EXTENDS Naturals + +VARIABLES x,y + +Spec == x = 0 /\ y \in 1..1000 /\ [][x'= x + 1 /\ UNCHANGED y]_<<x,y>> +============================================================================= diff --git a/tlatools/test-model/coverage/A.cfg b/tlatools/test-model/coverage/A.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e3e8c3d2505a0163440775d92531a92d4321811c --- /dev/null +++ b/tlatools/test-model/coverage/A.cfg @@ -0,0 +1,2 @@ +INIT Init +NEXT Next diff --git a/tlatools/test-model/coverage/A.tla b/tlatools/test-model/coverage/A.tla new file mode 100644 index 0000000000000000000000000000000000000000..4032c98fe581a8eafd84e2188acff006e044da8d --- /dev/null +++ b/tlatools/test-model/coverage/A.tla @@ -0,0 +1,18 @@ +---------------------------- MODULE A ---------------------------- +EXTENDS Naturals, FiniteSets +VARIABLE x + +Op1(S) == \A e \in SUBSET S : Cardinality(e) >= 0 + +Init == /\ x = 0 + /\ Op1(1..17) + +\* Max(s) +Op2(n) == CHOOSE i \in 1..n : \A j \in ((1..n) \ {i}) : i > j + +A(n) == x' = Op2(n) + +B(n) == x' = Op2(n) + +Next == A(10) \/ B(3) +============================================================================= diff --git a/tlatools/test-model/coverage/B.cfg b/tlatools/test-model/coverage/B.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e3e8c3d2505a0163440775d92531a92d4321811c --- /dev/null +++ b/tlatools/test-model/coverage/B.cfg @@ -0,0 +1,2 @@ +INIT Init +NEXT Next diff --git a/tlatools/test-model/coverage/B.tla b/tlatools/test-model/coverage/B.tla new file mode 100644 index 0000000000000000000000000000000000000000..53b166455fbc62956435386512ff9894862cc0cf --- /dev/null +++ b/tlatools/test-model/coverage/B.tla @@ -0,0 +1,13 @@ +---------------------------- MODULE B ---------------------------- +VARIABLE x + +Init == x = FALSE + +Switch(var) == ~var + +A == x' = Switch(x) + +B == x' = Switch(x) + +Next == A \/ B +============================================================================= diff --git a/tlatools/test-model/coverage/C.cfg b/tlatools/test-model/coverage/C.cfg new file mode 100644 index 0000000000000000000000000000000000000000..123888c29add0dae20544eefc45e779311ecaa30 --- /dev/null +++ b/tlatools/test-model/coverage/C.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +CONSTRAINT Constraint +INVARIANT Inv +INVARIANT Inv2 diff --git a/tlatools/test-model/coverage/C.tla b/tlatools/test-model/coverage/C.tla new file mode 100644 index 0000000000000000000000000000000000000000..0ee2d5da27eb2a5d279283e9e20a21a6ddc796a5 --- /dev/null +++ b/tlatools/test-model/coverage/C.tla @@ -0,0 +1,63 @@ +---------------------------- MODULE C ---------------------------- +EXTENDS Naturals, FiniteSets +VARIABLES x,y + +c == x +d == y + +vars == <<x,y>> + +a == x' + +Op(S) == \A e \in SUBSET S : Cardinality(e) >= 0 + +Init == /\ x \in 1..3 + /\ y = 0 + +A == /\ c \in Nat + /\ y \in Nat + /\ a = x + 1 + /\ UNCHANGED y + +B == /\ x \in Nat + /\ Op(1..5) + /\ UNCHANGED <<x,d>> + +C == /\ x = 42 + /\ c' = TRUE + /\ y' = FALSE + +D == x' \in 0..x /\ UNCHANGED y + +U1 == x < 0 /\ UNCHANGED vars + +U2 == x < 0 /\ UNCHANGED <<x,y>> + +U3 == x < 0 /\ UNCHANGED x /\ UNCHANGED y + +Next == A \/ B \/ C \/ D \/ U1 \/ U2 \/ U3 + +Spec == Init /\ [][Next]_vars + +Constraint == x < 20 + +(* Coverage/Cost statistics for Invariants too. *) + +expensive(N) == \A e \in SUBSET (1..N) : \A f \in e : f \in 1..N + +Inv == /\ x \in Nat + /\ y \in Nat + /\ expensive(8) + /\ LET frob == TRUE + IN /\ frob = TRUE + /\ \A i \in 1..5: i \in Nat + /\ 42 \in Nat + +Inv2 == /\ x \in Nat + /\ y \in Nat + /\ expensive(9) + /\ LET frob == TRUE + IN /\ frob = TRUE + /\ \A i \in 1..5: i \in Nat + /\ 42 \in Nat +============================================================================= diff --git a/tlatools/test-model/coverage/CoverageStatistics.cfg b/tlatools/test-model/coverage/CoverageStatistics.cfg new file mode 100644 index 0000000000000000000000000000000000000000..46c09d3371bbe6fa743e70c8adcdb79c89ea0723 --- /dev/null +++ b/tlatools/test-model/coverage/CoverageStatistics.cfg @@ -0,0 +1,4 @@ +CONSTRAINT +Constraint +SPECIFICATION +Spec diff --git a/tlatools/test-model/coverage/CoverageStatistics.tla b/tlatools/test-model/coverage/CoverageStatistics.tla new file mode 100644 index 0000000000000000000000000000000000000000..0eb6b975f2838a9e21a6ed2f5fe2e5dbd1f560f0 --- /dev/null +++ b/tlatools/test-model/coverage/CoverageStatistics.tla @@ -0,0 +1,50 @@ +---------------------------- MODULE CoverageStatistics ---------------------------- +EXTENDS Naturals, FiniteSets +VARIABLES x,y + +c == x +d == y + +vars == <<x,y>> + +a == x' + +Init == /\ x \in 1..3 + /\ y = 0 + +A == /\ c \in Nat + /\ y \in Nat + /\ a = x + 1 + /\ UNCHANGED d \* 18 should be covered (6 should be omitted) + +B == /\ x \in Nat + /\ UNCHANGED <<x,d>> \* 21 and 6 should be covered (6 should actually be omitted) + +B2 == /\ x \in Nat + /\ UNCHANGED vars \* 21 and 6 should be covered (6 should actually be omitted) + +C == /\ x = 42 + /\ c' = TRUE + /\ y' = FALSE + +U1 == x < 0 /\ UNCHANGED vars \* vars should be reported as uncovered instead of x and y on line 8 + +U2 == x < 0 /\ UNCHANGED <<x,y>> \* col 28 & 30 + +U3 == x < 0 /\ UNCHANGED x /\ UNCHANGED y \* col 26 & 41 + +U4 == x < 0 /\ UNCHANGED x /\ UNCHANGED d (* d itself instead of y is marked uncovered *) + +UC1 == x \in Nat /\ UNCHANGED <<x,y>> + +UC2 == x \in Nat /\ UNCHANGED x /\ UNCHANGED y + +UC3 == x \in Nat /\ UNCHANGED vars \* Do not mark vars on line 8 as covered + +Next == A \/ B \/ C \/ U1 \/ U2 \/ U3 \/ U4 \/ UC1 \/ UC2 \/ UC3 + +Spec == Init /\ [][Next]_vars + +Constraint == x < 20 + +============================================================================= diff --git a/tlatools/test-model/test56.cfg b/tlatools/test-model/coverage/D.cfg similarity index 52% rename from tlatools/test-model/test56.cfg rename to tlatools/test-model/coverage/D.cfg index 8a93632b965223198ef42bd956c09e80e1a9dfb5..4d07be4bdd383dc53e46a5cbb701afa9dba3c30d 100644 --- a/tlatools/test-model/test56.cfg +++ b/tlatools/test-model/coverage/D.cfg @@ -1,2 +1 @@ SPECIFICATION Spec -PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/coverage/D.tla b/tlatools/test-model/coverage/D.tla new file mode 100644 index 0000000000000000000000000000000000000000..41865d9289b8294117b0c79115a775d686b2354c --- /dev/null +++ b/tlatools/test-model/coverage/D.tla @@ -0,0 +1,18 @@ +---------------------------- MODULE D ---------------------------- +EXTENDS Naturals +VARIABLE x + +Init == x = 0 + +(* No endless recursion in Coverage/Cost with RECURSIVE. *) +RECURSIVE fact(_) +fact(n) == IF n = 1 THEN 1 ELSE n * fact(n - 1) + +A == x' = fact(3) + +B == x' = fact(9) + +Next == A \/ B + +Spec == Init /\ [][Next]_<<x>> +============================================================================= diff --git a/tlatools/test-model/coverage/E.cfg b/tlatools/test-model/coverage/E.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4ebe91bd18e2e5bbb5152db4a9abbaa2ea951bba --- /dev/null +++ b/tlatools/test-model/coverage/E.cfg @@ -0,0 +1,3 @@ +INIT Init +NEXT Next +CONSTANT Op <- Forty2 diff --git a/tlatools/test-model/coverage/E.tla b/tlatools/test-model/coverage/E.tla new file mode 100644 index 0000000000000000000000000000000000000000..fc774b97d8293f62bfd18ed6fad393fe826402fd --- /dev/null +++ b/tlatools/test-model/coverage/E.tla @@ -0,0 +1,13 @@ +---------------------------- MODULE E ---------------------------- +CONSTANT Op(_) + +VARIABLE x + +Id(n) == SUBSET {1,2,3} + +Forty2(n) == Id(n) + +Init == x = 0 + +Next == x' \in Op(x) +============================================================================= diff --git a/tlatools/test-model/coverage/F.cfg b/tlatools/test-model/coverage/F.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e3e8c3d2505a0163440775d92531a92d4321811c --- /dev/null +++ b/tlatools/test-model/coverage/F.cfg @@ -0,0 +1,2 @@ +INIT Init +NEXT Next diff --git a/tlatools/test-model/coverage/F.tla b/tlatools/test-model/coverage/F.tla new file mode 100644 index 0000000000000000000000000000000000000000..3d868458608285b71c5bb346e6b96abd43946d03 --- /dev/null +++ b/tlatools/test-model/coverage/F.tla @@ -0,0 +1,11 @@ +---------------------------- MODULE F ---------------------------- +EXTENDS Naturals + +VARIABLE x + +Op(S, P(_), Q(_, _)) == { s \in S : P(s) /\ Q(s, TRUE) } + +Init == x \in Op({1,2,3,4,5}, LAMBDA s: s > 1, LAMBDA odd, b: odd % 2 # 0 /\ b) + +Next == UNCHANGED x +============================================================================= diff --git a/tlatools/test-model/coverage/G.cfg b/tlatools/test-model/coverage/G.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9b60b87092e262903968bd979325348721290efb --- /dev/null +++ b/tlatools/test-model/coverage/G.cfg @@ -0,0 +1,3 @@ +INIT Init +NEXT Next +INVARIANT Prop \ No newline at end of file diff --git a/tlatools/test-model/coverage/G.tla b/tlatools/test-model/coverage/G.tla new file mode 100644 index 0000000000000000000000000000000000000000..d4592b9989c9b5602bc6f5a5fb4885d40880d006 --- /dev/null +++ b/tlatools/test-model/coverage/G.tla @@ -0,0 +1,13 @@ +---------------------------- MODULE G ---------------------------- +VARIABLES u1 + +vars == << u1 >> + +Init == /\ u1 = TRUE + +Next == /\ UNCHANGED vars + /\ UNCHANGED <<u1>> + /\ UNCHANGED u1 + +Prop == ENABLED Next +============================================================================= diff --git a/tlatools/test-model/coverage/Github314.cfg b/tlatools/test-model/coverage/Github314.cfg new file mode 100644 index 0000000000000000000000000000000000000000..dfd087d6b1871aee9e04413d19ed06afc6318409 --- /dev/null +++ b/tlatools/test-model/coverage/Github314.cfg @@ -0,0 +1,5 @@ +CONSTANT +Nat <- [Naturals]MyNat +\* No bug with Nat <- MyNat +SPECIFICATION +Spec diff --git a/tlatools/test-model/coverage/Github314.tla b/tlatools/test-model/coverage/Github314.tla new file mode 100644 index 0000000000000000000000000000000000000000..0df9fae4db25d8d9034a8c11560e4753dff2fb5c --- /dev/null +++ b/tlatools/test-model/coverage/Github314.tla @@ -0,0 +1,21 @@ +---- MODULE Github314 ---- +EXTENDS Naturals + +\* Begin nested (base) module + ---- MODULE Base ---- + EXTENDS Naturals + + VARIABLES x + + Spec == x = 0 /\ [][(x \in Nat /\ x' = x + 1)]_x + ===== +\* End nested (base) module + +VARIABLES x + +Spec == x = 0 /\ [][(x \in Nat /\ x' = x + 1)]_x + +F == INSTANCE Base + +MyNat == 0..1 +==== diff --git a/tlatools/test-model/coverage/H.cfg b/tlatools/test-model/coverage/H.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b --- /dev/null +++ b/tlatools/test-model/coverage/H.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec diff --git a/tlatools/test-model/coverage/H.tla b/tlatools/test-model/coverage/H.tla new file mode 100644 index 0000000000000000000000000000000000000000..cac9a4d2f35392b104ad29504b7b05a6d39382e3 --- /dev/null +++ b/tlatools/test-model/coverage/H.tla @@ -0,0 +1,27 @@ +------------------------------ MODULE H ------------------------------ +EXTENDS Naturals +VARIABLES x + +MyNat == 0..30 + +TypeOK == x \in MyNat + +Init == x = 0 + +A == x' = 23 + +BandC == \/ /\ x \in MyNat + /\ x' \in 23..25 + \/ /\ x < 25 + /\ x' = 26 + +DandE == (x = 23 /\ x' = 42) \/ (x = 123 /\ x' = 4711) + +Next == A \/ BandC \/ DandE + +Inv == /\ TypeOK + /\ x = 0 + +Spec == Inv /\ [][Next]_x + +============ diff --git a/tlatools/test-model/pcal/CCallReturn1.tla b/tlatools/test-model/pcal/CCallReturn1.tla index 5d0361ccbdc65799105abc5ff13a24a3681a50ec..68e80ddeb20d545f318a7f0b8d11187910508273 100644 --- a/tlatools/test-model/pcal/CCallReturn1.tla +++ b/tlatools/test-model/pcal/CCallReturn1.tla @@ -109,9 +109,11 @@ a1 == /\ pc = "a1" /\ pc' = "p1" /\ UNCHANGED << arg2, v, arg3 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Proc1 \/ Proc2 \/ Proc3 \/ a1 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/CEither1.tla b/tlatools/test-model/pcal/CEither1.tla index 69efa80a27cc8ba79f3a5be18d796a840a8c8667..03213f7164dfdf028d53c74368244cbc95f4f943 100644 --- a/tlatools/test-model/pcal/CEither1.tla +++ b/tlatools/test-model/pcal/CEither1.tla @@ -44,9 +44,11 @@ d == /\ pc = "d" /\ pc' = "Done" /\ UNCHANGED << x, y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/CMultiprocDefine.tla b/tlatools/test-model/pcal/CMultiprocDefine.tla index 020e5eb3d0affe7a510fc4860e416f2f1d610168..67e90be869bc8363172fe21f546863ffd24fce84 100644 --- a/tlatools/test-model/pcal/CMultiprocDefine.tla +++ b/tlatools/test-model/pcal/CMultiprocDefine.tla @@ -43,9 +43,12 @@ main(self) == /\ pc[self] = "main" Proc(self) == main(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in {1, 2, 3}: Proc(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in {1, 2, 3} : WF_vars(Proc(self)) diff --git a/tlatools/test-model/pcal/CallReturn1.tla b/tlatools/test-model/pcal/CallReturn1.tla index ca26d0b2cc3670d8ae537748b424989aad2b2b15..2ec4adf4bb1c1701cab7e6add941f72fd90eaa62 100644 --- a/tlatools/test-model/pcal/CallReturn1.tla +++ b/tlatools/test-model/pcal/CallReturn1.tla @@ -109,9 +109,11 @@ a1 == /\ pc = "a1" /\ pc' = "p1" /\ UNCHANGED << arg2, v, arg3 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Proc1 \/ Proc2 \/ Proc3 \/ a1 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/CallReturn2.tla b/tlatools/test-model/pcal/CallReturn2.tla index a7b88d2c7c161524b519012ca957070345fc52ee..287e0c983d450d78de9a92df16ac9c5c82c883a4 100644 --- a/tlatools/test-model/pcal/CallReturn2.tla +++ b/tlatools/test-model/pcal/CallReturn2.tla @@ -184,9 +184,11 @@ C == /\ pc = "C" /\ pc' = "PP1" /\ UNCHANGED << depth, a, x_, y, r, x, s >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == P \/ Q \/ PP \/ R \/ S \/ A \/ B \/ C - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Either1.tla b/tlatools/test-model/pcal/Either1.tla index 0c0915f5275e472f480b91c9df342c6880152f33..206eb4b2ca6ac15a68c96492cce40e63fd62f821 100644 --- a/tlatools/test-model/pcal/Either1.tla +++ b/tlatools/test-model/pcal/Either1.tla @@ -43,9 +43,11 @@ d == /\ pc = "d" /\ pc' = "Done" /\ UNCHANGED << x, y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Either2.tla b/tlatools/test-model/pcal/Either2.tla index 60f5f75fd1fb39e5e9ffc6a0dec0dce3d2fefe41..f7f2bd8276e9e74609bce617ecc836b3e7cc2882 100644 --- a/tlatools/test-model/pcal/Either2.tla +++ b/tlatools/test-model/pcal/Either2.tla @@ -55,9 +55,11 @@ d == /\ pc = "d" /\ pc' = "Done" /\ UNCHANGED << x, y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Either3.tla b/tlatools/test-model/pcal/Either3.tla index 8f1ebc0cdf5f159959ca94a9b4f61d001519142a..508eafb54de362f623417ca2851e3c04e859153f 100644 --- a/tlatools/test-model/pcal/Either3.tla +++ b/tlatools/test-model/pcal/Either3.tla @@ -60,9 +60,11 @@ d == /\ pc = "d" /\ pc' = "Done" /\ UNCHANGED << x, y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Either4.tla b/tlatools/test-model/pcal/Either4.tla index e0253f5d57af24a393ae3bf2f32468abc7d65e35..6cda9f2556d3ab91ddd9646d8e381c865f32a4ea 100644 --- a/tlatools/test-model/pcal/Either4.tla +++ b/tlatools/test-model/pcal/Either4.tla @@ -66,9 +66,12 @@ d(self) == /\ pc[self] = "d" Foo(self) == a(self) \/ b(self) \/ c(self) \/ d(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in {1, 2}: Foo(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in {1, 2} : WF_vars(Foo(self)) diff --git a/tlatools/test-model/pcal/Either5.tla b/tlatools/test-model/pcal/Either5.tla index 62ed5708362e30d6bfea4a51154784d4224cc062..8fa1a72d7301e738002683f6cf6705f59c7aef8d 100644 --- a/tlatools/test-model/pcal/Either5.tla +++ b/tlatools/test-model/pcal/Either5.tla @@ -68,9 +68,11 @@ d == /\ pc = "d" /\ pc' = "Done" /\ UNCHANGED << x, y, z, stack, a >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Foo \/ a_ \/ b \/ d - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Euclid.tla b/tlatools/test-model/pcal/Euclid.tla index 90b4c0b7503592a512bb3e766dd48b4e60c4ade2..b4e0381af90a7de778342bb7f9cafdb1136b1bce 100644 --- a/tlatools/test-model/pcal/Euclid.tla +++ b/tlatools/test-model/pcal/Euclid.tla @@ -73,9 +73,11 @@ b == /\ pc = "b" /\ pc' = "a" /\ UNCHANGED << u_ini, v_ini, v >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Euclid2.tla b/tlatools/test-model/pcal/Euclid2.tla index b3d0b032e98f392b881d0b09587ccde1198076bb..a0cd9e8b9e45f11442d82b044ad576feb14644b7 100644 --- a/tlatools/test-model/pcal/Euclid2.tla +++ b/tlatools/test-model/pcal/Euclid2.tla @@ -52,9 +52,11 @@ a == /\ pc = "a" /\ pc' = "lp" /\ UNCHANGED << v, v_ini >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == lp \/ a - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Euclid3.tla b/tlatools/test-model/pcal/Euclid3.tla index f652ff2864201c011df915bc5ab0efa9149e741f..ab6e006224232c1a15d616abdea29718a2365597 100644 --- a/tlatools/test-model/pcal/Euclid3.tla +++ b/tlatools/test-model/pcal/Euclid3.tla @@ -50,9 +50,11 @@ a == /\ pc = "a" /\ pc' = "lp" /\ UNCHANGED << v, v_ini >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == lp \/ a - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/EvenOdd.tla b/tlatools/test-model/pcal/EvenOdd.tla index d44ad522c275a705e2a2d41d4c228c01a177200b..d152527497cdf208265d266d6e1db4182d3cafe1 100644 --- a/tlatools/test-model/pcal/EvenOdd.tla +++ b/tlatools/test-model/pcal/EvenOdd.tla @@ -98,9 +98,11 @@ a2 == /\ pc = "a2" /\ pc' = "Done" /\ UNCHANGED << result, stack, xEven, xOdd >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Even \/ Odd \/ a1 \/ a2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/EvenOddBad.tla b/tlatools/test-model/pcal/EvenOddBad.tla index 78b15383a52e3bd6708c089d0116c8b27830930b..540a32c817cc7a58f783c5e4b01d4a7c7039bd07 100644 --- a/tlatools/test-model/pcal/EvenOddBad.tla +++ b/tlatools/test-model/pcal/EvenOddBad.tla @@ -97,9 +97,11 @@ a2 == /\ pc = "a2" /\ pc' = "Done" /\ UNCHANGED << result, stack, xEven, xOdd >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Even \/ Odd \/ a1 \/ a2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Factorial.tla b/tlatools/test-model/pcal/Factorial.tla index 2ddd42494740a85450d25194d2eccb555ccfd39f..08761dd309f4962785c3411100928ae929b4e55a 100644 --- a/tlatools/test-model/pcal/Factorial.tla +++ b/tlatools/test-model/pcal/Factorial.tla @@ -65,9 +65,11 @@ a2 == /\ pc = "a2" /\ pc' = "Done" /\ UNCHANGED << result, stack, arg1, u >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == FactProc \/ a1 \/ a2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Factorial2.tla b/tlatools/test-model/pcal/Factorial2.tla index bbb268db0be042960a1a9dd3153b7e591760c151..ffcfeebb766ebef16745fe87f16c5662506fb5ad 100644 --- a/tlatools/test-model/pcal/Factorial2.tla +++ b/tlatools/test-model/pcal/Factorial2.tla @@ -114,9 +114,11 @@ a2 == /\ pc = "a2" /\ pc' = "Done" /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == FactProc \/ FactProc2 \/ a1 \/ a2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/FairSeq.tla b/tlatools/test-model/pcal/FairSeq.tla index e79e6792c514252e31ceb06d38fc93beddfc443a..6bee108052f694f16dd2e56e7b7278ea4a625499 100644 --- a/tlatools/test-model/pcal/FairSeq.tla +++ b/tlatools/test-model/pcal/FairSeq.tla @@ -26,9 +26,11 @@ Lbl_1 == /\ pc = "Lbl_1" ELSE /\ pc' = "Done" /\ x' = x +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Lbl_1 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/FairSeq2.tla b/tlatools/test-model/pcal/FairSeq2.tla index 3cea3c950d94c8671ce985754aae9505883d92f4..61377df601050883ce9a64637d8e8c9426921edd 100644 --- a/tlatools/test-model/pcal/FairSeq2.tla +++ b/tlatools/test-model/pcal/FairSeq2.tla @@ -26,9 +26,11 @@ Lbl_1 == /\ pc = "Lbl_1" ELSE /\ pc' = "Done" /\ x' = x +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Lbl_1 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/InnerLabeledIf.tla b/tlatools/test-model/pcal/InnerLabeledIf.tla index b38129570c5a89818e978d719bf061974613811d..d9a4faba890a9f0956280f952f4431bac647e82a 100644 --- a/tlatools/test-model/pcal/InnerLabeledIf.tla +++ b/tlatools/test-model/pcal/InnerLabeledIf.tla @@ -66,9 +66,11 @@ f == /\ pc = "f" /\ pc' = "Done" /\ x' = x +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d \/ e \/ f - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/MPFactorial.tla b/tlatools/test-model/pcal/MPFactorial.tla index b95fa09e851356b52d8b2543bb31203243aa134e..505034c02a9aee8a3fc3d1e2c95faca2ffc26b3c 100644 --- a/tlatools/test-model/pcal/MPFactorial.tla +++ b/tlatools/test-model/pcal/MPFactorial.tla @@ -98,11 +98,14 @@ b2 == /\ pc[3] = "b2" Minor == b1 \/ b2 +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == Minor \/ (\E self \in ProcSet: FactProc(self)) \/ (\E self \in 1..2: Main(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in 1..2 : WF_vars(Main(self)) /\ WF_vars(FactProc(self)) diff --git a/tlatools/test-model/pcal/MPFactorial2.tla b/tlatools/test-model/pcal/MPFactorial2.tla index a5eb7fbcaa594551651ffda9da94c38e46df30db..3c9d313e54cfbea343a01ae97404900790cc9aee 100644 --- a/tlatools/test-model/pcal/MPFactorial2.tla +++ b/tlatools/test-model/pcal/MPFactorial2.tla @@ -142,11 +142,14 @@ b2 == /\ pc[3] = "b2" Minor == b1 \/ b2 +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == Minor \/ (\E self \in ProcSet: FactProc(self) \/ FactProc2(self)) \/ (\E self \in 1..2: Main(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in 1..2 : WF_vars(Main(self)) /\ WF_vars(FactProc(self)) /\ WF_vars(FactProc2(self)) diff --git a/tlatools/test-model/pcal/MPNoParams.tla b/tlatools/test-model/pcal/MPNoParams.tla index 4fa53d1b3f5929e5a841383d6a8b6282243e9015..60ea4ff1f30ad01c9786fa830e84fe000e1e8765 100644 --- a/tlatools/test-model/pcal/MPNoParams.tla +++ b/tlatools/test-model/pcal/MPNoParams.tla @@ -71,11 +71,14 @@ q2(self) == /\ pc[self] = "q2" P2(self) == q1(self) \/ q2(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == P1 \/ (\E self \in ProcSet: Sum(self)) \/ (\E self \in 2..4: P2(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(P1) /\ WF_vars(Sum(1)) diff --git a/tlatools/test-model/pcal/MergeSort.tla b/tlatools/test-model/pcal/MergeSort.tla index e544b07c05841c78198bc8c8ab1a240cd27a7b89..07a03d9c6b2f0bd5f67cfb158085277a31fa68ec 100644 --- a/tlatools/test-model/pcal/MergeSort.tla +++ b/tlatools/test-model/pcal/MergeSort.tla @@ -229,9 +229,11 @@ main == /\ pc = "main" /\ pc' = "l1" /\ UNCHANGED << a, b >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == mergesort \/ main - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/MultiAssignment.tla b/tlatools/test-model/pcal/MultiAssignment.tla index 942b10abf062f9b7454ca6b408ffc546f4fdde32..2f0085947e8c2a0aaf42b85869dc4d735d54f27b 100644 --- a/tlatools/test-model/pcal/MultiAssignment.tla +++ b/tlatools/test-model/pcal/MultiAssignment.tla @@ -49,9 +49,12 @@ b(self) == /\ pc[self] = "b" Proc(self) == a(self) \/ b(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in 1..3: Proc(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in 1..3 : WF_vars(Proc(self)) diff --git a/tlatools/test-model/pcal/MultiProc2.tla b/tlatools/test-model/pcal/MultiProc2.tla index 514fee77feceadf98c1e4be8bd975833e2a15e1c..1312740cf1c879f990b3a9084f960f32eccb1889 100644 --- a/tlatools/test-model/pcal/MultiProc2.tla +++ b/tlatools/test-model/pcal/MultiProc2.tla @@ -112,11 +112,14 @@ b2(self) == /\ pc[self] = "b2" ProcB(self) == b1(self) \/ b2(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == ProcA \/ (\E self \in ProcSet: Sum(self)) \/ (\E self \in {42, 43}: ProcB(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(ProcA) /\ WF_vars(Sum(41)) diff --git a/tlatools/test-model/pcal/MultiprocDefine.tla b/tlatools/test-model/pcal/MultiprocDefine.tla index 46de90cefd81be8be7c75518e13fe925df234754..8cb8847a02b83755f894ea5c1364a75f2467bcb3 100644 --- a/tlatools/test-model/pcal/MultiprocDefine.tla +++ b/tlatools/test-model/pcal/MultiprocDefine.tla @@ -44,9 +44,12 @@ main(self) == /\ pc[self] = "main" Proc(self) == main(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in {1, 2, 3}: Proc(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/NestedMacros.tla b/tlatools/test-model/pcal/NestedMacros.tla index 499a2fbe6e6cdc48dfcb528b31fe0a7da00c0def..864b61c94eb58c3aa9c9c60e27012b64dcbc0841 100644 --- a/tlatools/test-model/pcal/NestedMacros.tla +++ b/tlatools/test-model/pcal/NestedMacros.tla @@ -56,9 +56,12 @@ l2(self) == /\ pc[self] = "l2" foob(self) == l1(self) \/ l2(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in {1,2}: foob(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ \A self \in {1,2} : WF_vars(foob(self)) diff --git a/tlatools/test-model/pcal/NoLoop.tla b/tlatools/test-model/pcal/NoLoop.tla index 474a4aaf720278e74a3758a1460e33a434267417..e52f005b97ae4459c7d90b32ed79c69d22704f3f 100644 --- a/tlatools/test-model/pcal/NoLoop.tla +++ b/tlatools/test-model/pcal/NoLoop.tla @@ -41,9 +41,11 @@ c == /\ pc = "c" /\ pc' = "Done" /\ y' = y +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/NoLoop2.tla b/tlatools/test-model/pcal/NoLoop2.tla index fd12a280b201947166c524a354d51fcf781ab535..80e19d11af88016afe0b199703b4ae5d9bbd5ba5 100644 --- a/tlatools/test-model/pcal/NoLoop2.tla +++ b/tlatools/test-model/pcal/NoLoop2.tla @@ -55,9 +55,11 @@ e == /\ pc = "e" /\ pc' = "Done" /\ UNCHANGED << x, y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b \/ c \/ d \/ e - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/NoParams.tla b/tlatools/test-model/pcal/NoParams.tla index 6711b4eb7ff2734445c24b23042248c894a581e4..9ab5db57e13e02b29e8d391bf0e4b6d13e2273df 100644 --- a/tlatools/test-model/pcal/NoParams.tla +++ b/tlatools/test-model/pcal/NoParams.tla @@ -53,9 +53,11 @@ m3 == /\ pc = "m3" /\ pc' = "Done" /\ UNCHANGED << sum, stack >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Sum \/ m1 \/ m2 \/ m3 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/NotSoSimpleLoop.tla b/tlatools/test-model/pcal/NotSoSimpleLoop.tla index cea3b0486ebdf13131ba7360e3f81e6c0e81aec7..a2f41b8e339f0c7016ee32beb9f57259ac2968b5 100644 --- a/tlatools/test-model/pcal/NotSoSimpleLoop.tla +++ b/tlatools/test-model/pcal/NotSoSimpleLoop.tla @@ -40,9 +40,11 @@ b == /\ pc = "b" /\ pc' = "Done" /\ x' = x +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a \/ b - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Quicksort.tla b/tlatools/test-model/pcal/Quicksort.tla index c50fe77f188732881cb9c80c92637b41bb238af3..8b2604f57d9b072694885b6ffc7a689624ce093d 100644 --- a/tlatools/test-model/pcal/Quicksort.tla +++ b/tlatools/test-model/pcal/Quicksort.tla @@ -151,9 +151,11 @@ test == /\ pc = "test" /\ pc' = "Done" /\ UNCHANGED << Ainit, A, returnVal, stack, lo, hi, qlo, qhi, pivot >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Partition \/ QS \/ main \/ test - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/Quicksort2Procs.tla b/tlatools/test-model/pcal/Quicksort2Procs.tla index 592eb74ef76e959e632e8a30e3d5066253d03fba..5f6eab6552032bcf2a1237fac35ae8832a7c2e71 100644 --- a/tlatools/test-model/pcal/Quicksort2Procs.tla +++ b/tlatools/test-model/pcal/Quicksort2Procs.tla @@ -220,9 +220,11 @@ main == /\ pc = "main" /\ pc' = "qs1" /\ UNCHANGED << A, returnVal, lo, hi, qlo2, qhi2, pivot2 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Partition \/ QS \/ QS2 \/ main - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/QuicksortMacro.tla b/tlatools/test-model/pcal/QuicksortMacro.tla index 68abac3d107331073642b2e6b68cc6e9cbcd1c4c..d513cae2ea6c54e13d5cf61e2f613eac5531cc6f 100644 --- a/tlatools/test-model/pcal/QuicksortMacro.tla +++ b/tlatools/test-model/pcal/QuicksortMacro.tla @@ -117,9 +117,11 @@ main == /\ pc = "main" /\ pc' = "qs1" /\ UNCHANGED << A, returnVal >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == QS \/ main - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/RealQuicksort.tla b/tlatools/test-model/pcal/RealQuicksort.tla index 2f0caf8fd7d363d9dccdb39676da01b2275d7754..02d8d8ec0bf421d3d70a8168506601ec1bd6e57f 100644 --- a/tlatools/test-model/pcal/RealQuicksort.tla +++ b/tlatools/test-model/pcal/RealQuicksort.tla @@ -105,9 +105,11 @@ rqs2 == /\ pc = "rqs2" /\ pc' = "rqs" /\ UNCHANGED << A, new, stack, parg >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Part \/ rqs \/ rqs2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/RealQuicksort2.tla b/tlatools/test-model/pcal/RealQuicksort2.tla index 86f8975d839dc88c5b09d6a88123912e09192b59..edf8a6b1d4b50156712207da62becd73cbbab524 100644 --- a/tlatools/test-model/pcal/RealQuicksort2.tla +++ b/tlatools/test-model/pcal/RealQuicksort2.tla @@ -105,9 +105,11 @@ rqs2 == /\ pc = "rqs2" /\ pc' = "rqs" /\ UNCHANGED << A, new, next, stack, parg >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Part \/ rqs \/ rqs2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ReallySimpleMultiProc.tla b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla index 20536ba20e7b0743df2fdf955c7e8d47e3633558..3a264e4b8252da809cd0716dfa29bd429ce7efd3 100644 --- a/tlatools/test-model/pcal/ReallySimpleMultiProc.tla +++ b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla @@ -71,10 +71,13 @@ b2(self) == /\ pc[self] = "b2" ProcB(self) == b1(self) \/ b2(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == ProcA \/ (\E self \in {42, 43}: ProcB(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(ProcA) diff --git a/tlatools/test-model/pcal/SimpleLoop.tla b/tlatools/test-model/pcal/SimpleLoop.tla index 4b20698f62b1158ed31a822eb2ee2aa48d40f61a..11fc1cc2736dc6d290740a1be8d4c208bb25dde7 100644 --- a/tlatools/test-model/pcal/SimpleLoop.tla +++ b/tlatools/test-model/pcal/SimpleLoop.tla @@ -31,9 +31,11 @@ a == /\ pc = "a" ELSE /\ pc' = "Done" /\ x' = x +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == a - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla index a0b46cf46dca2a500e72f05bd5023615e198dade..6b459d29d371ef5b700697ad589759dc4a5f5528 100644 --- a/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla +++ b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla @@ -66,9 +66,11 @@ a == /\ pc = "a" /\ UNCHANGED << i, stack, incr, z >> /\ UNCHANGED << x, y, n >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Incr \/ a - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/SubSub.tla b/tlatools/test-model/pcal/SubSub.tla index 9c8aca26c4b1a5a64127a5080b3022d7a88e313e..30648976613f8ff4f493430ce6789d6d0db62ac8 100644 --- a/tlatools/test-model/pcal/SubSub.tla +++ b/tlatools/test-model/pcal/SubSub.tla @@ -50,9 +50,12 @@ lab(self) == /\ pc[self] = "lab" proc(self) == lab(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in 1..3: proc(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/SyncCons.tla b/tlatools/test-model/pcal/SyncCons.tla index c7c2a2ccf31d063d62c15dd62a61eebe6321d905..8d9d44681e0a178afb01a8703054d0aeb573a238 100644 --- a/tlatools/test-model/pcal/SyncCons.tla +++ b/tlatools/test-model/pcal/SyncCons.tla @@ -228,10 +228,13 @@ crash == /\ pc[N + 2] = "crash" Crash == crash +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == Clock \/ Crash \/ (\E self \in 1..N: Participant(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/Test.tla b/tlatools/test-model/pcal/Test.tla index 1b243a4e65ddbb88482c49a3af123d80698bf9cf..017d41b6eacfda45ee47ae481125488879713e57 100644 --- a/tlatools/test-model/pcal/Test.tla +++ b/tlatools/test-model/pcal/Test.tla @@ -89,9 +89,11 @@ L2 == /\ pc = "L2" /\ pc' = "Done" /\ UNCHANGED << x, stack >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Bar \/ L1 \/ L3 \/ L2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/TestReplace.tla b/tlatools/test-model/pcal/TestReplace.tla index 386a910f665d148779cbb6d89c26da94c4042ace..c9de9c214f76c634bcdabf1e8f496c73e5c74432 100644 --- a/tlatools/test-model/pcal/TestReplace.tla +++ b/tlatools/test-model/pcal/TestReplace.tla @@ -235,9 +235,11 @@ b == /\ pc = "b" /\ pc' = "a" /\ UNCHANGED << u_, v_, u_F, v_F, X_, Y >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Bar \/ Foo1 \/ Foo2 \/ start \/ b - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/TestTabs.tla b/tlatools/test-model/pcal/TestTabs.tla index 08c7f1b305bdeb0b66867b9c503778a7355b544f..fa285849ce5f4019da5c2b1a50ef297a1daf4ee8 100644 --- a/tlatools/test-model/pcal/TestTabs.tla +++ b/tlatools/test-model/pcal/TestTabs.tla @@ -37,9 +37,11 @@ l == /\ pc = "l" /\ Assert(x' = 1, "Failure of assertion at line 16, column 5.") /\ pc' = "Done" +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == l - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/TreeBarrier.tla b/tlatools/test-model/pcal/TreeBarrier.tla index b1f3a879a536cfa27b99ed68a91fb4f611f7f712..63982b5eb5a558e25fa50475b54f8495fdd4bc01 100644 --- a/tlatools/test-model/pcal/TreeBarrier.tla +++ b/tlatools/test-model/pcal/TreeBarrier.tla @@ -115,9 +115,12 @@ i(self) == prc(self) \/ comp(self) \/ b1(self) \/ b2(self) \/ b3(self) \/ b4(self) \/ b5(self) \/ b6(self) \/ b7(self) \/ b8(self) \/ b9(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in 1..N: i(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ULCallReturn1.tla b/tlatools/test-model/pcal/ULCallReturn1.tla index b4eebdd55642ed4c2aeeae5b1b73071d8866033d..72326d407151714785865aff5044dfa90c1b2b46 100644 --- a/tlatools/test-model/pcal/ULCallReturn1.tla +++ b/tlatools/test-model/pcal/ULCallReturn1.tla @@ -109,9 +109,11 @@ Lbl_5 == /\ pc = "Lbl_5" /\ pc' = "Lbl_1" /\ UNCHANGED << arg2, v, arg3 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Proc1 \/ Proc2 \/ Proc3 \/ Lbl_5 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ULEuclid.tla b/tlatools/test-model/pcal/ULEuclid.tla index 80c179322e6ee1a8d4e3cf47c541d3486065c9cc..a2b4d93e16157f36c219f0b1c1b841da6d0a4d62 100644 --- a/tlatools/test-model/pcal/ULEuclid.tla +++ b/tlatools/test-model/pcal/ULEuclid.tla @@ -72,9 +72,11 @@ Lbl_2 == /\ pc = "Lbl_2" /\ pc' = "Lbl_1" /\ UNCHANGED << u_ini, v_ini, v >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Lbl_1 \/ Lbl_2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ULEvenOdd.tla b/tlatools/test-model/pcal/ULEvenOdd.tla index dc5d6733f44e18e9235b3e0321239852c5dfb085..555439fac10e32161a01235218537c86e8acfc85 100644 --- a/tlatools/test-model/pcal/ULEvenOdd.tla +++ b/tlatools/test-model/pcal/ULEvenOdd.tla @@ -98,9 +98,11 @@ Lbl_5 == /\ pc = "Lbl_5" /\ pc' = "Done" /\ UNCHANGED << result, stack, xEven, xOdd >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Even \/ Odd \/ Lbl_4 \/ Lbl_5 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ULFactorial2.tla b/tlatools/test-model/pcal/ULFactorial2.tla index f4bcb3cb3770f524109f843f57a7f6e327bb5098..08483d2867605f47495b68bd08b6411a09ef9727 100644 --- a/tlatools/test-model/pcal/ULFactorial2.tla +++ b/tlatools/test-model/pcal/ULFactorial2.tla @@ -108,9 +108,11 @@ Lbl_4 == /\ pc = "Lbl_4" /\ pc' = "Done" /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == FactProc \/ FactProc2 \/ Lbl_3 \/ Lbl_4 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/ULQuicksortMacro.tla b/tlatools/test-model/pcal/ULQuicksortMacro.tla index 688c7d54f5d6902009019a079baf060ad6ad2f94..7f8114840addb9329795f58d5566c73fd6a0e4e0 100644 --- a/tlatools/test-model/pcal/ULQuicksortMacro.tla +++ b/tlatools/test-model/pcal/ULQuicksortMacro.tla @@ -113,9 +113,11 @@ Lbl_4 == /\ pc = "Lbl_4" /\ pc' = "Lbl_1" /\ UNCHANGED << A, returnVal >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == QS \/ Lbl_4 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(Next) diff --git a/tlatools/test-model/pcal/UniprocDefine.tla b/tlatools/test-model/pcal/UniprocDefine.tla index c75d634e1fbf4263783a0777de876a57bb833796..cb74ba0bbfd83f18feacbef2e1f181a3f98d8618 100644 --- a/tlatools/test-model/pcal/UniprocDefine.tla +++ b/tlatools/test-model/pcal/UniprocDefine.tla @@ -62,9 +62,11 @@ minor == /\ pc = "minor" /\ pc' = "Done" /\ UNCHANGED << n, stack, a, b >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == Foo \/ main \/ minor - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/bug_05_10_03.tla b/tlatools/test-model/pcal/bug_05_10_03.tla index deb38b272740458fe67868452d6b5915575ee055..78ee4dbbdbe18b648a14284c5aa4bee6b6dd2f2a 100644 --- a/tlatools/test-model/pcal/bug_05_10_03.tla +++ b/tlatools/test-model/pcal/bug_05_10_03.tla @@ -32,9 +32,12 @@ start(self) == /\ pc[self] = "start" Proc(self) == start(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in 1..2: Proc(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/bug_05_12_10a.tla b/tlatools/test-model/pcal/bug_05_12_10a.tla index 01fbeca72e8dd09c84bf0d71c4b4a1bf32d9a94c..0490c9d3a4dd283c5f894e419de09c7813f67eb2 100644 --- a/tlatools/test-model/pcal/bug_05_12_10a.tla +++ b/tlatools/test-model/pcal/bug_05_12_10a.tla @@ -294,10 +294,12 @@ Pc2 == /\ pc = "Pc2" /\ pc' = "Done" /\ UNCHANGED << stack, A, res, i_, exp, i, vdcl, prcdr, lstmt, proc >> +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == IsAlgorithm \/ IsExpr \/ IsVarDecl \/ IsProcedure \/ IsLabeledStmt \/ IsProcess \/ PC1 \/ Pc2 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/bug_05_12_16b.tla b/tlatools/test-model/pcal/bug_05_12_16b.tla index 94138bcbab932a46fc6ae8f3e2fbb9d8ff8503e1..ba41ad8238a05a17668d9610580c7f47c582dcaa 100644 --- a/tlatools/test-model/pcal/bug_05_12_16b.tla +++ b/tlatools/test-model/pcal/bug_05_12_16b.tla @@ -59,10 +59,13 @@ P2(self) == /\ pc[self] = "P2" P(self) == P1(self) \/ P2(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in ProcSet: Foo(self)) \/ (\E self \in 1..3: P(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/bug_05_12_31.tla b/tlatools/test-model/pcal/bug_05_12_31.tla index 181345b88fed1e1863cb2ec0cca14adb138fde44..928c3f2e9b0bdc0a12925b6e61bf5b5930cbad2b 100644 --- a/tlatools/test-model/pcal/bug_05_12_31.tla +++ b/tlatools/test-model/pcal/bug_05_12_31.tla @@ -52,9 +52,11 @@ A == /\ pc = "A" /\ y' = x'+1 /\ pc' = "P1" +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == pc = "Done" /\ UNCHANGED vars + Next == P \/ A - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/pcal/bug_06_01_25.tla b/tlatools/test-model/pcal/bug_06_01_25.tla index a23cb49fff9e4eda6723cd2c94473a74bb850a01..865b62cc687bc4566ccb82c70cb5fa64bdba85c2 100644 --- a/tlatools/test-model/pcal/bug_06_01_25.tla +++ b/tlatools/test-model/pcal/bug_06_01_25.tla @@ -210,12 +210,15 @@ P5(self) == /\ pc[self] = "P5" Q(self) == P1(self) \/ P15(self) \/ P2(self) \/ P3(self) \/ P4(self) \/ P5(self) +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == (\E self \in ProcSet: P(self)) \/ (\E self \in {qq \in {1,2} : /\ \A i \in {1} : i > 0 /\ \A j \in {1} : j > 0 /\ \A k \in {1} : k > 0 }: Q(self)) - \/ (* Disjunct to prevent deadlock on termination *) - ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + \/ Terminating Spec == Init /\ [][Next]_vars diff --git a/tlatools/test-model/simulation/BasicMultiTrace/BasicMultiTrace.tla b/tlatools/test-model/simulation/BasicMultiTrace/BasicMultiTrace.tla new file mode 100644 index 0000000000000000000000000000000000000000..c7d0ec58d042f7ed37c209571739538b8767ad8e --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/BasicMultiTrace.tla @@ -0,0 +1,63 @@ +------------------------------ MODULE BasicMultiTrace ------------------------------ +EXTENDS Integers + +\* +\* This spec attempts to define a simple state machine that has multiple behaviors. +\* Originally added to verify correctness of simulation mode in both single and multi-threaded mode. +\* + +VARIABLE branch, depth + +MaxDepth == 5 +Width == 10 + +Init == + /\ branch = 0 + /\ depth = 0 + +Next == + \* Pick a branch + \/ /\ branch = 0 + /\ branch' \in 1..Width /\ UNCHANGED depth + \* Traverse down that branch. + \/ /\ branch > 0 + /\ depth < MaxDepth + /\ depth' = depth + 1 /\ UNCHANGED branch + +Spec == Init /\ [][Next]_<<branch, depth>> + +UnderspecifiedNext == branch' = 0 +UnderspecifiedInit == branch = 0 + +UnderspecifiedInitSpec == UnderspecifiedInit /\ [][Next]_<<branch, depth>> +UnderspecifiedNextSpec == Init /\ [][UnderspecifiedNext]_<<branch, depth>> + +\* A valid invariant that should be violated by the initial state. +InvInitState == ~(branch = 0) + +\* A valid invariant that should be violated by the spec. +Inv == ~(depth = 2) + +\* A nonsensical invariant that will cause a runtime evaluation error on the initial state. +InvBadEvalInitState == (0 = "a") + +\* A nonsensical invariant that will cause a runtime evaluation error on a non-initial state. +InvBadEvalNonInitState == IF branch = 0 THEN TRUE ELSE (0 = "a") + +\* A valid action property that should be violated by the spec. +ActionProp == [][branch' > branch]_<<branch, depth>> + +\* A nonsensical action property that will cause a runtime evaluation error. +ActionPropBadEval == [][IF branch = 0 THEN TRUE ELSE 0 = "a"]_<<branch, depth>> + +\* A simple state and action constraint, and an invariant that should hold true +\* given either constraint. +StateConstraint == depth < 4 +ActionConstraint == ~(depth' = 4 /\ depth = 3) +InvConstraint == depth <= 4 + +\* A liveness property that should be violated. +LivenessProp == <>(branch = -1) + + +============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MC.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b763c9c194f8988812ce02ebc9f9012fe3a8b442 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MC.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCActionProp.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCActionProp.cfg new file mode 100644 index 0000000000000000000000000000000000000000..02c18eae9509cfeae0f88a0a8d500b6ae3da156e --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCActionProp.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +PROPERTY +ActionProp diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCActionPropBadEval.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCActionPropBadEval.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bba9f9740204b197987977900a83e634a9dc9927 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCActionPropBadEval.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +PROPERTY +ActionPropBadEval diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvInitState.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvInitState.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d01b36afe2405e3a02bd8a911bd65a427edc8f36 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvInitState.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +InvBadEvalInitState \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvNonInitState.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvNonInitState.cfg new file mode 100644 index 0000000000000000000000000000000000000000..6b7abf91a8e841503ff4472fbac021640a9c6c6d --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCBadInvNonInitState.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +InvBadEvalNonInitState \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCInv.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCInv.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCInv.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCInvInitState.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCInvInitState.cfg new file mode 100644 index 0000000000000000000000000000000000000000..564eb2d977457b3b535e66584faa46db08cd978e --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCInvInitState.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +InvInitState \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCLivenessProp.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCLivenessProp.cfg new file mode 100644 index 0000000000000000000000000000000000000000..2a5e4e9fb0e9b45e8355d4bf71d4f3f396cd7704 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCLivenessProp.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +PROPERTY +LivenessProp diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecInit.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecInit.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b1919bb49034f496f5204a62eacb6990c13e1ced --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecInit.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +UnderspecifiedInitSpec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecNext.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecNext.cfg new file mode 100644 index 0000000000000000000000000000000000000000..456896216d24793a361be6563c330eed792e0ab0 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCUnderspecNext.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +UnderspecifiedNextSpec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCWithActionConstraint.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCWithActionConstraint.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8e14f70964e994bb30e651bb896f0903de532b4b --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCWithActionConstraint.cfg @@ -0,0 +1,6 @@ +SPECIFICATION +Spec +INVARIANT +InvConstraint +ACTION_CONSTRAINT +ActionConstraint \ No newline at end of file diff --git a/tlatools/test-model/simulation/BasicMultiTrace/MCWithConstraint.cfg b/tlatools/test-model/simulation/BasicMultiTrace/MCWithConstraint.cfg new file mode 100644 index 0000000000000000000000000000000000000000..eb2ec2045cb216aca236f52b19e032281b7610c0 --- /dev/null +++ b/tlatools/test-model/simulation/BasicMultiTrace/MCWithConstraint.cfg @@ -0,0 +1,6 @@ +SPECIFICATION +Spec +INVARIANT +InvConstraint +CONSTRAINT +StateConstraint \ No newline at end of file diff --git a/tlatools/test-model/simulation/BenchmarkSpec/BenchmarkSpec.tla b/tlatools/test-model/simulation/BenchmarkSpec/BenchmarkSpec.tla new file mode 100644 index 0000000000000000000000000000000000000000..49eca6bb354bab0a5b5a450cbfded41e7c5d71d1 --- /dev/null +++ b/tlatools/test-model/simulation/BenchmarkSpec/BenchmarkSpec.tla @@ -0,0 +1,28 @@ +------------------------------ MODULE BenchmarkSpec ------------------------------ +EXTENDS Integers, Sequences + +\* +\* This spec produces a state space with a simple tree-like structure. The maximum depth and branching +\* factor of the state space tree can be controlled by setting the constant values of the spec. The goal +\* is to give a spec whose state space structure is easily understandable and controllable, for the sake +\* of running performance and/or correctness tests of TLC. +\* + +VARIABLE hist + +Init == hist = <<>> + +CONSTANTS Depth, BranchingFactor + +Next == + \E e \in 1..BranchingFactor : + hist' = Append(hist, e) + +Spec == Init /\ [][Next]_<<hist>> + +Constraint == Len(hist) < Depth + +\* An arbitrary state of max length. It's just a sequence filled with all 1's. +Inv == hist # [i \in 1..Depth |-> 1] + +============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/simulation/BenchmarkSpec/MCInv.cfg b/tlatools/test-model/simulation/BenchmarkSpec/MCInv.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4606d873bd81a8dc67cc6faf0a8337dd9c7e7421 --- /dev/null +++ b/tlatools/test-model/simulation/BenchmarkSpec/MCInv.cfg @@ -0,0 +1,9 @@ +SPECIFICATION +Spec +INVARIANT +Inv +CONSTANTS +BranchingFactor = 3 +Depth = 15 +CONSTRAINT +Constraint \ No newline at end of file diff --git a/tlatools/test-model/test52.cfg b/tlatools/test-model/test52.cfg deleted file mode 100644 index 942df65a55fdabbd31d3495a5c5124ef762101af..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test52.cfg +++ /dev/null @@ -1,6 +0,0 @@ -SPECIFICATION Spec -PROPERTY Property -\* The Invariant is commented because of a known bug in TLC. -\* If this bug is ever addressed, Invariant can be re-enabled -\* and the test test52enabled be deleted. -\*INVARIANT Invariant diff --git a/tlatools/test-model/test52.tla b/tlatools/test-model/test52.tla deleted file mode 100644 index 0cf62f56535b99a564eee848238b31b57ea68d98..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test52.tla +++ /dev/null @@ -1,71 +0,0 @@ ----------------------- MODULE test52 ----------------------- - -\* Test of prefix and postfix operators as arguments - -EXTENDS TLC - -VARIABLES x, y - -BoxTest(-._) == -(x=0) -Foo1 == BoxTest([]) -Foo2 == BoxTest(<>) - --. a == {{"a"}, {"b"}} \ a -a ^+ == {{"a"}, {"b"}} \ a -a ^* == {{"a"}, {"b"}} \ a -a ^# == {{"a"}, {"b"}} \ a - -SetOpTest(Foo(_)) == Foo({{"b"}, {"c"}}) -DomainTest(Foo(_)) == Foo([i\in {"a", "b"} |-> i]) - -ASSUME - /\ Print("Test1 Begun", TRUE) - /\ SetOpTest(-.) = - {{"b"}, {"c"}} - /\ SetOpTest(^+) = {{"b"}, {"c"}} ^+ - /\ SetOpTest(^*) = {{"b"}, {"c"}} ^* - /\ SetOpTest(^#) = {{"b"}, {"c"}} ^# - /\ SetOpTest(SUBSET) = SUBSET {{"b"}, {"c"}} - /\ SetOpTest(UNION) = UNION {{"b"}, {"c"}} - /\ DomainTest(DOMAIN) = DOMAIN [i\in {"a", "b"} |-> i] - /\ Print("Test1 Finished", TRUE) - - -Init == /\ x = {"a"} - /\ y = {"a"} -Next == /\ x'= x \cup {"a"} - /\ y'= y \cup {"b"} -Spec == Init /\ [][Next]_<<x, y>> - -EnabledTest(Foo(_)) == Foo(x'=x) -UnchangedTest(Foo(_)) == Foo(x) -PrimeTest(Foo(_)) == Foo(x) = x - -Invariant == - /\ EnabledTest(ENABLED) - -ImpliedAction == - /\ UnchangedTest(UNCHANGED) - /\ PrimeTest(') - -Property == [][ImpliedAction]_<<x, y>> - -================================================================== -\* Prefix Operators -~ -ENABLED -UNCHANGED -[] -<> -SUBSET -UNION -DOMAIN -- - -\* Postfix Operators -\* Predefined -' - -\* Undefined -^+ -^* -^# diff --git a/tlatools/test-model/test55.cfg b/tlatools/test-model/test55.cfg deleted file mode 100644 index 305c3a68fbd27fb38d68161f05488ca00c1b8202..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test55.cfg +++ /dev/null @@ -1,3 +0,0 @@ -SPECIFICATION Spec -INVARIANT Invariant -PROPERTY InitProperty diff --git a/tlatools/test-model/test55.tla b/tlatools/test-model/test55.tla deleted file mode 100644 index 3b94b2d51d54bd4283f59c7737a8e369b478416e..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test55.tla +++ /dev/null @@ -1,22 +0,0 @@ -------------------------------- MODULE test55 ------------------------------- -\* Test of ENABLED with INSTANCE semantics -EXTENDS Naturals - -VARIABLE z - -I == INSTANCE test55a WITH x <- z, y <- z - -Init == z = 0 -Next == z' = 1 - z - -Spec == Init /\ [][Next]_z /\ WF_z(Next) -Invariant == /\ I!F - /\ ~I!G - -InitProperty == I!Init -SafeProperty == I!SafeSpec -LiveProperty == I!LiveSpec - -============================================================================= - - diff --git a/tlatools/test-model/test55a.tla b/tlatools/test-model/test55a.tla deleted file mode 100644 index ad6aee45a926630145f1336ac71eb2fccdeb2ff2..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test55a.tla +++ /dev/null @@ -1,14 +0,0 @@ -------------------------------- MODULE test55a ------------------------------ -EXTENDS Naturals -VARIABLES x, y - -F == ENABLED (x'=0 /\ y'=1) -G == ENABLED ((x # y) /\ (x'=0) /\ (y'=1)) - -Init == (x = 0) /\ (y = 0) -Next == /\ x' = 1 - x - /\ y' = y - -SafeSpec == Init /\ [][Next]_<<x,y>> -LiveSpec == SafeSpec /\ WF_<<x,y>>(Next) -============================================================================= diff --git a/tlatools/test-model/test56.tla b/tlatools/test-model/test56.tla deleted file mode 100644 index e44515da94c7d77852bfd7b3994f8e0ceac11bbb..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test56.tla +++ /dev/null @@ -1,18 +0,0 @@ -------------------------------- MODULE test56 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test56a WITH u <- x - -NotIBangH == (x'=x) /\ I!G(x, x'=x+1) - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Property == [][I!H = NotIBangH]_x - -============================================================================= -I!H = (x'=x) /\ ENABLED (u'=x+1 \/ (u'=x /\ u'=x) \/ (u'=x /\ u'=x)) -NotIBangH = (x'=x) /\ ENABLED (x'=x+1 \/ (u'=x /\ x'=x) \/ (u'=x /\ x'=u)) diff --git a/tlatools/test-model/test56a.tla b/tlatools/test-model/test56a.tla deleted file mode 100644 index 449dd447ff88465b7a710a7eb77853c563fce942..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test56a.tla +++ /dev/null @@ -1,7 +0,0 @@ -------------------------------- MODULE test56a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE u -G(v, A) == ENABLED (A \/ (u'=u /\ v'=v) \/ (v'=u /\ u'=v)) -H == (u'=u) /\ G(u, u' = u + 1) -============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test57.cfg b/tlatools/test-model/test57.cfg deleted file mode 100644 index 1b03e11d2bb2c543031f557793dc2996896d77aa..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test57.cfg +++ /dev/null @@ -1,3 +0,0 @@ -SPECIFICATION Spec -INVARIANT Invariant0 Invariant2 Invariant3 Invariant1 -PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/test57.tla b/tlatools/test-model/test57.tla deleted file mode 100644 index 08adb6d0e2ac94935105328a0935bc037cbec538..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test57.tla +++ /dev/null @@ -1,20 +0,0 @@ -------------------------------- MODULE test57 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test57a WITH u <- x, v <- x - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Invariant0 == I!B(Next) -Invariant1 == I!C -Invariant2 == ~ I!B(I!A) -Invariant3 == I!D -Property == [][~I!A]_x -============================================================================= -I!C = ENABLED((u'=x) /\ (v' = x+1)) -I!B(I!A) = ENABLED ((x'=x) /\ (x'=x+1)) - diff --git a/tlatools/test-model/test57a.tla b/tlatools/test-model/test57a.tla deleted file mode 100644 index 4fde946c021c6d5e2ed2267ef65fa1fdb6376616..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test57a.tla +++ /dev/null @@ -1,9 +0,0 @@ -------------------------------- MODULE test57a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLES u, v -A == (u'=u) /\ (v'=v+1) -B(d) == ENABLED d -C == B(A) -D == ENABLED A -============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test59.cfg b/tlatools/test-model/test59.cfg deleted file mode 100644 index 8e570acdc96c3b5f8e28b4ecccd0273858365db2..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test59.cfg +++ /dev/null @@ -1,2 +0,0 @@ -SPECIFICATION Spec -PROPERTY Liveness diff --git a/tlatools/test-model/test59.tla b/tlatools/test-model/test59.tla deleted file mode 100644 index f1e1d2dff5279079471423bfa94b06a8450547d1..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test59.tla +++ /dev/null @@ -1,18 +0,0 @@ -------------------------------- MODULE test59 ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE y - -Next == LET x == y+1 - M == INSTANCE test59a - IN y' = (M!xplus1 - 1) % 5 - -Init == y = 0 - -Spec == Init /\ [][Next]_y /\ WF_y(Next) - -Invariant == y \in 0..4 -Liveness == []<>(y = 4) - -============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test59a.tla b/tlatools/test-model/test59a.tla deleted file mode 100644 index a5c42c5d2c8769bffa23a0d871a100c4d0799fda..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test59a.tla +++ /dev/null @@ -1,9 +0,0 @@ -------------------------------- MODULE test59a ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE x - -xplus1 == x+1 - -============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test63.cfg b/tlatools/test-model/test63.cfg deleted file mode 100644 index aedfc4d256b3ed021e905504203fd2f4df99ecfe..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test63.cfg +++ /dev/null @@ -1,12 +0,0 @@ -CONSTANTS - Rho = 1 - MaxReal = 5 - SecondsPerHour = 2 - -SPECIFICATION Spec -INVARIANT TypeOK -PROPERTY Property - -\* TEMPORAL Fairness -\* PROPERTY ErrorTemporal (* NonZeno ImpliedTemporal *) - diff --git a/tlatools/test-model/test63.tla b/tlatools/test-model/test63.tla deleted file mode 100644 index 1f7175f517c5b420de35cf7d9a2c5f2b3b496179..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test63.tla +++ /dev/null @@ -1,62 +0,0 @@ -\* Test of use of [A]_v within the next-state relation, checking -\* bug fix of 11 Mar 2009 -------------------------- MODULE test63 -------------------------- -EXTENDS Naturals, test63a -VARIABLE now -CONSTANT Rho, MaxReal, SecondsPerHour ------------------------------------------------------------------------------ - -Real == 0 .. MaxReal - -ASSUME (Rho \in Real) /\ (Rho > 0) - - VARIABLE t - TNext == t' = IF HCnxt THEN 0 ELSE t+(now'-now) - IsTimer == (t = 0) /\ [][TNext]_<<t,hr,now>> - MaxTime == [](t \leq SecondsPerHour + Rho) - MinTime == [][HCnxt => t \geq SecondsPerHour - Rho]_hr - HCTime == IsTimer /\ MaxTime /\ MinTime - - -NowNext == /\ now' \in {r \in Real : r > now} - /\ UNCHANGED hr - -BigNext == /\ [NowNext]_now - /\ [HCnxt]_hr - /\ TNext - /\ HCnxt => t \geq SecondsPerHour - Rho - /\ t' \leq SecondsPerHour + Rho - -BigNextX == - /\ NowNext \/ now'=now - /\ HCnxt \/ hr'=hr - /\ TNext - /\ HCnxt => t \geq SecondsPerHour - Rho - /\ t' \leq SecondsPerHour + Rho - -BigInit == /\ HCini - /\ t = 0 - /\ now \in Real - -Fairness == \A r \in Real : WF_now(NowNext /\ (now'>r)) - -NonZeno == \A r \in Real : <>(now \geq r) - -\* ImpliedTemporal == \A h \in 1..12 : []<>(hr = h) - -Spec == BigInit /\ [][BigNext]_<<hr, now, t>>\* /\ Fairness - -TypeOK == /\ now \in Nat - /\ hr \in 1..12 - -I == INSTANCE test63a - -Property == I!HC - -RT == /\ now \in Real - /\ [][NowNext]_now - /\ \A r \in Real : WF_now(NowNext /\ (now'>r)) - -ErrorTemporal == []((now # 4) => <>[](now # 4)) -============================================================================= - \ No newline at end of file diff --git a/tlatools/test-model/test63a.tla b/tlatools/test-model/test63a.tla deleted file mode 100644 index 85facb73fd18ebdbd58082093fddcc199cf04efb..0000000000000000000000000000000000000000 --- a/tlatools/test-model/test63a.tla +++ /dev/null @@ -1,9 +0,0 @@ ----------------------- MODULE test63a ---------------------- -EXTENDS Naturals -VARIABLE hr -HCini == hr \in (1 .. 12) -HCnxt == hr' = IF hr # 12 THEN hr + 1 ELSE 1 -HC == HCini /\ [][HCnxt]_hr --------------------------------------------------------------- -THEOREM HC => []HCini -============================================================== diff --git a/tlatools/test-verify/tlc2/tool/queue/StateQueueJFP.launch b/tlatools/test-verify/tlc2/tool/queue/StateQueueJFP.launch new file mode 100644 index 0000000000000000000000000000000000000000..f36bb231b11e3069caeaabd4020d4f7398e19976 --- /dev/null +++ b/tlatools/test-verify/tlc2/tool/queue/StateQueueJFP.launch @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication"> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> +<listEntry value="/tlatools/lib/jpf.jar"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> +<listEntry value="1"/> +</listAttribute> +<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/> +<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" javaProject="tlatools" path="1" type="4"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="tlatools"/> </runtimeClasspathEntry> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/tlatools/lib/jpf/jgraphx.jar" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/tlatools/lib/jpf/jpf-shell.jar" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/tlatools/lib/jpf/jpf-visual.jar" path="3" type="2"/> "/> +</listAttribute> +<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="gov.nasa.jpf.tool.RunJPF"/> +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="${project_loc:tlatools}/test-verify/tlc2/tool/queue/StateQueueJPFStandalone.jpf -show"/> +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="tlatools"/> +</launchConfiguration> diff --git a/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFStandalone.jpf b/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFStandalone.jpf new file mode 100644 index 0000000000000000000000000000000000000000..ce498466fcdff73f1cf6e367c7d270ff13285f83 --- /dev/null +++ b/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFStandalone.jpf @@ -0,0 +1,22 @@ +## +## Adjust for current system!!! Run in Eclispe with .launch file. +## +basepath=/home/markus/src/TLA/tla/tlatools + + +target=tlc2.tool.queue.StateQueueJPFTest +jpf-visual.sourcepath+=${basepath}/test-verify;${basepath}/src + +# register console errorTracePrinter as a publisher +report.publisher+=,errorTracePrinter +report.errorTracePrinter.class=ErrorTracePrinter + +# print trace when property is violated +report.errorTracePrinter.property_violation=trace + +#turn on the shell +shell=.shell.basicshell.BasicShell + +#turn on the new panel +shell.panels+=,errorTrace +shell.panels.errorTrace=ErrorTracePanel diff --git a/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFTest.java b/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFTest.java index 566fa087327e2e383b6659f3ad2986a569c70f93..f531a1111f9cf0487caab2370d37795d8ba20ab3 100644 --- a/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFTest.java +++ b/tlatools/test-verify/tlc2/tool/queue/StateQueueJPFTest.java @@ -35,6 +35,10 @@ import tlc2.tool.TLCState; public class StateQueueJPFTest extends TestJPF { + public static void main(String[] args) { + new StateQueueJPFTest().test(); + } + @Test public void test() { if (verifyNoPropertyViolation()) { @@ -50,21 +54,23 @@ public class StateQueueJPFTest extends TestJPF { } }, "Main"); main.start(); - - Thread worker = new Thread(new Runnable() { - public void run() { - for (int i = 0; i < 10; i++) { - TLCState state = queue.dequeue(); - if (state == null) { - queue.finishAll(); - return; + + for (int i = 0; i < 3; i++) { + Thread worker = new Thread(new Runnable() { + public void run() { + for (int i = 0; i < 3; i++) { + TLCState state = queue.dequeue(); + if (state == null) { + queue.finishAll(); + return; + } + queue.enqueue(tlcState); } - queue.enqueue(tlcState); + queue.finishAll(); } - queue.finishAll(); - } - }, "Worker"); - worker.start(); + }, "Worker" + i); + worker.start(); + } } } diff --git a/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java b/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java index 0cee19e1b625bee6fe40a55bb921e95fd242e96e..988f67fa208a34a3dbe7c3a135c6646f55dafe57 100644 --- a/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java +++ b/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java @@ -1,12 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ package pcal; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Arrays; import org.junit.Test; @@ -16,7 +38,7 @@ import util.ToolIO; public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void procedure() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -41,7 +63,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void process() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -68,7 +90,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void multiAssignment() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -91,7 +113,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void macro() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -114,7 +136,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void macroParam() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -137,7 +159,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void boundIdentifier() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -161,7 +183,7 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { @Test public void constant() throws IOException { - assertNull(trans.runMe(new String[] {"-nocfg", + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", writeTempFile("AssignmentToUndeclaredVariableTest", "---- MODULE algo ----\n" + "CONSTANT c\n" + @@ -180,13 +202,4 @@ public class AssignmentToUndeclaredVariableTest extends PCalTest { + " -- Assignment to undeclared variable c\n" + " at line 8, column 4.\n")); } - - private static String writeTempFile(String filename, String content) throws IOException { - final Path path = Files.createTempFile(filename, ".tla"); - Files.write(path, content.getBytes()); - - final File file = path.toFile(); - file.deleteOnExit(); - return file.getAbsolutePath(); - } } diff --git a/tlatools/test/pcal/BakeryTest.java b/tlatools/test/pcal/BakeryTest.java index b423978d671b138b41df0ce14dc1659e803e4aac..1735eb9b5dac6c4eb09480e7ed78470491d08233 100644 --- a/tlatools/test/pcal/BakeryTest.java +++ b/tlatools/test/pcal/BakeryTest.java @@ -45,5 +45,7 @@ public class BakeryTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1183", "668", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "41")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Bug051003Test.java b/tlatools/test/pcal/Bug051003Test.java index 4a2fc3565a4fc587479d36e18a06ac9f6d6995e8..3f783025f816e2b52ddd6a5a355e1f2c86716594 100644 --- a/tlatools/test/pcal/Bug051003Test.java +++ b/tlatools/test/pcal/Bug051003Test.java @@ -45,5 +45,7 @@ public class Bug051003Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6", "4", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Bug051210aTest.java b/tlatools/test/pcal/Bug051210aTest.java index 1d69aa1d0fca710314e2f2f0546b5dfd9a7f63ca..ada455e80a9e3418194f5b4f70144e779ec390b9 100644 --- a/tlatools/test/pcal/Bug051210aTest.java +++ b/tlatools/test/pcal/Bug051210aTest.java @@ -45,5 +45,48 @@ public class Bug051210aTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15", "14", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + + assertUncovered(" line 134, col 25 to line 137, col 42 of module bug_05_12_10a: 0\n" + + " line 138, col 25 to line 138, col 43 of module bug_05_12_10a: 0\n" + + " line 139, col 22 to line 139, col 32 of module bug_05_12_10a: 0\n" + + " line 140, col 22 to line 140, col 29 of module bug_05_12_10a: 0\n" + + " line 147, col 12 to line 147, col 21 of module bug_05_12_10a: 0\n" + + " line 148, col 12 to line 148, col 22 of module bug_05_12_10a: 0\n" + + " line 149, col 12 to line 149, col 74 of module bug_05_12_10a: 0\n" + + " line 153, col 25 to line 153, col 44 of module bug_05_12_10a: 0\n" + + " line 154, col 25 to line 157, col 42 of module bug_05_12_10a: 0\n" + + " line 158, col 22 to line 158, col 32 of module bug_05_12_10a: 0\n" + + " line 159, col 22 to line 159, col 29 of module bug_05_12_10a: 0\n" + + " line 167, col 33 to line 167, col 50 of module bug_05_12_10a: 0\n" + + " line 168, col 33 to line 168, col 43 of module bug_05_12_10a: 0\n" + + " line 173, col 12 to line 173, col 21 of module bug_05_12_10a: 0\n" + + " line 174, col 12 to line 174, col 22 of module bug_05_12_10a: 0\n" + + " line 175, col 12 to line 175, col 74 of module bug_05_12_10a: 0\n" + + " line 196, col 25 to line 196, col 43 of module bug_05_12_10a: 0\n" + + " line 197, col 25 to line 200, col 42 of module bug_05_12_10a: 0\n" + + " line 201, col 22 to line 201, col 33 of module bug_05_12_10a: 0\n" + + " line 202, col 22 to line 202, col 32 of module bug_05_12_10a: 0\n" + + " line 203, col 22 to line 203, col 48 of module bug_05_12_10a: 0\n" + + " line 204, col 11 to line 204, col 64 of module bug_05_12_10a: 0\n" + + " line 207, col 12 to line 207, col 21 of module bug_05_12_10a: 0\n" + + " line 208, col 12 to line 208, col 22 of module bug_05_12_10a: 0\n" + + " line 209, col 12 to line 209, col 74 of module bug_05_12_10a: 0\n" + + " line 232, col 22 to line 232, col 33 of module bug_05_12_10a: 0\n" + + " line 233, col 22 to line 233, col 50 of module bug_05_12_10a: 0\n" + + " line 241, col 12 to line 241, col 19 of module bug_05_12_10a: 0\n" + + " line 242, col 12 to line 242, col 22 of module bug_05_12_10a: 0\n" + + " line 243, col 12 to line 243, col 75 of module bug_05_12_10a: 0\n" + + " line 248, col 11 to line 248, col 30 of module bug_05_12_10a: 0\n" + + " line 249, col 11 to line 249, col 34 of module bug_05_12_10a: 0\n" + + " line 250, col 11 to line 250, col 30 of module bug_05_12_10a: 0\n" + + " line 251, col 11 to line 251, col 64 of module bug_05_12_10a: 0\n" + + " line 256, col 11 to line 256, col 30 of module bug_05_12_10a: 0\n" + + " line 257, col 11 to line 257, col 36 of module bug_05_12_10a: 0\n" + + " line 258, col 11 to line 258, col 30 of module bug_05_12_10a: 0\n" + + " line 259, col 11 to line 259, col 63 of module bug_05_12_10a: 0\n" + + " line 272, col 12 to line 272, col 31 of module bug_05_12_10a: 0\n" + + " line 273, col 12 to line 273, col 35 of module bug_05_12_10a: 0\n" + + " line 274, col 12 to line 274, col 31 of module bug_05_12_10a: 0\n" + + " line 275, col 12 to line 275, col 65 of module bug_05_12_10a: 0"); } } diff --git a/tlatools/test/pcal/Bug051216bTest.java b/tlatools/test/pcal/Bug051216bTest.java index 79b17e012eb887b86bb3ee5d214282f54b63a3f6..2de30905f074678c0ec5eb4fbf0f4456c89024d0 100644 --- a/tlatools/test/pcal/Bug051216bTest.java +++ b/tlatools/test/pcal/Bug051216bTest.java @@ -45,5 +45,7 @@ public class Bug051216bTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "146", "64", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "10")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Bug051231Test.java b/tlatools/test/pcal/Bug051231Test.java index 240c13e4d52db009752aaa5b098b792291ee8ac6..b8995126394988c6b6ce8a031d2bf99777739dc9 100644 --- a/tlatools/test/pcal/Bug051231Test.java +++ b/tlatools/test/pcal/Bug051231Test.java @@ -45,5 +45,7 @@ public class Bug051231Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4", "3", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Bug060125Test.java b/tlatools/test/pcal/Bug060125Test.java index 4e5522ed0091925d5619368e46694ed2a1618cae..725c05b6250335a9fd8581e490db25007804c020 100644 --- a/tlatools/test/pcal/Bug060125Test.java +++ b/tlatools/test/pcal/Bug060125Test.java @@ -45,5 +45,14 @@ public class Bug060125Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "130", "64", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + + assertUncovered("line 138, col 27 to line 138, col 53 of module bug_06_01_25: 0\n" + + "line 139, col 27 to line 139, col 53 of module bug_06_01_25: 0\n" + + "line 140, col 27 to line 140, col 53 of module bug_06_01_25: 0\n" + + "line 162, col 27 to line 162, col 53 of module bug_06_01_25: 0\n" + + "line 163, col 27 to line 163, col 53 of module bug_06_01_25: 0\n" + + "line 164, col 27 to line 164, col 53 of module bug_06_01_25: 0\n" + + "line 165, col 27 to line 167, col 75 of module bug_06_01_25: 0\n" + + "line 168, col 27 to line 168, col 58 of module bug_06_01_25: 0"); } } diff --git a/tlatools/test/pcal/CBakeryTest.java b/tlatools/test/pcal/CBakeryTest.java index dbced2596fc535cc97a9e33df2e9d61fd10e8b36..31b4ad2dbd6b22f82d16df947adbeabc10b0f84a 100644 --- a/tlatools/test/pcal/CBakeryTest.java +++ b/tlatools/test/pcal/CBakeryTest.java @@ -45,5 +45,7 @@ public class CBakeryTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "867", "486", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "31")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CCallReturn1Test.java b/tlatools/test/pcal/CCallReturn1Test.java index e61be7defd3a2da47bafeebcbe880727e56ecb1c..4285b5862412f57f1686b1b2df8d137b2d2c5a14 100644 --- a/tlatools/test/pcal/CCallReturn1Test.java +++ b/tlatools/test/pcal/CCallReturn1Test.java @@ -46,5 +46,7 @@ public class CCallReturn1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CDiningPhilosophersTest.java b/tlatools/test/pcal/CDiningPhilosophersTest.java index 8b4ffd5af7ff8bb5f8412d386a1d044898667099..2435f924a0ccd3bfacc94fd034c6489a33a8fa5d 100644 --- a/tlatools/test/pcal/CDiningPhilosophersTest.java +++ b/tlatools/test/pcal/CDiningPhilosophersTest.java @@ -45,5 +45,7 @@ public class CDiningPhilosophersTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "301", "118", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CEither1Test.java b/tlatools/test/pcal/CEither1Test.java index c6358c81931b2dd0666f059431f4f7e0158b3c05..270087db26b95f3fb7cd0c3ddb8ec0569cf34938 100644 --- a/tlatools/test/pcal/CEither1Test.java +++ b/tlatools/test/pcal/CEither1Test.java @@ -46,5 +46,7 @@ public class CEither1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CMultiprocDefineTest.java b/tlatools/test/pcal/CMultiprocDefineTest.java index 95318f7fb848055b2d4e9ef62b883130d393121f..d1df2feee8d3cd0a4d944432916a95ab7a2ac70f 100644 --- a/tlatools/test/pcal/CMultiprocDefineTest.java +++ b/tlatools/test/pcal/CMultiprocDefineTest.java @@ -46,5 +46,7 @@ public class CMultiprocDefineTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CallGotoUnlabeledTest.java b/tlatools/test/pcal/CallGotoUnlabeledTest.java index b977fb13501a7b5d49b981000f03f8dd31126f06..b2a535996eecdc771d31f58c92c4bf41c487d657 100644 --- a/tlatools/test/pcal/CallGotoUnlabeledTest.java +++ b/tlatools/test/pcal/CallGotoUnlabeledTest.java @@ -17,10 +17,12 @@ public class CallGotoUnlabeledTest extends PCalTest { @Test public void test() { - + ToolIO.setMode(ToolIO.TOOL); + final String fileName = "CallGotoUnlabeledTest.tla"; - final TLAtoPCalMapping mapping = trans.runMe(new String[] {"-nocfg", "-unixEOL", "-reportLabels", CommonTestCase.BASE_PATH + fileName}); + assertEquals(0, trans.runMe(new String[] {"-nocfg", "-unixEOL", "-reportLabels", CommonTestCase.BASE_PATH + fileName})); + final TLAtoPCalMapping mapping = PcalParams.tlaPcalMapping; assertNotNull(mapping); final String[] messages = ToolIO.getAllMessages(); diff --git a/tlatools/test/pcal/CallReturn1Test.java b/tlatools/test/pcal/CallReturn1Test.java index 2046e764ad3dae9c8337fb540662f1c5f2c9c4da..40b0b20d386ab06e9410102977f90771b4777a04 100644 --- a/tlatools/test/pcal/CallReturn1Test.java +++ b/tlatools/test/pcal/CallReturn1Test.java @@ -46,5 +46,7 @@ public class CallReturn1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/CallReturn2Test.java b/tlatools/test/pcal/CallReturn2Test.java index a2a9a75d8bab87a4ebafda6ccee6e2b35cf77b7e..f3be012b0aeec3235a4b28cd6de70318446c71e1 100644 --- a/tlatools/test/pcal/CallReturn2Test.java +++ b/tlatools/test/pcal/CallReturn2Test.java @@ -46,5 +46,18 @@ public class CallReturn2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "12", "11", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + + assertUncovered(" line 129, col 10 to line 129, col 15 of module CallReturn2: 0\n" + + " line 130, col 10 to line 130, col 19 of module CallReturn2: 0\n" + + " line 131, col 10 to line 131, col 65 of module CallReturn2: 0\n" + + " line 134, col 13 to line 134, col 18 of module CallReturn2: 0\n" + + " line 135, col 13 to line 138, col 36 of module CallReturn2: 0\n" + + " line 139, col 13 to line 139, col 30 of module CallReturn2: 0\n" + + " line 140, col 10 to line 140, col 19 of module CallReturn2: 0\n" + + " line 141, col 10 to line 141, col 55 of module CallReturn2: 0\n" + + " line 147, col 10 to line 147, col 29 of module CallReturn2: 0\n" + + " line 148, col 10 to line 148, col 27 of module CallReturn2: 0\n" + + " line 149, col 10 to line 149, col 29 of module CallReturn2: 0\n" + + " line 150, col 10 to line 150, col 58 of module CallReturn2: 0"); } } diff --git a/tlatools/test/pcal/DetlefSpecTest.java b/tlatools/test/pcal/DetlefSpecTest.java index 7a94a0c3e1782e2c843eb9ee37a471e6b0ab74a0..fdbb095f712f61624bc1fce46d61f0ff294ab5ae 100644 --- a/tlatools/test/pcal/DetlefSpecTest.java +++ b/tlatools/test/pcal/DetlefSpecTest.java @@ -45,5 +45,7 @@ public class DetlefSpecTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "31", "15", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/DetlefsTest.java b/tlatools/test/pcal/DetlefsTest.java index bdd914593e80054c8debda5c4b3790279e21d736..6d23fbf8dec62a95f5da9452442ebe84316eeba5 100644 --- a/tlatools/test/pcal/DetlefsTest.java +++ b/tlatools/test/pcal/DetlefsTest.java @@ -45,5 +45,7 @@ public class DetlefsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2127012", "952912", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "82")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Dijkstra1Test.java b/tlatools/test/pcal/Dijkstra1Test.java index 8d9659b901ae12f7a7b5aa2b56baa1aecf6496a7..7be46c0a75c086a374858d8f5f751f1fec6770c6 100644 --- a/tlatools/test/pcal/Dijkstra1Test.java +++ b/tlatools/test/pcal/Dijkstra1Test.java @@ -46,6 +46,8 @@ public class Dijkstra1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "16775", "5510", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "10")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/DiningPhilosophersTest.java b/tlatools/test/pcal/DiningPhilosophersTest.java index 815fc383ce3cd299a1061912e94d14dad8aa5237..57349d69ab7811ca7b458fc9ea9a731abb851c90 100644 --- a/tlatools/test/pcal/DiningPhilosophersTest.java +++ b/tlatools/test/pcal/DiningPhilosophersTest.java @@ -46,5 +46,7 @@ public class DiningPhilosophersTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "301", "118", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Either1Test.java b/tlatools/test/pcal/Either1Test.java index d9a51d1422707723b7391a1f85e255c61b82ee6b..47558d6d0d9b30d4fb36a0e12034ce21e1245eeb 100644 --- a/tlatools/test/pcal/Either1Test.java +++ b/tlatools/test/pcal/Either1Test.java @@ -46,5 +46,7 @@ public class Either1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Either2Test.java b/tlatools/test/pcal/Either2Test.java index 94c61c104bd4770afb1b33aafc986275af97293d..72809ff31b202d0617108231798953201efa7cbc 100644 --- a/tlatools/test/pcal/Either2Test.java +++ b/tlatools/test/pcal/Either2Test.java @@ -46,5 +46,7 @@ public class Either2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Either3Test.java b/tlatools/test/pcal/Either3Test.java index c4998c51b537e682a9e33a1ab8bb56d1528a2465..37494778c877542f53fbc5ab4831e574ccbd50da 100644 --- a/tlatools/test/pcal/Either3Test.java +++ b/tlatools/test/pcal/Either3Test.java @@ -46,5 +46,7 @@ public class Either3Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "12", "9", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Either4Test.java b/tlatools/test/pcal/Either4Test.java index b34891ce311673bc1eedecea4ed1a407c1880938..8d2eabd7bd20b36e5f736f976d81e2fc376502d6 100644 --- a/tlatools/test/pcal/Either4Test.java +++ b/tlatools/test/pcal/Either4Test.java @@ -46,5 +46,7 @@ public class Either4Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "154", "81", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Either5Test.java b/tlatools/test/pcal/Either5Test.java index 5ef4e87cbb8f34d7622deff693788be76c014e20..bb283cade8439d6fef412cb4314942ff2bb08828 100644 --- a/tlatools/test/pcal/Either5Test.java +++ b/tlatools/test/pcal/Either5Test.java @@ -46,5 +46,7 @@ public class Either5Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "7", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Euclid2Test.java b/tlatools/test/pcal/Euclid2Test.java index 2083719054204f79de93ca070fea202b9e3e570f..d44252a5aa71d5f279f8b01b3960ba0a6567292a 100644 --- a/tlatools/test/pcal/Euclid2Test.java +++ b/tlatools/test/pcal/Euclid2Test.java @@ -46,5 +46,7 @@ public class Euclid2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "19352", "18852", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "90")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Euclid3Test.java b/tlatools/test/pcal/Euclid3Test.java index fb10c50cd759e7c56fdc6d6096102a4e4a395b0f..1e41f3cc2da343165e01a9159ef4ae506f363d5a 100644 --- a/tlatools/test/pcal/Euclid3Test.java +++ b/tlatools/test/pcal/Euclid3Test.java @@ -46,5 +46,8 @@ public class Euclid3Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "97", "94", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "50")); + + assertUncovered("line 38, col 35 to line 38, col 40 of module Euclid3: 0\n" + + "line 39, col 35 to line 39, col 40 of module Euclid3: 0"); } } diff --git a/tlatools/test/pcal/EuclidTest.java b/tlatools/test/pcal/EuclidTest.java index 61167ed1d899695067b142bcc09d652ece1c3b1d..f865501ea24ae96939cd5613880a86f33291f49a 100644 --- a/tlatools/test/pcal/EuclidTest.java +++ b/tlatools/test/pcal/EuclidTest.java @@ -46,5 +46,7 @@ public class EuclidTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6752", "6352", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "42")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/EvenOddBadTest.java b/tlatools/test/pcal/EvenOddBadTest.java index 01cfc3fbe193028eaf5dd6904a3575457abff816..0f8e2d371cf0623db81fe21c980633a443d01ef7 100644 --- a/tlatools/test/pcal/EvenOddBadTest.java +++ b/tlatools/test/pcal/EvenOddBadTest.java @@ -47,5 +47,9 @@ public class EvenOddBadTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15", "13", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + + assertUncovered("line 66, col 23 to line 66, col 37 of module EvenOddBad: 0\n" + + "line 67, col 23 to line 67, col 32 of module EvenOddBad: 0\n" + + "line 68, col 23 to line 68, col 50 of module EvenOddBad: 0"); } } diff --git a/tlatools/test/pcal/EvenOddTest.java b/tlatools/test/pcal/EvenOddTest.java index 4bbee35bcdf3d43e5b80c6bc14ddf8c258b4d642..be0e4fbee2de067f04c035b8fcf28414b48801a9 100644 --- a/tlatools/test/pcal/EvenOddTest.java +++ b/tlatools/test/pcal/EvenOddTest.java @@ -46,5 +46,9 @@ public class EvenOddTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + + assertUncovered("line 67, col 23 to line 67, col 37 of module EvenOdd: 0\n" + + "line 68, col 23 to line 68, col 34 of module EvenOdd: 0\n" + + "line 69, col 23 to line 69, col 50 of module EvenOdd: 0"); } } diff --git a/tlatools/test/pcal/Factorial2Test.java b/tlatools/test/pcal/Factorial2Test.java index 010aab9e3d7852b3b29c22123d91ce3265643abb..516a50e7c89923fecd875b5e897e62515609470d 100644 --- a/tlatools/test/pcal/Factorial2Test.java +++ b/tlatools/test/pcal/Factorial2Test.java @@ -46,5 +46,11 @@ public class Factorial2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + + assertUncovered("line 53, col 21 to line 53, col 40 of module Factorial2: 0\n" + + "line 54, col 21 to line 54, col 38 of module Factorial2: 0\n" + + "line 55, col 21 to line 55, col 44 of module Factorial2: 0\n" + + "line 56, col 21 to line 56, col 40 of module Factorial2: 0\n" + + "line 57, col 21 to line 57, col 52 of module Factorial2: 0"); } } diff --git a/tlatools/test/pcal/FactorialTest.java b/tlatools/test/pcal/FactorialTest.java index cfa47463ce89f1056c5f09ec5b0337ac27f54fe0..870caefb161bc6da17b0accd2bc2d817395f31e1 100644 --- a/tlatools/test/pcal/FactorialTest.java +++ b/tlatools/test/pcal/FactorialTest.java @@ -46,5 +46,7 @@ public class FactorialTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "9", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FairSeq2Test.java b/tlatools/test/pcal/FairSeq2Test.java index 21d2e83f0b450d595b3b5a2017182be022d0ba17..a41d78c1c8fb99ebe387396cb0de5e823d0ec907 100644 --- a/tlatools/test/pcal/FairSeq2Test.java +++ b/tlatools/test/pcal/FairSeq2Test.java @@ -46,5 +46,7 @@ public class FairSeq2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FairSeqTest.java b/tlatools/test/pcal/FairSeqTest.java index a06b739637e48ae5cabdc3c0d8df6451b5dce530..af5d65c106045f162c9465935cebe52c961d89d2 100644 --- a/tlatools/test/pcal/FairSeqTest.java +++ b/tlatools/test/pcal/FairSeqTest.java @@ -46,5 +46,7 @@ public class FairSeqTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FastMutex2Test.java b/tlatools/test/pcal/FastMutex2Test.java index 5a76df2b7616a8bf670aded933cff78d98d1eb07..a75d6009d5c6a5aab8450b418f0bc8c811772e19 100644 --- a/tlatools/test/pcal/FastMutex2Test.java +++ b/tlatools/test/pcal/FastMutex2Test.java @@ -46,5 +46,7 @@ public class FastMutex2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FastMutex3Test.java b/tlatools/test/pcal/FastMutex3Test.java index 2d278a720e7ec04680ba7cd6a38d85fb4f243ac4..1a2c4b21593ee85245e4b8322e6b66ba0a8c4034 100644 --- a/tlatools/test/pcal/FastMutex3Test.java +++ b/tlatools/test/pcal/FastMutex3Test.java @@ -46,5 +46,7 @@ public class FastMutex3Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FastMutexTest.java b/tlatools/test/pcal/FastMutexTest.java index d0867c55d86fa81662b975312657f0285a311d42..75a2a9ae2f5d01525935e5500cd814137b4912c0 100644 --- a/tlatools/test/pcal/FastMutexTest.java +++ b/tlatools/test/pcal/FastMutexTest.java @@ -46,5 +46,7 @@ public class FastMutexTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FastMutexWithGoto2Test.java b/tlatools/test/pcal/FastMutexWithGoto2Test.java index 616788e3801babeccf21ad96a2b0e4eb52a374d5..4a14a4430ddbacc3c154c6f063c5ac6445618488 100644 --- a/tlatools/test/pcal/FastMutexWithGoto2Test.java +++ b/tlatools/test/pcal/FastMutexWithGoto2Test.java @@ -46,5 +46,7 @@ public class FastMutexWithGoto2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "42277", "15900", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "47")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FastMutexWithGotoTest.java b/tlatools/test/pcal/FastMutexWithGotoTest.java index 69b4e77b0f635d50c2bb842b3b61ee4b13f327af..a46bb0059f00927b927b0d5d45a282bc46b3ef66 100644 --- a/tlatools/test/pcal/FastMutexWithGotoTest.java +++ b/tlatools/test/pcal/FastMutexWithGotoTest.java @@ -46,5 +46,7 @@ public class FastMutexWithGotoTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "58")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/FischerTest.java b/tlatools/test/pcal/FischerTest.java index 1fa293f93fdeb896848d840e8b955614ba37eebf..37c3e49e0c1ffa8bf4d66b574dc9510dee69f547 100644 --- a/tlatools/test/pcal/FischerTest.java +++ b/tlatools/test/pcal/FischerTest.java @@ -46,6 +46,8 @@ public class FischerTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2487", "1002", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "24")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/InnerLabeledIfTest.java b/tlatools/test/pcal/InnerLabeledIfTest.java index a95419d8e50f63391c00ea2c9837d1d43fd3bc01..f97510f664c2eb732f017220835e9bd18d79b6a5 100644 --- a/tlatools/test/pcal/InnerLabeledIfTest.java +++ b/tlatools/test/pcal/InnerLabeledIfTest.java @@ -46,6 +46,7 @@ public class InnerLabeledIfTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "20", "16", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + assertZeroUncovered(); } } /* @@ -81,4 +82,4 @@ Model checking completed. No error has been found. 20 states generated, 16 distinct states found, 0 states left on queue. The depth of the complete state graph search is 4. Finished. (2012-08-10 17:38:14) -*/ \ No newline at end of file +*/ diff --git a/tlatools/test/pcal/MPFactorial2Test.java b/tlatools/test/pcal/MPFactorial2Test.java index 33d0353cafac25eaa095fa18fa30a9b267707197..5acbd064fac3b161549780de5840083a9a1de986 100644 --- a/tlatools/test/pcal/MPFactorial2Test.java +++ b/tlatools/test/pcal/MPFactorial2Test.java @@ -46,5 +46,11 @@ public class MPFactorial2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4754", "1728", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "34")); + + assertUncovered("line 61, col 27 to line 61, col 74 of module MPFactorial2: 0\n" + + "line 62, col 27 to line 62, col 71 of module MPFactorial2: 0\n" + + "line 63, col 27 to line 63, col 80 of module MPFactorial2: 0\n" + + "line 64, col 27 to line 64, col 77 of module MPFactorial2: 0\n" + + "line 65, col 27 to line 65, col 58 of module MPFactorial2: 0"); } } diff --git a/tlatools/test/pcal/MPFactorialTest.java b/tlatools/test/pcal/MPFactorialTest.java index ffebcfcba6d6c1a371502134e39aeee890a7833b..d0abcbfc1eb5696db7d1c97d263b4d175006913c 100644 --- a/tlatools/test/pcal/MPFactorialTest.java +++ b/tlatools/test/pcal/MPFactorialTest.java @@ -46,5 +46,7 @@ public class MPFactorialTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1946", "729", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "25")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/MPNoParamsTest.java b/tlatools/test/pcal/MPNoParamsTest.java index 5156082529a96fca194bf0418ae0825665177624..587d42992c0ffe1ed2ed3928cb5252d5d7d51e5c 100644 --- a/tlatools/test/pcal/MPNoParamsTest.java +++ b/tlatools/test/pcal/MPNoParamsTest.java @@ -46,5 +46,7 @@ public class MPNoParamsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "250", "96", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/MergeSortTest.java b/tlatools/test/pcal/MergeSortTest.java index 92106edd3c41077e665f82c7639c214688978262..994be4e7b6c3c2b14f64b81ba3d5928b11fc3b8d 100644 --- a/tlatools/test/pcal/MergeSortTest.java +++ b/tlatools/test/pcal/MergeSortTest.java @@ -46,6 +46,9 @@ public class MergeSortTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "86", "80", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "18")); + assertUncovered("line 162, col 32 to line 162, col 61 of module MergeSort: 0\n" + + "line 178, col 32 to line 178, col 61 of module MergeSort: 0\n" + + "line 179, col 32 to line 179, col 37 of module MergeSort: 0"); } } /* @@ -74,4 +77,4 @@ Model checking completed. No error has been found. 86 states generated, 80 distinct states found, 0 states left on queue. The depth of the complete state graph search is 18. Finished. (2012-08-10 17:38:17) -*/ \ No newline at end of file +*/ diff --git a/tlatools/test/pcal/MissingBodyInWhileTest.java b/tlatools/test/pcal/MissingBodyInWhileTest.java new file mode 100644 index 0000000000000000000000000000000000000000..898c952e8d0de0a34f866022a2a8bf5114cc868d --- /dev/null +++ b/tlatools/test/pcal/MissingBodyInWhileTest.java @@ -0,0 +1,26 @@ +package pcal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.tool.CommonTestCase; +import util.ToolIO; + +public class MissingBodyInWhileTest extends PCalTest { + + @Test + public void test() { + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, + trans.runMe(new String[] {"-nocfg", CommonTestCase.BASE_PATH + "MissingBodyInWhile.tla"})); + + final String[] messages = ToolIO.getAllMessages(); + assertTrue(messages.length == 1); + + final String msg = messages[0]; + assertEquals("Unrecoverable error:\n" + + " -- Missing body of while statement at\n" + + " line 6, column 14.", msg.trim()); + } +} diff --git a/tlatools/test/pcal/MissingBodyInWithTest.java b/tlatools/test/pcal/MissingBodyInWithTest.java index c184963b26483a1e7a7fa78a6dfdcf378a3ea2bb..a57b20270cc55b7b9fdd5c5ab284c2a1471e4013 100644 --- a/tlatools/test/pcal/MissingBodyInWithTest.java +++ b/tlatools/test/pcal/MissingBodyInWithTest.java @@ -1,7 +1,6 @@ package pcal; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -13,7 +12,8 @@ public class MissingBodyInWithTest extends PCalTest { @Test public void test() { - assertNull(trans.runMe(new String[] {"-nocfg", CommonTestCase.BASE_PATH + "MissingBodyInWith.tla"})); + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, + trans.runMe(new String[] { "-nocfg", CommonTestCase.BASE_PATH + "MissingBodyInWith.tla" })); final String[] messages = ToolIO.getAllMessages(); assertTrue(messages.length == 1); diff --git a/tlatools/test/pcal/MultiAssignmentTest.java b/tlatools/test/pcal/MultiAssignmentTest.java index 46c9819d51a0b8f7dc8402ecf3ed15d8cc2e90e3..296ae0ae6eddf95ee587df78437ef9690dbeceb9 100644 --- a/tlatools/test/pcal/MultiAssignmentTest.java +++ b/tlatools/test/pcal/MultiAssignmentTest.java @@ -46,6 +46,7 @@ public class MultiAssignmentTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "56", "27", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/MultiProc2Test.java b/tlatools/test/pcal/MultiProc2Test.java index 283fea019b7b68fc1e6f2486c7c229dd0494fc57..72d0af22c56cb3558d5bd197c4ec3843ebbca601 100644 --- a/tlatools/test/pcal/MultiProc2Test.java +++ b/tlatools/test/pcal/MultiProc2Test.java @@ -46,6 +46,7 @@ public class MultiProc2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1212", "504", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/MultiprocDefineTest.java b/tlatools/test/pcal/MultiprocDefineTest.java index 35a658ea7386687b855df34cf600bfdc21ec7045..227303870a8cfb3fbb65a2673cb9c101a93490f3 100644 --- a/tlatools/test/pcal/MultiprocDefineTest.java +++ b/tlatools/test/pcal/MultiprocDefineTest.java @@ -45,6 +45,8 @@ public class MultiprocDefineTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/NestedMacrosTest.java b/tlatools/test/pcal/NestedMacrosTest.java index 255a605311624a01bc92a334b97367655281cc00..e8b202d927bcd8e2d9a3ff6b2fbe40b1085d0ce7 100644 --- a/tlatools/test/pcal/NestedMacrosTest.java +++ b/tlatools/test/pcal/NestedMacrosTest.java @@ -46,5 +46,7 @@ public class NestedMacrosTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "9", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "5")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/NoLoop2Test.java b/tlatools/test/pcal/NoLoop2Test.java index 99917b0402eaca0374c22de25ba17474b5c4d0d4..62e5cd8e5a40eedc32d5a3127ddf2fbd4a7e6386 100644 --- a/tlatools/test/pcal/NoLoop2Test.java +++ b/tlatools/test/pcal/NoLoop2Test.java @@ -46,6 +46,8 @@ public class NoLoop2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "11", "9", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/NoLoopTest.java b/tlatools/test/pcal/NoLoopTest.java index 9a846828ebf6e7f94c23c7d768506a49d5ce5d9c..9fa96e5109e5f5a1d13eafbf4e5a412449ef1586 100644 --- a/tlatools/test/pcal/NoLoopTest.java +++ b/tlatools/test/pcal/NoLoopTest.java @@ -46,6 +46,8 @@ public class NoLoopTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "8", "6", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/NoParamsTest.java b/tlatools/test/pcal/NoParamsTest.java index 2c4d35107f32a7d941c6a2a0fc979b34544043e7..d84a809071b4894a20a59c3283fd428dde03ff0f 100644 --- a/tlatools/test/pcal/NoParamsTest.java +++ b/tlatools/test/pcal/NoParamsTest.java @@ -46,6 +46,8 @@ public class NoParamsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "7", "6", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/NotSoSimpleLoopTest.java b/tlatools/test/pcal/NotSoSimpleLoopTest.java index 9f498eb48fc03a23dc581a348514a7e205698dde..4df7ab3718a5b5588e60c453a13f6962ab6de4aa 100644 --- a/tlatools/test/pcal/NotSoSimpleLoopTest.java +++ b/tlatools/test/pcal/NotSoSimpleLoopTest.java @@ -46,6 +46,8 @@ public class NotSoSimpleLoopTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/OptionalSemicolonTest.java b/tlatools/test/pcal/OptionalSemicolonTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d1385820d82cdc1ce8721df17c45b5de54dc3748 --- /dev/null +++ b/tlatools/test/pcal/OptionalSemicolonTest.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + +import tla2sany.drivers.SANY; +import util.TestPrintStream; +import util.ToolIO; + +public class OptionalSemicolonTest extends PCalTest { + + /* + * A PlusCal User's Manual P-Syntax: + * "[...] the final semicolon [or comma] is optional in the p-syntax." + */ + + @Test + public void noOptionalSemiColonVariableList1() throws IOException { + // Translate from PCal to TLA+ + final String filename = "MissingSemiColonVariableListTest1" + System.currentTimeMillis(); + final String absolutePath = writeFile(System.getProperty("java.io.tmpdir") + File.separator + filename, + "---- MODULE " + filename + " ----\n" + + "(*\n" + + "--algorithm algo\n" + + "variables foo = 0" + // no optional semicolon + "\n" + + "fair process bug = 0\n" + // notice the "fair" statement + "begin\n" + + "L:\n" + + " skip\n" + + "end process\n" + + "\n" + + "end algorithm *)\n" + + "====" + ); + test(filename, absolutePath); + } + + @Test + public void noOptionalSemiColonVariableList2() throws IOException { + // Translate from PCal to TLA+ + final String filename = "MissingSemiColonVariableListTest2" + System.currentTimeMillis(); + final String absolutePath = writeFile(System.getProperty("java.io.tmpdir") + File.separator + filename, + "---- MODULE " + filename + " ----\n" + + "(*\n" + + "--algorithm algo\n" + + "variables foo = 0 ;" + // optional semicolon + "\n" + + "fair process bug = 0\n" + // notice the "fair" statement + "begin\n" + + "L:\n" + + " skip\n" + + "end process\n" + + "\n" + + "end algorithm *)\n" + + "====" + ); + test(filename, absolutePath); + } + + @Test + public void noOptionalSemiColonVariableList3() throws IOException { + // Translate from PCal to TLA+ + final String filename = "MissingSemiColonVariableListTest3" + System.currentTimeMillis(); + final String absolutePath = writeFile(System.getProperty("java.io.tmpdir") + File.separator + filename, + "---- MODULE " + filename + " ----\n" + + "(*\n" + + "--algorithm algo\n" + + "variables foo = 0 ;" + // optional semicolon + "\n" + + "process bug = 0\n" + // notice the "fair" statement + "begin\n" + + "L:\n" + + " skip\n" + + "end process\n" + + "\n" + + "end algorithm *)\n" + + "====" + ); + test(filename, absolutePath); + } + + @Test + public void noOptionalSemiColonVariableList4() throws IOException { + // Translate from PCal to TLA+ + final String filename = "MissingSemiColonVariableListTest4" + System.currentTimeMillis(); + final String absolutePath = writeFile(System.getProperty("java.io.tmpdir") + File.separator + filename, + "---- MODULE " + filename + " ----\n" + + "(*\n" + + "--algorithm algo\n" + + "variables foo = 0" + // no optional semicolon + "\n" + + "process bug = 0\n" + // no "fair" statement + "begin\n" + + "L:\n" + + " skip\n" + + "end process\n" + + "\n" + + "end algorithm *)\n" + + "====" + ); + test(filename, absolutePath); + } + + private void test(final String filename, final String absolutePath) { + assertEquals(trans.STATUS_EXIT_WITHOUT_ERROR, trans.runMe(new String[] { "-nocfg", absolutePath })); + + // Parse with SANY and check for errors (collects parse errors into ToolIO.out) + final TestPrintStream testPrintStream = new TestPrintStream(); + ToolIO.out = testPrintStream; + SANY.SANYmain(new String[] { absolutePath }); + testPrintStream.assertSubstring("Semantic processing of module " + filename); + } +} diff --git a/tlatools/test/pcal/PCalModelCheckerTestCase.java b/tlatools/test/pcal/PCalModelCheckerTestCase.java index b291923729ed7bbcc6f18881f6db68ff15d8463d..88a634b663ea1b8efc45df65c49424889074717d 100644 --- a/tlatools/test/pcal/PCalModelCheckerTestCase.java +++ b/tlatools/test/pcal/PCalModelCheckerTestCase.java @@ -25,6 +25,7 @@ ******************************************************************************/ package pcal; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -35,6 +36,7 @@ import java.util.List; import org.junit.Before; +import tlc2.output.EC; import tlc2.tool.CommonTestCase; import tlc2.tool.liveness.ModelCheckerTestCase; import util.ToolIO; @@ -44,26 +46,38 @@ public abstract class PCalModelCheckerTestCase extends ModelCheckerTestCase { private final List<String> pcalArgs = new ArrayList<String>(); public PCalModelCheckerTestCase(final String spec, final String path) { - super(spec, path); - this.pcalArgs.add("-unixEOL"); + this(spec, path, EC.ExitStatus.SUCCESS); } public PCalModelCheckerTestCase(final String spec, final String path, final String[] extraPcalArgs) { - this(spec, path); + this(spec, path, EC.ExitStatus.SUCCESS); this.pcalArgs.addAll(Arrays.asList(extraPcalArgs)); } + public PCalModelCheckerTestCase(final String spec, final String path, final int exitStatus) { + super(spec, path, exitStatus); + this.pcalArgs.add("-unixEOL"); + } + @Before @Override public void setUp() { + // Make tool capture the output written to ToolIO.out. Otherwise, + // ToolIO#getAllMessages returns an empty array. + ToolIO.setMode(ToolIO.TOOL); + + // Reset ToolIO for each test case. Otherwise, a test case sees the output of + // the previous tests. + ToolIO.reset(); + this.pcalArgs.add(CommonTestCase.BASE_PATH + File.separator + path + File.separator + spec + ".tla"); // Run PCal translator - final TLAtoPCalMapping pcal2tla = trans.runMe(pcalArgs.toArray(new String[pcalArgs.size()])); - assertNotNull(pcal2tla); // successfully translated PCal to TLA+ + assertEquals(0, trans.runMe(pcalArgs.toArray(new String[pcalArgs.size()]))); + assertNotNull(PcalParams.tlaPcalMapping); // successfully translated PCal to TLA+ final String[] messages = ToolIO.getAllMessages(); - assertTrue(Arrays.toString(messages), messages.length == 0); + assertTrue(Arrays.toString(messages), messages.length == 4 || messages.length == 5); // Run TLC super.setUp(); diff --git a/tlatools/test/pcal/PCalTest.java b/tlatools/test/pcal/PCalTest.java index 100ed726e11abd87ee52564c4a11091dda622ae0..0db4abf6133ed8f994caa29281c2a6bc98ee5596 100644 --- a/tlatools/test/pcal/PCalTest.java +++ b/tlatools/test/pcal/PCalTest.java @@ -1,5 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ package pcal; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + import org.junit.Before; import util.ToolIO; @@ -16,4 +47,22 @@ public abstract class PCalTest { // the previous tests. ToolIO.reset(); } + + protected static String writeFile(String filename, String content) throws IOException { + final Path path = Files.createFile(Paths.get(filename + ".tla")); + Files.write(path, content.getBytes()); + + final File file = path.toFile(); + file.deleteOnExit(); + return file.getAbsolutePath(); + } + + protected static String writeTempFile(String filename, String content) throws IOException { + final Path path = Files.createTempFile(filename, ".tla"); + Files.write(path, content.getBytes()); + + final File file = path.toFile(); + file.deleteOnExit(); + return file.getAbsolutePath(); + } } diff --git a/tlatools/test/pcal/PetersonTest.java b/tlatools/test/pcal/PetersonTest.java index 6238f85d2bf82bcb025048e14a785932c1f27559..6928eb13bcd43aa9a38f1e8eef85a0085a99af47 100644 --- a/tlatools/test/pcal/PetersonTest.java +++ b/tlatools/test/pcal/PetersonTest.java @@ -45,5 +45,7 @@ public class PetersonTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "85", "42", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/Quicksort2ProcsTest.java b/tlatools/test/pcal/Quicksort2ProcsTest.java index 4750a70ffba8c9be04b6c1acc415eb2a4436f75a..2f3b17ac4c23650783d1e08e0a730f2a75db0a18 100644 --- a/tlatools/test/pcal/Quicksort2ProcsTest.java +++ b/tlatools/test/pcal/Quicksort2ProcsTest.java @@ -46,6 +46,8 @@ public class Quicksort2ProcsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "445", "361", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/QuicksortMacroTest.java b/tlatools/test/pcal/QuicksortMacroTest.java index b59d9bd21a488551ee49d6a5cb79d08c785ba909..19876442cab166a454bbd210ecf71fc9836da533 100644 --- a/tlatools/test/pcal/QuicksortMacroTest.java +++ b/tlatools/test/pcal/QuicksortMacroTest.java @@ -46,6 +46,8 @@ public class QuicksortMacroTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "390", "306", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/QuicksortTest.java b/tlatools/test/pcal/QuicksortTest.java index 3a26d807e8e340fa119672b008d997a463e283c7..bc8a6bb67e257c743723346e35dc0d99f3fb7db4 100644 --- a/tlatools/test/pcal/QuicksortTest.java +++ b/tlatools/test/pcal/QuicksortTest.java @@ -46,6 +46,8 @@ public class QuicksortTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1017", "933", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "16")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/RABTest.java b/tlatools/test/pcal/RABTest.java index fe470122f450c612d02ad63e5262e8ae6bc6954b..a3099d1f12eaaf2365c6ddb6be7c6a5d666e74f3 100644 --- a/tlatools/test/pcal/RABTest.java +++ b/tlatools/test/pcal/RABTest.java @@ -25,6 +25,7 @@ ******************************************************************************/ package pcal; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -38,7 +39,7 @@ import tlc2.output.EC; public class RABTest extends PCalModelCheckerTestCase { public RABTest() { - super("RAB", "pcal"); + super("RAB", "pcal", EC.ExitStatus.VIOLATION_SAFETY); } @Test @@ -47,7 +48,7 @@ public class RABTest extends PCalModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "551", "350", "130")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + assertEquals(7, recorder.getRecordAsInt(EC.TLC_SEARCH_DEPTH)); assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); final List<String> expectedTrace = new ArrayList<String>(); @@ -129,6 +130,8 @@ public class RABTest extends PCalModelCheckerTestCase { "/\\ flags = [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/RealQuicksort2Test.java b/tlatools/test/pcal/RealQuicksort2Test.java index ea4a5563fb2028c748f3f75ce63b4a30210fe391..ea808b8e35609fc52d7ac42321572d515bda2e42 100644 --- a/tlatools/test/pcal/RealQuicksort2Test.java +++ b/tlatools/test/pcal/RealQuicksort2Test.java @@ -46,6 +46,8 @@ public class RealQuicksort2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "853", "612", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/RealQuicksortTest.java b/tlatools/test/pcal/RealQuicksortTest.java index d7ba5e6841521f84e7812165cea7ea1f4557523d..c7d0548c4dffd809d214b431802a93dc25d5f1c3 100644 --- a/tlatools/test/pcal/RealQuicksortTest.java +++ b/tlatools/test/pcal/RealQuicksortTest.java @@ -46,6 +46,8 @@ public class RealQuicksortTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "706", "495", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/ReallySimpleMultiProcTest.java b/tlatools/test/pcal/ReallySimpleMultiProcTest.java index 7e11812a17c7f0db2d4bca86e0529a7a57a1615a..2c2ed58b2f4cfb07b427cb5d97fab2d8f44e5a43 100644 --- a/tlatools/test/pcal/ReallySimpleMultiProcTest.java +++ b/tlatools/test/pcal/ReallySimpleMultiProcTest.java @@ -46,5 +46,7 @@ public class ReallySimpleMultiProcTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "144", "76", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/SBBTest.java b/tlatools/test/pcal/SBBTest.java index 420682afb32bfec7321d8c6ea38c514a0c240d48..f9c4074439642a999e0bf7aa127e9cfb9ca4a78b 100644 --- a/tlatools/test/pcal/SBBTest.java +++ b/tlatools/test/pcal/SBBTest.java @@ -25,6 +25,7 @@ ******************************************************************************/ package pcal; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,11 +35,12 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class SBBTest extends PCalModelCheckerTestCase { public SBBTest() { - super("SBB", "pcal"); + super("SBB", "pcal", ExitStatus.VIOLATION_SAFETY); } @Test @@ -47,7 +49,7 @@ public class SBBTest extends PCalModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3126", "1617", "328")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + assertEquals(15, recorder.getRecordAsInt(EC.TLC_SEARCH_DEPTH)); assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); final List<String> expectedTrace = new ArrayList<String>(); @@ -142,5 +144,7 @@ public class SBBTest extends PCalModelCheckerTestCase { "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + "/\\ pc = (p0 :> \"Loop\" @@ p1 :> \"Modify2\")"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/SemaphoreMutexTest.java b/tlatools/test/pcal/SemaphoreMutexTest.java index a91ce5e588e603e393f399d8081ac31341e9f601..bab0bb2def3a75de5850115ebb55ea8d55cf95c3 100644 --- a/tlatools/test/pcal/SemaphoreMutexTest.java +++ b/tlatools/test/pcal/SemaphoreMutexTest.java @@ -46,6 +46,8 @@ public class SemaphoreMutexTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "73", "32", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/SimpleLoopTest.java b/tlatools/test/pcal/SimpleLoopTest.java index d2a45d36af00cfe6ac888469af6407433b5bf21a..81e655475b07724106015170b4d7add0bd0f217e 100644 --- a/tlatools/test/pcal/SimpleLoopTest.java +++ b/tlatools/test/pcal/SimpleLoopTest.java @@ -46,6 +46,8 @@ public class SimpleLoopTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/SimpleLoopWithProcedureTest.java b/tlatools/test/pcal/SimpleLoopWithProcedureTest.java index 8e94b05443fcbc8392785208f56e1b3141b71555..6d03a43224c5eb7484d02fa39dd0ea93d8e83aa5 100644 --- a/tlatools/test/pcal/SimpleLoopWithProcedureTest.java +++ b/tlatools/test/pcal/SimpleLoopWithProcedureTest.java @@ -46,6 +46,8 @@ public class SimpleLoopWithProcedureTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "66", "64", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "32")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/SubSubTest.java b/tlatools/test/pcal/SubSubTest.java index f141f444a79a3c33fd61da51d0fec12d2a99ac61..dedd8655e10c8d52b4aeff0f3530be41bcb05c96 100644 --- a/tlatools/test/pcal/SubSubTest.java +++ b/tlatools/test/pcal/SubSubTest.java @@ -45,5 +45,7 @@ public class SubSubTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/SyncConsTest.java b/tlatools/test/pcal/SyncConsTest.java index 792a988f6694e7a65dd064a21779e48ecf924892..43b92e126ba523f65ee5116d0d95e74b270c251c 100644 --- a/tlatools/test/pcal/SyncConsTest.java +++ b/tlatools/test/pcal/SyncConsTest.java @@ -45,6 +45,8 @@ public class SyncConsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "22580", "8754", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "48")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/TestReplaceTest.java b/tlatools/test/pcal/TestReplaceTest.java index f592c99d182dea0809a0eb038b7f65142ac51f2e..9d498528eb300167cbe4c0197ea05d64079741ec 100644 --- a/tlatools/test/pcal/TestReplaceTest.java +++ b/tlatools/test/pcal/TestReplaceTest.java @@ -45,5 +45,8 @@ public class TestReplaceTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "18", "17", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "17")); + + assertUncovered("line 124, col 32 to line 124, col 41 of module TestReplace: 0\n" + + "line 175, col 33 to line 175, col 41 of module TestReplace: 0"); } } diff --git a/tlatools/test/pcal/TestTabsTest.java b/tlatools/test/pcal/TestTabsTest.java index e5b966d56ba831aaaa1d9cd3bfad09d4dda966af..ceb4f580356c4e591874fa11552cf94ec13a77dd 100644 --- a/tlatools/test/pcal/TestTabsTest.java +++ b/tlatools/test/pcal/TestTabsTest.java @@ -45,6 +45,8 @@ public class TestTabsTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/pcal/TestTest.java b/tlatools/test/pcal/TestTest.java index 5bbcd74821e3610f5c6ee9aaa0eee14c35bce052..3385dd16518e10f3274ca807df8eed09ec630166 100644 --- a/tlatools/test/pcal/TestTest.java +++ b/tlatools/test/pcal/TestTest.java @@ -46,5 +46,18 @@ public class TestTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5", "4", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertUncovered("line 47, col 31 to line 47, col 37 of module Test: 0\n" + + "line 48, col 31 to line 48, col 37 of module Test: 0\n" + + "line 51, col 24 to line 51, col 30 of module Test: 0\n" + + "line 52, col 9 to line 52, col 28 of module Test: 0\n" + + "line 53, col 9 to line 53, col 28 of module Test: 0\n" + + "line 54, col 9 to line 54, col 14 of module Test: 0\n" + + "line 68, col 43 to line 68, col 49 of module Test: 0\n" + + "line 69, col 43 to line 69, col 49 of module Test: 0\n" + + "line 72, col 36 to line 72, col 42 of module Test: 0\n" + + "line 73, col 21 to line 73, col 26 of module Test: 0\n" + + "line 84, col 32 to line 84, col 38 of module Test: 0\n" + + "line 87, col 25 to line 87, col 31 of module Test: 0"); } } diff --git a/tlatools/test/pcal/TreeBarrierTest.java b/tlatools/test/pcal/TreeBarrierTest.java index 7a49f45f027f08ff0a0709f5b694adb88c379631..8822ae03f635310f0d1504afe54292ac280b7a84 100644 --- a/tlatools/test/pcal/TreeBarrierTest.java +++ b/tlatools/test/pcal/TreeBarrierTest.java @@ -46,6 +46,8 @@ public class TreeBarrierTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5414", "2095", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "106")); + + assertUncovered("line 120, col 19 to line 120, col 32 of module TreeBarrier: 0"); } } /* diff --git a/tlatools/test/pcal/ULCallReturn1Test.java b/tlatools/test/pcal/ULCallReturn1Test.java index 5361b36bb5f25d8ac6fffec723809b9d7bb2a922..89275814ba9f7e0567180f8eb7bc07251354e74e 100644 --- a/tlatools/test/pcal/ULCallReturn1Test.java +++ b/tlatools/test/pcal/ULCallReturn1Test.java @@ -46,5 +46,7 @@ public class ULCallReturn1Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/ULEuclidTest.java b/tlatools/test/pcal/ULEuclidTest.java index 083d044e728fc04bd97fcd6122c41f95847e9aa6..f6a144210ca0a39eda9a94c95a9edacadfc4d569 100644 --- a/tlatools/test/pcal/ULEuclidTest.java +++ b/tlatools/test/pcal/ULEuclidTest.java @@ -46,5 +46,7 @@ public class ULEuclidTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6752", "6352", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "42")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/ULEvenOddTest.java b/tlatools/test/pcal/ULEvenOddTest.java index ce398ab24330a40d31cdd4e29a12588cd1a335fe..534f8af2c4001b1faca9e048b0f254469ee364a4 100644 --- a/tlatools/test/pcal/ULEvenOddTest.java +++ b/tlatools/test/pcal/ULEvenOddTest.java @@ -46,5 +46,9 @@ public class ULEvenOddTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + + assertUncovered("line 67, col 24 to line 67, col 38 of module ULEvenOdd: 0\n" + + "line 68, col 24 to line 68, col 36 of module ULEvenOdd: 0\n" + + "line 69, col 24 to line 69, col 51 of module ULEvenOdd: 0"); } } diff --git a/tlatools/test/pcal/ULFactorial2Test.java b/tlatools/test/pcal/ULFactorial2Test.java index 7503893b4f8306a9619a087b3ec2cead3e0fe9f6..facd2dd7b9170b111acc7856ab3f8aadea9db34e 100644 --- a/tlatools/test/pcal/ULFactorial2Test.java +++ b/tlatools/test/pcal/ULFactorial2Test.java @@ -46,5 +46,11 @@ public class ULFactorial2Test extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "9", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + + assertUncovered("line 53, col 24 to line 53, col 43 of module ULFactorial2: 0\n" + + "line 54, col 24 to line 54, col 41 of module ULFactorial2: 0\n" + + "line 55, col 24 to line 55, col 47 of module ULFactorial2: 0\n" + + "line 56, col 24 to line 56, col 43 of module ULFactorial2: 0\n" + + "line 57, col 24 to line 57, col 55 of module ULFactorial2: 0"); } } diff --git a/tlatools/test/pcal/ULQuicksortMacroTest.java b/tlatools/test/pcal/ULQuicksortMacroTest.java index d943dfefc7e2352be2ccc7daf263622dd655a57c..2d256c3c1085c8457c67a791b957828e494ef4b7 100644 --- a/tlatools/test/pcal/ULQuicksortMacroTest.java +++ b/tlatools/test/pcal/ULQuicksortMacroTest.java @@ -46,5 +46,7 @@ public class ULQuicksortMacroTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "342", "258", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/pcal/UnhandledInvalidSyntaxTest.java b/tlatools/test/pcal/UnhandledInvalidSyntaxTest.java new file mode 100644 index 0000000000000000000000000000000000000000..32442af1b6c8bd84890e3948f16cd72e66145bbf --- /dev/null +++ b/tlatools/test/pcal/UnhandledInvalidSyntaxTest.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; + +import util.ToolIO; + +public class UnhandledInvalidSyntaxTest extends PCalTest { + + @Test + public void test1() throws IOException { + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", + writeTempFile("MissingSemicolonTest1", + "---- MODULE algo ----\n" + + "(*\n" + + " --algorithm algo\n" + + " begin\n" + + " await;\n" + + " end algorithm;\n" + + "*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Unknown error at or before\n" + + " line 5, column 2.\n")); + } + + @Test + public void test2() throws IOException { + assertEquals(trans.STATUS_EXIT_WITH_ERRORS, trans.runMe(new String[] {"-nocfg", + writeTempFile("MissingSemicolonTest2", + "---- MODULE algo ----\n" + + "(*\n" + + " --algorithm algo\n" + + " begin\n" + + " if TRUE then\n" + // missing semicolon + " end if;\n" + + " end algorithm;\n" + + "*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Unknown error at or before\n" + + " line 6, column 8.\n")); + } +} \ No newline at end of file diff --git a/tlatools/test/pcal/UniprocDefineTest.java b/tlatools/test/pcal/UniprocDefineTest.java index 2ed81ff4704b7b1e9e8d442b32fa0c418cc5e118..eb85e1c2689b8e4a2ec3c75e6ef327a8bd324e3b 100644 --- a/tlatools/test/pcal/UniprocDefineTest.java +++ b/tlatools/test/pcal/UniprocDefineTest.java @@ -45,6 +45,8 @@ public class UniprocDefineTest extends PCalModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5", "4", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + + assertZeroUncovered(); } } /* diff --git a/tlatools/test/tla2sany/drivers/Bug156TEStackOverflowTest.java b/tlatools/test/tla2sany/drivers/Bug156TEStackOverflowTest.java index 0e5132d34a1fc80ed4ad341fd2b907393ad90428..02f935a051e68e4f3e00fae06ce8e5ca6bb0517e 100644 --- a/tlatools/test/tla2sany/drivers/Bug156TEStackOverflowTest.java +++ b/tlatools/test/tla2sany/drivers/Bug156TEStackOverflowTest.java @@ -2,6 +2,7 @@ package tla2sany.drivers; import org.junit.Before; import org.junit.Test; + import tla2sany.modanalyzer.SpecObj; import tla2sany.parser.ParseException; import util.SimpleFilenameToStream; diff --git a/tlatools/test/tla2sany/st/LocationTest.java b/tlatools/test/tla2sany/st/LocationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..214250a399ff4b078885f644d24115e6a5347a20 --- /dev/null +++ b/tlatools/test/tla2sany/st/LocationTest.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tla2sany.st; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.TreeSet; + +import org.junit.Test; + +public class LocationTest { + + @Test + public void testContains() { + assertTrue(new Location(0, 0, 10, 10).includes(new Location(0, 0, 10, 10))); + assertFalse(new Location(1, 0, 10, 9).includes(new Location(0, 0, 10, 10))); + + assertTrue(new Location(0, 0, 10, 10).includes(new Location(1, 0, 10, 9))); + assertFalse(new Location(1, 0, 10, 9).includes(new Location(0, 0, 10, 10))); + + + Location[] parsedLocations = Location + .getParsedLocations("line 781, col 31 to line 784, col 68 of module OpenAddressing\n" + + "line 783, col 38 to line 784, col 68 of module OpenAddressing\n" + + "line 784, col 41 to line 784, col 68 of module OpenAddressing\n" + + + "line 786, col 30 to line 786, col 69 of module OpenAddressing\n" + + "line 793, col 29 to line 793, col 63 of module OpenAddressing"); + + assertTrue(parsedLocations[0].includes(parsedLocations[0])); + + assertTrue(parsedLocations[0].includes(parsedLocations[1])); + assertFalse(parsedLocations[1].includes(parsedLocations[0])); + + assertTrue(parsedLocations[0].includes(parsedLocations[2])); + assertFalse(parsedLocations[2].includes(parsedLocations[0])); + + assertFalse(parsedLocations[0].includes(parsedLocations[3])); + assertFalse(parsedLocations[3].includes(parsedLocations[0])); + assertFalse(parsedLocations[4].includes(parsedLocations[0])); + } + + @Test + public void testComparator() { + final Location[] parsedLocations = Location.getParsedLocations( + "line 15, col 9 to line 15, col 9 of module CostMetrics\n" + + "line 15, col 9 to line 15, col 17 of module CostMetrics\n" + + "line 8, col 11 to line 8, col 11 of module CostMetrics\n" + + "line 8, col 13 to line 8, col 13 of module CostMetrics\n" + + "line 8, col 9 to line 8, col 15 of module CostMetrics\n" + + "line 14, col 15 to line 14, col 17 of module CostMetrics\n" + + "line 15, col 15 to line 15, col 17 of module CostMetrics\n" + + "line 16, col 34 to line 16, col 52 of module CostMetrics\n" + + "line 8, col 9 to line 8, col 15 of module CostMetrics\n" + + "line 16, col 42 to line 16, col 51 of module CostMetrics\n" + + "line 16, col 42 to line 16, col 50 of module CostMetrics\n" + + "line 16, col 46 to line 16, col 46 of module CostMetrics\n" + + "line 16, col 46 to line 16, col 50 of module CostMetrics\n" + + "line 16, col 46 to line 16, col 50 of module CostMetrics\n" + + "line 23, col 6 to line 25, col 18 of module CostMetrics\n" + + "line 18, col 9 to line 18, col 9 of module CostMetrics"); + assertEquals(16, parsedLocations.length); + + final TreeSet<Location> locations = new TreeSet<>(Arrays.asList(parsedLocations)); + assertEquals(14, locations.size()); + + final Iterator<Location> iterator = locations.iterator(); + Location l = iterator.next(); + for (int i = 1; i < locations.size(); i++) { + final Location next = iterator.next(); + assertTrue(l.bLine <= next.bLine); + if (l.bLine == next.bLine) { + assertTrue(l.bColumn <= next.bColumn); + if (l.bColumn == next.bColumn) { + assertTrue(l.eLine <= next.eLine); + if (l.eLine == next.eLine) { + assertTrue(l.eColumn < next.eColumn); + } + } + } + l = next; + } + } +} diff --git a/tlatools/test/tlc2/TLCTest.java b/tlatools/test/tlc2/TLCTest.java index dc3ffe81d0110ab6afb15017f7fb50f10b068ea3..4b4adee6ee95c50ff9178c96054deb65d1bed12c 100644 --- a/tlatools/test/tlc2/TLCTest.java +++ b/tlatools/test/tlc2/TLCTest.java @@ -5,11 +5,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; -import org.junit.Assume; import org.junit.Test; -import tlc2.TLC; -import tlc2.TLCGlobals; import tlc2.tool.fp.FPSetConfiguration; import tlc2.tool.fp.FPSetFactory; import util.TLCRuntime; diff --git a/tlatools/test/tlc2/TestDriver2.java b/tlatools/test/tlc2/TestDriver2.java deleted file mode 100644 index f5819464273da62f94398d4aa2e1f55117120c11..0000000000000000000000000000000000000000 --- a/tlatools/test/tlc2/TestDriver2.java +++ /dev/null @@ -1,232 +0,0 @@ -package tlc2; - -import java.io.File; - -import util.SimpleFilenameToStream; -import util.ToolIO; - -public class TestDriver2 -{ - - /** - * @author Simon Zambrovski - * @version $Id: TLCJob.java 638 2009-04-10 04:08:14Z simonzam $ - */ - private static final long TIMEOUT = 1000 * 5; - private static final int REPEATS = 10; - - private String rootModule; - private String cfgFile; - private String projectDir; - - private TLCThread tlcThread; - private int workers = 2; - - private int reported; - - - public static void main(String[] args) - { - if (args.length < 6 ) - { - // -workers 2 -config AtomicBakery_MC_1.cfg -metadir C:\org.zambrovski\download\AtomicBakery_MC_1.toolbox AtomicBakery_MC_1 - System.out.println("Call with: -workers <num> -config <name-of-config.cfg> -metadir <dir-to-put-states> <name-of-module>"); - } - TestDriver2 testDriver2 = new TestDriver2(args[6], args[3], args[5]); - testDriver2.setWorkers(Integer.parseInt(args[1])); - - for (int i = 0 ; i < REPEATS; i++) - { - testDriver2.reported = 0; - testDriver2.run(); - } - System.exit(0); - } - /** - * @param name - */ - public TestDriver2(String rootModule, String cfgFile, String projectDir) - { - - this.rootModule = rootModule; - this.cfgFile = cfgFile; - this.projectDir = projectDir; - - // initialize the progress reporting variable - this.reported = 0; - - } - - /** - * Sets the number of workers - * @param workers number of threads to be run in parallel - */ - public void setWorkers(int workers) - { - this.workers = workers; - } - - protected int run() - { - report("entering run"); - - // setup tool IO - // Reset the tool output messages. - ToolIO.reset(); - ToolIO.setMode(ToolIO.TOOL); - ToolIO.setUserDir(new File(rootModule).getParent()); - - // create a TLC instance - TLC tlc = new TLC(); - report("tlc created " + tlc.toString()); - - // setup name resolver - // in RCP FS model use: - // tlc.setResolver(new RCPNameToFileIStream(null)); - - // for simple FS model: - tlc.setResolver(new SimpleFilenameToStream()); - - // setup SpecObj from parser - // SpecObj specObj = ToolboxHandle.getSpecObj(); - // tlc.setSpecObject(specObj); - - // handle parameters - String[] params = new String[] { - "-config", cfgFile, - // "-coverage", "0.1", - "-workers", "" + workers, - "-metadir", projectDir, - rootModule }; - boolean status = tlc.handleParameters(params); - - // report errors in parameters - if (!status) - { - return -1; - } - - // create thread for TLC running - tlcThread = new TLCThread(tlc); - tlcThread.setName("TLC Thread"); - report("tlcthread created " + tlcThread.getId()); - - // Start the TLC thread - tlcThread.start(); - report("tlcthread started"); - - while (this.checkAndSleep()) - { - // report the messages created since last reporting - // check the cancellation status - if (isCancelled()) - { - // cancel the TLC - tlc.setCanceledFlag(true); - - // report the messages created since last reporting - reportProgress(); - - // abnormal termination - return -1; - } - } - // report progress - reportProgress(); - - // successful termination - return 1; - } - - /** - * Method for external cancellation - */ - private boolean isCancelled() - { - return false; - } - - - // check if TLC is ready and sleep - private boolean checkAndSleep() - { - report("entering checkAndSleep()"); - try - { - report("Go sleep \t" + System.currentTimeMillis()); - // go sleep - Thread.sleep(TIMEOUT); - - report("Wake up \t" + System.currentTimeMillis()); - - } catch (InterruptedException e) - { - // nothing to do - e.printStackTrace(); - } - - // return true if the tlc is still calculating - boolean result = tlcThread.isRunning(); - report("leaving checkAndSleep() with " + result); - return result; - } - - /** - * Report progress to the monitor - */ - protected void reportProgress() - { - // report progress - String[] messages = ToolIO.getAllMessages(); - for (; reported < messages.length; reported++) - { - System.out.println(messages[reported]); - } - } - - /** - * Thread to run TLC in - */ - class TLCThread extends Thread - { - private boolean isRunning = false; - private TLC tlc; - - public TLCThread(TLC tlc) - { - this.tlc = tlc; - } - - public void run() - { - synchronized (this) - { - report("TLC Thread: {STARTED}"); - isRunning = true; - } - // start TLC - this.tlc.process(); - - synchronized (this) - { - isRunning = false; - report("TLC Thread: {FINISHED}"); - } - } - - /** - * - * @return - */ - public synchronized boolean isRunning() - { - return isRunning; - } - } - - public void report(String message) - { - // System.err.println("" + Thread.currentThread().getId() + "\t" + message); - } - -} diff --git a/tlatools/test/tlc2/TestMPRecorder.java b/tlatools/test/tlc2/TestMPRecorder.java index cb5c02d9a6bf17b519f56fa535e4a9107004c4d7..54dc1c6be99d516b45b8cfac45eac2c0fcdbedb5 100644 --- a/tlatools/test/tlc2/TestMPRecorder.java +++ b/tlatools/test/tlc2/TestMPRecorder.java @@ -30,6 +30,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import tlc2.output.EC; public class TestMPRecorder extends tlc2.output.MPRecorder { private final Map<Integer, List<Object>> records = new HashMap<Integer, List<Object>>(); @@ -48,10 +52,24 @@ public class TestMPRecorder extends tlc2.output.MPRecorder { public List<Object> getRecords(int code) { return records.get(code); } + + private List<Object> getRecordsOrDefault(final int code, final List<Object> defaultValue) { + return records.getOrDefault(code, defaultValue); + } public int getRecordAsInt(int code) { return Integer.parseInt(((String[]) records.get(code).get(0))[0]); } + + public List<String[]> getRecordAsStringArray(int code) { + final List<Object> l = records.get(code); + + final List<String[]> strs = new ArrayList<>(l.size()); + for (Object o : l) { + strs.add((String[]) o); + } + return strs; + } // This is a best effort implementation that only checks the first // elements of the nested records and contained arrays @@ -112,6 +130,139 @@ public class TestMPRecorder extends tlc2.output.MPRecorder { return true; } + public String getCoverageRecords() { + final List<Object> coverages = getRecords(EC.TLC_COVERAGE_VALUE); + String out = ""; + if (coverages == null) { + return out; + } + for (final Object o : coverages) { + final String[] coverage = (String[]) o; + out += coverage[0] + ": " + Integer.parseInt(coverage[1]) + "\n"; + } + return out; + } + + public List<Coverage> getActionCoverage() { + final List<Object> init = getRecordsOrDefault(EC.TLC_COVERAGE_INIT, new ArrayList<>(0)); + final List<Object> next = getRecordsOrDefault(EC.TLC_COVERAGE_NEXT, new ArrayList<>(0)); + final List<Object> prop = getRecordsOrDefault(EC.TLC_COVERAGE_PROPERTY, new ArrayList<>(0)); + init.addAll(next); + init.addAll(prop); + + return init.stream().map(o -> (String[]) o).map(a -> new Coverage(a)).filter(Coverage::isAction) + .collect(Collectors.toList()); + } + + public List<Coverage> getZeroCoverage() { + return getCoverage(EC.TLC_COVERAGE_VALUE, (Predicate<? super Coverage>) o -> o.isZero()); + } + + public List<Coverage> getNonZeroCoverage() { + return getCoverage(EC.TLC_COVERAGE_VALUE, (Predicate<? super Coverage>) o -> !o.isZero()); + } + + public List<Coverage> getCostCoverage() { + return getCoverage(EC.TLC_COVERAGE_VALUE_COST, (Predicate<? super Coverage>) o -> !o.isZero()); + } + + private List<Coverage> getCoverage(final int code, Predicate<? super Coverage> p) { + final List<Object> coverages = getRecordsOrDefault(code, new ArrayList<>(0)); + return coverages.stream().map(o -> (String[]) o).map(a -> new Coverage(a)).filter(p) + .collect(Collectors.toList()); + } + + public static class Coverage { + private final String line; + private final long count; + private final long cost; + //TODO Take level into account in comparison! + private final int level; + private final boolean isAction; + + public Coverage(String[] line) { + this.isAction = line[0].startsWith("<"); + this.line = line[0].replace("|", "").trim(); + this.level = line[0].length() - this.line.length(); + if (line.length == 1) { + this.count = -1; + this.cost = -1; + } else if (line.length == 2) { + this.count = Long.valueOf(line[1].trim()); + this.cost = -1; + } else if (line.length == 3) { + this.count = Long.valueOf(line[1].trim()); + this.cost = Long.valueOf(line[2].trim()); + } else { + throw new IllegalArgumentException(); + } + } + + public String getLine() { + return line; + } + + public long getCount() { + return count; + } + + public int getLevel() { + return level; + } + + public boolean isZero() { + return count == 0L; + } + + public boolean isCoverage() { + return !isAction; + } + + public boolean isCost() { + return cost >= 0; + } + + public boolean isAction() { + return isAction; + } + + @Override + public String toString() { + return "Coverage [line=" + line + ", count=" + count + ", cost=" + cost + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (count ^ (count >>> 32)); + result = prime * result + (int) (cost ^ (cost >>> 32)); + result = prime * result + ((line == null) ? 0 : line.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Coverage other = (Coverage) obj; + if (count != other.count) + return false; + if (cost != other.cost) + return false; + if (line == null) { + if (other.line != null) + return false; + } else if (!line.equals(other.line)) + return false; + return true; + } + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ diff --git a/tlatools/test/tlc2/module/RandomizationTest.java b/tlatools/test/tlc2/module/RandomizationTest.java index 2d5660a4ddbf31fa9263281b4a2a9dac984f8389..75132a85135dcc9099a558fbf46cdfe7ca6f7f9c 100644 --- a/tlatools/test/tlc2/module/RandomizationTest.java +++ b/tlatools/test/tlc2/module/RandomizationTest.java @@ -35,20 +35,20 @@ import org.junit.Test; import tlc2.tool.EvalException; import tlc2.util.FP64; -import tlc2.value.Enumerable; -import tlc2.value.EnumerableValue; -import tlc2.value.IntValue; -import tlc2.value.IntervalValue; -import tlc2.value.SetEnumValue; -import tlc2.value.StringValue; -import tlc2.value.Value; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.StringValue; +import tlc2.value.impl.Value; public class RandomizationTest { @BeforeClass public static void setup() { // Make test repeatable by setting random seed always to same value. - EnumerableValue.setRandom(15041980L); + RandomEnumerableValues.setSeed(15041980L); // Initialize FP64 to prevent NPE in hashCode (which relies on Value#fingerprint). FP64.Init(); diff --git a/tlatools/test/tlc2/module/TLCTest.java b/tlatools/test/tlc2/module/TLCTest.java index 9a5dfc0e793d7b5145168dcb5136e40ecd4158cc..78a310b6d080cf42be789617ed2b32de7ec3479f 100644 --- a/tlatools/test/tlc2/module/TLCTest.java +++ b/tlatools/test/tlc2/module/TLCTest.java @@ -34,14 +34,14 @@ import org.junit.BeforeClass; import org.junit.Test; import tlc2.util.FP64; -import tlc2.value.EnumerableValue; -import tlc2.value.FcnRcdValue; -import tlc2.value.IntValue; -import tlc2.value.IntervalValue; -import tlc2.value.SetEnumValue; -import tlc2.value.TupleValue; -import tlc2.value.Value; -import tlc2.value.ValueEnumeration; +import tlc2.value.impl.Enumerable; +import tlc2.value.impl.FcnRcdValue; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SetEnumValue; +import tlc2.value.impl.TupleValue; +import tlc2.value.impl.Value; +import tlc2.value.impl.ValueEnumeration; public class TLCTest { @@ -56,10 +56,10 @@ public class TLCTest { */ @Test public void testA() { - final Value f = new FcnRcdValue(new Value[] { IntValue.gen(3) }, new Value[] { IntValue.gen(11) }, true); - final Value g = new TupleValue(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3) }); + final Value f = new FcnRcdValue(new Value [] { IntValue.gen(3) }, new Value [] { IntValue.gen(11) }, true); + final Value g = new TupleValue(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3) }); - final Value combined = TLC.CombineFcn(f, g); + final Value combined = TLC.CombineFcn(f, g); Assert.assertTrue(combined instanceof FcnRcdValue); final FcnRcdValue rcdVal = (FcnRcdValue) combined; // Have to normalize to bring values/domain into natural order expected by assertions below @@ -67,11 +67,11 @@ public class TLCTest { // domain Assert.assertEquals(3, rcdVal.domain.length); - Assert.assertArrayEquals(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3) }, rcdVal.domain); + Assert.assertArrayEquals(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3) }, rcdVal.domain); // values Assert.assertEquals(3, rcdVal.values.length); - Assert.assertArrayEquals(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(11) }, rcdVal.values); + Assert.assertArrayEquals(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(11) }, rcdVal.values); } /** @@ -80,10 +80,10 @@ public class TLCTest { */ @Test public void testB() { - final Value f = new FcnRcdValue(new Value[] { IntValue.gen(4) }, new Value[] { IntValue.gen(11) }, true); - final Value g = new TupleValue(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(11) }); + final Value f = new FcnRcdValue(new Value [] { IntValue.gen(4) }, new Value [] { IntValue.gen(11) }, true); + final Value g = new TupleValue(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(11) }); - final Value combined = TLC.CombineFcn(f, g); + final Value combined = TLC.CombineFcn(f, g); Assert.assertTrue(combined instanceof FcnRcdValue); final FcnRcdValue rcdVal = (FcnRcdValue) combined; // Have to normalize to bring values/domain into natural order expected by assertions below @@ -91,28 +91,28 @@ public class TLCTest { // domain Assert.assertEquals(4, rcdVal.domain.length); - Assert.assertArrayEquals(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(4) }, + Assert.assertArrayEquals(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(4) }, rcdVal.domain); // values Assert.assertEquals(4, rcdVal.values.length); - Assert.assertArrayEquals(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(11) }, + Assert.assertArrayEquals(new Value [] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(11) }, rcdVal.values); } @Test public void testPermutations() { - final SetEnumValue in = SetEnumValue.convert(new IntervalValue(1, 5)); + final SetEnumValue in = (SetEnumValue) new IntervalValue(1, 5).toSetEnum(); Assert.assertEquals(5, in.size()); - final Value permutations = TLC.Permutations(in); - Assert.assertTrue(permutations instanceof EnumerableValue); + final Value permutations = TLC.Permutations(in); + Assert.assertTrue(permutations instanceof Enumerable); Assert.assertEquals(120, permutations.size()); - final Set<Value> values = new HashSet<>(permutations.size()); + final Set<Value > values = new HashSet<>(permutations.size()); - final ValueEnumeration elements = ((EnumerableValue) permutations).elements(); - Value val = null; + final ValueEnumeration elements = ((Enumerable) permutations).elements(); + Value val = null; while ((val = elements.nextElement()) != null) { Assert.assertEquals(in.size(), val.size()); values.add(val); diff --git a/tlatools/test/tlc2/output/ErrorPrinterTest.java b/tlatools/test/tlc2/output/MPTest.java similarity index 65% rename from tlatools/test/tlc2/output/ErrorPrinterTest.java rename to tlatools/test/tlc2/output/MPTest.java index e857e1e3cb2e5a92856b2f6c6cf90200dcbeceb7..3b40cfc3986cfae053dbed05fe58c9ee4532f8ab 100644 --- a/tlatools/test/tlc2/output/ErrorPrinterTest.java +++ b/tlatools/test/tlc2/output/MPTest.java @@ -1,16 +1,14 @@ package tlc2.output; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; + import util.ToolIO; -/** - * @author Simon Zambrovski - * @version $Id$ - */ -public class ErrorPrinterTest +public class MPTest { /* (non-Javadoc) @@ -61,5 +59,19 @@ public class ErrorPrinterTest assertEquals("Error: [" + parameters[0] + "][" + parameters[1] + "]", allMessages[0]); } - + @Test + public void testPrintProgressStats() { + String[] parameters = new String[] { + "this.trace.getLevelForReporting()", + MP.format(3000000), + MP.format(5000), + MP.format(1222333444), + MP.format(10000), + MP.format(1234) + }; + MP.printMessage(EC.TLC_PROGRESS_STATS, parameters); + String[] allMessages = ToolIO.getAllMessages(); + assertEquals(1, allMessages.length); + assertTrue(allMessages[0], allMessages[0].contains("3,000,000 states generated (10,000 s/min), 5,000 distinct states found (1,234 ds/min), 1,222,333,444 states left on queue.")); + } } diff --git a/tlatools/test/tlc2/tool/.gitattributes b/tlatools/test/tlc2/tool/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..918458c130d4d970d54568d475c092205fce9ebc --- /dev/null +++ b/tlatools/test/tlc2/tool/.gitattributes @@ -0,0 +1,3 @@ +## Declare DumpAsDotTest.dot to keep unix line endings on checkout even on Windows. +## With "crlf" DumpAsDotTest fails on Windows. +DumpAsDotTest.dot text eol=lf \ No newline at end of file diff --git a/tlatools/test/tlc2/tool/ASTest.java b/tlatools/test/tlc2/tool/ASTest.java index d00e3ae2a9eca4bb80e762c7644c0860570426cb..1d8bcc269b8acb1f254d326df625d91749813b17 100644 --- a/tlatools/test/tlc2/tool/ASTest.java +++ b/tlatools/test/tlc2/tool/ASTest.java @@ -31,12 +31,13 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class ASTest extends ModelCheckerTestCase { public ASTest() { - super("AS", "AS"); + super("AS", "AS", ExitStatus.FAILURE_SPEC_EVAL); } @Test diff --git a/tlatools/test/tlc2/tool/AbsoluteSpecPathTest.java b/tlatools/test/tlc2/tool/AbsoluteSpecPathTest.java new file mode 100644 index 0000000000000000000000000000000000000000..62b4d921aab72a793326020738dbf9bbc72721dd --- /dev/null +++ b/tlatools/test/tlc2/tool/AbsoluteSpecPathTest.java @@ -0,0 +1,42 @@ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + +import org.junit.Test; + +import tlc2.TLC; +import tlc2.TestMPRecorder; +import tlc2.output.EC; +import tlc2.output.MP; + +public class AbsoluteSpecPathTest extends CommonTestCase { + + public AbsoluteSpecPathTest() { + super(new TestMPRecorder()); + } + + @Test + public void test() throws Exception { + // Check that BASE_DIR is actually set to make sure we have an absolute path to + // work with. If this test gets executed from within the Eclipse IDE, manually + // set -Dbasedir=/path/to/tlatools/ + assumeFalse(BASE_DIR.equals("")); + + MP.setRecorder(recorder); + + // Do not call TLC#main because we won't get control back (system.exit) to check + // assertions below. + final TLC tlc = new TLC(); + tlc.handleParameters(new String[] {BASE_PATH + "Test2"}); + tlc.process(); + + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "5")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6", "5", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + } +} diff --git a/tlatools/test/tlc2/tool/AssignmentInitExpensiveTest.java b/tlatools/test/tlc2/tool/AssignmentInitExpensiveTest.java index 51f7fb0e5c305936edac8ade3aad5942286eec3a..1e43faa4135164bad5ea49a35ae441b6745cdda8 100644 --- a/tlatools/test/tlc2/tool/AssignmentInitExpensiveTest.java +++ b/tlatools/test/tlc2/tool/AssignmentInitExpensiveTest.java @@ -44,5 +44,7 @@ public class AssignmentInitExpensiveTest extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10002", "1", "0")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/AssignmentInitNegTest.java b/tlatools/test/tlc2/tool/AssignmentInitNegTest.java index efe3d70b403ce0070707514fd6de3d1e9707db56..cec19a9cca35c3ee1441d07e96dbc0f347885a83 100644 --- a/tlatools/test/tlc2/tool/AssignmentInitNegTest.java +++ b/tlatools/test/tlc2/tool/AssignmentInitNegTest.java @@ -44,5 +44,7 @@ public class AssignmentInitNegTest extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/AssignmentInitTest.java b/tlatools/test/tlc2/tool/AssignmentInitTest.java index 78fe339dae1621f5495f5b3b2bd012d462f2dbfa..2e18f1fc888032751ec9740ee314675f05bc1ead 100644 --- a/tlatools/test/tlc2/tool/AssignmentInitTest.java +++ b/tlatools/test/tlc2/tool/AssignmentInitTest.java @@ -44,5 +44,7 @@ public class AssignmentInitTest extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6", "5", "0")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/AssignmentNext2Test.java b/tlatools/test/tlc2/tool/AssignmentNext2Test.java index b92c86bd844e421bd131e8e833f39f7327dc18f3..e3bdff754b77e1eaa537d5540f1f74e54b748741 100644 --- a/tlatools/test/tlc2/tool/AssignmentNext2Test.java +++ b/tlatools/test/tlc2/tool/AssignmentNext2Test.java @@ -44,5 +44,6 @@ public class AssignmentNext2Test extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/AssignmentNext3Test.java b/tlatools/test/tlc2/tool/AssignmentNext3Test.java index 8831dafa87ad0ce33c6b2c8e1c3abf88d339263f..a02f8a42855ceb747e807a31dbf3805888c2a5dc 100644 --- a/tlatools/test/tlc2/tool/AssignmentNext3Test.java +++ b/tlatools/test/tlc2/tool/AssignmentNext3Test.java @@ -44,5 +44,6 @@ public class AssignmentNext3Test extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "26", "5", "0")); + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/AssignmentNextTest.java b/tlatools/test/tlc2/tool/AssignmentNextTest.java index 682cd3e5d499e023afb926ddbd8776ae5bd34f8e..accf6f366173fceeb5f25f6d16dad799b065d9c5 100644 --- a/tlatools/test/tlc2/tool/AssignmentNextTest.java +++ b/tlatools/test/tlc2/tool/AssignmentNextTest.java @@ -45,5 +45,7 @@ public class AssignmentNextTest extends ModelCheckerTestCase { assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/BugzillaBug279Test.java b/tlatools/test/tlc2/tool/BugzillaBug279Test.java new file mode 100644 index 0000000000000000000000000000000000000000..600d376390bebc53a9c620d61f390d81c8b4d0ab --- /dev/null +++ b/tlatools/test/tlc2/tool/BugzillaBug279Test.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ + +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; +import tlc2.value.Values; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SubsetValue; + +/** + * TLC bug caused by TLC's not preserving the semantics of CHOOSE + * + * Leslie Lamport 2012-03-08 00:26:08 UTC + * + * Running TLC on the spec written by Tom + * Rodeheffer that I will attach finds a deadlock (as it should) and then + * produces the following error when trying to generate the error trace: + * + * Failed to recover the initial state from its fingerprint. + * This is probably a TLC bug(2). + * + * The problem occurs because the value that TLC computes for a CHOOSE + * depends on TLC's internal representation of its argument. To compute + * the 2nd state of the trace, TLC sets the variables 'set' and 'fun' to S1 + * and Ch(S1), respectively, where Ch(S1) equals CHOOSE of an expression + * containing S1. Fingerprinting that state causes TLC to canonicalize + * the representation of the value of 'set', changing its representation of + * the value of S1. When TLC constructs the error trace, it must + * re-execute the spec to get the states in the trace. When it tries to + * compute the 2nd state of the trace, it uses the canonicalized + * representation of S1, causing it to compute a different value of + * variable 'set' than it did the first time, so it doesn't find a state + * with the correct fingerprint as the next state of the trace. (Note that + * the error message is misleading, since it's not the intiial state that + * TLC fails to recover.) + * + * There seem to be two possible fixes. The first is to canonicalize the + * argument of CHOOSE whenever it is evaluated. The second is to create a + * separate deep copy of the state before fingerprinting it. The first + * seems like the best solution, since I can't think of any practical case + * in which this would cause performance problems. However, I will consult + * with Yuan Yu before doing anything about this. + */ +public class BugzillaBug279Test extends ModelCheckerTestCase { + + public BugzillaBug279Test() { + super("InitStateBug", "Bug279", ExitStatus.VIOLATION_DEADLOCK); + } + + @Override + protected boolean checkDeadLock() { + return true; + } + + @Override + protected boolean doDump() { + // For this test, dumping means enumerating the SUBSETs which creates too much + // overhead. The test is also about avoiding enumerating SUBSET. + return false; + } + + @Test + public void testSpec() { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "3", "0")); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Assert the error trace + assertTrue(recorder.recorded(EC.TLC_DEADLOCK_REACHED)); + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(6); + expectedTrace.add("/\\ set = {}\n/\\ pc = 0\n/\\ fun = {}"); + expectedTrace.add("/\\ set = SUBSET 1..20\n/\\ pc = 1\n/\\ fun = {5}"); + expectedTrace.add( + "/\\ set = " + Values.ppr(new SubsetValue(new IntervalValue(1, 8)).toSetEnum().normalize()) + + "\n/\\ pc = 2\n/\\ fun = {5}"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); + } +} diff --git a/tlatools/test/tlc2/tool/CommonTestCase.java b/tlatools/test/tlc2/tool/CommonTestCase.java index ac3370ee934b899b070690f9211201f7eecd52ec..b6453ec86fcafdccdb01037daa99e73d7991197c 100644 --- a/tlatools/test/tlc2/tool/CommonTestCase.java +++ b/tlatools/test/tlc2/tool/CommonTestCase.java @@ -31,16 +31,24 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.Arrays; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.junit.runner.RunWith; import tlc2.TLCGlobals; import tlc2.TestMPRecorder; +import tlc2.TestMPRecorder.Coverage; import tlc2.output.EC; import tlc2.output.MPRecorder; import tlc2.tool.liveness.GraphNode; import tlc2.util.BitVector; import tlc2.util.BufferedRandomAccessFile; +import util.IsolatedTestCaseRunner; +@RunWith(IsolatedTestCaseRunner.class) public abstract class CommonTestCase { protected static final String BASE_DIR = System.getProperty("basedir", ""); @@ -162,4 +170,65 @@ public abstract class CommonTestCase { assertEquals(ptrsSize, ptrs.length()); } + // Checks if all uncovered (zero) lines are found and no more (don't care if the invocation and costs match). + protected void assertUncovered(final String expectedUncovered) { + final List<Coverage> expected = Arrays.asList(expectedUncovered.trim().split("\n")).stream() + .map(o -> new Coverage(o.split(":"))).collect(Collectors.toList()); + + final Set<Coverage> expectedZero = expected.stream().filter(Coverage::isZero).collect(Collectors.toSet()); + final Set<Coverage> actualZeroCoverage = recorder.getZeroCoverage().stream().collect(Collectors.toSet()); + assertEquals(expectedZero, actualZeroCoverage); + } + + protected void assertZeroUncovered() { + assertTrue(recorder.getZeroCoverage().isEmpty()); + } + + protected void assertCoverage(final String expectedCoverage) { + // Lines can be reported multiple times if invoked from different actions!!! + + final List<Coverage> expected = Arrays.asList(expectedCoverage.split("\n")).stream() + .map(o -> new Coverage(o.split(":"))).collect(Collectors.toList()); + + // Step A: + // Validation of coverage results is split into two steps. Step A checks if all + // uncovered (zero) lines are found, step B checks if non-zero lines exist. + final Set<Coverage> expectedZero = expected.stream().filter(Coverage::isZero) + .filter(Coverage::isCoverage).collect(Collectors.toSet()); + final Set<Coverage> actualZeroCoverage = recorder.getZeroCoverage().stream().collect(Collectors.toSet()); + assertEquals(expectedZero, actualZeroCoverage); + + // Step B1 (coverage): + final List<Coverage> actualNonZeroCoverage = recorder.getNonZeroCoverage(); + final List<Coverage> expectedNonZeroCoverage = expected.stream().filter(Coverage::isCoverage). + filter(c -> !c.isCost()).collect(Collectors.toList()); + expectedNonZeroCoverage.removeAll(actualZeroCoverage); + for (int i = 0; i < actualNonZeroCoverage.size(); i++) { + final Coverage a = actualNonZeroCoverage.get(i); + final Coverage e = expectedNonZeroCoverage.get(i); + assertEquals(e, a); + } + assertTrue(expectedNonZeroCoverage.size() == actualNonZeroCoverage.size()); + + // Step B2 (coverage with cost): + final List<Coverage> actualCostCoverage = recorder.getCostCoverage(); + final List<Coverage> expectedCostCoverage = expected.stream().filter(Coverage::isCoverage) + .filter(Coverage::isCost).collect(Collectors.toList()); + for (int i = 0; i < actualCostCoverage.size(); i++) { + final Coverage a = actualCostCoverage.get(i); + final Coverage e = expectedCostCoverage.get(i); + assertEquals(e, a); + } + assertTrue(expectedCostCoverage.size() == actualCostCoverage.size()); + + // Step C (actions): + final List<Coverage> actualActions = recorder.getActionCoverage(); + final List<Coverage> expectedActions = expected.stream().filter(Coverage::isAction).collect(Collectors.toList()); + for (int i = 0; i < actualActions.size(); i++) { + final Coverage a = actualActions.get(i); + final Coverage e = expectedActions.get(i); + assertEquals(e, a); + } + assertTrue(expectedActions.size() == actualActions.size()); + } } diff --git a/tlatools/test/tlc2/tool/DepthFirstDieHardTest.java b/tlatools/test/tlc2/tool/DepthFirstDieHardTest.java index 6a33c34ef85738a809cf75d40b0f03206d4c347e..75997ec73551443a41d04fe7e57bcf6787f936c9 100644 --- a/tlatools/test/tlc2/tool/DepthFirstDieHardTest.java +++ b/tlatools/test/tlc2/tool/DepthFirstDieHardTest.java @@ -31,14 +31,17 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DepthFirstDieHardTest extends ModelCheckerTestCase { public DepthFirstDieHardTest() { - super("DieHard", "", new String[] {"-dfid", "7"}); + super("DieHard", "", new String[] {"-dfid", "7"}, ExitStatus.VIOLATION_SAFETY); } @Test @@ -60,5 +63,6 @@ public class DepthFirstDieHardTest extends ModelCheckerTestCase { expectedTrace.add("/\\ action = \"pour big to small\"\n/\\ smallBucket = 3\n/\\ bigBucket = 4\n/\\ water_to_pour = 1"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT1), expectedTrace); + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/DepthFirstErrorTraceTest.java b/tlatools/test/tlc2/tool/DepthFirstErrorTraceTest.java index a53e65cb94eb0e2f4b89221e2cf3888c9465cce2..c6249216383b02c3cc08eab681dd481ff9f50212 100644 --- a/tlatools/test/tlc2/tool/DepthFirstErrorTraceTest.java +++ b/tlatools/test/tlc2/tool/DepthFirstErrorTraceTest.java @@ -31,14 +31,17 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DepthFirstErrorTraceTest extends ModelCheckerTestCase { public DepthFirstErrorTraceTest() { - super("DepthFirstErrorTrace", "", new String[] {"-dfid", "9"}); + super("DepthFirstErrorTrace", "", new String[] {"-dfid", "9"}, ExitStatus.VIOLATION_SAFETY); } @Test @@ -59,5 +62,6 @@ public class DepthFirstErrorTraceTest extends ModelCheckerTestCase { expectedTrace.add("x = 6"); expectedTrace.add("x = 7"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT1), expectedTrace); + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/DiameterTest.java b/tlatools/test/tlc2/tool/DiameterTest.java index 94d8e9c8a86f289a5e2d844f60860820dfd2fbf1..34d28c0f2d626a9971bad3e4351bbdb7dbbae00f 100644 --- a/tlatools/test/tlc2/tool/DiameterTest.java +++ b/tlatools/test/tlc2/tool/DiameterTest.java @@ -52,6 +52,8 @@ public class DiameterTest extends ModelCheckerTestCase { // or a lower number. final int level = recorder.getRecordAsInt(EC.TLC_SEARCH_DEPTH); assertTrue(String.format("Level below threshold: %s", level), level >= 8); + + assertZeroUncovered(); } /* (non-Javadoc) diff --git a/tlatools/test/tlc2/tool/DistributedTrace.java b/tlatools/test/tlc2/tool/DistributedTrace.java new file mode 100644 index 0000000000000000000000000000000000000000..5fe2b89677972dc12fc8cfbb59134dfb76326864 --- /dev/null +++ b/tlatools/test/tlc2/tool/DistributedTrace.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class DistributedTrace extends ModelCheckerTestCase { + + public DistributedTrace() { + super("DistributedTrace"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Assert the error trace + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(5); + expectedTrace.add("x = 10"); + expectedTrace.add("x = 11"); + expectedTrace.add("x = 12"); + expectedTrace.add("x = 13"); + expectedTrace.add("x = 14"); + expectedTrace.add("x = 15"); + expectedTrace.add("x = 16"); + expectedTrace.add("x = 17"); + expectedTrace.add("x = 18"); + expectedTrace.add("x = 19"); + expectedTrace.add("x = 20"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } + + /* (non-Javadoc) + * @see tlc2.tool.liveness.ModelCheckerTestCase#getNumberOfThreads() + */ + protected int getNumberOfThreads() { + return 4; + } +} diff --git a/tlatools/test/tlc2/tool/DumpAsDotTest.dot b/tlatools/test/tlc2/tool/DumpAsDotTest.dot index 88ab3c184ebc2776d4b3f40e09ce5301cb0f4368..09c7b56bab8a6a27c66ec21a90730e0a67b5c251 100644 --- a/tlatools/test/tlc2/tool/DumpAsDotTest.dot +++ b/tlatools/test/tlc2/tool/DumpAsDotTest.dot @@ -3,78 +3,45 @@ edge [colorscheme="paired12"] nodesep=0.35; subgraph cluster_graph { color="white"; -609737673425276830 [style = filled] [label="/\\ b = FALSE -/\\ x = 0"] -6816998822487979083 [style = filled] [label="/\\ b = TRUE -/\\ x = 0"] -3365478001808954030 [style = filled] [label="/\\ b = FALSE -/\\ x = 1"] -8671809759910816123 [style = filled] [label="/\\ b = TRUE -/\\ x = 1"] -5040481953810085374 [style = filled] [label="/\\ b = FALSE -/\\ x = 2"] -1377963776297717291 [style = filled] [label="/\\ b = TRUE -/\\ x = 2"] -7147721571019581646 [style = filled] [label="/\\ b = FALSE -/\\ x = 3"] -3881310712274735899 [style = filled] [label="/\\ b = TRUE -/\\ x = 3"] -609737673425276830 -> 8671809759910816123 [label="B" color="2" fontcolor="2"]; +609737673425276830 [label="/\\ b = FALSE\n/\\ x = 0",style = filled] +6816998822487979083 [label="/\\ b = TRUE\n/\\ x = 0",style = filled] +3365478001808954030 [label="/\\ b = FALSE\n/\\ x = 1",style = filled] +8671809759910816123 [label="/\\ b = TRUE\n/\\ x = 1",style = filled] +5040481953810085374 [label="/\\ b = FALSE\n/\\ x = 2",style = filled] +1377963776297717291 [label="/\\ b = TRUE\n/\\ x = 2",style = filled] +7147721571019581646 [label="/\\ b = FALSE\n/\\ x = 3",style = filled] +3881310712274735899 [label="/\\ b = TRUE\n/\\ x = 3",style = filled] +609737673425276830 -> 8671809759910816123 [label="B",color="2",fontcolor="2"]; 609737673425276830 -> 609737673425276830 [style="dashed"]; -609737673425276830 [label="/\\ b = FALSE -/\\ x = 0"]; -6816998822487979083 -> 609737673425276830 [label="A" color="3" fontcolor="3"]; +6816998822487979083 -> 609737673425276830 [label="A",color="3",fontcolor="3"]; 6816998822487979083 -> 6816998822487979083 [style="dashed"]; -6816998822487979083 [label="/\\ b = TRUE -/\\ x = 0"]; -3365478001808954030 -> 1377963776297717291 [label="B" color="2" fontcolor="2"]; +3365478001808954030 -> 1377963776297717291 [label="B",color="2",fontcolor="2"]; 3365478001808954030 -> 3365478001808954030 [style="dashed"]; -3365478001808954030 [label="/\\ b = FALSE -/\\ x = 1"]; -8671809759910816123 -> 3365478001808954030 [label="A" color="3" fontcolor="3"]; +8671809759910816123 -> 3365478001808954030 [label="A",color="3",fontcolor="3"]; 8671809759910816123 -> 8671809759910816123 [style="dashed"]; -8671809759910816123 [label="/\\ b = TRUE -/\\ x = 1"]; -5040481953810085374 -> 3881310712274735899 [label="B" color="2" fontcolor="2"]; +5040481953810085374 -> 3881310712274735899 [label="B",color="2",fontcolor="2"]; 5040481953810085374 -> 5040481953810085374 [style="dashed"]; -5040481953810085374 [label="/\\ b = FALSE -/\\ x = 2"]; -1377963776297717291 -> 5040481953810085374 [label="A" color="3" fontcolor="3"]; +1377963776297717291 -> 5040481953810085374 [label="A",color="3",fontcolor="3"]; 1377963776297717291 -> 1377963776297717291 [style="dashed"]; -1377963776297717291 [label="/\\ b = TRUE -/\\ x = 2"]; -7147721571019581646 -> -4210745456684007285 [label="B" color="2" fontcolor="2"]; --4210745456684007285 [label="/\\ b = TRUE -/\\ x = 4"]; +7147721571019581646 -> -4210745456684007285 [label="B",color="2",fontcolor="2"]; +-4210745456684007285 [label="/\\ b = TRUE\n/\\ x = 4"]; 7147721571019581646 -> 7147721571019581646 [style="dashed"]; -7147721571019581646 [label="/\\ b = FALSE -/\\ x = 3"]; -3881310712274735899 -> 7147721571019581646 [label="A" color="3" fontcolor="3"]; +3881310712274735899 -> 7147721571019581646 [label="A",color="3",fontcolor="3"]; 3881310712274735899 -> 3881310712274735899 [style="dashed"]; -3881310712274735899 [label="/\\ b = TRUE -/\\ x = 3"]; --4210745456684007285 -> -7819220713745958050 [label="A" color="3" fontcolor="3"]; --7819220713745958050 [label="/\\ b = FALSE -/\\ x = 4"]; +-4210745456684007285 -> -7819220713745958050 [label="A",color="3",fontcolor="3"]; +-7819220713745958050 [label="/\\ b = FALSE\n/\\ x = 4"]; -4210745456684007285 -> -4210745456684007285 [style="dashed"]; --4210745456684007285 [label="/\\ b = TRUE -/\\ x = 4"]; --7819220713745958050 -> -2066378075513578053 [label="B" color="2" fontcolor="2"]; --2066378075513578053 [label="/\\ b = TRUE -/\\ x = 5"]; +-7819220713745958050 -> -2066378075513578053 [label="B",color="2",fontcolor="2"]; +-2066378075513578053 [label="/\\ b = TRUE\n/\\ x = 5"]; -7819220713745958050 -> -7819220713745958050 [style="dashed"]; --7819220713745958050 [label="/\\ b = FALSE -/\\ x = 4"]; -2066378075513578053 -> -2066378075513578053 [style="dashed"]; --2066378075513578053 [label="/\\ b = TRUE -/\\ x = 5"]; {rank = same; 1377963776297717291;5040481953810085374;8671809759910816123;3365478001808954030;6816998822487979083;609737673425276830;3881310712274735899;7147721571019581646;} {rank = same; -4210745456684007285;} {rank = same; -7819220713745958050;} {rank = same; -2066378075513578053;} } subgraph cluster_legend {graph[style=bold];label = "Next State Actions" style="solid" -node [ labeljust="l" colorscheme="paired12" style=filled shape=record ] -A [label="A" fillcolor=3] -B [label="B" fillcolor=2] +node [ labeljust="l",colorscheme="paired12",style=filled,shape=record ] +A [label="A",fillcolor=3] +B [label="B",fillcolor=2] }} \ No newline at end of file diff --git a/tlatools/test/tlc2/tool/DumpAsDotTest.java b/tlatools/test/tlc2/tool/DumpAsDotTest.java index 884d788a84a8d6b4ee9f38541753b39f07253a04..314d42d6a1c4aba93db91ec5c3622255fe8e713f 100644 --- a/tlatools/test/tlc2/tool/DumpAsDotTest.java +++ b/tlatools/test/tlc2/tool/DumpAsDotTest.java @@ -38,13 +38,14 @@ import java.util.Arrays; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DumpAsDotTest extends ModelCheckerTestCase { public DumpAsDotTest() { super("MCa", "CodePlexBug08", new String[] { "-dump", "dot,colorize,actionlabels", - System.getProperty("java.io.tmpdir") + File.separator + "DumpAsDotTest" }); + System.getProperty("java.io.tmpdir") + File.separator + "DumpAsDotTest" }, ExitStatus.VIOLATION_LIVENESS); } @Test @@ -61,6 +62,8 @@ public class DumpAsDotTest extends ModelCheckerTestCase { // If the file exist, simply compare it to a correct and manually checked version. final InputStream master = getClass().getResourceAsStream("DumpAsDotTest.dot"); assertTrue(Arrays.equals(getBytes(master), getBytes(new FileInputStream(dumpFile)))); + + assertZeroUncovered(); } // http://stackoverflow.com/a/17861016 diff --git a/tlatools/test/tlc2/tool/EmptySubsetEqTest.java b/tlatools/test/tlc2/tool/EmptySubsetEqTest.java index 1f1ceed4230d60d59e7453a7f20302db13fefab9..17faf52b0cf9ad97022804ff229d9a736ba2607f 100644 --- a/tlatools/test/tlc2/tool/EmptySubsetEqTest.java +++ b/tlatools/test/tlc2/tool/EmptySubsetEqTest.java @@ -33,6 +33,7 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class EmptySubsetEqTest extends ModelCheckerTestCase { @@ -41,7 +42,7 @@ public class EmptySubsetEqTest extends ModelCheckerTestCase { // incorrectly reduce the expression SUBSET (1..3) \subseteq (1..4). The // empty subset {} is not a subset of (1..4). public EmptySubsetEqTest() { - super("EmptySubsetEq"); + super("EmptySubsetEq", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -55,11 +56,13 @@ public class EmptySubsetEqTest extends ModelCheckerTestCase { + "for clues to what happened.\nThe exception was a " + "java.lang.RuntimeException\n: Attempted to check if the value:\n" + "{}\nis in the integer interval 1..4")); - + // Expect an error trace consisting of a single state. assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); final List<String> expectedTrace = new ArrayList<String>(4); expectedTrace.add("b = TRUE"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertUncovered("line 8, col 9 to line 8, col 48 of module EmptySubsetEq: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/EmptyTest.java b/tlatools/test/tlc2/tool/EmptyTest.java index 39edcf3473ff8ef1f5f959a7277f28f96eaa4730..2e5f9b0d2e11b9f6016a3d4d952f2a2884ca422e 100644 --- a/tlatools/test/tlc2/tool/EmptyTest.java +++ b/tlatools/test/tlc2/tool/EmptyTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; diff --git a/tlatools/test/tlc2/tool/EvalControlTest.java b/tlatools/test/tlc2/tool/EvalControlTest.java index 7e869cf8691a3a42aa00248b8b28abd9a9b4ba93..6eac3c251b203ee7c69a04d9d9c97ca1af8d7e49 100644 --- a/tlatools/test/tlc2/tool/EvalControlTest.java +++ b/tlatools/test/tlc2/tool/EvalControlTest.java @@ -1,6 +1,7 @@ package tlc2.tool; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; diff --git a/tlatools/test/tlc2/tool/FingerprintExceptionInitTest.java b/tlatools/test/tlc2/tool/FingerprintExceptionInitTest.java index defa78974cba2f033bf415f77c88ef0de37560fa..ee6e6474e1580c3de9e0e54a7819757a995ee2be 100644 --- a/tlatools/test/tlc2/tool/FingerprintExceptionInitTest.java +++ b/tlatools/test/tlc2/tool/FingerprintExceptionInitTest.java @@ -32,12 +32,13 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class FingerprintExceptionInitTest extends ModelCheckerTestCase { public FingerprintExceptionInitTest() { - super("FingerprintExceptionInit"); + super("FingerprintExceptionInit", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -50,6 +51,8 @@ public class FingerprintExceptionInitTest extends ModelCheckerTestCase { String arg2 = "Overflow when computing the number of elements in:\n" + "SUBSET 1..36"; assertTrue(recorder.recordedWithStringValues(EC.TLC_FINGERPRINT_EXCEPTION, arg1, arg2)); + + assertUncovered("line 8, col 39 to line 8, col 64 of module FingerprintExceptionInit: 0\n" + + "line 8, col 71 to line 8, col 76 of module FingerprintExceptionInit: 0\n"); } - } diff --git a/tlatools/test/tlc2/tool/FingerprintExceptionNextTest.java b/tlatools/test/tlc2/tool/FingerprintExceptionNextTest.java index a516c8c0f9f2320789b95404092664fe2b3ab017..e78f039cb40b5e6a25ab05789a3fc8b67b3c4098 100644 --- a/tlatools/test/tlc2/tool/FingerprintExceptionNextTest.java +++ b/tlatools/test/tlc2/tool/FingerprintExceptionNextTest.java @@ -31,12 +31,13 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class FingerprintExceptionNextTest extends ModelCheckerTestCase { public FingerprintExceptionNextTest() { - super("FingerprintExceptionNext"); + super("FingerprintExceptionNext", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -51,6 +52,7 @@ public class FingerprintExceptionNextTest extends ModelCheckerTestCase { String arg2 = "Overflow when computing the number of elements in:\n" + "SUBSET 1..32"; assertTrue(recorder.recordedWithStringValues(EC.TLC_FINGERPRINT_EXCEPTION, arg1, arg2)); + + assertUncovered("line 8, col 71 to line 8, col 76 of module FingerprintExceptionNext: 0\n"); } - } diff --git a/tlatools/test/tlc2/tool/Github179aTest.java b/tlatools/test/tlc2/tool/Github179aTest.java new file mode 100644 index 0000000000000000000000000000000000000000..659032fa67c77990324af1ff6efcb7f94a7be84a --- /dev/null +++ b/tlatools/test/tlc2/tool/Github179aTest.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class Github179aTest extends ModelCheckerTestCase { + + public Github179aTest() { + super("Github179a", ExitStatus.VIOLATION_ASSUMPTION); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + + assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, + "public static tlc2.value.impl.Value tlc2.module.TLC.PrintT(tlc2.value.impl.Value)", + "Attempted to check equality of integer 1 with non-integer:\n" + + "{1}")); + } +} diff --git a/tlatools/test/tlc2/tool/Github179bTest.java b/tlatools/test/tlc2/tool/Github179bTest.java new file mode 100644 index 0000000000000000000000000000000000000000..48cff9f0cf00ba0f6ce57d3746efd90770c943a9 --- /dev/null +++ b/tlatools/test/tlc2/tool/Github179bTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class Github179bTest extends ModelCheckerTestCase { + + public Github179bTest() { + super("Github179b", ExitStatus.FAILURE_SPEC_EVAL); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + + assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, + "public static tlc2.value.impl.Value tlc2.module.TLC.Print(tlc2.value.impl.Value,tlc2.value.impl.Value)", + "Attempted to check equality of integer 1 with non-integer:\n" + + "{1}")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_NESTED_EXPRESSION, + "0. Line 13, column 1 to line 13, column 30 in Github179b\n" + + "1. Line 13, column 1 to line 13, column 23 in Github179b\n" + + "2. Line 9, column 27 to line 9, column 79 in Github179b\n" + + "3. Line 9, column 40 to line 9, column 79 in Github179b\n" + + "4. Line 9, column 43 to line 9, column 52 in Github179b\n" + + "\n")); + } +} diff --git a/tlatools/test/tlc2/tool/Github179cTest.java b/tlatools/test/tlc2/tool/Github179cTest.java new file mode 100644 index 0000000000000000000000000000000000000000..12425d933c63950d600378b58fd7cd61835acae7 --- /dev/null +++ b/tlatools/test/tlc2/tool/Github179cTest.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class Github179cTest extends ModelCheckerTestCase { + + public Github179cTest() { + super("Github179c", ExitStatus.FAILURE_SPEC_EVAL); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + + assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, + "public static tlc2.value.impl.Value tlc2.module.TLC.PrintT(tlc2.value.impl.Value)", + "Attempted to check equality of integer 1 with non-integer:\n" + + "{1}")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_NESTED_EXPRESSION, + "0. Line 16, column 9 to line 16, column 42 in Github179c\n" + + "1. Line 16, column 9 to line 16, column 33 in Github179c\n" + + "2. Line 16, column 9 to line 16, column 25 in Github179c\n" + + "3. Line 10, column 11 to line 12, column 39 in Github179c\n" + + "4. Line 10, column 24 to line 12, column 39 in Github179c\n" + + "5. Line 10, column 27 to line 10, column 36 in Github179c\n" + + "\n")); + } +} diff --git a/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java b/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java index b5ea799253314503885909be9547195ba973aa5b..e7bd8a3107b02283aef55e64d5eb484b751ec282 100644 --- a/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java +++ b/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java @@ -32,14 +32,17 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class IncompleteNextMultipleActionsTest extends ModelCheckerTestCase { public IncompleteNextMultipleActionsTest() { - super("IncompleteNextMultipleActions", ""); + super("IncompleteNextMultipleActions", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -63,5 +66,9 @@ public class IncompleteNextMultipleActionsTest extends ModelCheckerTestCase { assertEquals("A1", ((String[]) records.get(0))[0]); assertEquals("s are", ((String[]) records.get(0))[1]); assertEquals("y, z", ((String[]) records.get(0))[2]); + + assertUncovered("line 8, col 16 to line 8, col 21 of module IncompleteNextMultipleActions: 0\n" + + "line 8, col 26 to line 8, col 31 of module IncompleteNextMultipleActions: 0\n" + + "line 8, col 7 to line 8, col 11 of module IncompleteNextMultipleActions: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/IncompleteNextTest.java b/tlatools/test/tlc2/tool/IncompleteNextTest.java index 0ecc3aea801b058683ccf67e7dd455fabdf024c4..cc16dcacfd17877197f599dbd63b05b131f447e1 100644 --- a/tlatools/test/tlc2/tool/IncompleteNextTest.java +++ b/tlatools/test/tlc2/tool/IncompleteNextTest.java @@ -32,14 +32,17 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class IncompleteNextTest extends ModelCheckerTestCase { public IncompleteNextTest() { - super("IncompleteNext", ""); + super("IncompleteNext", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -62,5 +65,7 @@ public class IncompleteNextTest extends ModelCheckerTestCase { final List<Object> records = recorder.getRecords(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT); assertEquals(" is", ((String[]) records.get(0))[0]); assertEquals("y", ((String[]) records.get(0))[1]); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java b/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java index 9c80fa4cb56ae61072a4ca113966ac8c89bd92c3..e454c39c3a9ff169540dd3f692d1b525c26baa0c 100644 --- a/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java +++ b/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java @@ -50,6 +50,8 @@ public class MinimalSetOfInitStatesTest extends ModelCheckerTestCase { // evaluate the init predicate and avoid generating the two duplicates. assertTrue(recorder.recordedWithStringValues(EC.TLC_INIT_GENERATED2, "8", "s", "6")); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "6", "0")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java b/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java index b5ca39459207136cf3f975adf31de6d97a4277c3..c8297a265bd9418fa8c523fae735811dc4f31fd5 100644 --- a/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java +++ b/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java @@ -47,5 +47,8 @@ public class MinimalSetOfNextStatesTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "57", "7", "0")); // 57 instead of 71. assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + + assertUncovered("line 33, col 10 to line 33, col 15 of module MinimalSetOfNextStates: 0\n" + + "line 41, col 10 to line 41, col 15 of module MinimalSetOfNextStates: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/liveness/Test056.java b/tlatools/test/tlc2/tool/MinimumDiameterTest.java similarity index 76% rename from tlatools/test/tlc2/tool/liveness/Test056.java rename to tlatools/test/tlc2/tool/MinimumDiameterTest.java index 3484d273d73766aa2487f52dd25995c0f96ef4ab..c1f96240de0bc70c0bba6260f745c58de797ff3f 100644 --- a/tlatools/test/tlc2/tool/liveness/Test056.java +++ b/tlatools/test/tlc2/tool/MinimumDiameterTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. + * Copyright (c) 2018 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -23,30 +23,36 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ - -package tlc2.tool.liveness; +package tlc2.tool; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; -public class Test056 extends ModelCheckerTestCase { +public class MinimumDiameterTest extends ModelCheckerTestCase { - public Test056() { - super("test56"); + public MinimumDiameterTest() { + super("MinimumDiameter"); } @Test public void testSpec() { - // ModelChecker has finished and generated the expected amount of states - assertTrue(recorder.recorded(EC.TLC_MODE_MC)); - assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recorded(EC.TLC_COMPUTING_INIT)); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "3")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "6", "0")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + + // Minimum diameter with a single state is 1 (not zero)! + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1")); + + assertZeroUncovered(); + } + + @Override + protected boolean doDump() { + return false; } } diff --git a/tlatools/test/tlc2/tool/PrintTraceRaceTest.java b/tlatools/test/tlc2/tool/PrintTraceRaceTest.java index d42540e39191e437ac84f82c5d9ccbb4bf74add4..88aee752c450a52d9be67084a7e2b46fe0482371 100644 --- a/tlatools/test/tlc2/tool/PrintTraceRaceTest.java +++ b/tlatools/test/tlc2/tool/PrintTraceRaceTest.java @@ -31,14 +31,17 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class PrintTraceRaceTest extends ModelCheckerTestCase { public PrintTraceRaceTest() { - super("MC", "PrintTraceRace"); + super("MC", "PrintTraceRace", ExitStatus.FAILURE_SAFETY_EVAL); } @Test @@ -65,6 +68,8 @@ public class PrintTraceRaceTest extends ModelCheckerTestCase { assertEquals(i, objs[1]); assertEquals(2, objs.length); + + assertUncovered("line 15, col 12 to line 15, col 28 of module PrintTraceRace: 0"); } protected int getNumberOfThreads() { diff --git a/tlatools/test/tlc2/tool/RandomElementT4Test.java b/tlatools/test/tlc2/tool/RandomElementT4Test.java index e331c7ddd7fa6dad23f4ae2371b890eade096d4c..c45a2181a320b3b3e9d23260d8f7d721f83ba1e8 100644 --- a/tlatools/test/tlc2/tool/RandomElementT4Test.java +++ b/tlatools/test/tlc2/tool/RandomElementT4Test.java @@ -35,15 +35,16 @@ import java.util.Map; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; -import tlc2.value.IntValue; -import tlc2.value.Value; +import tlc2.value.IValue; +import tlc2.value.impl.IntValue; import util.UniqueString; public class RandomElementT4Test extends ModelCheckerTestCase { public RandomElementT4Test() { - super("RandomElement", new String[] {"-seed", Long.toString(15041980L)}); + super("RandomElement", new String[] {"-seed", Long.toString(15041980L)}, ExitStatus.VIOLATION_SAFETY); } @Test @@ -60,13 +61,13 @@ public class RandomElementT4Test extends ModelCheckerTestCase { for (Object r : records) { final Object[] objs = (Object[]) r; final TLCStateInfo info = (TLCStateInfo) objs[0]; - final Map<UniqueString, Value> vals = info.state.getVals(); + final Map<UniqueString, IValue> vals = info.state.getVals(); - final Value y = vals.get(UniqueString.uniqueStringOf("y")); + final IValue y = vals.get(UniqueString.uniqueStringOf("y")); assertEquals(cnt++, ((IntValue) y).val); - final Value x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); - assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val < 1000); + final IValue x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); + assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val <= 1000); final int statenum = (int) objs[1]; assertEquals(cnt, statenum); diff --git a/tlatools/test/tlc2/tool/RandomElementTest.java b/tlatools/test/tlc2/tool/RandomElementTest.java index 8f6302620d906f57aee0d1a96aac305ed709efad..d118507c7142fed88856c652b492667d40c389f9 100644 --- a/tlatools/test/tlc2/tool/RandomElementTest.java +++ b/tlatools/test/tlc2/tool/RandomElementTest.java @@ -25,7 +25,8 @@ ******************************************************************************/ package tlc2.tool; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; @@ -33,12 +34,13 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class RandomElementTest extends ModelCheckerTestCase { public RandomElementTest() { - super("RandomElement", new String[] {"-seed", Long.toString(8006803340504660123L)}); + super("RandomElement", new String[] {"-seed", Long.toString(8006803340504660123L)}, ExitStatus.VIOLATION_SAFETY); } @Test @@ -62,5 +64,7 @@ public class RandomElementTest extends ModelCheckerTestCase { expectedTrace.add("/\\ x = 151\n/\\ y = 9"); expectedTrace.add("/\\ x = 767\n/\\ y = 10"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/RandomElementXandYTest.java b/tlatools/test/tlc2/tool/RandomElementXandYTest.java index 40423ffd01834869437e977ae67c6d66750e0738..15effbe5bd21dddc8f3aeb0b38f0739273cbd722 100644 --- a/tlatools/test/tlc2/tool/RandomElementXandYTest.java +++ b/tlatools/test/tlc2/tool/RandomElementXandYTest.java @@ -34,12 +34,13 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class RandomElementXandYTest extends ModelCheckerTestCase { public RandomElementXandYTest() { - super("RandomElementXandY", new String[] {"-seed", Long.toString(8006642976694192746L)}); + super("RandomElementXandY", new String[] {"-seed", Long.toString(8006642976694192746L)}, ExitStatus.VIOLATION_SAFETY); // 8006642976694192746L produces a trace of three states. // 8006642976346685430L and 8006642974998076619L results in no violation of an invariant // 8006642972812024640L a trace with two states @@ -57,5 +58,7 @@ public class RandomElementXandYTest extends ModelCheckerTestCase { expectedTrace.add("/\\ x = 1\n/\\ y = 1"); expectedTrace.add("/\\ x = 0\n/\\ y = 1"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/RandomSubset.java b/tlatools/test/tlc2/tool/RandomSubset.java index f2d2a06e003e4c23a607ac2d513d2ac0d2e6398f..539455fc48d1fbe64e249111df0d224522a8bd63 100644 --- a/tlatools/test/tlc2/tool/RandomSubset.java +++ b/tlatools/test/tlc2/tool/RandomSubset.java @@ -25,6 +25,7 @@ ******************************************************************************/ package tlc2.tool; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,6 +35,7 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public abstract class RandomSubset extends ModelCheckerTestCase { @@ -45,7 +47,7 @@ public abstract class RandomSubset extends ModelCheckerTestCase { // Initial seed with a randomly chosen but fixed value for x and y to be // predictable. The two subclasses chose different values to test that different // seeds result in different values. - super("RandomSubset", new String[] {"-seed", Long.toString(seed)}); + super("RandomSubset", new String[] {"-seed", Long.toString(seed)}, ExitStatus.VIOLATION_SAFETY); this.x = x; this.y = y; } @@ -57,7 +59,7 @@ public abstract class RandomSubset extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2002")); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2003", "2003", "2001")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertEquals(2, recorder.getRecordAsInt(EC.TLC_SEARCH_DEPTH)); assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); final List<String> expectedTrace = new ArrayList<String>(); diff --git a/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java b/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java index 81f34bebf39bdf0d339e6885753f2579423d6c0c..04d2708f57481898553119367d864bacbf167efd 100644 --- a/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java +++ b/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java @@ -35,15 +35,16 @@ import java.util.Map; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; -import tlc2.value.IntValue; -import tlc2.value.Value; +import tlc2.value.IValue; +import tlc2.value.impl.IntValue; import util.UniqueString; public class RandomSubsetNextT4Test extends ModelCheckerTestCase { public RandomSubsetNextT4Test() { - super("RandomSubsetNext"); + super("RandomSubsetNext", ExitStatus.VIOLATION_SAFETY); } @Test @@ -60,13 +61,13 @@ public class RandomSubsetNextT4Test extends ModelCheckerTestCase { for (Object r : records) { final Object[] objs = (Object[]) r; final TLCStateInfo info = (TLCStateInfo) objs[0]; - final Map<UniqueString, Value> vals = info.state.getVals(); + final Map<UniqueString, IValue> vals = info.state.getVals(); - final Value y = vals.get(UniqueString.uniqueStringOf("y")); + final IValue y = vals.get(UniqueString.uniqueStringOf("y")); assertEquals(cnt++, ((IntValue) y).val); - final Value x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); - assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val < 1000); + final IValue x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); + assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val <= 1000); final int statenum = (int) objs[1]; assertEquals(cnt, statenum); diff --git a/tlatools/test/tlc2/tool/RandomSubsetNextTest.java b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java index 378c735ad0ace9522ff14988d731ed70a6bff71c..3b7bef50eef93328be779dd9bda57a634e4b824b 100644 --- a/tlatools/test/tlc2/tool/RandomSubsetNextTest.java +++ b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java @@ -34,12 +34,13 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class RandomSubsetNextTest extends ModelCheckerTestCase { public RandomSubsetNextTest() { - super("RandomSubsetNext", new String[] {"-seed", Long.toString(15041980L)}); + super("RandomSubsetNext", new String[] {"-seed", Long.toString(15041980L)}, ExitStatus.VIOLATION_SAFETY); } @Test @@ -63,5 +64,7 @@ public class RandomSubsetNextTest extends ModelCheckerTestCase { expectedTrace.add("/\\ x = 8\n/\\ y = 9"); expectedTrace.add("/\\ x = 30\n/\\ y = 10"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java b/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java index 8a74c0583ea4c54b97f0b8cad61baf9be92d2665..8140b06efc02d0024b5418d3701c5dc92384cfb2 100644 --- a/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java +++ b/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java @@ -25,21 +25,13 @@ ******************************************************************************/ package tlc2.tool; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import java.util.List; -import java.util.Map; - import org.junit.Test; import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.Value; -import util.UniqueString; public class RandomSubsetSetOfFcnsTest extends ModelCheckerTestCase { @@ -54,7 +46,7 @@ public class RandomSubsetSetOfFcnsTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1000")); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2000", "1000", "0")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1")); // // assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); // @@ -84,5 +76,7 @@ public class RandomSubsetSetOfFcnsTest extends ModelCheckerTestCase { // assertEquals(firstY.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("y"))).val); // // Check z is false // assertEquals(BoolValue.ValFalse, (BoolValue) secondState.get(UniqueString.uniqueStringOf("z"))); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/RandomSubsetTest.java b/tlatools/test/tlc2/tool/RandomSubsetTest.java index 2a134577172894a9c523964a40f876b1de5f4893..fb562980cefd954f72780e821a444c5935089220 100644 --- a/tlatools/test/tlc2/tool/RandomSubsetTest.java +++ b/tlatools/test/tlc2/tool/RandomSubsetTest.java @@ -35,16 +35,18 @@ import java.util.Map; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; -import tlc2.value.BoolValue; -import tlc2.value.IntValue; -import tlc2.value.Value; +import tlc2.value.IBoolValue; +import tlc2.value.IValue; +import tlc2.value.impl.BoolValue; +import tlc2.value.impl.IntValue; import util.UniqueString; public class RandomSubsetTest extends ModelCheckerTestCase { public RandomSubsetTest() { - super("RandomSubset"); + super("RandomSubset", ExitStatus.VIOLATION_SAFETY); } @Test @@ -54,7 +56,7 @@ public class RandomSubsetTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2002")); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2003", "2003", "2001")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertEquals(2, recorder.getRecordAsInt(EC.TLC_SEARCH_DEPTH)); assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); @@ -63,7 +65,7 @@ public class RandomSubsetTest extends ModelCheckerTestCase { final TLCStateInfo first = (TLCStateInfo) ((Object[]) actual.get(0))[0]; assertTrue(((String) first.info).startsWith("<Initial predicate>")); - final Map<UniqueString, Value> firstState = first.state.getVals(); + final Map<UniqueString, IValue> firstState = first.state.getVals(); assertEquals(3, firstState.size()); // Check x and y values are within defined ranges. @@ -73,16 +75,18 @@ public class RandomSubsetTest extends ModelCheckerTestCase { assertTrue(100000000 <= firstY.val && firstX.val <= 100000010); // Check z is true - assertEquals(BoolValue.ValTrue, (BoolValue) firstState.get(UniqueString.uniqueStringOf("z"))); + assertEquals(BoolValue.ValTrue, (IBoolValue) firstState.get(UniqueString.uniqueStringOf("z"))); final TLCStateInfo second = (TLCStateInfo) ((Object[]) actual.get(1))[0]; assertTrue(((String) second.info).startsWith("<Next line 10, col 9 to line 11, col 21 of module RandomSubset>")); - final Map<UniqueString, Value> secondState = second.state.getVals(); + final Map<UniqueString, IValue> secondState = second.state.getVals(); assertEquals(3, secondState.size()); // UNCHANGED x,y assertEquals(firstX.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("x"))).val); assertEquals(firstY.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("y"))).val); // Check z is false - assertEquals(BoolValue.ValFalse, (BoolValue) secondState.get(UniqueString.uniqueStringOf("z"))); + assertEquals(BoolValue.ValFalse, (IBoolValue) secondState.get(UniqueString.uniqueStringOf("z"))); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/StandardModulesTest.java b/tlatools/test/tlc2/tool/StandardModulesTest.java index cb44f02e65cbe17325fcd429594abbc191188fc5..c3f766e33b51db43f061ac9f5c1c2b68216c098a 100644 --- a/tlatools/test/tlc2/tool/StandardModulesTest.java +++ b/tlatools/test/tlc2/tool/StandardModulesTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; diff --git a/tlatools/test/tlc2/tool/SubsetEqTest.java b/tlatools/test/tlc2/tool/SubsetEqTest.java index 4ffde29d2ff2cb2c8db31e1a256e988ab0a7593b..b1c81b690e525a9b3fb841209724e42ee505328f 100644 --- a/tlatools/test/tlc2/tool/SubsetEqTest.java +++ b/tlatools/test/tlc2/tool/SubsetEqTest.java @@ -51,5 +51,7 @@ public class SubsetEqTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); // No error trace! assertFalse(recorder.recorded(EC.TLC_STATE_PRINT2)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/TLCGetLevelTest.java b/tlatools/test/tlc2/tool/TLCGetLevelTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c807d3064a9a9520a8c930920fb26c597c969abf --- /dev/null +++ b/tlatools/test/tlc2/tool/TLCGetLevelTest.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class TLCGetLevelTest extends ModelCheckerTestCase { + + public TLCGetLevelTest() { + super("TLCGetLevel", ExitStatus.VIOLATION_LIVENESS); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4", "4", "0")); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Assert TLC has found a temporal violation and a counter example + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + + // Assert the error trace + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(4); + expectedTrace.add("/\\ x = 0\n" + + "/\\ y = 0"); + expectedTrace.add("/\\ x = 1\n" + + "/\\ y = 1"); + expectedTrace.add("/\\ x = 2\n" + + "/\\ y = 2"); + expectedTrace.add("/\\ x = 3\n" + + "/\\ y = 3"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertStuttering(5); + } +} diff --git a/tlatools/test/tlc2/tool/TLCGetNamedUndefinedTest.java b/tlatools/test/tlc2/tool/TLCGetNamedUndefinedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd47a068673481c6e170bb4fe1cb4d4a338bc3bb --- /dev/null +++ b/tlatools/test/tlc2/tool/TLCGetNamedUndefinedTest.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class TLCGetNamedUndefinedTest extends ModelCheckerTestCase { + + public TLCGetNamedUndefinedTest() { + super("TLCGetNamedUndefined", ExitStatus.ERROR_CONFIG_PARSE); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recorded(EC.TLC_MODULE_TLCGET_UNDEFINED)); + assertTrue(recorder.recorded(EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT)); + } +} diff --git a/tlatools/test/tlc2/tool/TLCGetNonDeterminismTest.java b/tlatools/test/tlc2/tool/TLCGetNonDeterminismTest.java new file mode 100644 index 0000000000000000000000000000000000000000..87ebb1020f26ed16f06c1ecdb559eaa5698d1ee6 --- /dev/null +++ b/tlatools/test/tlc2/tool/TLCGetNonDeterminismTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class TLCGetNonDeterminismTest extends ModelCheckerTestCase { + + public TLCGetNonDeterminismTest() { + super("TLCGetNonDeterminism"); + } + + @Test + @Ignore("No known fix/By design") + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Assert TLC has found a temporal violation and a counter example + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + + // Assert the error trace + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(4); + expectedTrace.add("/\\ x = 0\n" + + "/\\ y = 0"); + expectedTrace.add("/\\ x = 1\n" + + "/\\ y = 1"); + expectedTrace.add("/\\ x = 2\n" + + "/\\ y = 2"); + expectedTrace.add("/\\ x = 3\n" + + "/\\ y = 3"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertStuttering(5); + } + + @Override + protected int getNumberOfThreads() { + // This test passes with a single worker! There is a slim chance it passes with more workers. + return 4; + } +} diff --git a/tlatools/test/tlc2/tool/TLCSetInitTest.java b/tlatools/test/tlc2/tool/TLCSetInitTest.java index 1cd186ada104cde423778683a745095a46b61218..478ef7a4d004a6dd97da92cf6e6be43db2db6afa 100644 --- a/tlatools/test/tlc2/tool/TLCSetInitTest.java +++ b/tlatools/test/tlc2/tool/TLCSetInitTest.java @@ -42,5 +42,7 @@ public class TLCSetInitTest extends ModelCheckerTestCase { @Test public void testSpec() { assertFalse(recorder.recorded(EC.GENERAL)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/Test052.java b/tlatools/test/tlc2/tool/TLCSetTest.java similarity index 73% rename from tlatools/test/tlc2/tool/liveness/Test052.java rename to tlatools/test/tlc2/tool/TLCSetTest.java index 6c767175035288dc79f03104fcdc4284c669605a..69a2c87e501fc88e5d581593de8d5ca757e29bc5 100644 --- a/tlatools/test/tlc2/tool/liveness/Test052.java +++ b/tlatools/test/tlc2/tool/TLCSetTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. + * Copyright (c) 2018 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -23,30 +23,31 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ - -package tlc2.tool.liveness; +package tlc2.tool; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; -public class Test052 extends ModelCheckerTestCase { +public class TLCSetTest extends ModelCheckerTestCase { - public Test052() { - super("test52"); + public TLCSetTest() { + super("TLCSet"); } @Test public void testSpec() { - // ModelChecker has finished and generated the expected amount of states - assertTrue(recorder.recorded(EC.TLC_MODE_MC)); assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recorded(EC.TLC_COMPUTING_INIT)); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); + assertZeroUncovered(); + } + + @Override + protected boolean doDump() { + return false; } } diff --git a/tlatools/test/tlc2/tool/TLCStates.java b/tlatools/test/tlc2/tool/TLCStates.java new file mode 100644 index 0000000000000000000000000000000000000000..c05339e98b228baf2dbf441465ca5cc55a05e94a --- /dev/null +++ b/tlatools/test/tlc2/tool/TLCStates.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import tla2sany.semantic.ASTConstants; +import tla2sany.semantic.OpDeclNode; +import tlc2.value.impl.IntValue; +import util.UniqueString; + +public abstract class TLCStates { + + public static TLCState createDummyState() { + return createDummyState(1); + } + + public static TLCState createDummyState(final int numVars) { + UniqueString.setVariableCount(numVars); + + // Create variable declarations (no values yet). + final OpDeclNode[] variables = new OpDeclNode[numVars]; + for (int i = 0; i < numVars; i++) { + UniqueString us = UniqueString.uniqueStringOf("v" + Integer.toString(i)); + us.setLoc(i); + variables[i] = new OpDeclNode(us, ASTConstants.VariableDeclKind, 1, 0, null, null, null); + } + + // Initialize the empty state (variable declarations are static/final per TLC + // run). + TLCStateMut.setVariables(variables); + final TLCState state = TLCState.Empty.createEmpty(); + state.uid = 0; + + // Assign values to variables. + for (int i = 0; i < numVars; i++) { + state.bind(variables[i].getName(), IntValue.gen(i)); + } + + return state; + } +} diff --git a/tlatools/test/tlc2/tool/TSnapShotTest.java b/tlatools/test/tlc2/tool/TSnapShotTest.java index 077e3c2e93e89dba69c02f192a5d00e03d864cbb..fd9f94b84a9166a8afaa1237d7c697e200a6be39 100644 --- a/tlatools/test/tlc2/tool/TSnapShotTest.java +++ b/tlatools/test/tlc2/tool/TSnapShotTest.java @@ -30,13 +30,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class TSnapShotTest extends ModelCheckerTestCase { public TSnapShotTest() { - super("MC", "TSnapShot"); + super("MC", "TSnapShot", ExitStatus.FAILURE_SAFETY_EVAL); } @Test diff --git a/tlatools/test/tlc2/tool/TraceWithLargeSetOfInitialStatesTest.java b/tlatools/test/tlc2/tool/TraceWithLargeSetOfInitialStatesTest.java index 11fbafd364040f1c87b45cd7c9e0fedb2b61bfb6..dfb79ba450383a06a7adb9c2d9e67e6f6ca50e1c 100644 --- a/tlatools/test/tlc2/tool/TraceWithLargeSetOfInitialStatesTest.java +++ b/tlatools/test/tlc2/tool/TraceWithLargeSetOfInitialStatesTest.java @@ -34,12 +34,13 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class TraceWithLargeSetOfInitialStatesTest extends ModelCheckerTestCase { public TraceWithLargeSetOfInitialStatesTest() { - super("TraceWithLargeSetOfInitialStatesTest", new String[] { "-maxSetSize", "10" }); + super("TraceWithLargeSetOfInitialStatesTest", new String[] { "-maxSetSize", "10" }, ExitStatus.VIOLATION_SAFETY); } @Test @@ -54,5 +55,7 @@ public class TraceWithLargeSetOfInitialStatesTest extends ModelCheckerTestCase { expectedTrace.add("/\\ x = 1\n/\\ y = FALSE"); expectedTrace.add("/\\ x = 1\n/\\ y = TRUE"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/UserModuleOverrideFromJarTest.java b/tlatools/test/tlc2/tool/UserModuleOverrideFromJarTest.java new file mode 100644 index 0000000000000000000000000000000000000000..48122f345fb66c16c8c9616988169d84c4f3c43f --- /dev/null +++ b/tlatools/test/tlc2/tool/UserModuleOverrideFromJarTest.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2016 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +@RunWith(BlockJUnit4ClassRunner.class) +public class UserModuleOverrideFromJarTest extends ModelCheckerTestCase { + + public UserModuleOverrideFromJarTest() { + // This test only works when executed from customBuild.xml because it requires an extra classpath setting. + super("UserModuleOverrideBase"); + } + + @Test + public void testSpec() { + final List<String[]> mismatches = recorder.getRecordAsStringArray(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH); + assertEquals(2, mismatches.size()); + Collections.sort(mismatches, new Comparator<String[]>() { + @Override + public int compare(String[] o1, String[] o2) { + return o1[0].compareTo(o2[0]); + } + }); + + // arity mismatch + String[] strs = mismatches.get(0); + assertEquals("Get2", strs[0]); + assertTrue(strs[1].endsWith("UserModuleOverrideFromJar.class")); // This contains a system dependent path. + assertEquals("<Java Method: public static tlc2.value.impl.Value UserModuleOverrideFromJar.Get2(tlc2.value.impl.Value)>", strs[2]); + + // name mismatch (no such operator) + strs = mismatches.get(1); + assertEquals("Get3", strs[0]); + assertTrue(strs[1].endsWith("UserModuleOverrideFromJar.class")); + assertEquals("<Java Method: public static tlc2.value.impl.Value UserModuleOverrideFromJar.Get3()>", strs[2]); + + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertZeroUncovered(); + } +} diff --git a/tlatools/test/tlc2/tool/UserModuleOverrideTest.java b/tlatools/test/tlc2/tool/UserModuleOverrideTest.java index 23133cd278a8044baa76f1336a34b539b11b34e0..63c672bf1d6d1b575085507c5be85b9dc98b32f7 100644 --- a/tlatools/test/tlc2/tool/UserModuleOverrideTest.java +++ b/tlatools/test/tlc2/tool/UserModuleOverrideTest.java @@ -25,14 +25,22 @@ ******************************************************************************/ package tlc2.tool; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; +@RunWith(BlockJUnit4ClassRunner.class) public class UserModuleOverrideTest extends ModelCheckerTestCase { public UserModuleOverrideTest() { @@ -41,9 +49,32 @@ public class UserModuleOverrideTest extends ModelCheckerTestCase { @Test public void testSpec() { + final List<String[]> mismatches = recorder.getRecordAsStringArray(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH); + assertEquals(2, mismatches.size()); + Collections.sort(mismatches, new Comparator<String[]>() { + @Override + public int compare(String[] o1, String[] o2) { + return o1[0].compareTo(o2[0]); + } + }); + + // arity mismatch + String[] strs = mismatches.get(0); + assertEquals("Get2", strs[0]); + assertTrue(strs[1].endsWith("UserModuleOverride.class")); // This contains a system dependent path. + assertEquals("<Java Method: public static tlc2.value.impl.Value UserModuleOverride.Get2(tlc2.value.impl.Value)>", strs[2]); + + // name mismatch (no such operator) + strs = mismatches.get(1); + assertEquals("Get3", strs[0]); + assertTrue(strs[1].endsWith("UserModuleOverride.class")); + assertEquals("<Java Method: public static tlc2.value.impl.Value UserModuleOverride.Get3()>", strs[2]); + // ModelChecker has finished and generated the expected amount of states assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); assertFalse(recorder.recorded(EC.GENERAL)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/ViewMapTest.java b/tlatools/test/tlc2/tool/ViewMapTest.java index 70e3b98cf51c9953cc2b8e3f97af6500a9f2fd52..c2cc3934953326351cdb319b778e3becacfd5e21 100644 --- a/tlatools/test/tlc2/tool/ViewMapTest.java +++ b/tlatools/test/tlc2/tool/ViewMapTest.java @@ -34,12 +34,13 @@ import java.util.List; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class ViewMapTest extends ModelCheckerTestCase { public ViewMapTest() { - super("ViewMap", new String[] { "-view" }); + super("ViewMap", new String[] { "-view" }, ExitStatus.VIOLATION_SAFETY); } @Test @@ -61,5 +62,7 @@ public class ViewMapTest extends ModelCheckerTestCase { expectedTrace.add("/\\ buffer = << >>\n/\\ waitset = {c1, p1}"); expectedTrace.add("/\\ buffer = << >>\n/\\ waitset = {c1, c2, p1}"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertUncovered("line 91, col 60 to line 91, col 73 of module ViewMap: 0"); } } diff --git a/tlatools/test/tlc2/tool/checkpoint/CheckpointOnViolationTest.java b/tlatools/test/tlc2/tool/checkpoint/CheckpointOnViolationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0415bab18a7e6c34f45f78e98395ee84a30f49c2 --- /dev/null +++ b/tlatools/test/tlc2/tool/checkpoint/CheckpointOnViolationTest.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.checkpoint; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class CheckpointOnViolationTest extends ModelCheckerTestCase { + + public CheckpointOnViolationTest() { + super("DieHard", ExitStatus.VIOLATION_SAFETY); + } + + @Test + public void testSpec() { + // ModelChecker has finished and generated the expected amount of states. + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "252", "54", "11")); + + // Check the violation + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + assertEquals(7, recorder.getRecords(EC.TLC_STATE_PRINT2).size()); + + // Check that a checkpoint has been taken. + assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_START)); + assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_END)); + + assertZeroUncovered(); + } + + @Override + protected int doCheckpoint() { + // Request checkpoints but make it highly unlike for the test to ever create a + // checkpoint because the checkpoint interval was exceeded. We want to test + // TLC's functionality to take a checkpoint when time-bound model-checking is on + // and/or a violation has been found. + return (Integer.MAX_VALUE / 60000); + } +} diff --git a/tlatools/test/tlc2/tool/checkpoint/CheckpointWhenTimeBoundTest.java b/tlatools/test/tlc2/tool/checkpoint/CheckpointWhenTimeBoundTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a9142f70501d65c41c51a499dfbd259b6b051843 --- /dev/null +++ b/tlatools/test/tlc2/tool/checkpoint/CheckpointWhenTimeBoundTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.checkpoint; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.TLC; +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class CheckpointWhenTimeBoundTest extends ModelCheckerTestCase { + + public CheckpointWhenTimeBoundTest() { + super("InfiniteStateSpace", "checkpoint"); + } + + @Override + public void setUp() { + System.setProperty(TLC.class.getName() + ".stopAfter", "5"); // five seconds + super.setUp(); + } + + @Test + public void testSpec() { + // ModelChecker has finished and generated the expected amount of states. + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_STATE_PRINT1)); + assertFalse(recorder.recorded(EC.TLC_STATE_PRINT2)); + + // Check that a checkpoint has been taken. + assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_START)); + assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_END)); + + assertZeroUncovered(); + } + + @Override + protected int doCheckpoint() { + // Request checkpoints but make it highly unlike for the test to ever create a + // checkpoint because the checkpoint interval was exceeded. We want to test + // TLC's functionality to take a checkpoint when time-bound model-checking is on + // and/or a violation has been found. + return (Integer.MAX_VALUE / 60000); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/ACoverageTest.java b/tlatools/test/tlc2/tool/coverage/ACoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1c09fcec324f1e276e1ea62c2c63c8c9ed072466 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/ACoverageTest.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ACoverageTest extends AbstractCoverageTest { + + public ACoverageTest () { + super("A"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "7", "3", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 7, col 1 to line 7, col 4 of module A>: 1:1\n" + + " line 7, col 12 to line 7, col 16 of module A: 1\n" + + " line 8, col 12 to line 8, col 21 of module A: 1\n" + + " |line 5, col 11 to line 5, col 49 of module A: 1\n" + + " ||line 5, col 31 to line 5, col 49 of module A: 131072\n" + + " ||line 5, col 20 to line 5, col 27 of module A: 1\n" + // This used to be a level deeper and value 131072 + " |line 8, col 16 to line 8, col 20 of module A: 1\n" + + "<A line 13, col 1 to line 13, col 4 of module A>: 1:3\n" + + " line 13, col 9 to line 13, col 19 of module A: 3\n" + + " |line 13, col 14 to line 13, col 19 of module A: 3\n" + + " ||line 11, col 11 to line 11, col 61 of module A: 3\n" + + " |||line 11, col 31 to line 11, col 61 of module A: 30\n" + + " ||||line 11, col 57 to line 11, col 61 of module A: 162\n" + + " ||||line 11, col 41 to line 11, col 52 of module A: 30\n" + + " |||line 11, col 24 to line 11, col 27 of module A: 3\n" + + " ||line 13, col 18 to line 13, col 18 of module A: 3\n" + + "<B line 15, col 1 to line 15, col 4 of module A>: 1:3\n" + + " line 15, col 9 to line 15, col 19 of module A: 3\n" + + " |line 15, col 14 to line 15, col 19 of module A: 3\n" + + " ||line 11, col 11 to line 11, col 61 of module A: 3\n" + + " |||line 11, col 31 to line 11, col 61 of module A: 9\n" + + " ||||line 11, col 57 to line 11, col 61 of module A: 15\n" + + " ||||line 11, col 41 to line 11, col 52 of module A: 9\n" + + " |||line 11, col 24 to line 11, col 27 of module A: 3\n" + + " ||line 15, col 18 to line 15, col 18 of module A: 3"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/AbstractCoverageTest.java b/tlatools/test/tlc2/tool/coverage/AbstractCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1d733ef19520f486bef631d553a12ec2d6546732 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/AbstractCoverageTest.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import tlc2.tool.liveness.ModelCheckerTestCase; + +public abstract class AbstractCoverageTest extends ModelCheckerTestCase { + + public AbstractCoverageTest(String spec) { + super(spec, "coverage", new String[] {"-coverage", "9999"}); // To not interfere with testing, 9999 to make sure only final coverage is reported. + } +} diff --git a/tlatools/test/tlc2/tool/coverage/BCoverageTest.java b/tlatools/test/tlc2/tool/coverage/BCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eb1386c47d105527daee3494b0911e3716f49556 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/BCoverageTest.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class BCoverageTest extends AbstractCoverageTest { + + public BCoverageTest () { + super("B"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5", "2", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 4, col 1 to line 4, col 4 of module B>: 1:1\n" + + " line 4, col 9 to line 4, col 17 of module B: 1\n" + + "<A line 8, col 1 to line 8, col 1 of module B>: 1:2\n" + + " line 8, col 6 to line 8, col 19 of module B: 2\n" + + "<B line 10, col 1 to line 10, col 1 of module B>: 0:2\n" + + " line 10, col 6 to line 10, col 19 of module B: 2"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/CCoverageTest.java b/tlatools/test/tlc2/tool/coverage/CCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b5a40b16da90067cca0c51b1666fbbb5e01d9c1a --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/CCoverageTest.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CCoverageTest extends AbstractCoverageTest { + + public CCoverageTest () { + super("C"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "17")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "253", "20", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 14, col 1 to line 14, col 4 of module C>: 3:3\n" + + " line 14, col 12 to line 14, col 21 of module C: 1\n" + + " line 15, col 12 to line 15, col 16 of module C: 3\n" + + "<A line 17, col 1 to line 17, col 1 of module C>: 16:20\n" + + " line 17, col 9 to line 17, col 17 of module C: 40\n" + + " |line 17, col 9 to line 17, col 9 of module C: 20\n" + + " |line 17, col 15 to line 17, col 17 of module C: 20\n" + + " line 18, col 9 to line 18, col 17 of module C: 40\n" + + " |line 18, col 9 to line 18, col 9 of module C: 20\n" + + " |line 18, col 15 to line 18, col 17 of module C: 20\n" + + " line 19, col 9 to line 19, col 17 of module C: 20\n" + + " line 20, col 9 to line 20, col 19 of module C: 20\n" + + "<B line 22, col 1 to line 22, col 1 of module C>: 0:20\n" + + " line 22, col 9 to line 22, col 17 of module C: 40\n" + + " |line 22, col 9 to line 22, col 9 of module C: 20\n" + + " |line 22, col 15 to line 22, col 17 of module C: 20\n" + + " line 12, col 30 to line 12, col 48 of module C: 640\n" + + " line 12, col 19 to line 12, col 26 of module C: 20\n" + + " line 23, col 12 to line 23, col 15 of module C: 20\n" + + " line 24, col 9 to line 24, col 25 of module C: 20\n" + + "<C line 26, col 1 to line 26, col 1 of module C>: 0:0\n" + + " line 26, col 9 to line 26, col 14 of module C: 20\n" + + " line 27, col 9 to line 27, col 17 of module C: 0\n" + + " line 28, col 9 to line 28, col 18 of module C: 0\n" + + "<D line 30, col 1 to line 30, col 1 of module C>: 1:210\n" + + " line 30, col 6 to line 30, col 16 of module C: 210\n" + + " |line 30, col 13 to line 30, col 16 of module C: 20\n" + + " line 30, col 21 to line 30, col 31 of module C: 210\n" + + "<U1 line 32, col 1 to line 32, col 2 of module C>: 0:0\n" + + " line 32, col 7 to line 32, col 11 of module C: 20\n" + + " line 32, col 16 to line 32, col 29 of module C: 0\n" + + "<U2 line 34, col 1 to line 34, col 2 of module C>: 0:0\n" + + " line 34, col 7 to line 34, col 11 of module C: 20\n" + + " line 34, col 16 to line 34, col 32 of module C: 0\n" + + "<U3 line 36, col 1 to line 36, col 2 of module C>: 0:0\n" + + " line 36, col 7 to line 36, col 11 of module C: 20\n" + + " line 36, col 16 to line 36, col 26 of module C: 0\n" + + " line 36, col 31 to line 36, col 41 of module C: 0\n" + + "<Inv line 48, col 1 to line 48, col 3 of module C>\n" + + " line 48, col 8 to line 54, col 26 of module C: 21\n" + + " |line 48, col 11 to line 48, col 19 of module C: 21\n" + + " |line 49, col 11 to line 49, col 19 of module C: 21\n" + + " |line 50, col 11 to line 50, col 22 of module C: 21\n" + + " ||line 46, col 17 to line 46, col 64 of module C: 21\n" + + " |||line 46, col 42 to line 46, col 64 of module C: 5376\n" + + " ||||line 46, col 55 to line 46, col 64 of module C: 21504\n" + + " ||||line 46, col 51 to line 46, col 51 of module C: 5376\n" + + " |||line 46, col 26 to line 46, col 38 of module C: 21:26880\n" + + " |line 51, col 23 to line 51, col 26 of module C: 21\n" + + " |line 52, col 14 to line 54, col 26 of module C: 21\n" + + " ||line 52, col 17 to line 52, col 27 of module C: 21\n" + + " ||line 53, col 17 to line 53, col 40 of module C: 21\n" + + " |||line 53, col 32 to line 53, col 40 of module C: 105\n" + + " |||line 53, col 26 to line 53, col 29 of module C: 21\n" + + " ||line 54, col 17 to line 54, col 26 of module C: 21\n" + + "<Inv2 line 56, col 1 to line 56, col 4 of module C>\n" + + " line 56, col 9 to line 62, col 27 of module C: 21\n" + + " |line 56, col 12 to line 56, col 20 of module C: 21\n" + + " |line 57, col 12 to line 57, col 20 of module C: 21\n" + + " |line 58, col 12 to line 58, col 23 of module C: 21\n" + + " ||line 46, col 17 to line 46, col 64 of module C: 21\n" + + " |||line 46, col 42 to line 46, col 64 of module C: 10752\n" + + " ||||line 46, col 55 to line 46, col 64 of module C: 48384\n" + + " ||||line 46, col 51 to line 46, col 51 of module C: 10752\n" + + " |||line 46, col 26 to line 46, col 38 of module C: 21:59136\n" + + " |line 59, col 24 to line 59, col 27 of module C: 21\n" + + " |line 60, col 15 to line 62, col 27 of module C: 21\n" + + " ||line 60, col 15 to line 60, col 28 of module C: 21\n" + + " ||line 61, col 17 to line 62, col 27 of module C: 21\n" + + " |||line 61, col 32 to line 62, col 27 of module C: 105\n" + + " |||line 61, col 26 to line 61, col 29 of module C: 21"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/CoverageStatisticsTest.java b/tlatools/test/tlc2/tool/coverage/CoverageStatisticsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b6926887f6f2f03166f1f29e5d83150c4bbc6ac5 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/CoverageStatisticsTest.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CoverageStatisticsTest extends AbstractCoverageTest { + + public CoverageStatisticsTest () { + super("CoverageStatistics"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "17")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "98", "19", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertCoverage("<Init line 12, col 1 to line 12, col 4 of module CoverageStatistics>: 3:3\n" + + " line 12, col 12 to line 12, col 21 of module CoverageStatistics: 1\n" + + " line 13, col 12 to line 13, col 16 of module CoverageStatistics: 3\n" + + "<A line 15, col 1 to line 15, col 1 of module CoverageStatistics>: 16:19\n" + + " line 15, col 9 to line 15, col 17 of module CoverageStatistics: 38\n" + + " |line 15, col 9 to line 15, col 9 of module CoverageStatistics: 19\n" + + " |line 15, col 15 to line 15, col 17 of module CoverageStatistics: 19\n" + + " line 16, col 9 to line 16, col 17 of module CoverageStatistics: 38\n" + + " |line 16, col 9 to line 16, col 9 of module CoverageStatistics: 19\n" + + " |line 16, col 15 to line 16, col 17 of module CoverageStatistics: 19\n" + + " line 17, col 9 to line 17, col 17 of module CoverageStatistics: 19\n" + + " line 18, col 9 to line 18, col 19 of module CoverageStatistics: 19\n" + + "<B line 20, col 1 to line 20, col 1 of module CoverageStatistics>: 0:19\n" + + " line 20, col 9 to line 20, col 17 of module CoverageStatistics: 38\n" + + " |line 20, col 9 to line 20, col 9 of module CoverageStatistics: 19\n" + + " |line 20, col 15 to line 20, col 17 of module CoverageStatistics: 19\n" + + " line 21, col 9 to line 21, col 25 of module CoverageStatistics: 19\n" + + "<C line 26, col 1 to line 26, col 1 of module CoverageStatistics>: 0:0\n" + + " line 26, col 9 to line 26, col 14 of module CoverageStatistics: 19\n" + + " line 27, col 9 to line 27, col 17 of module CoverageStatistics: 0\n" + + " line 28, col 9 to line 28, col 18 of module CoverageStatistics: 0\n" + + "<U1 line 30, col 1 to line 30, col 2 of module CoverageStatistics>: 0:0\n" + + " line 30, col 7 to line 30, col 11 of module CoverageStatistics: 19\n" + + " line 30, col 16 to line 30, col 29 of module CoverageStatistics: 0\n" + + "<U2 line 32, col 1 to line 32, col 2 of module CoverageStatistics>: 0:0\n" + + " line 32, col 7 to line 32, col 11 of module CoverageStatistics: 19\n" + + " line 32, col 16 to line 32, col 32 of module CoverageStatistics: 0\n" + + "<U3 line 34, col 1 to line 34, col 2 of module CoverageStatistics>: 0:0\n" + + " line 34, col 7 to line 34, col 11 of module CoverageStatistics: 19\n" + + " line 34, col 16 to line 34, col 26 of module CoverageStatistics: 0\n" + + " line 34, col 31 to line 34, col 41 of module CoverageStatistics: 0\n" + + "<U4 line 36, col 1 to line 36, col 2 of module CoverageStatistics>: 0:0\n" + + " line 36, col 7 to line 36, col 11 of module CoverageStatistics: 19\n" + + " line 36, col 16 to line 36, col 26 of module CoverageStatistics: 0\n" + + " line 36, col 31 to line 36, col 41 of module CoverageStatistics: 0\n" + + "<UC1 line 38, col 1 to line 38, col 3 of module CoverageStatistics>: 0:19\n" + + " line 38, col 8 to line 38, col 16 of module CoverageStatistics: 38\n" + + " |line 38, col 8 to line 38, col 8 of module CoverageStatistics: 19\n" + + " |line 38, col 14 to line 38, col 16 of module CoverageStatistics: 19\n" + + " line 38, col 21 to line 38, col 37 of module CoverageStatistics: 19\n" + + "<UC2 line 40, col 1 to line 40, col 3 of module CoverageStatistics>: 0:19\n" + + " line 40, col 8 to line 40, col 16 of module CoverageStatistics: 38\n" + + " |line 40, col 8 to line 40, col 8 of module CoverageStatistics: 19\n" + + " |line 40, col 14 to line 40, col 16 of module CoverageStatistics: 19\n" + + " line 40, col 21 to line 40, col 31 of module CoverageStatistics: 19\n" + + " line 40, col 36 to line 40, col 46 of module CoverageStatistics: 19\n" + + "<UC3 line 42, col 1 to line 42, col 3 of module CoverageStatistics>: 0:19\n" + + " line 42, col 8 to line 42, col 16 of module CoverageStatistics: 38\n" + + " |line 42, col 8 to line 42, col 8 of module CoverageStatistics: 19\n" + + " |line 42, col 14 to line 42, col 16 of module CoverageStatistics: 19\n" + + " line 42, col 21 to line 42, col 34 of module CoverageStatistics: 19"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/DCoverageTest.java b/tlatools/test/tlc2/tool/coverage/DCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..205fde171dfa1e4de2fedf655c8fe90e9b1752eb --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/DCoverageTest.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class DCoverageTest extends AbstractCoverageTest { + + public DCoverageTest () { + super("D"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "7", "3", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 5, col 1 to line 5, col 4 of module D>: 1:1\n" + + " line 5, col 9 to line 5, col 13 of module D: 1\n" + + "<A line 11, col 1 to line 11, col 1 of module D>: 1:3\n" + + " line 11, col 6 to line 11, col 17 of module D: 3\n" + + " |line 11, col 11 to line 11, col 17 of module D: 3\n" + + " ||line 9, col 12 to line 9, col 47 of module D: 9\n" + + " |||line 9, col 15 to line 9, col 19 of module D: 9\n" + + " |||line 9, col 33 to line 9, col 47 of module D: 6\n" + + "<B line 13, col 1 to line 13, col 1 of module D>: 1:3\n" + + " line 13, col 6 to line 13, col 17 of module D: 3\n" + + " |line 13, col 11 to line 13, col 17 of module D: 3\n" + + " ||line 9, col 12 to line 9, col 47 of module D: 27\n" + + " |||line 9, col 15 to line 9, col 19 of module D: 27\n" + + " |||line 9, col 33 to line 9, col 47 of module D: 24"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/ECoverageTest.java b/tlatools/test/tlc2/tool/coverage/ECoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..944dbaa32237592ee8cd9a49cabfdf9095adeaae --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/ECoverageTest.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ECoverageTest extends AbstractCoverageTest { + + public ECoverageTest () { + super("E"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "73", "9", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 10, col 1 to line 10, col 4 of module E>: 1:1\n" + + " line 10, col 9 to line 10, col 13 of module E: 1\n" + + "<Next line 12, col 1 to line 12, col 4 of module E>: 8:72\n" + + " line 12, col 9 to line 12, col 20 of module E: 72\n" + + " |line 12, col 16 to line 12, col 20 of module E: 9"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/FCoverageTest.java b/tlatools/test/tlc2/tool/coverage/FCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..25c48c58cd10d58693b7f525d27222fbaaeccd6a --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/FCoverageTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * loki der quaeler - initial API and implementation + * Markus Alexander Kuppe + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FCoverageTest extends AbstractCoverageTest { + + public FCoverageTest () { + super("F"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4", "2", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + assertCoverage("<Init line 8, col 1 to line 8, col 4 of module F>: 2:2\n" + + " line 8, col 9 to line 8, col 79 of module F: 2\n" + + " |line 8, col 15 to line 8, col 79 of module F: 1\n" + + " ||line 6, col 25 to line 6, col 56 of module F: 1:3\n" + + " |||line 6, col 37 to line 6, col 54 of module F: 5\n" + + " ||||line 6, col 37 to line 6, col 40 of module F: 5\n" + + " ||||line 6, col 45 to line 6, col 54 of module F: 4\n" + + " |||||line 6, col 47 to line 6, col 47 of module F: 4\n" + + " |||||line 6, col 50 to line 6, col 53 of module F: 2\n" + + " |||||line 8, col 63 to line 8, col 78 of module F: 4\n" + + " ||||||line 8, col 63 to line 8, col 73 of module F: 4\n" + + " ||||||line 8, col 78 to line 8, col 78 of module F: 2\n" + + " |||line 6, col 33 to line 6, col 33 of module F: 1\n" + + " ||line 8, col 18 to line 8, col 28 of module F: 1:6\n" + + " ||line 8, col 41 to line 8, col 45 of module F: 5\n" + + " ||line 8, col 63 to line 8, col 78 of module F: 4\n" + + " |||line 8, col 63 to line 8, col 73 of module F: 4\n" + + " |||line 8, col 78 to line 8, col 78 of module F: 2\n" + + "<Next line 10, col 1 to line 10, col 4 of module F>: 0:2\n" + + " line 10, col 9 to line 10, col 19 of module F: 2"); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/GCoverageTest.java b/tlatools/test/tlc2/tool/coverage/GCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..340eeb8a17b325aa7df3b6934aedbab06d04fc95 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/GCoverageTest.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class GCoverageTest extends AbstractCoverageTest { + + public GCoverageTest () { + super("G"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertCoverage("<Init line 6, col 1 to line 6, col 4 of module G>: 1:1\n" + + " line 6, col 9 to line 6, col 20 of module G: 1\n" + + "<Next line 8, col 1 to line 8, col 4 of module G>: 0:1\n" + + " line 8, col 12 to line 8, col 25 of module G: 1\n" + + " line 9, col 12 to line 9, col 27 of module G: 2\n" + + " line 10, col 12 to line 10, col 23 of module G: 2\n" + + "<Prop line 12, col 1 to line 12, col 4 of module G>\n" + + " line 12, col 9 to line 12, col 20 of module G: 1\n" + + " |line 8, col 12 to line 8, col 25 of module G: 1\n" + + " |line 9, col 12 to line 9, col 27 of module G: 1\n" + + " |line 10, col 12 to line 10, col 23 of module G: 1"); + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/Test055.java b/tlatools/test/tlc2/tool/coverage/Github314CoverageTest.java similarity index 80% rename from tlatools/test/tlc2/tool/liveness/Test055.java rename to tlatools/test/tlc2/tool/coverage/Github314CoverageTest.java index 9a8329e315079091f8ee8828023fc3c643c71390..4f8f86f0c87b0e705ae6d82147af14c1d2c7d1d7 100644 --- a/tlatools/test/tlc2/tool/liveness/Test055.java +++ b/tlatools/test/tlc2/tool/coverage/Github314CoverageTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. + * Copyright (c) 2019 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -23,30 +23,31 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ - -package tlc2.tool.liveness; +package tlc2.tool.coverage; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; -public class Test055 extends ModelCheckerTestCase { +public class Github314CoverageTest extends AbstractCoverageTest { - public Test055() { - super("test55"); - } + public Github314CoverageTest () { + super("Github314"); + } - @Test - public void testSpec() { + @Test + public void testSpec () { // ModelChecker has finished and generated the expected amount of states - assertTrue(recorder.recorded(EC.TLC_MODE_MC)); assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "3", "0")); + + // No 'general' errors recorded assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recorded(EC.TLC_COMPUTING_INIT)); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); - } + + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + } } diff --git a/tlatools/test/tlc2/tool/coverage/HCoverageTest.java b/tlatools/test/tlc2/tool/coverage/HCoverageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7dcb347651e6f5779b06e2003bd0c1f940543739 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/HCoverageTest.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class HCoverageTest extends AbstractCoverageTest { + + public HCoverageTest () { + super("H"); + } + + @Test + public void testSpec () { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "26", "6", "0")); + + // No 'general' errors recorded + assertFalse(recorder.recorded(EC.GENERAL)); + + assertCoverage("<Inv line 22, col 1 to line 22, col 3 of module H>: 1:31\n" + + " line 22, col 11 to line 22, col 16 of module H: 1\n" + + " line 23, col 11 to line 23, col 15 of module H: 31\n" + + "<A line 11, col 1 to line 11, col 1 of module H>: 1:6\n" + + " line 11, col 6 to line 11, col 12 of module H: 6\n" + + "<BandC line 13, col 1 to line 13, col 5 of module H (13 13 14 28)>: 2:15\n" + + " line 13, col 16 to line 13, col 26 of module H: 11\n" + + " |line 13, col 16 to line 13, col 16 of module H: 6\n" + + " |line 13, col 22 to line 13, col 26 of module H: 6\n" + + " line 14, col 16 to line 14, col 28 of module H: 15\n" + + " |line 14, col 23 to line 14, col 28 of module H: 5\n" + + "<BandC line 13, col 1 to line 13, col 5 of module H (15 13 16 22)>: 1:3\n" + + " line 15, col 16 to line 15, col 21 of module H: 3\n" + + " |line 15, col 16 to line 15, col 16 of module H: 6\n" + + " line 16, col 16 to line 16, col 22 of module H: 3\n" + + "<DandE line 18, col 1 to line 18, col 5 of module H (18 11 18 27)>: 1:1\n" + + " line 18, col 11 to line 18, col 16 of module H: 7\n" + + " |line 18, col 11 to line 18, col 11 of module H: 6\n" + + " line 18, col 21 to line 18, col 27 of module H: 1\n" + + "<DandE line 18, col 1 to line 18, col 5 of module H (18 34 18 53)>: 0:0\n" + + " line 18, col 34 to line 18, col 40 of module H: 6\n" + + " line 18, col 45 to line 18, col 53 of module H: 0"); + assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH)); + } +} diff --git a/tlatools/test/tlc2/tool/coverage/OpApplNodeWrapperTest.java b/tlatools/test/tlc2/tool/coverage/OpApplNodeWrapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..29b6f3ff8fe6b785bb704c4b64e341a3ca27b956 --- /dev/null +++ b/tlatools/test/tlc2/tool/coverage/OpApplNodeWrapperTest.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.coverage; + +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import tla2sany.parser.SyntaxTreeNode; +import tla2sany.semantic.AbortException; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.SymbolNode; +import tla2sany.xml.SymbolContext; +import tlc2.TLCGlobals; +import util.TestPrintStream; +import util.ToolIO; +import util.UniqueString; + +public class OpApplNodeWrapperTest { + + @Before + public void setup() { + TLCGlobals.coverageInterval = 1; + ToolIO.out = new TestPrintStream(); + } + + @Test + public void testReportCoverage01() { + final OpApplNodeWrapper root = new OpApplNodeWrapper(); + root.report(); + ((TestPrintStream) ToolIO.out).assertEmpty(); + + root.addChild(new OpApplNodeWrapper()); + } + + @Test + public void testReportCoverage02() { + final OpApplNodeWrapper root = new OpApplNodeWrapper(); + root.incInvocations(42); + + root.addChild(getNode(23)); + root.addChild(getNode(24)); + root.addChild(getNode(0)); // Not reported + + root.report(); + ((TestPrintStream) ToolIO.out) + .assertContains(" Unknown location: 42\n" + + " |In module --TLA+ BUILTINS--: 23\n" + + " |In module --TLA+ BUILTINS--: 24"); + } + + @Test + public void testReportCoverage03() { + final OpApplNodeWrapper root = new OpApplNodeWrapper(); + root.incInvocations(42); + + OpApplNodeWrapper childA = getNode(23); + childA.addChild(getNode(546)); + root.addChild(childA); + + OpApplNodeWrapper childB = getNode(24); + root.addChild(childB); + childB.addChild(getNode(0)); // Not reported because 0 + + OpApplNodeWrapper childC = getNode(0); + root.addChild(childC); // Not reported + + childC.addChild(getNode(17)); // Must be reported despite C being 0 + + root.report(); + ((TestPrintStream) ToolIO.out) + .assertContains(" Unknown location: 42\n" + + " |In module --TLA+ BUILTINS--: 23\n" + + " ||In module --TLA+ BUILTINS--: 546\n" + + " |In module --TLA+ BUILTINS--: 24\n" + + " |In module --TLA+ BUILTINS--: 17"); + } + + /* + line 8, col 12 to line 8, col 21 of module A: 1 + |line 5, col 11 to line 5, col 49 of module A: 1 + ||line 5, col 31 to line 5, col 49 of module A: 131072 + ||line 5, col 20 to line 5, col 27 of module A: 131072 + |||line 5, col 27 to line 5, col 27 of module A: 1 + |line 8, col 16 to line 8, col 20 of module A: 1 + */ + @Test + public void testReportCoverage04() { + final OpApplNodeWrapper root = new OpApplNodeWrapper(); + root.incInvocations(1); + + OpApplNodeWrapper childA = getNode(1); + root.addChild(childA); + + childA.addChild(getNode(131072)); + + OpApplNodeWrapper cChildA = getNode(131072); + childA.addChild(cChildA); + + cChildA.addChild(getNode(1)); + + OpApplNodeWrapper childB = getNode(1); + root.addChild(childB); + + root.report(); + ((TestPrintStream) ToolIO.out) + .assertContains(" Unknown location: 1\n" + + " |In module --TLA+ BUILTINS--: 1\n" + + " ||In module --TLA+ BUILTINS--: 131072\n" + + " ||In module --TLA+ BUILTINS--: 131072\n" + + " |||In module --TLA+ BUILTINS--: 1\n" + + " |In module --TLA+ BUILTINS--: 1"); + } + + // It is dummies all the way down... + + private OpApplNodeWrapper getNode(long count) { + final SymbolNode sn = new DummySymbolNode(Long.toString(count)); + final OpApplNode node = new DummyOpApplNode(sn); + return new OpApplNodeWrapper(node, count); + } + + private static class DummySymbolNode extends SymbolNode { + + protected DummySymbolNode(String name) { + super(1, SyntaxTreeNode.nullSTN, UniqueString.uniqueStringOf(name)); + } + + @Override + public int getArity() { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean isLocal() { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean match(OpApplNode test, ModuleNode mn) throws AbortException { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + protected Element getSymbolElement(Document doc, SymbolContext context) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + protected String getNodeRef() { + throw new UnsupportedOperationException("not implemented"); + } + + } + + private static class DummyOpApplNode extends OpApplNode { + + public DummyOpApplNode(SymbolNode sn) { + super(sn); + } + } +} diff --git a/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantContinueTest.java b/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantContinueTest.java index 751b7894dd876dc12b0c497aa2278d7679ff28fc..b2af922ee3c6544c9c695b1356e937a0d2322d07 100644 --- a/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantContinueTest.java +++ b/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantContinueTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; @@ -46,5 +47,7 @@ public class DistributedDoInitFunctorInvariantContinueTest extends ModelCheckerT assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "NotNine", "x = 9\n")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantTest.java b/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantTest.java index cc29b649e7d0be8fb50e6f4e040f0ad038bd91dd..da25cffc787b1917441045450700c4432b7c1bae 100644 --- a/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantTest.java +++ b/tlatools/test/tlc2/tool/distributed/DistributedDoInitFunctorInvariantTest.java @@ -30,13 +30,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DistributedDoInitFunctorInvariantTest extends ModelCheckerTestCase { public DistributedDoInitFunctorInvariantTest() { - super("DoInitFunctorInvariant", "DoInitFunctor"); + super("DoInitFunctorInvariant", "DoInitFunctor", ExitStatus.VIOLATION_SAFETY); } @Test diff --git a/tlatools/test/tlc2/tool/distributed/TLCServerTestCase.java b/tlatools/test/tlc2/tool/distributed/TLCServerTestCase.java index ff9f53e1efd6bb239ca2e38330a261882b7ba7d4..c714c36cdd0f5d6bb817ec607dd1d2d791cf7f75 100644 --- a/tlatools/test/tlc2/tool/distributed/TLCServerTestCase.java +++ b/tlatools/test/tlc2/tool/distributed/TLCServerTestCase.java @@ -33,13 +33,17 @@ import java.io.IOException; import java.rmi.RemoteException; import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; import tlc2.TLCGlobals; import tlc2.output.MP; import tlc2.tool.fp.FPSetConfiguration; import tlc2.tool.fp.MSBDiskFPSet; import tlc2.tool.liveness.ModelCheckerTestCase; +import util.ToolIO; +@RunWith(BlockJUnit4ClassRunner.class) public abstract class TLCServerTestCase extends ModelCheckerTestCase { public TLCServerTestCase(String spec) { @@ -64,9 +68,12 @@ public abstract class TLCServerTestCase extends ModelCheckerTestCase { final String fqSpec = BASE_DIR + TEST_MODEL + path + File.separator + spec; final FPSetConfiguration fpSetConfig = new DummyFPSetConfig(); - final TLCApp app = new TLCApp(fqSpec, fqSpec, false, null, fpSetConfig); + ToolIO.setUserDir(BASE_DIR + File.separator + TEST_MODEL + path + File.separator); + final TLCApp app = new TLCApp(fqSpec, spec, false, null, fpSetConfig); final TLCServer server = new TLCServer(app); server.modelCheck(); + //TODO Implement exit status for distributed TLC + actualExitStatus = 0; } catch (Exception e) { fail(e.getMessage()); } diff --git a/tlatools/test/tlc2/tool/distributed/TLCWorkerSmartProxyTest.java b/tlatools/test/tlc2/tool/distributed/TLCWorkerSmartProxyTest.java index 5f5ead665bdb795b09bb5c3b7006798a66fed279..6c0e2564ebb40799bd77b9702841a73ced8738bd 100644 --- a/tlatools/test/tlc2/tool/distributed/TLCWorkerSmartProxyTest.java +++ b/tlatools/test/tlc2/tool/distributed/TLCWorkerSmartProxyTest.java @@ -4,7 +4,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.rmi.RemoteException; + import org.junit.Test; + import tlc2.tool.TLCState; import tlc2.tool.WorkerException; import tlc2.tool.distributed.selector.DummyTLCWorker; diff --git a/tlatools/test/tlc2/tool/distributed/fp/DynamicFPSetManagerTest.java b/tlatools/test/tlc2/tool/distributed/fp/DynamicFPSetManagerTest.java index caf20ee613ea6dd08df8d7f6cd8073590f434797..860ea3cef22b040a6fe29e34dd955e7c7c5d5908 100644 --- a/tlatools/test/tlc2/tool/distributed/fp/DynamicFPSetManagerTest.java +++ b/tlatools/test/tlc2/tool/distributed/fp/DynamicFPSetManagerTest.java @@ -14,7 +14,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; + import org.junit.Test; + import tlc2.tool.fp.FPSet; import tlc2.tool.fp.MemFPSet; import tlc2.util.BitVector; diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java index d351c5dde8382f31d3ce256096e021bb21251192..71d6b10c37d507cf16c12c16ae256a859b069816 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java @@ -30,13 +30,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorEvalExceptionTest extends ModelCheckerTestCase { public DoInitFunctorEvalExceptionTest() { - super("DoInitFunctorEvalException", "DoInitFunctor"); + super("DoInitFunctorEvalException", "DoInitFunctor", ExitStatus.FAILURE_SPEC_EVAL); } @Test @@ -48,5 +50,7 @@ public class DoInitFunctorEvalExceptionTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_INITIAL_STATE, "TLC expected a boolean value, but did not find one. line 15, col 15 to line 15, col 18 of module DoInitFunctorEvalException", "x = 1\n")); + + assertUncovered("line 9, col 9 to line 9, col 14 of module DoInitFunctorEvalException: 0"); } } diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java index 2f9d01e63e29882f9b40389fc90b2ef987e14beb..a68ee5cd21eaaa7cda6aa049981c7c3cc7ee3ce6 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java @@ -33,13 +33,14 @@ import static org.junit.Assert.assertTrue; import java.util.List; import org.junit.Test; + import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorInvariantContinueTest extends ModelCheckerTestCase { public DoInitFunctorInvariantContinueTest() { - super("DoInitFunctorInvariantContinue", "DoInitFunctor", new String[] {"-continue"}); + super("DoInitFunctorInvariantContinue", "DoInitFunctor", new String[] {"-continue"}/*, ExitStatus.VIOLATION_SAFETY*/); //TODO The exit status is incorrect because TLC shows "no error" regardless of the number of violations with "-continue" } @Test @@ -57,5 +58,7 @@ public class DoInitFunctorInvariantContinueTest extends ModelCheckerTestCase { assertEquals("Inv", violation[0]); assertEquals("x = " + (j+1) + "\n", violation[1]); } + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java index 80bf8a24000a1d6cfe18d95eff9eee20c09ecfa7..497dbbc4d6fdd5be04affefc435419e8d60c36e5 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java @@ -25,35 +25,34 @@ ******************************************************************************/ package tlc2.tool.doinitfunctor; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorInvariantMinimalErrorStackTest extends ModelCheckerTestCase { public DoInitFunctorInvariantMinimalErrorStackTest() { - super("DoInitFunctorMinimalErrorStack", "DoInitFunctor"); + super("DoInitFunctorMinimalErrorStack", "DoInitFunctor", ExitStatus.FAILURE_SPEC_EVAL); } @Test public void testSpec() { assertTrue(recorder.recorded(EC.TLC_FINISHED)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "2", "2")); - assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1", "1", "1")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, - "public static tlc2.value.BoolValue tlc2.module.Naturals.GEQ(tlc2.value.Value,tlc2.value.Value)", - "The first argument of > should be an integer, but instead it is:\n" + - "<<1, 1>>")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_ARGUMENT_ERROR_AN, + "first", ">", "integer", "<<1, 1>>")); String errorStack = "0. Line 8, column 3 to line 9, column 13 in DoInitFunctorMinimalErrorStack\n" + "1. Line 8, column 6 to line 8, column 25 in DoInitFunctorMinimalErrorStack\n" + "2. Line 9, column 6 to line 9, column 13 in DoInitFunctorMinimalErrorStack\n" + "3. Line 14, column 8 to line 14, column 13 in DoInitFunctorMinimalErrorStack\n\n"; assertTrue(recorder.recordedWithStringValue(EC.TLC_NESTED_EXPRESSION, errorStack)); + + assertUncovered("line 11, col 20 to line 11, col 33 of module DoInitFunctorMinimalErrorStack: 0"); } } diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java index 899ca79cba008ba08832de8f3a1d5a087ce78748..c93e93ab0b51c519161d0204b1740c9190932b80 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java @@ -32,12 +32,13 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorInvariantNoContinueTest extends ModelCheckerTestCase { public DoInitFunctorInvariantNoContinueTest() { - super("DoInitFunctorInvariantContinue", "DoInitFunctor"); + super("DoInitFunctorInvariantContinue", "DoInitFunctor", ExitStatus.VIOLATION_SAFETY); } @Test diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java index 2f92e1b1925738cf80d40faecef0c829ccd3c12e..06a7e815fc5af4d2c49a59e1e7059991fa787bd5 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java @@ -31,13 +31,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorInvariantTest extends ModelCheckerTestCase { public DoInitFunctorInvariantTest() { - super("DoInitFunctorInvariant", "DoInitFunctor"); + super("DoInitFunctorInvariant", "DoInitFunctor", ExitStatus.VIOLATION_SAFETY); } @Test diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java index 37a8637a2092a0698456e3220833d1d1ae5a95c1..d6133b07900ddcb2eead9cfbc83b9410a662a073 100644 --- a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java @@ -30,13 +30,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorPropertyTest extends ModelCheckerTestCase { public DoInitFunctorPropertyTest() { - super("DoInitFunctorProperty", "DoInitFunctor"); + super("DoInitFunctorProperty", "DoInitFunctor", ExitStatus.VIOLATION_LIVENESS); } @Test diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrder1Test.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..40a246a50aecfbe6da630e1331642c54b93623b4 --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder1Test.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +public class InitEvalOrder1Test extends InitEvalOrderTest { + + public InitEvalOrder1Test() { + super("InitEvalOrder1.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrder2Test.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..3e29ed4d47486714557136eb77ca6163781530c1 --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder2Test.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +public class InitEvalOrder2Test extends InitEvalOrderTest { + + public InitEvalOrder2Test() { + super("InitEvalOrder2.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrder3Test.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder3Test.java new file mode 100644 index 0000000000000000000000000000000000000000..011bc55d58f001f3395839917f779584f6c3678d --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder3Test.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +public class InitEvalOrder3Test extends InitEvalOrderTest { + + public InitEvalOrder3Test() { + super("InitEvalOrder3.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrder4Test.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder4Test.java new file mode 100644 index 0000000000000000000000000000000000000000..969fb147a5264c3ac821fa9097da5e381e539b37 --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrder4Test.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +public class InitEvalOrder4Test extends InitEvalOrderTest { + + public InitEvalOrder4Test() { + super("InitEvalOrder4.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrderBasicTest.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrderBasicTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4e942b61465700843427a280397637a8456c2f30 --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrderBasicTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class InitEvalOrderBasicTest extends ModelCheckerTestCase { + + public InitEvalOrderBasicTest() { + super("InitEvalOrderBasic", "EvalOrder"); + } + + @Test + public void test() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + + assertZeroUncovered(); + } +} diff --git a/tlatools/test/tlc2/tool/evalorder/InitEvalOrderTest.java b/tlatools/test/tlc2/tool/evalorder/InitEvalOrderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f50d2109880c9d4c6096efcd47acc1e517157e9a --- /dev/null +++ b/tlatools/test/tlc2/tool/evalorder/InitEvalOrderTest.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.evalorder; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public abstract class InitEvalOrderTest extends ModelCheckerTestCase { + + public InitEvalOrderTest(String config) { + super("InitEvalOrder", "EvalOrder", new String[] {"-config", config}); + } + + @Test + public void test() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + } +} diff --git a/tlatools/test/tlc2/tool/fp/AbstractFPSetTest.java b/tlatools/test/tlc2/tool/fp/AbstractFPSetTest.java index 832e61dfb2532ea502aa4d19d06c919deab8d7c9..fc0864fd1652de90f3404df6d412a52ac277dd17 100644 --- a/tlatools/test/tlc2/tool/fp/AbstractFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/AbstractFPSetTest.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.text.DecimalFormat; import java.util.Date; + import org.junit.After; import org.junit.Before; diff --git a/tlatools/test/tlc2/tool/fp/AbstractHeapBasedDiskFPSetTest.java b/tlatools/test/tlc2/tool/fp/AbstractHeapBasedDiskFPSetTest.java index 8342c7b06c53bfff9e8ef16696b330a309164ffb..dc16b7db2e83ea897c2496027b4ce65011ed451f 100644 --- a/tlatools/test/tlc2/tool/fp/AbstractHeapBasedDiskFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/AbstractHeapBasedDiskFPSetTest.java @@ -109,7 +109,7 @@ public abstract class AbstractHeapBasedDiskFPSetTest { // Create a DiskFPSet final DiskFPSet fpSet = getDiskFPSet(new FPSetConfiguration()); fpSet.init(1, metadir, filename); - fpSet.recover(); + fpSet.recover(trace); // Verify successful recovery assertEquals(limit-1, fpSet.size()); diff --git a/tlatools/test/tlc2/tool/fp/Bug210DiskFPSetTest.java b/tlatools/test/tlc2/tool/fp/Bug210DiskFPSetTest.java index c193aca1289b92076d44ce10619d9d10875d432c..ed22315a6bc97c30531fed3e26ad6fe1dfde51a4 100644 --- a/tlatools/test/tlc2/tool/fp/Bug210DiskFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/Bug210DiskFPSetTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import java.io.IOException; + import org.junit.Test; public class Bug210DiskFPSetTest extends AbstractFPSetTest { diff --git a/tlatools/test/tlc2/tool/fp/Bug242DiskFPSetTest.java b/tlatools/test/tlc2/tool/fp/Bug242DiskFPSetTest.java index b740e9992c38cc6da9ca531006e378863907ddf6..71df2e53717d5244ee5ff03b4841c5ac4186f3ef 100644 --- a/tlatools/test/tlc2/tool/fp/Bug242DiskFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/Bug242DiskFPSetTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.rmi.RemoteException; + import org.junit.Test; /** diff --git a/tlatools/test/tlc2/tool/fp/Bug246DiskFPSetTest.java b/tlatools/test/tlc2/tool/fp/Bug246DiskFPSetTest.java index 92f221cf9ff078aec013b557c306e932f7c717a6..341fb5a7ccc99ce568b06661331c0319aa3e192b 100644 --- a/tlatools/test/tlc2/tool/fp/Bug246DiskFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/Bug246DiskFPSetTest.java @@ -7,7 +7,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; + import org.junit.Test; + import util.TLCRuntime; /** diff --git a/tlatools/test/tlc2/tool/fp/LongArrayTest.java b/tlatools/test/tlc2/tool/fp/LongArrayTest.java index 98ef627e9078ca64f824272d8bff9bd73d6fa273..a697289756087f1b88734efd197fe9627e24a9a1 100644 --- a/tlatools/test/tlc2/tool/fp/LongArrayTest.java +++ b/tlatools/test/tlc2/tool/fp/LongArrayTest.java @@ -30,6 +30,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; import org.junit.Assume; import org.junit.Before; @@ -49,7 +53,7 @@ public class LongArrayTest { final int elements = 100; final LongArray array = new LongArray(elements); - array.zeroMemory(1); + array.zeroMemory(); for (long i = 0L; i < elements; i++) { assertEquals(0L, array.get(i)); @@ -107,7 +111,7 @@ public class LongArrayTest { final int elements = 100; final LongArray array = new LongArray(elements); - array.zeroMemory(1); + array.zeroMemory(); // Assert zero successful for (long i = 0L; i < elements; i++) { @@ -155,4 +159,54 @@ public class LongArrayTest { } } } + + @Test + public void testSwap() throws IOException { + final int elements = 10321; + + final LongArray array = new LongArray(elements); + array.zeroMemory(); + + for (long i = 0L; i < elements; i++) { + long value = Long.MAX_VALUE - i; + array.set(i, value); + } + + for (int i = 0; i < (elements / 2); i++) { + array.swapCopy(i, (elements - 1) - i); + } + + for (long i = 0L; i < elements; i++) { + assertEquals(Long.MAX_VALUE - (elements -1) + i, array.get(i)); + } + } + + @Test + public void testSwapRandom() throws IOException { + final int elements = 21383; + + final List<Long> vals = new ArrayList<Long>(); + final Random rnd = new Random(); + + for (int i = 0; i < elements; i++) { + vals.add(rnd.nextLong()); + } + + final LongArray array = new LongArray(elements); + array.zeroMemory(); + + for (int i = 0; i < elements; i++) { + array.set(i, vals.get(i)); + } + + for (int i = 0; i < (elements / 2); i++) { + array.swapCopy(i, (elements - 1) - i); + } + + Collections.reverse(vals); + + for (int i = 0; i < elements; i++) { + assertEquals((long) vals.get(i), array.get(i)); + } + } } diff --git a/tlatools/test/tlc2/tool/fp/LongArraysTest.java b/tlatools/test/tlc2/tool/fp/LongArraysTest.java index 9fce0cb921e2c56079135064c63650b63adfb0fe..9713ff757e698b1965a524934c0cad33acb0bda0 100644 --- a/tlatools/test/tlc2/tool/fp/LongArraysTest.java +++ b/tlatools/test/tlc2/tool/fp/LongArraysTest.java @@ -16,7 +16,6 @@ import org.junit.Test; import tlc2.tool.fp.LongArrays.LongComparator; import tlc2.tool.fp.OffHeapDiskFPSet.Indexer; -import util.TLCRuntime; public class LongArraysTest { diff --git a/tlatools/test/tlc2/tool/fp/MSBDiskFPSetTest2.java b/tlatools/test/tlc2/tool/fp/MSBDiskFPSetTest2.java index 35f596756175f9e4e555aa9135379d900d7f5db6..ad9daec5719ec4182332b68f91626f695ac0d237 100644 --- a/tlatools/test/tlc2/tool/fp/MSBDiskFPSetTest2.java +++ b/tlatools/test/tlc2/tool/fp/MSBDiskFPSetTest2.java @@ -9,7 +9,9 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.rmi.RemoteException; import java.util.NoSuchElementException; + import org.junit.Test; + import tlc2.tool.fp.MSBDiskFPSet.TLCIterator; public class MSBDiskFPSetTest2 extends AbstractHeapBasedDiskFPSetTest { diff --git a/tlatools/test/tlc2/tool/fp/OffHeapIteratorTest.java b/tlatools/test/tlc2/tool/fp/OffHeapIteratorTest.java index 83f6ff0e2a06a9e118345078c72a7a6e9c03072d..e2e68d96e9ba38ec270eff8ec1765704ff19ddc5 100644 --- a/tlatools/test/tlc2/tool/fp/OffHeapIteratorTest.java +++ b/tlatools/test/tlc2/tool/fp/OffHeapIteratorTest.java @@ -7,7 +7,6 @@ import org.junit.Before; import org.junit.Test; import tlc2.tool.fp.OffHeapDiskFPSet.Iterator; -import util.TLCRuntime; public class OffHeapIteratorTest { diff --git a/tlatools/test/tlc2/tool/fp/ShortDiskFPSetTest.java b/tlatools/test/tlc2/tool/fp/ShortDiskFPSetTest.java index aab3e2b70ce1fd8904e0722bcf85f7bfc65fe713..cfd4d3fa09bfd9ebf768156272bd4fe4ce716b22 100644 --- a/tlatools/test/tlc2/tool/fp/ShortDiskFPSetTest.java +++ b/tlatools/test/tlc2/tool/fp/ShortDiskFPSetTest.java @@ -10,7 +10,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; + import org.junit.Test; + import tlc2.util.LongVec; public class ShortDiskFPSetTest extends AbstractFPSetTest { diff --git a/tlatools/test/tlc2/tool/fp/iterator/TLCIteratorTest.java b/tlatools/test/tlc2/tool/fp/iterator/TLCIteratorTest.java index 388222b1a5d444427bd29272e92cafb0b9e4b6d7..7b79f655b62b0c605b1fcf3c04653cf97ac8dd28 100644 --- a/tlatools/test/tlc2/tool/fp/iterator/TLCIteratorTest.java +++ b/tlatools/test/tlc2/tool/fp/iterator/TLCIteratorTest.java @@ -8,8 +8,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.NoSuchElementException; + import org.junit.Before; import org.junit.Test; + import tlc2.tool.fp.MSBDiskFPSet; public class TLCIteratorTest { diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d318270f571745d5f318f5fa53c71a54b92ceefc --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; + +public abstract class BidirectionalTransitions1BTest extends ModelCheckerTestCase { + + public BidirectionalTransitions1BTest(final String config) { + super("BidirectionalTransitions", new String[] {"-config", config}, ExitStatus.VIOLATION_LIVENESS); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "3", "0")); + + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(3); + expectedTrace.add("x = 0"); + expectedTrace.add("x = 2"); + expectedTrace.add("x = 1"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertBackToState(1); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BxTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BxTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f723b7000bb15fc41b8bad6df7d9b31e56cbc6d6 --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1BxTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +public class BidirectionalTransitions1BxTest extends BidirectionalTransitions1BTest { + + public BidirectionalTransitions1BxTest() { + super("BidirectionalTransitions1Bx.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1ByTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1ByTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2ac3fb7c4262a0a4cedb8d0a5c9bcc3df1400979 --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1ByTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +public class BidirectionalTransitions1ByTest extends BidirectionalTransitions1BTest { + + public BidirectionalTransitions1ByTest() { + super("BidirectionalTransitions1By.cfg"); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/Test063.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1Test.java similarity index 81% rename from tlatools/test/tlc2/tool/liveness/Test063.java rename to tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1Test.java index 4a34dc101240d0014150372ede7260d44fcf010d..67b2717e6bb9a084b8e3fa68063e28106c5f963a 100644 --- a/tlatools/test/tlc2/tool/liveness/Test063.java +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions1Test.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. + * Copyright (c) 2018 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -23,28 +23,28 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ - package tlc2.tool.liveness; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; -public class Test063 extends ModelCheckerTestCase { +public class BidirectionalTransitions1Test extends ModelCheckerTestCase { - public Test063() { - super("test63"); + public BidirectionalTransitions1Test() { + super("BidirectionalTransitions", new String[] {"-config", "BidirectionalTransitions1.cfg"}); } - + @Test public void testSpec() { - // ModelChecker has finished and generated the expected amount of states assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "3", "0")); assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "72")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "696", "216", "0")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6879a0c45624f5fd9d6ff1141c4b080e7592848d --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CTest.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; + +public abstract class BidirectionalTransitions2CTest extends ModelCheckerTestCase { + + public BidirectionalTransitions2CTest(final String config) { + super("BidirectionalTransitions", new String[] { "-config", config }, ExitStatus.VIOLATION_LIVENESS); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "4", "0")); + + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(3); + expectedTrace.add("x = 0"); + expectedTrace.add("x = 1"); + expectedTrace.add("x = 2"); + expectedTrace.add("x = 3"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + assertBackToState(1); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CxTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CxTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7475a9b6ea72b257b80afa6c73130ee9c336a3cd --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CxTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +public class BidirectionalTransitions2CxTest extends BidirectionalTransitions2CTest { + + public BidirectionalTransitions2CxTest() { + super("BidirectionalTransitions2Cx"); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CyTest.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e120364ce1bea66be87ca34a8063b68e91393b0a --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2CyTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +public class BidirectionalTransitions2CyTest extends BidirectionalTransitions2CTest { + + public BidirectionalTransitions2CyTest() { + super("BidirectionalTransitions2Cy"); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/Test059.java b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2Test.java similarity index 81% rename from tlatools/test/tlc2/tool/liveness/Test059.java rename to tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2Test.java index 6d8fb81bd3da3ae6879a7c45e6775f7a0be73066..e72686cf17f294df8c8bedc3a249a55705734bdf 100644 --- a/tlatools/test/tlc2/tool/liveness/Test059.java +++ b/tlatools/test/tlc2/tool/liveness/BidirectionalTransitions2Test.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. + * Copyright (c) 2018 Microsoft Research. All rights reserved. * * The MIT License (MIT) * @@ -23,28 +23,28 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ - package tlc2.tool.liveness; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; -public class Test059 extends ModelCheckerTestCase { +public class BidirectionalTransitions2Test extends ModelCheckerTestCase { - public Test059() { - super("test59"); + public BidirectionalTransitions2Test() { + super("BidirectionalTransitions", new String[] {"-config", "BidirectionalTransitions2.cfg"}); } @Test public void testSpec() { - // ModelChecker has finished and generated the expected amount of states assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "5")); - assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6", "5", "0")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "4", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTest.java b/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTest.java index d5c9e70b984438faa40d150fa4a287a9e4c5d119..4cd7caa5a655c0c2f7071b0e918855e25cec985f 100644 --- a/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTest.java +++ b/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTest.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class ChooseTableauSymmetryTest extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTestA.java b/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTestA.java index b3a2fdd1e057f2b167943490d79051e5b28a78e0..13198ab605c01fff06a9ce0542acd157c4219220 100644 --- a/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTestA.java +++ b/tlatools/test/tlc2/tool/liveness/ChooseTableauSymmetryTestA.java @@ -31,13 +31,16 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ChooseTableauSymmetryTestA extends ModelCheckerTestCase { public ChooseTableauSymmetryTestA() { - super("ChooseTableauSymmetryMCa", "symmetry"); + super("ChooseTableauSymmetryMCa", "symmetry", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -62,5 +65,7 @@ public class ChooseTableauSymmetryTestA extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(3, "<Ready line 7, col 13 to line 8, col 47 of module ChooseTableauSymmetry>"); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08AgentRingTest.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08AgentRingTest.java index bcf6e3d272753f95334669356e929b24453c813c..a4d22559a1f8886d4feff0e96b74bc7d17412490 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08AgentRingTest.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08AgentRingTest.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08AgentRingTest extends ModelCheckerTestCase { public CodePlexBug08AgentRingTest() { - super("AgentRingMC", "CodePlexBug08"); + super("AgentRingMC", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -106,5 +109,7 @@ public class CodePlexBug08AgentRingTest extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(10); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL1Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL1Test.java index 8d4a2ed62ed84c90ab3f37087c8f87298079ca8f..814dc1d96c20846863cd60240e83182ab0a0e029 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL1Test.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL1Test.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08EWD840FL1Test extends ModelCheckerTestCase { public CodePlexBug08EWD840FL1Test() { - super("EWD840MC1", "CodePlexBug08"); + super("EWD840MC1", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -102,5 +105,7 @@ public class CodePlexBug08EWD840FL1Test extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(1); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java index e09084076ba6838cf97160d4b3a495ebea23255d..3af646ba5360d97194ec8577bbe43e01c7f2eb05 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java @@ -42,6 +42,7 @@ import java.util.zip.ZipFile; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -49,13 +50,22 @@ import tlc2.output.EC; public class CodePlexBug08EWD840FL2FromCheckpointTest extends ModelCheckerTestCase { public CodePlexBug08EWD840FL2FromCheckpointTest() { - super("EWD840MC2", "CodePlexBug08", new String[] {"-gzip", "-recover", BASE_DIR + TEST_MODEL + "CodePlexBug08" + File.separator + "checkpoint"}); + super("EWD840MC2", "CodePlexBug08", new String[] {"-gzip", "-recover", BASE_DIR + TEST_MODEL + "CodePlexBug08" + File.separator + "checkpoint"}, ExitStatus.VIOLATION_LIVENESS); } @Override public void setUp() { try { + /* Recreate checkpoint.zip whenever file format changes: + * + * 1) Run CodePlexBug08EWD840FL2Test with "-gzip" + * 2) Connect to running test via JMX and request TLC checkpoint to be taken + * 3) Terminate CodePlexBug08EWD840FL2Test once checkpoint successfully taken + * 4) Locate the directory with the checkpoint data + * 5) Replace the content of checkpoint.zip with the content of 4) + * 6) Update the number below on states found... + */ String prefix = BASE_DIR + TEST_MODEL + "CodePlexBug08" + File.separator; ZipFile zipFile = new ZipFile(prefix + "checkpoint.zip"); Enumeration<?> enu = zipFile.entries(); @@ -95,17 +105,17 @@ public class CodePlexBug08EWD840FL2FromCheckpointTest extends ModelCheckerTestCa public void testSpec() { assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_RECOVER_START)); // Recovery completed. 1032 states examined. 996 states on queue. - assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKPOINT_RECOVER_END, "1028", "1013")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKPOINT_RECOVER_END, "1510", "39")); // ModelChecker has finished and generated the expected amount of states assertTrue(recorder.recorded(EC.TLC_FINISHED)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15961", "1566","0")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2334", "1566","0")); assertFalse(recorder.recorded(EC.GENERAL)); // Assert it has found the temporal violation and also a counter example assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); - assertNodeAndPtrSizes(54037212L, 831296L); + assertNodeAndPtrSizes(54038132L, 831296L); // Assert the error trace assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); @@ -155,4 +165,12 @@ public class CodePlexBug08EWD840FL2FromCheckpointTest extends ModelCheckerTestCa // last state points back to state 1 assertBackToState(1); } + + + @Override + protected int getNumberOfThreads() { + return 3; + } + + } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2Test.java index 2a57e3311e27088f4e8f209a9b413916d920854e..d81be0bbfc73c0b8589dc61991156983cd13f989 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2Test.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2Test.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08EWD840FL2Test extends ModelCheckerTestCase { public CodePlexBug08EWD840FL2Test() { - super("EWD840MC2", "CodePlexBug08"); + super("EWD840MC2", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL3Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL3Test.java index 36ef06dac38a083beb81ad9a6784f1853341ea96..9181588a17ff35d7fd00ae31a79147898d420953 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL3Test.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL3Test.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08EWD840FL3Test extends ModelCheckerTestCase { public CodePlexBug08EWD840FL3Test() { - super("EWD840MC3", "CodePlexBug08"); + super("EWD840MC3", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -95,5 +98,7 @@ public class CodePlexBug08EWD840FL3Test extends ModelCheckerTestCase { // last state loops back to state 1 assertBackToState(1); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL4Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL4Test.java index a011674c4f28875887dca87acfdcf6ea355ed046..94a18f4f9e5e696f4fe02fb5a65ffa3074f44c33 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL4Test.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL4Test.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08EWD840FL4Test extends ModelCheckerTestCase { public CodePlexBug08EWD840FL4Test() { - super("EWD840MC4", "CodePlexBug08"); + super("EWD840MC4", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -71,5 +74,7 @@ public class CodePlexBug08EWD840FL4Test extends ModelCheckerTestCase { // state 3 is stuttering assertStuttering(3); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java index 4a34df33f3d03bf26e1efa8edea6f7beaa1a3cae..c27b3d0647cde8feda1e3b86a77a9ce07f7bbbd6 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08Test extends ModelCheckerTestCase { public CodePlexBug08Test() { - super("MC", "CodePlexBug08"); + super("MC", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -68,5 +71,7 @@ public class CodePlexBug08Test extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertStuttering(7); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08aTest.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08aTest.java index 930a2f7d4dfd8bafa62f0a4394451ef002958cfe..da9653beb6618bafa8e1eb9793e54b7647555d57 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08aTest.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08aTest.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * see http://tlaplus.codeplex.com/workitem/8 @@ -40,7 +43,7 @@ import tlc2.output.EC; public class CodePlexBug08aTest extends ModelCheckerTestCase { public CodePlexBug08aTest() { - super("MCa", "CodePlexBug08"); + super("MCa", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -71,5 +74,7 @@ public class CodePlexBug08aTest extends ModelCheckerTestCase { // Assert the error trace contains a stuttering step at position 5 assertStuttering(9); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/EmptyOrderOfSolutionsTest.java b/tlatools/test/tlc2/tool/liveness/EmptyOrderOfSolutionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a336a1d3c846f4936f8ac34636c7fd298935c29d --- /dev/null +++ b/tlatools/test/tlc2/tool/liveness/EmptyOrderOfSolutionsTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.liveness; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; + +public class EmptyOrderOfSolutionsTest extends ModelCheckerTestCase { + + public EmptyOrderOfSolutionsTest() { + super("EmptyOrderOfSolutions", ExitStatus.FAILURE_LIVENESS_EVAL); + } + + @Test + public void testSpec() throws IOException { + assertTrue(recorder.recorded(EC.TLC_LIVE_FORMULA_TAUTOLOGY)); + } +} diff --git a/tlatools/test/tlc2/tool/liveness/ErrorTraceConstructionTest.java b/tlatools/test/tlc2/tool/liveness/ErrorTraceConstructionTest.java index abd430a752ddc873036e3f63f948c2a865f5a3fe..088864085c1ab0e6e1770608d46ec3b5afa0be86 100644 --- a/tlatools/test/tlc2/tool/liveness/ErrorTraceConstructionTest.java +++ b/tlatools/test/tlc2/tool/liveness/ErrorTraceConstructionTest.java @@ -31,13 +31,16 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ErrorTraceConstructionTest extends ModelCheckerTestCase { public ErrorTraceConstructionTest() { - super("ErrorTraceConstructionMC", "symmetry"); + super("ErrorTraceConstructionMC", "symmetry", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -67,5 +70,7 @@ public class ErrorTraceConstructionTest extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(4, "<N7 line 32, col 7 to line 34, col 19 of module ErrorTraceConstruction>"); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/GraphNodeTest.java b/tlatools/test/tlc2/tool/liveness/GraphNodeTest.java index 697d4208ddb488258c734e556be1a95f9e8d0d3d..ccd827982cb68113ca6026035c68e85819dc4a87 100644 --- a/tlatools/test/tlc2/tool/liveness/GraphNodeTest.java +++ b/tlatools/test/tlc2/tool/liveness/GraphNodeTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import java.util.Random; + import org.junit.Test; public class GraphNodeTest { diff --git a/tlatools/test/tlc2/tool/liveness/LoopTest.java b/tlatools/test/tlc2/tool/liveness/LoopTest.java index c7f47ce344067c8e74cfb4e6389832525404be49..0bd0f27d98c21afdc48ebe8c29f32380871ef528 100644 --- a/tlatools/test/tlc2/tool/liveness/LoopTest.java +++ b/tlatools/test/tlc2/tool/liveness/LoopTest.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; /** * System LOOP as described by Manna & Pneuli on page 423ff @@ -40,7 +43,7 @@ import tlc2.output.EC; public class LoopTest extends ModelCheckerTestCase { public LoopTest() { - super("SystemLoop", "Loop"); + super("SystemLoop", "Loop", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -76,5 +79,7 @@ public class LoopTest extends ModelCheckerTestCase { // not start to end. // If liveness is (forcefully) triggered after the initial state, stuttering // after the initial state is correctly detected. + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/LoopTestForcedPartial.java b/tlatools/test/tlc2/tool/liveness/LoopTestForcedPartial.java index 394b6d461de7bb017d1b7d76294ee85fe883386b..f1cb43c74a5696db1cf8af9b80267b3fc402f572 100644 --- a/tlatools/test/tlc2/tool/liveness/LoopTestForcedPartial.java +++ b/tlatools/test/tlc2/tool/liveness/LoopTestForcedPartial.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.AbstractChecker; /** @@ -47,7 +50,7 @@ public class LoopTestForcedPartial extends ModelCheckerTestCase { } public LoopTestForcedPartial() { - super("SystemLoop", "Loop"); + super("SystemLoop", "Loop", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -70,5 +73,7 @@ public class LoopTestForcedPartial extends ModelCheckerTestCase { // Stuttering after the init state. assertStuttering(2); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/LoopTestWeakFair.java b/tlatools/test/tlc2/tool/liveness/LoopTestWeakFair.java index ee4551a195af734164f556d768dd267e3ec05e30..bf8a7900bb5ed5e9c5ed2c9b437d6d025696fd9a 100644 --- a/tlatools/test/tlc2/tool/liveness/LoopTestWeakFair.java +++ b/tlatools/test/tlc2/tool/liveness/LoopTestWeakFair.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; /** @@ -51,5 +52,7 @@ public class LoopTestWeakFair extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "4")); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java b/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java index 675fcd1a8ccf63e47f032b12bb1c91f893184f66..258067947519b8ec8b4841245c70e67eb56805be 100644 --- a/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java +++ b/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java @@ -25,6 +25,7 @@ ******************************************************************************/ package tlc2.tool.liveness; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.lang.reflect.Field; @@ -32,11 +33,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.junit.After; import org.junit.Before; import tlc2.TLC; import tlc2.TLCGlobals; import tlc2.TestMPRecorder; +import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.output.MP; import tlc2.tool.CommonTestCase; import tlc2.tool.ModelChecker; @@ -50,26 +54,45 @@ public abstract class ModelCheckerTestCase extends CommonTestCase { protected String spec; protected String[] extraArguments = new String[0]; protected TLC tlc; + protected int actualExitStatus = -1; + protected int expectedExitStatus = ExitStatus.SUCCESS; public ModelCheckerTestCase(String spec) { - super(new TestMPRecorder()); - this.spec = spec; + this(spec, ExitStatus.SUCCESS); + } + + public ModelCheckerTestCase(String spec, final int exitStatus) { + this(spec, "", exitStatus); } public ModelCheckerTestCase(String spec, String path) { - this(spec); - this.path = path; + this(spec, path, ExitStatus.SUCCESS); } public ModelCheckerTestCase(String spec, String[] extraArguments) { - this(spec, "", extraArguments); + this(spec, "", extraArguments, ExitStatus.SUCCESS); + } + + public ModelCheckerTestCase(String spec, String[] extraArguments, final int exitStatus) { + this(spec, "", extraArguments, exitStatus); } public ModelCheckerTestCase(String spec, String path, String[] extraArguments) { - this(spec, path); + this(spec, path, extraArguments, ExitStatus.SUCCESS); + } + + public ModelCheckerTestCase(String spec, String path, String[] extraArguments, final int exitStatus) { + this(spec, path, exitStatus); this.extraArguments = extraArguments; } + public ModelCheckerTestCase(final String spec, final String path, final int exitStatus) { + super(new TestMPRecorder()); + this.spec = spec; + this.path = path; + this.expectedExitStatus = exitStatus; + } + /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ @@ -110,18 +133,26 @@ public abstract class ModelCheckerTestCase extends CommonTestCase { args.add("-deadlock"); } + args.add("-fp"); + args.add("0"); + + args.add("-coverage"); + args.add("1"); + args.add("-workers"); args.add(Integer.toString(getNumberOfThreads())); // Never create checkpoints. They distort performance tests and are // of no use anyway. args.add("-checkpoint"); - args.add("0"); + args.add(Integer.toString(doCheckpoint())); // Always print the state graph in dot file notation. - args.add("-dump"); - args.add("dot"); - args.add("${metadir}" + FileUtil.separator + getClass().getCanonicalName() + ".dot"); + if (doDump()) { + args.add("-dump"); + args.add("dot"); + args.add("${metadir}" + FileUtil.separator + getClass().getCanonicalName() + ".dot"); + } args.addAll(Arrays.asList(extraArguments)); @@ -129,12 +160,18 @@ public abstract class ModelCheckerTestCase extends CommonTestCase { tlc.handleParameters(args.toArray(new String[args.size()])); // Run the ModelChecker - tlc.process(); + final int errorCode = tlc.process(); + actualExitStatus = EC.ExitStatus.errorConstantToExitStatus(errorCode); } catch (Exception e) { fail(e.getMessage()); } } + + @After + public void assertExitStatus() { + assertEquals(expectedExitStatus, actualExitStatus); + } /** * @return True if TLC is to be called with "-deadlock". @@ -142,6 +179,14 @@ public abstract class ModelCheckerTestCase extends CommonTestCase { protected boolean checkDeadLock() { return false; } + + protected boolean doDump() { + return true; + } + + protected int doCheckpoint() { + return 0; + } /** * @return The number of worker threads TLC should use. @@ -150,6 +195,10 @@ public abstract class ModelCheckerTestCase extends CommonTestCase { return 1; } + protected void setExitStatus(final int exitStatus) { + this.expectedExitStatus = exitStatus; + } + /** * E.g. * ILiveCheck liveCheck = (ILiveCheck) getField(AbstractChecker.class, "liveCheck", diff --git a/tlatools/test/tlc2/tool/liveness/NQaTest.java b/tlatools/test/tlc2/tool/liveness/NQaTest.java index 739c1226fd9597a1faa9a5492c87d856062744f2..cdb678cf644c0faae5a4c2f7d0076807143b4813 100644 --- a/tlatools/test/tlc2/tool/liveness/NQaTest.java +++ b/tlatools/test/tlc2/tool/liveness/NQaTest.java @@ -30,10 +30,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; + import org.junit.Ignore; import org.junit.Test; -import java.io.File; import tlc2.output.EC; public class NQaTest extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/NoSymmetryTableauModelCheckerTest.java b/tlatools/test/tlc2/tool/liveness/NoSymmetryTableauModelCheckerTest.java index b28c4cad270e16fceca6cf4c22c2537013ec8d52..a03385af36d77ad0a9daaca19cec43ccfe1810d5 100644 --- a/tlatools/test/tlc2/tool/liveness/NoSymmetryTableauModelCheckerTest.java +++ b/tlatools/test/tlc2/tool/liveness/NoSymmetryTableauModelCheckerTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; public class NoSymmetryTableauModelCheckerTest extends ModelCheckerTestCase { @@ -53,5 +54,7 @@ public class NoSymmetryTableauModelCheckerTest extends ModelCheckerTestCase { assertFalse(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); assertFalse(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); assertFalse(recorder.recorded(EC.TLC_STATE_PRINT2)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/OneBitMutexNoSymmetryTest.java b/tlatools/test/tlc2/tool/liveness/OneBitMutexNoSymmetryTest.java index a928797343bec7faa9d561903cb6a8085cd99e3f..765435664b315f101d36e9287be4a31fecf5aa31 100644 --- a/tlatools/test/tlc2/tool/liveness/OneBitMutexNoSymmetryTest.java +++ b/tlatools/test/tlc2/tool/liveness/OneBitMutexNoSymmetryTest.java @@ -32,13 +32,16 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class OneBitMutexNoSymmetryTest extends ModelCheckerTestCase { public OneBitMutexNoSymmetryTest() { - super("OneBitMutexNoSymmetryMC", "symmetry" + File.separator + "OneBitMutex"); + super("OneBitMutexNoSymmetryMC", "symmetry" + File.separator + "OneBitMutex", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -159,5 +162,9 @@ public class OneBitMutexNoSymmetryTest extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(9, "<e2 line 66, col 13 to line 74, col 21 of module OneBitMutex>"); + + assertUncovered("line 80, col 38 to line 80, col 69 of module OneBitMutex: 0\n" + + "line 96, col 16 to line 96, col 47 of module OneBitMutex: 0\n" + + "line 97, col 16 to line 97, col 50 of module OneBitMutex: 0"); } } diff --git a/tlatools/test/tlc2/tool/liveness/OneBitMutexTest.java b/tlatools/test/tlc2/tool/liveness/OneBitMutexTest.java index c4a415d850628aee2dc1145d8e0f637a79884254..fce4d244ed2bd8174673b3760ce9ad5646d14482 100644 --- a/tlatools/test/tlc2/tool/liveness/OneBitMutexTest.java +++ b/tlatools/test/tlc2/tool/liveness/OneBitMutexTest.java @@ -35,6 +35,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class OneBitMutexTest extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java index 37fc9bc8de07c79abe2adb8578bac5983448f5e8..72c61c6c1544b690adf6a3aa32b3e799992f3d54 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class SymmetryModelCheckerTest3 extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3a.java b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3a.java index d414072e49a74cdf6405d624287d8802ae92a5c4..e2d1ee5821880900693fdf440c15392568dd9215 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3a.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3a.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class SymmetryModelCheckerTest3a extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLong.java b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLong.java index d51282b3c8fd20899c11ed906ea75fe439d5b7f9..897af5e7d1c0d4c4461a3a2046d7ffe831979854 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLong.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLong.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class SymmetryModelCheckerTestLong extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLonga.java b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLonga.java index 817e4334851ee6f9c836b87a6a393ed8689624b6..b92e7632b62a070edc93ea1c3952998e1a484b91 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLonga.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTestLonga.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class SymmetryModelCheckerTestLonga extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryTableauLiveCheckTest.java b/tlatools/test/tlc2/tool/liveness/SymmetryTableauLiveCheckTest.java index 779162afa2867099dfa82ac1b36ec1194955c1e6..508212d0c01ed43009be3cd8d3f74a3303a9e6a4 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryTableauLiveCheckTest.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryTableauLiveCheckTest.java @@ -36,13 +36,14 @@ import org.easymock.Capture; import org.easymock.EasyMock; import org.easymock.IAnswer; import org.junit.Assert; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import tlc2.tool.Action; +import tlc2.tool.ITool; import tlc2.tool.StateVec; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.tool.liveness.GraphNode.Transition; import tlc2.tool.queue.DummyTLCState; import tlc2.util.BitVector; @@ -51,6 +52,13 @@ import tlc2.util.statistics.DummyBucketStatistics; public class SymmetryTableauLiveCheckTest { + private ITool tool; + + @Before + public void createTool() { + this.tool = EasyMock.createNiceMock(ITool.class); + } + @Test @Ignore("Ignored for as long as symmetry is incorrectly handled by TLC with liveness checking.") public void testTableau() throws IOException { @@ -61,7 +69,7 @@ public class SymmetryTableauLiveCheckTest { // Add init state v final TLCState v = new DummyTLCState(100L); - lc.addInitState(v, v.fingerPrint()); + lc.addInitState(tool, v, v.fingerPrint()); // one init node (two elements in LongVec) assertEquals(1, diskGraph.getInitNodes().size() / 2); @@ -69,7 +77,7 @@ public class SymmetryTableauLiveCheckTest { // Add v > s final TLCState s = new DummyTLCState(200L); nexts.put(s); - lc.addNextState(v, v.fingerPrint(), nexts); + lc.addNextState(null, v, v.fingerPrint(), nexts); assertEquals(2, diskGraph.getNode(v.fingerPrint(), 0).succSize()); assertEquals(0, diskGraph.getNode(v.fingerPrint(), 1).succSize()); // only tidx0 is an init node @@ -81,7 +89,7 @@ public class SymmetryTableauLiveCheckTest { nexts.clear(); final TLCState t = new DummyTLCState(300L); nexts.put(t); - lc.addNextState(s, s.fingerPrint(), nexts); + lc.addNextState(null, s, s.fingerPrint(), nexts); assertEquals(2, diskGraph.getNode(v.fingerPrint(), 0).succSize()); assertEquals(0, diskGraph.getNode(v.fingerPrint(), 1).succSize()); @@ -96,7 +104,7 @@ public class SymmetryTableauLiveCheckTest { nexts.clear(); final TLCState u = new DummyTLCState(400L); nexts.put(u); - lc.addNextState(s, s.fingerPrint(), nexts); + lc.addNextState(null, s, s.fingerPrint(), nexts); Assert.fail("finish incomplete test! Assertions below are partially bogus."); @@ -117,14 +125,14 @@ public class SymmetryTableauLiveCheckTest { private ILiveCheck getLiveCheckWithTwoNodeTableau() throws IOException { final TBGraphNode node1 = EasyMock.createNiceMock(TBGraphNode.class); - EasyMock.expect(node1.isConsistent((TLCState) EasyMock.anyObject(), (Tool) EasyMock.anyObject())) + EasyMock.expect(node1.isConsistent((TLCState) EasyMock.anyObject(), (ITool) EasyMock.anyObject())) .andReturn(true).anyTimes(); EasyMock.expect(node1.nextSize()).andReturn(0).anyTimes(); EasyMock.expect(node1.getIndex()).andReturn(1).anyTimes(); EasyMock.replay(node1); final TBGraphNode node0 = EasyMock.createMock(TBGraphNode.class); - EasyMock.expect(node0.isConsistent((TLCState) EasyMock.anyObject(), (Tool) EasyMock.anyObject())) + EasyMock.expect(node0.isConsistent((TLCState) EasyMock.anyObject(), (ITool) EasyMock.anyObject())) .andReturn(true).anyTimes(); EasyMock.expect(node0.nextSize()).andReturn(2).anyTimes(); EasyMock.expect(node0.nextAt(0)).andReturn(node0).anyTimes(); @@ -145,10 +153,10 @@ public class SymmetryTableauLiveCheckTest { EasyMock.expect(oos.getTableau()).andReturn(tbGraph).anyTimes(); EasyMock.expect(oos.getCheckAction()).andReturn(new LiveExprNode[0]).anyTimes(); EasyMock.expect(oos.getCheckState()).andReturn(new LiveExprNode[0]).anyTimes(); - EasyMock.expect(oos.checkState((TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); + EasyMock.expect(oos.checkState(null, (TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); EasyMock.replay(oos); - return new LiveCheck(EasyMock.createNiceMock(Tool.class), new Action[0], + return new LiveCheck(tool, new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics(), null); } @@ -166,14 +174,14 @@ public class SymmetryTableauLiveCheckTest { // Add init state v final TLCState v = new DummyTLCState(100L); - lc.addInitState(v, v.fingerPrint()); + lc.addInitState(tool, v, v.fingerPrint()); // one init node (two elements in LongVec) assertEquals(1, diskGraph.getInitNodes().size() / 2); // Add v > s nexts.put(s); - lc.addNextState(v, v.fingerPrint(), nexts); + lc.addNextState(null, v, v.fingerPrint(), nexts); GraphNode vgn = diskGraph.getNode(v.fingerPrint(), 0); assertEquals(2, vgn.succSize()); // s is consistent with tidx0 and tidx1, but not with tidx2 @@ -190,7 +198,7 @@ public class SymmetryTableauLiveCheckTest { // Add s > t nexts.clear(); nexts.put(t); - lc.addNextState(s, s.fingerPrint(), nexts); + lc.addNextState(null, s, s.fingerPrint(), nexts); assertEquals(2, diskGraph.getNode(v.fingerPrint(), 0).succSize()); assertEquals(0, diskGraph.getNode(v.fingerPrint(), 1).succSize()); @@ -210,7 +218,7 @@ public class SymmetryTableauLiveCheckTest { // Add additional init state u final TLCState u = new DummyTLCState(400L); - lc.addInitState(u, u.fingerPrint()); + lc.addInitState(tool, u, u.fingerPrint()); // two init nodes now (four elements in LongVec) assertEquals(2, diskGraph.getInitNodes().size() / 2); @@ -234,7 +242,7 @@ public class SymmetryTableauLiveCheckTest { // add a symmetric s1 (same fingerprint as s) nexts.clear(); nexts.put(s1); - lc.addNextState(u, u.fingerPrint(), nexts); + lc.addNextState(null, u, u.fingerPrint(), nexts); assertEquals(2, diskGraph.getNode(v.fingerPrint(), 0).succSize()); assertEquals(0, diskGraph.getNode(v.fingerPrint(), 1).succSize()); @@ -278,12 +286,11 @@ public class SymmetryTableauLiveCheckTest { * @param s The smallest state under symmetry * @param sSymmetric A symmetric state to s */ - @SuppressWarnings("deprecation") private ILiveCheck getLiveCheckWithTwoNodeTableauSymmetry(final TLCState s, final TLCState sSymmetric, final TLCState t) throws IOException { final TBGraphNode node2 = EasyMock.createMock(TBGraphNode.class); // consistency final Capture<TLCState> capture = new Capture<TLCState>(); - EasyMock.expect(node2.isConsistent(EasyMock.capture(capture), (Tool) EasyMock.anyObject())).andAnswer(new IAnswer<Boolean>() { + EasyMock.expect(node2.isConsistent(EasyMock.capture(capture), (ITool) EasyMock.anyObject())).andAnswer(new IAnswer<Boolean>() { public Boolean answer() throws Throwable { final TLCState value = capture.getValue(); if (value == s) { @@ -303,7 +310,7 @@ public class SymmetryTableauLiveCheckTest { final TBGraphNode node1 = EasyMock.createMock(TBGraphNode.class); // consistency final Capture<TLCState> capture1 = new Capture<TLCState>(); - EasyMock.expect(node1.isConsistent(EasyMock.capture(capture1), (Tool) EasyMock.anyObject())).andAnswer(new IAnswer<Boolean>() { + EasyMock.expect(node1.isConsistent(EasyMock.capture(capture1), (ITool) EasyMock.anyObject())).andAnswer(new IAnswer<Boolean>() { public Boolean answer() throws Throwable { final TLCState value = capture1.getValue(); if (value == sSymmetric) { @@ -323,7 +330,7 @@ public class SymmetryTableauLiveCheckTest { final TBGraphNode node0 = EasyMock.createMock(TBGraphNode.class); // consistency (simpler to node1 and node2) - EasyMock.expect(node0.isConsistent((TLCState) EasyMock.anyObject(), (Tool) EasyMock.anyObject())).andReturn(true).anyTimes(); + EasyMock.expect(node0.isConsistent((TLCState) EasyMock.anyObject(), (ITool) EasyMock.anyObject())).andReturn(true).anyTimes(); // index EasyMock.expect(node0.getIndex()).andReturn(0).anyTimes(); // nextSize @@ -347,10 +354,10 @@ public class SymmetryTableauLiveCheckTest { EasyMock.expect(oos.getTableau()).andReturn(tbGraph).anyTimes(); EasyMock.expect(oos.getCheckAction()).andReturn(new LiveExprNode[0]).anyTimes(); EasyMock.expect(oos.getCheckState()).andReturn(new LiveExprNode[0]).anyTimes(); - EasyMock.expect(oos.checkState((TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); + EasyMock.expect(oos.checkState(null, (TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); EasyMock.replay(oos); - final Tool tool = EasyMock.createNiceMock(Tool.class); + final ITool tool = EasyMock.createNiceMock(ITool.class); EasyMock.expect(tool.hasSymmetry()).andReturn(true); final Capture<TLCState> nextStates = new Capture<TLCState>(); EasyMock.expect(tool.getNextStates((Action) EasyMock.anyObject(), EasyMock.capture(nextStates))).andAnswer(new IAnswer<StateVec>() { @@ -367,7 +374,7 @@ public class SymmetryTableauLiveCheckTest { EasyMock.expect(tool.isInModel((TLCState) EasyMock.anyObject())).andReturn(true).anyTimes(); EasyMock.expect(tool.isInActions((TLCState) EasyMock.anyObject(), (TLCState) EasyMock.anyObject())).andReturn(true).anyTimes(); EasyMock.replay(tool); - return new LiveCheck(tool, new Action[1], + return new LiveCheck(tool, new OrderOfSolution[] { oos }, "states", new DummyBucketStatistics(), null); } } diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryTableauModelCheckerTest.java b/tlatools/test/tlc2/tool/liveness/SymmetryTableauModelCheckerTest.java index 9dd871594013378af673351e96b21a8272e3b1c0..286fa498606ad4b5ed650ae382a5a43de291ecf0 100644 --- a/tlatools/test/tlc2/tool/liveness/SymmetryTableauModelCheckerTest.java +++ b/tlatools/test/tlc2/tool/liveness/SymmetryTableauModelCheckerTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class SymmetryTableauModelCheckerTest extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/TableauNodePtrTableTest.java b/tlatools/test/tlc2/tool/liveness/TableauNodePtrTableTest.java index b7b7c647d486d7b00d02666517864440b9697d0e..c2c1c300a8171085df5c6036443b4a7a6d30dffa 100644 --- a/tlatools/test/tlc2/tool/liveness/TableauNodePtrTableTest.java +++ b/tlatools/test/tlc2/tool/liveness/TableauNodePtrTableTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; + import org.junit.Test; public class TableauNodePtrTableTest { diff --git a/tlatools/test/tlc2/tool/liveness/TableauSymmetryTest.java b/tlatools/test/tlc2/tool/liveness/TableauSymmetryTest.java index 649cac5b4f72bb3a5c7ac90e5110c9e492cdbd76..697e7aef2110aae13024b0584056dd95e1318f99 100644 --- a/tlatools/test/tlc2/tool/liveness/TableauSymmetryTest.java +++ b/tlatools/test/tlc2/tool/liveness/TableauSymmetryTest.java @@ -34,6 +34,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; + import tlc2.output.EC; public class TableauSymmetryTest extends ModelCheckerTestCase { diff --git a/tlatools/test/tlc2/tool/liveness/Test3.java b/tlatools/test/tlc2/tool/liveness/Test3.java index 38728b3fafb13cc182f282306d48078b8ef94cb7..d87879af307516db66a7b62ae037b2b2e33258f1 100644 --- a/tlatools/test/tlc2/tool/liveness/Test3.java +++ b/tlatools/test/tlc2/tool/liveness/Test3.java @@ -31,13 +31,16 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test3 extends ModelCheckerTestCase { public Test3() { - super("Test3"); + super("Test3", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -61,5 +64,7 @@ public class Test3 extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(1); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java b/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java index 0c414d720f5e094cdc40fbcd5303cada7eb57587..3c5950a54025dc87f300300ca426ed77241e8866 100644 --- a/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java +++ b/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java @@ -42,5 +42,7 @@ public class TwoPhaseCommitTest extends ModelCheckerTestCase { @Test public void testSpec() { assertFalse(recorder.recorded(EC.GENERAL)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestA.java b/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestA.java index aceaa5e2fffda9b421ed280e18ff69ac5a65651d..a469e74413a17fb5d5873d06ab9b9dbf43982a69 100644 --- a/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestA.java +++ b/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestA.java @@ -31,13 +31,16 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class UnsymmetricModelCheckerTestA extends ModelCheckerTestCase { public UnsymmetricModelCheckerTestA() { - super("UnsymmetricMCA", "symmetry"); + super("UnsymmetricMCA", "symmetry", ExitStatus.VIOLATION_LIVENESS); } @Test @@ -62,5 +65,7 @@ public class UnsymmetricModelCheckerTestA extends ModelCheckerTestCase { assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); assertBackToState(1); + + assertUncovered("line 19, col 31 to line 19, col 36 of module Unsymmetric: 0"); } } diff --git a/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestB.java b/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestB.java index edf127fd3d4e3bc29fc709b6ae6e8f70b16aba76..1012a8feb1de618e944903d26bc6536c95ecbc13 100644 --- a/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestB.java +++ b/tlatools/test/tlc2/tool/liveness/UnsymmetricModelCheckerTestB.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; public class UnsymmetricModelCheckerTestB extends ModelCheckerTestCase { @@ -51,5 +52,7 @@ public class UnsymmetricModelCheckerTestB extends ModelCheckerTestCase { // Contrary to UMCTA, B doesn't find a counter-example. This is due to // the CHOOSE on S and the selected initial state. + + assertUncovered("line 37, col 31 to line 37, col 36 of module Unsymmetric: 0"); } } diff --git a/tlatools/test/tlc2/tool/liveness/simulation/AbstractExampleTestCase.java b/tlatools/test/tlc2/tool/liveness/simulation/AbstractExampleTestCase.java index 4ffaecc8805d9fa7c341a33c0ff9bd0d1f0def6a..192c88e8a186bad2ce5b5ccc4648f99dd63633bd 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/AbstractExampleTestCase.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/AbstractExampleTestCase.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.TLCStateInfo; import tlc2.tool.liveness.ModelCheckerTestCase; @@ -41,7 +44,7 @@ public abstract class AbstractExampleTestCase extends ModelCheckerTestCase { public AbstractExampleTestCase(final String cfg) { // Checks the depth parameter too. Depth <= 100 will cause simluation to // go on forever. - super(cfg, "simulation", new String[] {"-simulate", "-depth", "11"}); + super(cfg, "simulation", new String[] { "-simulate", "-depth", "11" }, ExitStatus.VIOLATION_LIVENESS); } @Test diff --git a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2.java b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2.java index 55fc30dde773c7b7d7eebf5a090f35ef03f07b80..a2ee64447c80ac68c598b663bc82f30e9bb4439c 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2.java @@ -37,6 +37,6 @@ public class LiveCheckSimulationTest2 extends SuccessfulSimulationTestCase { public LiveCheckSimulationTest2() { super("Test2", "/", new String[] {"-simulate", "-depth", "10"}); - TLC.traceNum = 50; + TLC.setTraceNum(50); } } diff --git a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2a.java b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2a.java index b0e2e976d106c822516548d5f2fa077fb2df4948..26413ee3bc93b791f59f6ef0589d40c21f42c0f0 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2a.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckSimulationTest2a.java @@ -31,9 +31,12 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; + import org.junit.Test; + import tlc2.TLC; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.Simulator; import tlc2.tool.TLCStateInfo; import tlc2.tool.liveness.ModelCheckerTestCase; @@ -48,10 +51,10 @@ public class LiveCheckSimulationTest2a extends ModelCheckerTestCase { } public LiveCheckSimulationTest2a() { - super("Test2a", "/", new String[] {"-simulate", "-depth", "10"}); + super("Test2a", "/", new String[] {"-simulate", "-depth", "10"}, ExitStatus.VIOLATION_LIVENESS); // Stop after 100 traces due to lack of general timeout regardless of outcome - TLC.traceNum = 100; + TLC.setTraceNum(100); } @Test diff --git a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java index 85e3c0e031e596c86c645dd96b08b362166e0945..b090a8f57ee02036357c58d966134a5ee12c7d22 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java @@ -32,11 +32,11 @@ import static org.junit.Assert.assertNotNull; import java.io.IOException; import org.easymock.EasyMock; +import org.junit.Before; import org.junit.Test; -import tlc2.tool.Action; +import tlc2.tool.ITool; import tlc2.tool.TLCState; -import tlc2.tool.Tool; import tlc2.tool.liveness.AbstractDiskGraph; import tlc2.tool.liveness.ILiveCheck; import tlc2.tool.liveness.LiveCheck; @@ -50,6 +50,13 @@ import tlc2.util.statistics.DummyBucketStatistics; public class LiveCheckTest { + private ITool tool; + + @Before + public void createTool() { + this.tool = EasyMock.createNiceMock(ITool.class); + } + // Add identical state twice, which can happen in simulation mode when the // trace is: <<100L, 200L, ..., 100L, 200L>> (as in a cycle that is // repeated due to the trace length). In this scenario DiskGraph should @@ -80,39 +87,40 @@ public class LiveCheckTest { assertNotNull(diskGraph); final TLCState state = new DummyTLCState(); - liveCheck.addInitState(state, 100L); + liveCheck.addInitState(tool, state, 100L); final SetOfStates setOfStates = new SetOfStates(1); setOfStates.put(200L, new DummyTLCState(200L)); // Add state 100L the first time, then add its successor - liveCheck.addNextState(state, 100L, setOfStates); - liveCheck.addNextState(state, 200L, setOfStates); + liveCheck.addNextState(tool, state, 100L, setOfStates); + liveCheck.addNextState(tool, state, 200L, setOfStates); assertEquals(0, diskGraph.getPtr(100L, tableauId)); // Add state 100L again and check that it does *not* // end up in disk graph. - liveCheck.addNextState(state, 100L, setOfStates); + liveCheck.addNextState(tool, state, 100L, setOfStates); assertEquals(0, diskGraph.getPtr(100L, tableauId)); } private ILiveCheck getLiveCheck() throws IOException { + final ITool tool = EasyMock.createNiceMock(ITool.class); // Configure OOS mock to react to the subsequent invocation. This is // essentially the list of calls being made on OOS during // LiveCheck#addInitState and LiveCheck#addNextState final OrderOfSolution oos = EasyMock.createNiceMock(OrderOfSolution.class); EasyMock.expect(oos.hasTableau()).andReturn(false); EasyMock.expect(oos.getCheckAction()).andReturn(new LiveExprNode[0]).anyTimes(); - EasyMock.expect(oos.checkState((TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); + EasyMock.expect(oos.checkState((ITool) EasyMock.anyObject(), (TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); EasyMock.replay(oos); - return new LiveCheck(EasyMock.createNiceMock(Tool.class), new Action[0], + return new LiveCheck(tool, new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics()); } private ILiveCheck getLiveCheckWithTableau() throws IOException { final TBGraphNode node = EasyMock.createMock(TBGraphNode.class); - EasyMock.expect(node.isConsistent((TLCState) EasyMock.anyObject(), (Tool) EasyMock.anyObject())).andReturn(true) + EasyMock.expect(node.isConsistent((TLCState) EasyMock.anyObject(), (ITool) EasyMock.anyObject())).andReturn(true) .anyTimes(); EasyMock.expect(node.nextSize()).andReturn(1).anyTimes(); EasyMock.expect(node.nextAt(0)).andReturn(node).anyTimes(); @@ -130,10 +138,10 @@ public class LiveCheckTest { EasyMock.expect(oos.hasTableau()).andReturn(true); EasyMock.expect(oos.getTableau()).andReturn(tbGraph).anyTimes(); EasyMock.expect(oos.getCheckAction()).andReturn(new LiveExprNode[0]).anyTimes(); - EasyMock.expect(oos.checkState((TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); + EasyMock.expect(oos.checkState((ITool) EasyMock.anyObject(), (TLCState) EasyMock.anyObject())).andReturn(new boolean[0]).anyTimes(); EasyMock.replay(oos); - return new LiveCheck(EasyMock.createNiceMock(Tool.class), new Action[0], + return new LiveCheck(tool, new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics()); } } diff --git a/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2.java b/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2.java index bcd53fdd3ceb1a6aeca9b8010a2b29afc6527ab9..1cb5fffdf0ab1f0edf267dfdc6261bc2f33db371 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2.java @@ -32,6 +32,6 @@ public class SimulationTest2 extends SuccessfulSimulationTestCase { public SimulationTest2() { super("Test2", "/", new String[] {"-simulate", "-depth", "6"}); - TLC.traceNum = 50; + TLC.setTraceNum(50); } } diff --git a/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2a.java b/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2a.java index c1ad559e6de984ee7cc8d7b403ced4b57dcf3c62..2fab67fdfef3c27cedd857c5dc40acbbc32578c8 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2a.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/SimulationTest2a.java @@ -31,8 +31,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; + import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.TLCStateInfo; import tlc2.tool.liveness.ModelCheckerTestCase; @@ -42,7 +45,7 @@ import tlc2.tool.liveness.ModelCheckerTestCase; public class SimulationTest2a extends ModelCheckerTestCase { public SimulationTest2a() { - super("Test2a", "/", new String[] {"-simulate", "-depth", "6"}); + super("Test2a", "/", new String[] {"-simulate", "-depth", "6"}, ExitStatus.VIOLATION_LIVENESS); } @Test diff --git a/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java b/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java index fcffab9731778f6bea89c2256ca3f8a5bb35262f..4ed5fa134e96b3b3010801f347357289aebe94d4 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java @@ -30,13 +30,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class StutteringTest extends ModelCheckerTestCase { public StutteringTest() { - super("MC", "CodePlexBug08", new String[] { "-simulate" }); + super("MC", "CodePlexBug08", new String[] { "-simulate" }, ExitStatus.VIOLATION_LIVENESS); } @Test diff --git a/tlatools/test/tlc2/tool/liveness/simulation/SuccessfulSimulationTestCase.java b/tlatools/test/tlc2/tool/liveness/simulation/SuccessfulSimulationTestCase.java index 66ce18651a82041bcf4aa544e90ae275521f9109..2eb3c22857017d75737719f160977454a0bfde3b 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/SuccessfulSimulationTestCase.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/SuccessfulSimulationTestCase.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; diff --git a/tlatools/test/tlc2/tool/queue/DummyTLCState.java b/tlatools/test/tlc2/tool/queue/DummyTLCState.java index cf40e6d0307be835e480014c1edfb0298451c065..dbaedada12287e4da6a399cfef909e974239a3c9 100644 --- a/tlatools/test/tlc2/tool/queue/DummyTLCState.java +++ b/tlatools/test/tlc2/tool/queue/DummyTLCState.java @@ -4,11 +4,10 @@ import java.util.HashSet; import java.util.Set; import tla2sany.semantic.OpDeclNode; -import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.tool.StateVec; import tlc2.tool.TLCState; -import tlc2.value.Value; +import tlc2.value.IValue; import util.UniqueString; @SuppressWarnings("serial") @@ -29,14 +28,14 @@ public class DummyTLCState extends TLCState { /* (non-Javadoc) * @see tlc2.tool.TLCState#bind(util.UniqueString, tlc2.value.Value, tla2sany.semantic.SemanticNode) */ - public TLCState bind(UniqueString name, Value value, SemanticNode expr) { + public TLCState bind(UniqueString name, IValue value) { return null; } /* (non-Javadoc) * @see tlc2.tool.TLCState#bind(tla2sany.semantic.SymbolNode, tlc2.value.Value, tla2sany.semantic.SemanticNode) */ - public TLCState bind(SymbolNode id, Value value, SemanticNode expr) { + public TLCState bind(SymbolNode id, IValue value) { return null; } @@ -50,7 +49,7 @@ public class DummyTLCState extends TLCState { /* (non-Javadoc) * @see tlc2.tool.TLCState#lookup(util.UniqueString) */ - public Value lookup(UniqueString var) { + public IValue lookup(UniqueString var) { return null; } diff --git a/tlatools/test/tlc2/tool/queue/StateQueueTest.java b/tlatools/test/tlc2/tool/queue/StateQueueTest.java index 058912f0408808d3fdd429a18b05ed4cadc39ed1..855d34066ccafda706839c925f641a162cd47ef0 100644 --- a/tlatools/test/tlc2/tool/queue/StateQueueTest.java +++ b/tlatools/test/tlc2/tool/queue/StateQueueTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.fail; import org.junit.Before; import org.junit.Test; + import tlc2.tool.TLCState; public class StateQueueTest { @@ -112,7 +113,7 @@ public class StateQueueTest { private void expectRuntimeException(IStateQueue aQueue, int size) { try { aQueue.sDequeue(size); - } catch(RuntimeException e) { + } catch(RuntimeException|AssertionError e) { return; } fail("expected to throw RuntimeException with <= input"); diff --git a/tlatools/test/tlc2/tool/simulation/NQSpecTest.java b/tlatools/test/tlc2/tool/simulation/NQSpecTest.java index ee145ae1c797c3df25a0e84c5feae2f2a76e420b..6391d4936c31d3b21e3f6b360fa4c6ee6ef556ea 100644 --- a/tlatools/test/tlc2/tool/simulation/NQSpecTest.java +++ b/tlatools/test/tlc2/tool/simulation/NQSpecTest.java @@ -41,7 +41,7 @@ public class NQSpecTest extends ModelCheckerTestCase { public NQSpecTest() { super("MC", "simulation" + File.separator + "NQSpec", new String[] { "-simulate" }); - TLC.traceNum = 100; + TLC.setTraceNum(100); } @Test diff --git a/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java b/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fcf29d22d17e648463dccb63acf1583cf782ca8d --- /dev/null +++ b/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java @@ -0,0 +1,428 @@ +package tlc2.tool.simulation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.LongAdder; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import tlc2.TLCGlobals; +import tlc2.TestMPRecorder; +import tlc2.output.EC; +import tlc2.tool.CommonTestCase; +import tlc2.tool.ITool; +import tlc2.tool.SimulationWorker; +import tlc2.tool.SimulationWorker.SimulationWorkerError; +import tlc2.tool.SimulationWorker.SimulationWorkerResult; +import tlc2.tool.impl.Tool; +import tlc2.tool.StateVec; +import tlc2.tool.TLCState; +import tlc2.tool.liveness.ILiveCheck; +import tlc2.tool.liveness.NoOpLiveCheck; +import util.FileUtil; +import util.SimpleFilenameToStream; +import util.ToolIO; +import util.UniqueString; + +/** + * Correctness tests for the SimulationWorker. + */ +public class SimulationWorkerTest extends CommonTestCase { + + public SimulationWorkerTest() { + super(new TestMPRecorder()); + } + + @Before + public void setUp() throws Exception{ + ToolIO.setUserDir(BASE_PATH + File.separator + "simulation" + File.separator + "BasicMultiTrace"); + } + + @After + public void tearDown() throws Exception{ + FileUtil.deleteDir(TLCGlobals.metaRoot, true); + } + + /** + * Return a value from a TLCState as a string. + */ + public String getStateVal(TLCState s, String name) { + UniqueString us = UniqueString.uniqueStringOf(name); + return s.getVals().get(us).toString(); + } + + @Test + public void testSuccessfulRun() throws Exception { + Tool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream()); + + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + StateVec initStates = tool.getInitStates(); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 1000, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + assertFalse(res.isError()); + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testInvariantViolation() throws Exception { + Tool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream()); + + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + StateVec initStates = tool.getInitStates(); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + int maxTraceNum = 3; + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, maxTraceNum, false, + null, liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(3, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.stateTrace.elementAt(2), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(2), "branch")); + + assertEquals("2", getStateVal(err.state, "depth")); + assertEquals("6", getStateVal(err.state, "branch")); + + // The worker should continue to generate random traces even after an invariant violation, so we should be + // able to receive more results. The worker should generate 2 more results before hitting the maximum trace count. + // For the next traces generated, we check their contents to make sure that the worker is actually producing traces + // "randomly" i.e. not generating the same trace every time. + res = resultQueue.take(); + assertTrue(res.isError()); + err = res.error(); + assertEquals(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(3, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("2", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.stateTrace.elementAt(2), "depth")); + assertEquals("2", getStateVal(err.stateTrace.elementAt(2), "branch")); + + res = resultQueue.take(); + assertTrue(res.isError()); + err = res.error(); + assertEquals(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(3, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("5", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.stateTrace.elementAt(2), "depth")); + assertEquals("5", getStateVal(err.stateTrace.elementAt(2), "branch")); + + // The worker should push one final OK result onto the queue upon termination. + res = resultQueue.take(); + assertFalse(res.isError()); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testActionPropertyViolation() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCActionProp", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + + SimulationWorkerResult res = resultQueue.take(); + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(2, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.state, "depth")); + assertEquals("6", getStateVal(err.state, "branch")); + + // Check another result. + res = resultQueue.take(); + assertTrue(res.isError()); + err = res.error(); + assertEquals(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(2, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("10", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.state, "depth")); + assertEquals("10", getStateVal(err.state, "branch")); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testInvariantBadEval() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCBadInvNonInitState", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_INVARIANT_EVALUATION_FAILED, err.errorCode); + assertEquals(1, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.state, "depth")); + assertEquals("1", getStateVal(err.state, "branch")); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testActionPropertyBadEval() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCActionPropBadEval", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, err.errorCode); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testUnderspecifiedNext() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCUnderspecNext", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, err.errorCode); + assertEquals(1, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals(null, err.state.getVals().get(UniqueString.uniqueStringOf("depth"))); + assertEquals("0", getStateVal(err.state, "branch")); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testDeadlock() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, true, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_DEADLOCK_REACHED, err.errorCode); + + System.out.println(err.stateTrace.toString()); + assertEquals(7, err.stateTrace.size()); + + // Check the generated trace. + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "depth")); + assertEquals("0", getStateVal(err.stateTrace.elementAt(0), "branch")); + + assertEquals("0", getStateVal(err.stateTrace.elementAt(1), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(1), "branch")); + + assertEquals("1", getStateVal(err.stateTrace.elementAt(2), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(2), "branch")); + + assertEquals("2", getStateVal(err.stateTrace.elementAt(3), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(3), "branch")); + + assertEquals("3", getStateVal(err.stateTrace.elementAt(4), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(4), "branch")); + + assertEquals("4", getStateVal(err.stateTrace.elementAt(5), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(5), "branch")); + + assertEquals("5", getStateVal(err.stateTrace.elementAt(6), "depth")); + assertEquals("6", getStateVal(err.stateTrace.elementAt(6), "branch")); + + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testModelStateConstraint() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCWithConstraint", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + assertFalse(res.isError()); + worker.join(); + assertTrue(resultQueue.isEmpty()); + assertFalse(worker.isAlive()); + } + + @Test + public void testModelActionConstraint() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCWithActionConstraint", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, 100, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + assertFalse(res.isError()); + worker.join(); + assertTrue(resultQueue.isEmpty()); + assertFalse(worker.isAlive()); + } + + @Test + public void testWorkerInterruption() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + + // If we set the trace limit to the max, the worker should effectively run forever. We verify that after it generates + // a result, we can cancel it and the worker will terminate. + long traceNum = Long.MAX_VALUE; + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, 100, traceNum, false, null, + liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + + // Check one result. + SimulationWorkerResult res = resultQueue.take(); + + assertTrue(res.isError()); + SimulationWorkerError err = res.error(); + assertEquals(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, err.errorCode); + assertEquals(3, err.stateTrace.size()); + + // Cancel the worker. + worker.interrupt(); + worker.join(); + assertFalse(worker.isAlive()); + } + + @Test + public void testTraceDepthObeyed() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + + // At this trace depth, the worker should never find the invariant violation. + long traceDepth = 1; + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, traceDepth, 100, false, + null, liveCheck, new LongAdder(), new LongAdder()); + worker.start(); + SimulationWorkerResult res = resultQueue.take(); + assertFalse(res.isError()); + + worker.join(); + assertTrue(resultQueue.isEmpty()); + assertFalse(worker.isAlive()); + } + + @Test + public void testStateAndTraceGenerationCount() throws Exception { + ITool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream()); + + StateVec initStates = tool.getInitStates(); + ILiveCheck liveCheck = new NoOpLiveCheck(tool, "BasicMultiTrace"); + BlockingQueue<SimulationWorkerResult> resultQueue = new LinkedBlockingQueue<>(); + + // Have the worker generate a specified number of traces of a fixed length. + LongAdder numOfGenStates = new LongAdder(); + LongAdder numOfGenTraces = new LongAdder(); + long traceDepth = 5; + long traceNum = 5; + SimulationWorker worker = new SimulationWorker(0, tool, initStates, resultQueue, 0, traceDepth, traceNum, false, + null, liveCheck, numOfGenStates, numOfGenTraces); + + worker.start(); + worker.join(); + assertFalse(worker.isAlive()); + assertEquals(70, numOfGenStates.longValue()); + assertEquals(5, numOfGenTraces.longValue()); + } +} diff --git a/tlatools/test/tlc2/tool/simulation/SimulatorMultiThreadTest.java b/tlatools/test/tlc2/tool/simulation/SimulatorMultiThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2623a1ff89498c1889f5d100dcf8e15c8c1489d3 --- /dev/null +++ b/tlatools/test/tlc2/tool/simulation/SimulatorMultiThreadTest.java @@ -0,0 +1,18 @@ +package tlc2.tool.simulation; + +/** + * Correctness tests of a multi-threaded Simulator. + * + * This test intends to verify that, from a correctness perspective, running the + * Simulator with multiple threads is equivalent to running it with a single + * thread i.e. it should pass all of the same tests. + */ +public class SimulatorMultiThreadTest extends SimulatorTest { + + public int numWorkers() { + // A somewhat arbitrary value, but 4 threads seems like a reasonable amount of + // parallelism. + return 4; + } + +} diff --git a/tlatools/test/tlc2/tool/simulation/SimulatorTest.java b/tlatools/test/tlc2/tool/simulation/SimulatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..214d281818aa182d0d873bbe78a19cc8a2008bfb --- /dev/null +++ b/tlatools/test/tlc2/tool/simulation/SimulatorTest.java @@ -0,0 +1,151 @@ +package tlc2.tool.simulation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import tlc2.TLCGlobals; +import tlc2.TestMPRecorder; +import tlc2.output.EC; +import tlc2.output.MP; +import tlc2.tool.CommonTestCase; +import tlc2.tool.Simulator; +import tlc2.util.FP64; +import tlc2.util.RandomGenerator; +import util.FileUtil; +import util.SimpleFilenameToStream; +import util.ToolIO; + +/** + * Correctness tests for a Simulator. + */ +public class SimulatorTest extends CommonTestCase { + + RandomGenerator rng = new RandomGenerator(); + + public SimulatorTest() { + super(new TestMPRecorder()); + MP.setRecorder(recorder); + } + + @Before + public void setUp() throws Exception{ + // Make the each unit test execution as deterministic as possible. + rng = new RandomGenerator(0); + ToolIO.setUserDir(BASE_PATH + File.separator + "simulation" + File.separator + "BasicMultiTrace"); + } + + @After + public void tearDown() throws Exception{ + FileUtil.deleteDir(TLCGlobals.metaRoot, true); + } + + /** + * The number of threads to run the Simulator with. Can be overridden by + * sub-classes that want to test with different values. + */ + public int numWorkers() { + return 1; + } + + public void runSimulatorTest(String specFile, String configFile, Boolean deadlock, int traceDepth, long traceNum) { + try { + Simulator simulator = new Simulator(specFile, configFile, null, deadlock, traceDepth, traceNum, rng, 0, + new SimpleFilenameToStream(), numWorkers()); + simulator.simulate(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void testSuccessfulSimulation() { + runSimulatorTest("BasicMultiTrace", "MC", false, 100, 100); + assertFalse(recorder.recorded(EC.TLC_INVARIANT_VIOLATED_INITIAL)); + assertTrue(recorder.recorded(EC.TLC_PROGRESS_SIMU)); + } + + @Test + public void testInvariantViolationInitialState() { + runSimulatorTest("BasicMultiTrace", "MCInvInitState", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_VIOLATED_INITIAL, "InvInitState")); + } + + @Test + public void testInvariantViolation() { + runSimulatorTest("BasicMultiTrace", "MCInv", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, "Inv")); + } + + @Test + public void testInvariantBadEvalInitState() { + runSimulatorTest("BasicMultiTrace", "MCBadInvInitState", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recorded(EC.TLC_INITIAL_STATE)); + } + + @Test + public void testInvariantBadEvalNonInitState() { + runSimulatorTest("BasicMultiTrace", "MCBadInvNonInitState", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_EVALUATION_FAILED, "InvBadEvalNonInitState")); + } + + @Test + public void testUnderspecifiedInit() { + runSimulatorTest("BasicMultiTrace", "MCUnderspecInit", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recorded(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL)); + } + + @Test + public void testInvariantViolationContinue() { + TLCGlobals.continuation = true; + runSimulatorTest("BasicMultiTrace", "MCInv", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, "Inv")); + } + + @Test + public void testDontContinueOnRuntimeSpecError() { + // We should only continue simulating if a worker encounters a safety or liveness violation. + // Errors in the spec e.g. runtime evaluation errors should terminate all workers, even if + // continue=true. We set the traceCnt to something extremely high, so that this test should + // hang if the simulator does not terminate on the first error. + TLCGlobals.continuation = true; + runSimulatorTest("BasicMultiTrace", "MCBadInvNonInitState", false, 100, Long.MAX_VALUE); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_EVALUATION_FAILED, "InvBadEvalNonInitState")); + } + + @Test + public void testLivenessViolation() { + FP64.Init(); + runSimulatorTest("BasicMultiTrace", "MCLivenessProp", false, 100, 100); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + } + + @Test + public void testLivenessViolationIgnoresContinue() { + FP64.Init(); + TLCGlobals.continuation = true; + // We should always terminate after the first liveness violation, regardless of + // the "continue" parameter. + runSimulatorTest("BasicMultiTrace", "MCLivenessProp", false, 100, Long.MAX_VALUE); + assertTrue(recorder.recordedWithStringValue(EC.TLC_COMPUTING_INIT_PROGRESS, "1")); + assertTrue(recorder.recorded(EC.TLC_TEMPORAL_PROPERTY_VIOLATED)); + assertTrue(recorder.recorded(EC.TLC_COUNTER_EXAMPLE)); + } + + +} diff --git a/tlatools/test/tlc2/tool/suite/ETest1.java b/tlatools/test/tlc2/tool/suite/ETest1.java index 0d510851567b9aa9e122586d8cce4ce4deabbf61..07ddcc64130234566fe126674c71d0ef81dc14d7 100644 --- a/tlatools/test/tlc2/tool/suite/ETest1.java +++ b/tlatools/test/tlc2/tool/suite/ETest1.java @@ -25,17 +25,18 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; - import org.junit.Test; -import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest1 extends SuiteETestCase { + public ETest1() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); assertSubstring("*** Errors: 1\n\n" + "line 18, col 12 to line 18, col 17 of module etest1\n\n" + "The operator Foo requires 1 arguments."); } diff --git a/tlatools/test/tlc2/tool/suite/ETest10.java b/tlatools/test/tlc2/tool/suite/ETest10.java index b7d3798909dbe2d7aadc572f32156e18a20f84fe..f69ed798ecb498dc2bde45471b126ea605fd7e20 100644 --- a/tlatools/test/tlc2/tool/suite/ETest10.java +++ b/tlatools/test/tlc2/tool/suite/ETest10.java @@ -30,12 +30,19 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest10 extends SuiteETestCase { + public ETest10() { + super(ExitStatus.FAILURE_SPEC_EVAL); + } + @Test public void testSpec() { assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, "Attempted to check if the value:\n\"a\"\nis an element of Int.")); + + assertUncovered("line 13, col 12 to line 13, col 15 of module etest10: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest11.java b/tlatools/test/tlc2/tool/suite/ETest11.java index de177831ca36d9cc648d62a8560dafce49b8ea55..a06acff72eb2f69a433f3a5062c42e110aff6abb 100644 --- a/tlatools/test/tlc2/tool/suite/ETest11.java +++ b/tlatools/test/tlc2/tool/suite/ETest11.java @@ -30,12 +30,19 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest11 extends SuiteETestCase { + public ETest11() { + super(ExitStatus.FAILURE_SPEC_EVAL); + } + @Test public void testSpec() { assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, "Attempted to check if the value:\n1\nis an element of STRING.")); + + assertUncovered("line 13, col 12 to line 13, col 15 of module etest11: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest12.java b/tlatools/test/tlc2/tool/suite/ETest12.java index bdb542361b280dcc9b8760cb557a6a15e3038d18..3f2a55bf4dd48f0f66ae9403d62b26b8b77e985a 100644 --- a/tlatools/test/tlc2/tool/suite/ETest12.java +++ b/tlatools/test/tlc2/tool/suite/ETest12.java @@ -30,14 +30,19 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest12 extends SuiteETestCase { + public ETest12() { + super(ExitStatus.VIOLATION_ASSUMPTION); + } + @Test public void testSpec() { assertTrue(recorder.toString(), recorder.recordedWithSubStringValue(EC.TLC_ASSUMPTION_EVALUATION_ERROR, "Attempted to apply the operator overridden by the Java method\n" - + "public static tlc2.value.IntValue tlc2.module.FiniteSets.Cardinality(tlc2.value.Value),\n" + + "public static tlc2.value.impl.IntValue tlc2.module.FiniteSets.Cardinality(tlc2.value.impl.Value),\n" + "but it produced the following error:\n" + "Overflow when computing the number of elements in:" + "\n[0..2 -> 1..2000]")); diff --git a/tlatools/test/tlc2/tool/suite/ETest13.java b/tlatools/test/tlc2/tool/suite/ETest13.java index 98db4229e3d3e67ad6b4b03877c1e2f80a52e552..732b0d5859cc46915e9f8fbfd95881e57d46bc20 100644 --- a/tlatools/test/tlc2/tool/suite/ETest13.java +++ b/tlatools/test/tlc2/tool/suite/ETest13.java @@ -30,14 +30,19 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest13 extends SuiteETestCase { + public ETest13() { + super(ExitStatus.VIOLATION_ASSUMPTION); + } + @Test public void testSpec() { assertTrue(recorder.toString(), recorder.recordedWithSubStringValue(EC.TLC_ASSUMPTION_EVALUATION_ERROR, "Attempted to apply the operator overridden by the Java method\n" - + "public static tlc2.value.IntValue tlc2.module.FiniteSets.Cardinality(tlc2.value.Value),\n" + + "public static tlc2.value.impl.IntValue tlc2.module.FiniteSets.Cardinality(tlc2.value.impl.Value),\n" + "but it produced the following error:\n" + "Overflow when computing the number of elements in:" + "\n[0..2 -> 1..2000]")); diff --git a/tlatools/test/tlc2/tool/suite/ETest14.java b/tlatools/test/tlc2/tool/suite/ETest14.java index 894b16c62e6410f2196894f5c1337c9cf7381ae2..d5d33ce56d52c8d204493e8c3f7c14b4e5e1b96b 100644 --- a/tlatools/test/tlc2/tool/suite/ETest14.java +++ b/tlatools/test/tlc2/tool/suite/ETest14.java @@ -30,9 +30,14 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest14 extends SuiteETestCase { + public ETest14() { + super(ExitStatus.VIOLATION_ASSUMPTION); + } + @Test public void testSpec() { assertTrue(recorder.toString(), recorder.recordedWithSubStringValue(EC.TLC_ASSUMPTION_EVALUATION_ERROR, diff --git a/tlatools/test/tlc2/tool/suite/ETest15.java b/tlatools/test/tlc2/tool/suite/ETest15.java index 24f6bb6945937290b938100cb0de7e74a35a7321..e6d6cbdb919a2f535e230628766a5718eae4eaac 100644 --- a/tlatools/test/tlc2/tool/suite/ETest15.java +++ b/tlatools/test/tlc2/tool/suite/ETest15.java @@ -30,9 +30,14 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest15 extends SuiteETestCase { + public ETest15() { + super(ExitStatus.VIOLATION_ASSUMPTION); + } + @Test public void testSpec() { assertTrue(recorder.toString(), recorder.recordedWithSubStringValue(EC.TLC_ASSUMPTION_EVALUATION_ERROR, diff --git a/tlatools/test/tlc2/tool/suite/ETest16.java b/tlatools/test/tlc2/tool/suite/ETest16.java index 81b5ffb6789e3ddaa4d8f99bd121bacb2cac040e..7113568ae522c1e05142479d1e141b8aa6de3e70 100644 --- a/tlatools/test/tlc2/tool/suite/ETest16.java +++ b/tlatools/test/tlc2/tool/suite/ETest16.java @@ -25,17 +25,18 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; - import org.junit.Test; -import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest16 extends SuiteETestCase { + public ETest16() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); assertSubstring("*** Errors: 2\n\n" + "line 5, col 27 to line 5, col 27 of module etest16\n\n" + "Non-unique fields in constructor.\n\n\n" + "line 7, col 27 to line 7, col 27 of module etest16\n\n" diff --git a/tlatools/test/tlc2/tool/suite/ETest2.java b/tlatools/test/tlc2/tool/suite/ETest2.java index a560dd836704cdd5ce0c1e31f038a04d8438f506..be48e0e0ad51854db5457670ab687510521fa165 100644 --- a/tlatools/test/tlc2/tool/suite/ETest2.java +++ b/tlatools/test/tlc2/tool/suite/ETest2.java @@ -25,17 +25,22 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest2 extends SuiteETestCase { + public ETest2() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); + assertFalse(recorder.recorded(EC.GENERAL)); assertSubstring("*** Errors: 1\n\n" + "line 18, col 12 to line 18, col 14 of module etest2\n\n" + "The operator Foo requires 2 arguments."); diff --git a/tlatools/test/tlc2/tool/suite/ETest3.java b/tlatools/test/tlc2/tool/suite/ETest3.java index 37c802da1f8e0555550bda416f18f804cfb6e8a9..9a67bf0c00d91124b7b41c04d065fcd2d481181a 100644 --- a/tlatools/test/tlc2/tool/suite/ETest3.java +++ b/tlatools/test/tlc2/tool/suite/ETest3.java @@ -31,9 +31,14 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest3 extends SuiteETestCase { + public ETest3() { + super(ExitStatus.VIOLATION_DEADLOCK); + } + /* (non-Javadoc) * @see tlc2.tool.liveness.ModelCheckerTestCase#checkDeadLock() */ @@ -47,5 +52,7 @@ public class ETest3 extends SuiteETestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "2", "0")); assertFalse(recorder.recorded(EC.GENERAL)); + + assertZeroUncovered(); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest4.java b/tlatools/test/tlc2/tool/suite/ETest4.java index 9125b626ce987b027a9a539e8b2ea842461f3396..e6747c7502d159cd65fc5d6dfb4d0a29146ada2c 100644 --- a/tlatools/test/tlc2/tool/suite/ETest4.java +++ b/tlatools/test/tlc2/tool/suite/ETest4.java @@ -30,9 +30,14 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest4 extends SuiteETestCase { + public ETest4() { + super(ExitStatus.FAILURE_SPEC_EVAL); + } + @Test public void testSpec() { assertTrue(recorder.recorded(EC.TLC_FINISHED)); @@ -42,5 +47,7 @@ public class ETest4 extends SuiteETestCase { + "2. Line 15, column 12 to line 15, column 26 in etest4\n" + "3. Line 15, column 12 to line 15, column 22 in etest4\n\n"; assertTrue(recorder.recordedWithStringValues(EC.TLC_NESTED_EXPRESSION, s)); + + assertUncovered("line 18, col 9 to line 18, col 19 of module etest4: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest5.java b/tlatools/test/tlc2/tool/suite/ETest5.java index 119c466d61bec13ef3926146658bfd8f5ddba63e..59238d5adf5394df92f0cfbc4c95fdedd747660d 100644 --- a/tlatools/test/tlc2/tool/suite/ETest5.java +++ b/tlatools/test/tlc2/tool/suite/ETest5.java @@ -25,16 +25,24 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest5 extends SuiteETestCase { + public ETest5() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("*** Errors: 1\n\n" + + "line 13, col 17 to line 13, col 20 of module etest5\n\n" + + "Unknown operator: `Init'."); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest6.java b/tlatools/test/tlc2/tool/suite/ETest6.java index 7404ca4f182ae9f1162cf6c3f2451c6a210bbaff..874649a8ebb5c24447ab0a375c98a61d3ff7ccb0 100644 --- a/tlatools/test/tlc2/tool/suite/ETest6.java +++ b/tlatools/test/tlc2/tool/suite/ETest6.java @@ -30,12 +30,20 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest6 extends SuiteETestCase { + public ETest6() { + super(ExitStatus.FAILURE_SPEC_EVAL); + } + @Test public void testSpec() { assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, "In evaluation, the identifier x is either undefined or not an operator.\nline 16, col 23 to line 16, col 23 of module etest6")); + + assertUncovered("line 13, col 14 to line 13, col 43 of module etest6: 0\n" + + "line 19, col 13 to line 19, col 23 of module etest6: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest7.java b/tlatools/test/tlc2/tool/suite/ETest7.java index c9da47ecb9470cc98eb9740bbd51fbc33bb0b043..95f4e38bdaf398e33f9cc93099336b1a55313bf2 100644 --- a/tlatools/test/tlc2/tool/suite/ETest7.java +++ b/tlatools/test/tlc2/tool/suite/ETest7.java @@ -30,12 +30,17 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest7 extends SuiteETestCase { + public ETest7() { + super(ExitStatus.ERROR_CONFIG_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, - "The configuration file substitutes constant C with non-constant Foo.")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT, + "C", "Foo")); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest8.java b/tlatools/test/tlc2/tool/suite/ETest8.java index 2ea0eec705edfcb2a8010adcdc6bbad4512276e6..c08b0c2b2b21ac4942a60f11557cbaf65b07d076 100644 --- a/tlatools/test/tlc2/tool/suite/ETest8.java +++ b/tlatools/test/tlc2/tool/suite/ETest8.java @@ -31,11 +31,12 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest8 extends SuiteETestCase { public ETest8() { - super(new String[]{"-simulate"}); + super(new String[]{"-simulate"}, ExitStatus.ERROR /*ExitStatus.VIOLATION_ASSERT*/); //TODO Simulator doesn't report correct exit status. } /* (non-Javadoc) @@ -50,5 +51,7 @@ public class ETest8 extends SuiteETestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertTrue(recorder.recorded(EC.TLC_STATS_SIMU)); assertFalse(recorder.recorded(EC.TLC_DEADLOCK_REACHED)); + + assertUncovered("line 18, col 15 to line 18, col 22 of module etest8: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/ETest9.java b/tlatools/test/tlc2/tool/suite/ETest9.java index f37a5702b05d8afa1f6c5685628be5014d69bf5e..5546e91b72110c79dcfe637d41ff27e2b4934cfc 100644 --- a/tlatools/test/tlc2/tool/suite/ETest9.java +++ b/tlatools/test/tlc2/tool/suite/ETest9.java @@ -30,12 +30,19 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class ETest9 extends SuiteETestCase { + public ETest9() { + super(ExitStatus.FAILURE_SPEC_EVAL); + } + @Test public void testSpec() { assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, "Attempted to check if the value:\n\"a\"\nis an element of Nat.")); + + assertUncovered("line 13, col 12 to line 13, col 15 of module etest9: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/SuiteETestCase.java b/tlatools/test/tlc2/tool/suite/SuiteETestCase.java index de11017f98f1586146b894b9c48f5240824c8841..87924b0ab44dd6c2808997301d2281e8926c8012 100644 --- a/tlatools/test/tlc2/tool/suite/SuiteETestCase.java +++ b/tlatools/test/tlc2/tool/suite/SuiteETestCase.java @@ -26,11 +26,13 @@ package tlc2.tool.suite; import static org.junit.Assert.fail; + import java.io.PipedOutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; import util.ToolIO; @@ -39,11 +41,19 @@ public abstract class SuiteETestCase extends ModelCheckerTestCase { private TestPrintStream testPrintStream = new TestPrintStream(); public SuiteETestCase() { - super("setBySetUp", "suite"); + this(ExitStatus.SUCCESS); + } + + public SuiteETestCase(int exitStatus) { + super("setBySetUp", "suite", exitStatus); } public SuiteETestCase(String[] params) { - super("setBySetUp", "suite", params); + this(params, ExitStatus.SUCCESS); + } + + public SuiteETestCase(String[] params, int exitStatus) { + super("setBySetUp", "suite", params, exitStatus); } /* (non-Javadoc) diff --git a/tlatools/test/tlc2/tool/suite/SuiteTestCase.java b/tlatools/test/tlc2/tool/suite/SuiteTestCase.java index 049a57ba6b2398394eb90be15750c8710f5f3c30..8d3ff58afa48b3a7e5f155382fdc581800cd494c 100644 --- a/tlatools/test/tlc2/tool/suite/SuiteTestCase.java +++ b/tlatools/test/tlc2/tool/suite/SuiteTestCase.java @@ -39,6 +39,7 @@ public abstract class SuiteTestCase extends ModelCheckerTestCase { private String leftStates = "0"; private String distinctStates = "1"; private String stateGenerated = "2"; + private String uncovered; public SuiteTestCase() { super("setBySetUp", "suite"); @@ -52,6 +53,10 @@ public abstract class SuiteTestCase extends ModelCheckerTestCase { this.initStates = initStates; } + public SuiteTestCase(String stateGenerated, String distinctStates, String leftStates, String initStates, final String uncovered) { + this(stateGenerated, distinctStates, leftStates, initStates); + this.uncovered = uncovered; + } /* (non-Javadoc) * @see tlc2.tool.liveness.ModelCheckerTestCase#setUp() */ @@ -68,5 +73,11 @@ public abstract class SuiteTestCase extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, stateGenerated, distinctStates, leftStates)); assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, initStates)); assertFalse(recorder.recorded(EC.GENERAL)); + + if (this.uncovered != null) { + assertUncovered(this.uncovered); + } else { + assertZeroUncovered(); + } } } diff --git a/tlatools/test/tlc2/tool/suite/Test17.java b/tlatools/test/tlc2/tool/suite/Test17.java index f1e76c53446ee97b9cb9862d53c8101cb336caf9..3ed73263a9ea7e940f58e90011ab57f254f96ba0 100644 --- a/tlatools/test/tlc2/tool/suite/Test17.java +++ b/tlatools/test/tlc2/tool/suite/Test17.java @@ -28,6 +28,6 @@ package tlc2.tool.suite; public class Test17 extends SuiteTestCase { public Test17() { - super("7", "2", "0", "1"); + super("7", "2", "0", "1", "line 101, col 20 to line 101, col 23 of module test17: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test20.java b/tlatools/test/tlc2/tool/suite/Test20.java index 7e713a3dd1a42e5c93699669f5b127d3d56cb5b3..75505ceb7e84c0db434a5f047352b5b3f7674294 100644 --- a/tlatools/test/tlc2/tool/suite/Test20.java +++ b/tlatools/test/tlc2/tool/suite/Test20.java @@ -27,6 +27,15 @@ package tlc2.tool.suite; public class Test20 extends SuiteTestCase { public Test20() { - super("5", "1", "0", "1"); + super("5", "1", "0", "1", " |||line 16, col 9 to line 16, col 12 of module test20: 0\n" + + " |||line 17, col 9 to line 17, col 12 of module test20: 0\n" + + " |||line 25, col 16 to line 25, col 33 of module test20: 0\n" + + " |||line 29, col 17 to line 29, col 34 of module test20: 0\n" + + " |||line 34, col 17 to line 34, col 34 of module test20: 0\n" + + " ||||line 16, col 9 to line 16, col 12 of module test20: 0\n" + + " ||||line 17, col 9 to line 17, col 12 of module test20: 0\n" + + " ||||line 25, col 16 to line 25, col 33 of module test20: 0\n" + + " ||||line 29, col 17 to line 29, col 34 of module test20: 0\n" + + " ||||line 34, col 17 to line 34, col 34 of module test20: 0"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test21.java b/tlatools/test/tlc2/tool/suite/Test21.java index c2074db4b7fd0661a384ed17436dadbe71a2c7dc..344b694f43559ef73e07d2658023ee448be1392d 100644 --- a/tlatools/test/tlc2/tool/suite/Test21.java +++ b/tlatools/test/tlc2/tool/suite/Test21.java @@ -27,6 +27,7 @@ package tlc2.tool.suite; public class Test21 extends SuiteTestCase { public Test21() { - super("8", "2", "0", "1"); + super("8", "2", "0", "1", "line 59, col 16 to line 59, col 21 of module test21: 0\n" + + "line 60, col 16 to line 60, col 19 of module test21: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test210.java b/tlatools/test/tlc2/tool/suite/Test210.java index 0c2d4022688777f59ffb1cb8b55e66499912d696..9974e3a5c6b6d9f669c80dc4e13e14e6d4178fae 100644 --- a/tlatools/test/tlc2/tool/suite/Test210.java +++ b/tlatools/test/tlc2/tool/suite/Test210.java @@ -25,17 +25,76 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test210 extends SuiteETestCase { + + public Test210() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 9\n\n" + "line 33, col 16 to line 33, col 19 of module test210\n\n" - + "Accessing subexpression labeled `laby' of ASSUME/PROVE clause within the scope of a declaration"); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 9\n" + + "\n" + + "line 33, col 16 to line 33, col 19 of module test210\n" + + "\n" + + "Accessing subexpression labeled `laby' of ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n" + + "line 35, col 16 to line 35, col 16 of module test210\n" + + "\n" + + "Accessing ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n" + + "line 42, col 41 to line 42, col 55 of module test210\n" + + "\n" + + "Label not allowed within scope of declaration in nested ASSUME/PROVE.\n" + + "\n" + + "\n" + + "line 43, col 30 to line 43, col 44 of module test210\n" + + "\n" + + "Label not allowed within scope of declaration in nested ASSUME/PROVE.\n" + + "\n" + + "\n" + + "line 55, col 16 to line 55, col 16 of module test210\n" + + "\n" + + "Accessing non-existent subexpression of a SUFFICES\n" + + "\n" + + "\n" + + "line 62, col 15 to line 62, col 18 of module test210\n" + + "\n" + + "Accessing subexpression labeled `laby' of ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n" + + "line 63, col 15 to line 63, col 18 of module test210\n" + + "\n" + + "Accessing subexpression labeled `labi' of ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n" + + "line 64, col 15 to line 64, col 18 of module test210\n" + + "\n" + + "Accessing subexpression labeled `labu' of ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n" + + "line 65, col 15 to line 65, col 15 of module test210\n" + + "\n" + + "Accessing ASSUME/PROVE clause within the scope of a declaration\n" + + " from outside that declaration's scope.\n" + + "\n" + + "\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test212.java b/tlatools/test/tlc2/tool/suite/Test212.java index 1d7130ab060f07f5f5af82968c43eb37ff70d8a5..5a1cb6cec586378cf63e7653158785c48952867d 100644 --- a/tlatools/test/tlc2/tool/suite/Test212.java +++ b/tlatools/test/tlc2/tool/suite/Test212.java @@ -25,17 +25,62 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test212 extends SuiteETestCase { + + public Test212() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 6\n\n" + "line 27, col 1 to line 27, col 62 of module test212\n\n" - + "Error in instantiating module 'test212a':"); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 6\n" + + "\n" + + "line 27, col 1 to line 27, col 62 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op2'.\n" + + "\n" + + "\n" + + "line 28, col 1 to line 28, col 62 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op'.\n" + + "\n" + + "\n" + + "line 29, col 1 to line 29, col 62 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op'.\n" + + "\n" + + "\n" + + "line 30, col 1 to line 30, col 64 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op2'.\n" + + "\n" + + "\n" + + "line 31, col 1 to line 31, col 63 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op2'.\n" + + "\n" + + "\n" + + "line 32, col 1 to line 32, col 63 of module test212\n" + + "\n" + + "Error in instantiating module 'test212a':\n" + + " A non-Leibniz operator substituted for 'Op2'.\n" + + "\n" + + "\n" + + ""); } } diff --git a/tlatools/test/tlc2/tool/suite/Test213.java b/tlatools/test/tlc2/tool/suite/Test213.java index 8ecf01b2db9f21584d7353c82118c9d0fdca3e4b..e11f6b635b2df304e4a1ee36ab1c7ef35e49949a 100644 --- a/tlatools/test/tlc2/tool/suite/Test213.java +++ b/tlatools/test/tlc2/tool/suite/Test213.java @@ -25,18 +25,55 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test213 extends SuiteETestCase { + + public Test213() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 5\n\n" - + "line 13, col 1 to line 13, col 52 of module test213\n\n" - + "Level error in instantiating module 'test213b':"); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 5\n" + + "\n" + + "line 13, col 1 to line 13, col 52 of module test213\n" + + "\n" + + "Level error in instantiating module 'test213b':\n" + + "The level of the expression or operator substituted for 'C' \n" + + "must be at most 2.\n" + + "\n" + + "\n" + + "line 14, col 1 to line 14, col 52 of module test213\n" + + "\n" + + "Level error in instantiating module 'test213b':\n" + + "The level of the expression or operator substituted for 'D' \n" + + "must be at most 2.\n" + + "\n" + + "\n" + + "line 29, col 8 to line 29, col 15 of module test213\n" + + "\n" + + "Non-constant CASE for temporal goal.\n" + + "\n" + + "\n" + + "line 31, col 8 to line 31, col 15 of module test213\n" + + "\n" + + "Non-constant TAKE, WITNESS, or HAVE for temporal goal.\n" + + "\n" + + "\n" + + "line 33, col 8 to line 33, col 22 of module test213\n" + + "\n" + + "Non-constant TAKE, WITNESS, or HAVE for temporal goal.\n" + + "\n" + + "\n" + + ""); } } diff --git a/tlatools/test/tlc2/tool/suite/Test214.java b/tlatools/test/tlc2/tool/suite/Test214.java index 5cc5a90225f598e7703a3450d26bfaee5709d869..d2cbd0887e04170b92772eea9a49f883fb17d65f 100644 --- a/tlatools/test/tlc2/tool/suite/Test214.java +++ b/tlatools/test/tlc2/tool/suite/Test214.java @@ -25,18 +25,31 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test214 extends SuiteETestCase { + + public Test214() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 1\n\n" - + "line 10, col 11 to line 10, col 14 of module test214\n\n" - + "The only expression allowed as a fact in a HIDE is"); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 1\n" + + "\n" + + "line 10, col 11 to line 10, col 14 of module test214\n" + + "\n" + + "The only expression allowed as a fact in a HIDE is \n" + + "the name of a theorem, assumption, or step.\n" + + "\n" + + "\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test215.java b/tlatools/test/tlc2/tool/suite/Test215.java index 5fb8a29b6964ab2880897a8ac1166bf03a0c6838..0b1d74e75cd73c5caec98c4cd791867275912ded 100644 --- a/tlatools/test/tlc2/tool/suite/Test215.java +++ b/tlatools/test/tlc2/tool/suite/Test215.java @@ -25,18 +25,65 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test215 extends SuiteETestCase { + + public Test215() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 8\n\n" - + "line 8, col 6 to line 8, col 14 of module test215\n\n" - + "Action used where only temporal formula or state predicate allowed."); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 8\n" + + "\n" + + "line 8, col 6 to line 8, col 14 of module test215\n" + + "\n" + + "Action used where only temporal formula or state predicate allowed.\n" + + "\n" + + "\n" + + "line 9, col 6 to line 9, col 14 of module test215\n" + + "\n" + + "Action used where only temporal formula or state predicate allowed.\n" + + "\n" + + "\n" + + "line 12, col 6 to line 12, col 16 of module test215\n" + + "\n" + + "Action used where only temporal formula or state predicate allowed.\n" + + "\n" + + "\n" + + "line 13, col 6 to line 13, col 16 of module test215\n" + + "\n" + + "Action used where only temporal formula or state predicate allowed.\n" + + "\n" + + "\n" + + "line 16, col 6 to line 16, col 11 of module test215\n" + + "\n" + + "<> followed by action not of form <<A>>_v.\n" + + "\n" + + "\n" + + "line 20, col 8 to line 20, col 13 of module test215\n" + + "\n" + + "[] followed by action not of form [A]_v.\n" + + "\n" + + "\n" + + "line 23, col 25 to line 23, col 26 of module test215\n" + + "\n" + + "Action-level bound of quantified temporal formula.\n" + + "\n" + + "\n" + + "line 26, col 26 to line 26, col 27 of module test215\n" + + "\n" + + "Action-level bound of quantified temporal formula.\n" + + "\n" + + "\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test216.java b/tlatools/test/tlc2/tool/suite/Test216.java index e25554ac685f93d7a63ded5a1106068ca71c3479..ace958c23af804ff79b3a63b90963494b2f9d6c7 100644 --- a/tlatools/test/tlc2/tool/suite/Test216.java +++ b/tlatools/test/tlc2/tool/suite/Test216.java @@ -39,5 +39,7 @@ public class Test216 extends SuiteETestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "28", "7", "0")); assertTrue(recorder.recordedWithStringValues(EC.TLC_INIT_GENERATED2, "21", "s", "7")); assertFalse(recorder.recorded(EC.GENERAL)); + + assertUncovered("line 12, col 22 to line 12, col 32 of module test216: 0\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test217.java b/tlatools/test/tlc2/tool/suite/Test217.java index 573b322b7e60ebbb00899760a11c01f223dffa33..4575c00f5737ab1d314bd5cee3a747204115b445 100644 --- a/tlatools/test/tlc2/tool/suite/Test217.java +++ b/tlatools/test/tlc2/tool/suite/Test217.java @@ -25,18 +25,37 @@ ******************************************************************************/ package tlc2.tool.suite; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; public class Test217 extends SuiteETestCase { + + public Test217() { + super(ExitStatus.ERROR_SPEC_PARSE); + } + @Test public void testSpec() { - assertTrue(recorder.recorded(EC.GENERAL)); - assertSubstring("*** Errors: 2\n\n" - + "line 12, col 11 to line 12, col 19 of module test217\n\n" - + "Level error in applying operator I!Foo:"); + assertFalse(recorder.recorded(EC.GENERAL)); + assertSubstring("Semantic errors:\n" + + "\n" + + "*** Errors: 2\n" + + "\n" + + "line 12, col 11 to line 12, col 19 of module test217\n" + + "\n" + + "Level error in applying operator I!Foo:\n" + + "The level of argument 1 exceeds the maximum level allowed by the operator.\n" + + "\n" + + "\n" + + "line 13, col 9 to line 13, col 19 of module test217\n" + + "\n" + + "Level error in applying operator I!Foo:\n" + + "The level of argument 1 exceeds the maximum level allowed by the operator.\n" + + "\n" + + "\n"); } } diff --git a/tlatools/test/tlc2/tool/suite/Test32.java b/tlatools/test/tlc2/tool/suite/Test32.java index efe17f4a1b3dceb8f29b40c66dbf8f375c7f823b..94decb30f94b876e76acdbd948b3919973ab001d 100644 --- a/tlatools/test/tlc2/tool/suite/Test32.java +++ b/tlatools/test/tlc2/tool/suite/Test32.java @@ -27,6 +27,8 @@ package tlc2.tool.suite; public class Test32 extends SuiteTestCase { public Test32() { - super("3", "1", "0", "1"); + super("3", "1", "0", "1", "line 23, col 17 to line 23, col 21 of module test32: 0\n" + + "line 23, col 26 to line 23, col 29 of module test32: 0\n" + + "line 27, col 23 to line 27, col 29 of module test32: 0\n"); } } \ No newline at end of file diff --git a/tlatools/test/tlc2/tool/liveness/Test057.java b/tlatools/test/tlc2/tool/suite/Test57.java similarity index 88% rename from tlatools/test/tlc2/tool/liveness/Test057.java rename to tlatools/test/tlc2/tool/suite/Test57.java index 9b0459f9c354a7d60f2b844161c68236303b5e95..7ee10dec3881f10844dbac36e338ab103d4ba3d8 100644 --- a/tlatools/test/tlc2/tool/liveness/Test057.java +++ b/tlatools/test/tlc2/tool/suite/Test57.java @@ -24,18 +24,22 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.tool.liveness; +package tlc2.tool.suite; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; + import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; -public class Test057 extends ModelCheckerTestCase { +public class Test57 extends SuiteTestCase { - public Test057() { - super("test57"); + public Test57() { + // Can pass any value to super because testSpec is overriden. + super("-1", "-1", "-1", "-1"); + setExitStatus(ExitStatus.VIOLATION_SAFETY); } @Test diff --git a/tlatools/test/tlc2/tool/suite/TestInvalidInvariant.java b/tlatools/test/tlc2/tool/suite/TestInvalidInvariant.java index 1e7f5b1d3ff37fe87eee2fc38fff698e7bbeea7b..e0941db03c9974c4aa9b0029da99c161821877bc 100644 --- a/tlatools/test/tlc2/tool/suite/TestInvalidInvariant.java +++ b/tlatools/test/tlc2/tool/suite/TestInvalidInvariant.java @@ -31,20 +31,20 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.output.EC; +import tlc2.output.EC.ExitStatus; import tlc2.tool.liveness.ModelCheckerTestCase; public class TestInvalidInvariant extends ModelCheckerTestCase { public TestInvalidInvariant() { - super("testinvalidinvariant"); + super("testinvalidinvariant", ExitStatus.FAILURE_SAFETY_EVAL); } @Test public void testSpec() { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertTrue(recorder.recordedWithStringValue(EC.TLC_INVARIANT_VIOLATED_LEVEL, "Invariant")); - assertTrue(recorder.recordedWithSubStringValue(EC.GENERAL, - "The invariant Invariant is not a state predicate (one with no primes or temporal operators).")); + assertFalse(recorder.recorded(EC.GENERAL)); // See LevelNode.java line 590ff and tlc2.tool.Spec.processConfigInvariants(). assertFalse(recorder.recordedWithSubStringValue(EC.GENERAL, "Note that a bug can cause TLC to incorrectly report this error.")); diff --git a/tlatools/test/tlc2/util/BitVectorTest.java b/tlatools/test/tlc2/util/BitVectorTest.java index a7015b015f340f25903a9b2a2b076af43ee0c665..f996d8ba3e485689bde1e0cf194be63c2f0828e9 100644 --- a/tlatools/test/tlc2/util/BitVectorTest.java +++ b/tlatools/test/tlc2/util/BitVectorTest.java @@ -26,7 +26,7 @@ package tlc2.util; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import org.junit.Test; diff --git a/tlatools/test/tlc2/util/ByteUtilsTest.java b/tlatools/test/tlc2/util/ByteUtilsTest.java index 94e0d57c494498ba4cb15305a259813791e2bad4..f84ecdf5d6c6f630874daf8b5e22ff2c85ff7f9c 100644 --- a/tlatools/test/tlc2/util/ByteUtilsTest.java +++ b/tlatools/test/tlc2/util/ByteUtilsTest.java @@ -7,8 +7,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.util.Random; + import org.junit.Before; import org.junit.Test; + import util.ToolIO; /** diff --git a/tlatools/test/tlc2/util/CombinatoricsTest.java b/tlatools/test/tlc2/util/CombinatoricsTest.java index 1bf0e968c8986b708d8adc0906924bd655d8af35..6696b19fd6d7e1e4a3b8e9970d1f76b70cf5b175 100644 --- a/tlatools/test/tlc2/util/CombinatoricsTest.java +++ b/tlatools/test/tlc2/util/CombinatoricsTest.java @@ -25,7 +25,7 @@ ******************************************************************************/ package tlc2.util; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.math.BigInteger; diff --git a/tlatools/test/tlc2/util/MemIntQueueTest.java b/tlatools/test/tlc2/util/MemIntQueueTest.java index e82fe4f173e33abb7cb72cfc7e9e64fd62250722..e32fd2ff9b43d4ada16a0c134f1b2ed45c37c25d 100644 --- a/tlatools/test/tlc2/util/MemIntQueueTest.java +++ b/tlatools/test/tlc2/util/MemIntQueueTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.NoSuchElementException; + import org.junit.Test; public class MemIntQueueTest { diff --git a/tlatools/test/tlc2/util/SynchronousDiskIntStackTest.java b/tlatools/test/tlc2/util/SynchronousDiskIntStackTest.java index 96d650c7ec2dc18796aaba975ac89d8b9afc8a3d..1c52a98a268e0d8c7e1acc7754560eaa498e8e52 100644 --- a/tlatools/test/tlc2/util/SynchronousDiskIntStackTest.java +++ b/tlatools/test/tlc2/util/SynchronousDiskIntStackTest.java @@ -29,6 +29,7 @@ package tlc2.util; import static org.junit.Assert.assertEquals; import java.io.File; + import org.junit.Test; public class SynchronousDiskIntStackTest { diff --git a/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java b/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java index dda13c636836ca12e8ea2e8f21d7ca93e4b92c30..e35e6d2126505e0a7bcf90507371ec991f287545 100644 --- a/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java +++ b/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java @@ -25,7 +25,7 @@ ******************************************************************************/ package tlc2.value; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.io.File; import java.io.IOException; diff --git a/tlatools/test/tlc2/value/EnumerableValueTest.java b/tlatools/test/tlc2/value/impl/EnumerableValueTest.java similarity index 90% rename from tlatools/test/tlc2/value/EnumerableValueTest.java rename to tlatools/test/tlc2/value/impl/EnumerableValueTest.java index 553fbcbdb2df856d78a22ecd2cb2e0eb7cb7cc6f..38584cb63f9743eed6aea9c95cd2c57fbcd40934 100644 --- a/tlatools/test/tlc2/value/EnumerableValueTest.java +++ b/tlatools/test/tlc2/value/impl/EnumerableValueTest.java @@ -24,7 +24,7 @@ * Markus Alexander Kuppe - initial API and implementation * Ian Morris Nieves - added support for fingerprint stack trace ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -34,13 +34,15 @@ import java.util.Set; import org.junit.Test; -import tlc2.value.EnumerableValue.SubsetEnumerator; +import tlc2.value.IValue; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.EnumerableValue.SubsetEnumerator; public class EnumerableValueTest { @Test public void test() { - EnumerableValue.setRandom(15041980); + RandomEnumerableValues.setSeed(15041980); final Set<Integer> indices = new HashSet<>(); // For the first n \in Nat+ up to 10657 show that: @@ -132,7 +134,7 @@ public class EnumerableValueTest { } @Override - public Value deepCopy() { + public IValue deepCopy() { return null; } @@ -142,8 +144,8 @@ public class EnumerableValueTest { } @Override - public StringBuffer toString(StringBuffer sb, int offset) { - return null; + public StringBuffer toString(StringBuffer sb, int offset, boolean swallow) { + return toString(sb, offset, swallow); } } } diff --git a/tlatools/test/tlc2/value/IntervalValueTest.java b/tlatools/test/tlc2/value/impl/IntervalValueTest.java similarity index 79% rename from tlatools/test/tlc2/value/IntervalValueTest.java rename to tlatools/test/tlc2/value/impl/IntervalValueTest.java index 67d6ce80814ae7ab0525be8124af2ab6a2c71b35..9520823a06e35485c866d2fcbc15b77ceb6c6bf0 100644 --- a/tlatools/test/tlc2/value/IntervalValueTest.java +++ b/tlatools/test/tlc2/value/impl/IntervalValueTest.java @@ -1,9 +1,12 @@ -package tlc2.value; +package tlc2.value.impl; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import org.junit.Test; +import tlc2.value.impl.IntValue; +import tlc2.value.impl.IntervalValue; import util.Assert.TLCRuntimeException; public class IntervalValueTest { diff --git a/tlatools/test/tlc2/value/RecordValueTest.java b/tlatools/test/tlc2/value/impl/RecordValueTest.java similarity index 97% rename from tlatools/test/tlc2/value/RecordValueTest.java rename to tlatools/test/tlc2/value/impl/RecordValueTest.java index 57f44dcb7c9d45bc1b5e165c18752d6bd396b6b8..694acb43ad73a7b3bdfd3af480d11c1de4cced96 100644 --- a/tlatools/test/tlc2/value/RecordValueTest.java +++ b/tlatools/test/tlc2/value/impl/RecordValueTest.java @@ -24,18 +24,19 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertTrue; import org.junit.Test; + import util.InternTable; import util.UniqueString; public class RecordValueTest { /** - * Test method for {@link tlc2.value.RecordValue#deepCopy()}. + * Test method for {@link tlc2.value.impl.RecordValue#deepCopy()}. * * This test reveals a bug in the implementation of RecordValue#deepCopy() * when the original instance from which the deep copy has been created is diff --git a/tlatools/test/tlc2/value/SetOfFcnsValueTest.java b/tlatools/test/tlc2/value/impl/SetOfFcnsValueTest.java similarity index 96% rename from tlatools/test/tlc2/value/SetOfFcnsValueTest.java rename to tlatools/test/tlc2/value/impl/SetOfFcnsValueTest.java index b492a81defd5c956164c8762e452f88114462e32..98d73b1e61fc4ca8675f3a59ce73044da28e3b2a 100644 --- a/tlatools/test/tlc2/value/SetOfFcnsValueTest.java +++ b/tlatools/test/tlc2/value/impl/SetOfFcnsValueTest.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -41,7 +41,7 @@ import java.util.stream.IntStream; import org.junit.Test; import tlc2.util.FP64; -import tlc2.value.SetOfFcnsValue.SubsetEnumerator; +import tlc2.value.impl.SetOfFcnsValue.SubsetEnumerator; import util.Assert.TLCRuntimeException; public class SetOfFcnsValueTest { @@ -80,16 +80,14 @@ public class SetOfFcnsValueTest { new SetEnumValue(new Value[] { new StringValue("b") }, true) }, true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(values, + new Value[] { emptyset, emptyset, + new SetEnumValue(new Value[] { new StringValue("c") }, true) }, + true), enumerator.elementAt(i++)); assertEquals(new FcnRcdValue(values, new Value[] { emptyset, emptyset, new SetEnumValue(new Value[] { new StringValue("a"), new StringValue("b") }, true) }, true), enumerator.elementAt(i++)); - assertEquals( - new FcnRcdValue(values, - new Value[] { emptyset, emptyset, - new SetEnumValue(new Value[] { new StringValue("c") }, true) }, - true), - enumerator.elementAt(i++)); // Last element final SetEnumValue setEnumValue = new SetEnumValue( @@ -111,7 +109,7 @@ public class SetOfFcnsValueTest { assertNull(elements.nextElement()); // Subset behaves similar. - final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + final Enumerable subset = setOfFcnsValue.getRandomSubset(5); final ValueEnumeration subsetElements = subset.elements(); assertEquals(1, subset.size()); assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), subsetElements.nextElement()); @@ -128,7 +126,7 @@ public class SetOfFcnsValueTest { assertNull(setOfFcnsValue.elements().nextElement()); // Subset behaves similar. - final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + final Enumerable subset = setOfFcnsValue.getRandomSubset(5); assertEquals(0, subset.size()); assertNull(subset.elements().nextElement()); assertEquals(new SetEnumValue(), subset); @@ -146,7 +144,7 @@ public class SetOfFcnsValueTest { assertNull(elements.nextElement()); // Subset behaves similar. - final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + final Enumerable subset = setOfFcnsValue.getRandomSubset(5); final ValueEnumeration subsetElements = subset.elements(); assertEquals(1, subset.size()); assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), subsetElements.nextElement()); @@ -172,7 +170,7 @@ public class SetOfFcnsValueTest { enumeratorValues.add(rcd); } - final EnumerableValue randomSubset = setOfFcnsValue.getRandomSubset(27); + final Enumerable randomSubset = setOfFcnsValue.getRandomSubset(27); final Set<FcnRcdValue> randomsubsetValues = new HashSet<>(27); final ValueEnumeration enumerator2 = randomSubset.elements(); @@ -366,7 +364,7 @@ public class SetOfFcnsValueTest { IntStream.of(0, 1, 2, 799, 1024, 8932, 16933/*, 109031*/).forEach(new IntConsumer() { // 109031 causes the test to take a little long to be included in the overall test suite. @Override public void accept(int kOutOfN) { - final EnumerableValue randomSubset = sofv.getRandomSubset(kOutOfN); + final Enumerable randomSubset = sofv.getRandomSubset(kOutOfN); // Check expected amount of elements. assertEquals(kOutOfN, randomSubset.size()); diff --git a/tlatools/test/tlc2/value/SetOfRcrdValueTest.java b/tlatools/test/tlc2/value/impl/SetOfRcrdValueTest.java similarity index 95% rename from tlatools/test/tlc2/value/SetOfRcrdValueTest.java rename to tlatools/test/tlc2/value/impl/SetOfRcrdValueTest.java index 94e312cfc08a2912ff7eb6245ba14b186bf95170..8b1200dfbd06d41b7ac0a93cc44f534e21e9c39e 100644 --- a/tlatools/test/tlc2/value/SetOfRcrdValueTest.java +++ b/tlatools/test/tlc2/value/impl/SetOfRcrdValueTest.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -37,7 +37,7 @@ import org.junit.BeforeClass; import org.junit.Test; import tlc2.util.FP64; -import tlc2.value.SetOfRcdsValue.SubsetEnumerator; +import tlc2.value.impl.SetOfRcdsValue.SubsetEnumerator; import util.UniqueString; public class SetOfRcrdValueTest { @@ -125,7 +125,7 @@ public class SetOfRcrdValueTest { final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(3, names), true); final int size = 27; - final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(size); + final Enumerable randomSubset = setOfRcrdValue.getRandomSubset(size); final Set<RecordValue> randomsubsetValues = new HashSet<>(size); final ValueEnumeration enumerator = randomSubset.elements(); @@ -149,7 +149,7 @@ public class SetOfRcrdValueTest { final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(m, names), true); final Set<RecordValue> randomsubsetValues = new HashSet<>(); for (int kOutOfN = 0; kOutOfN < setOfRcrdValue.size(); kOutOfN++) { - final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(kOutOfN); + final Enumerable randomSubset = setOfRcrdValue.getRandomSubset(kOutOfN); final ValueEnumeration enumerator = randomSubset.elements(); RecordValue rcd; @@ -178,7 +178,7 @@ public class SetOfRcrdValueTest { final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(50, names), true); final int k = 10000; - final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(k); + final Enumerable randomSubset = setOfRcrdValue.getRandomSubset(k); final Set<RecordValue> randomsubsetValues = new HashSet<>(k); final ValueEnumeration enumerator = randomSubset.elements(); diff --git a/tlatools/test/tlc2/value/SetOfTuplesValueTest.java b/tlatools/test/tlc2/value/impl/SetOfTuplesValueTest.java similarity index 95% rename from tlatools/test/tlc2/value/SetOfTuplesValueTest.java rename to tlatools/test/tlc2/value/impl/SetOfTuplesValueTest.java index 64948b79def1d3dca9d08536f455ced668d28e79..ab56fd81fc6b92bc80db91da0d344944af77c970 100644 --- a/tlatools/test/tlc2/value/SetOfTuplesValueTest.java +++ b/tlatools/test/tlc2/value/impl/SetOfTuplesValueTest.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -31,6 +31,8 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import tlc2.TLCGlobals; +import tlc2.value.impl.IntervalValue; +import tlc2.value.impl.SetOfTuplesValue; public class SetOfTuplesValueTest { diff --git a/tlatools/test/tlc2/value/SubsetEnumeratorTest.java b/tlatools/test/tlc2/value/impl/SubsetEnumeratorTest.java similarity index 95% rename from tlatools/test/tlc2/value/SubsetEnumeratorTest.java rename to tlatools/test/tlc2/value/impl/SubsetEnumeratorTest.java index acf3d31fddd05607418cacc2e0c926db9b204c7f..187ef6256c4d6bdfb26a6b508b0106ad1a45f2b2 100644 --- a/tlatools/test/tlc2/value/SubsetEnumeratorTest.java +++ b/tlatools/test/tlc2/value/impl/SubsetEnumeratorTest.java @@ -24,7 +24,7 @@ * Markus Alexander Kuppe - initial API and implementation * Ian Morris Nieves - added support for fingerprint stack trace ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertEquals; @@ -56,8 +56,8 @@ public class SubsetEnumeratorTest { } @Parameters - public static List<EnumerableValue> getEnumerable() { - final List<EnumerableValue> params = new ArrayList<EnumerableValue>(); + public static List<Enumerable> getEnumerable() { + final List<Enumerable> params = new ArrayList<Enumerable>(); // IntervalValue params.add(new IntervalValue(1, 10)); @@ -147,12 +147,12 @@ public class SubsetEnumeratorTest { public void accept(final double fraction) { final int k = (int) Math.ceil(enumerable.size() * fraction); - final EnumerableValue enumValue = enumerable.getRandomSubset(k); + final Enumerable enumValue = enumerable.getRandomSubset(k); // Expected size. assertEquals(String.format("Failed for fraction: %s", fraction), k, enumValue.size()); - final Set<Value> values = new HashSet<Value>(enumValue.size()); + final Set<Value> values = new HashSet<>(enumValue.size()); // Each value is actually a member of enumerable. ValueEnumeration elements = enumValue.elements(); diff --git a/tlatools/test/tlc2/value/SubsetValueTest.java b/tlatools/test/tlc2/value/impl/SubsetValueTest.java similarity index 92% rename from tlatools/test/tlc2/value/SubsetValueTest.java rename to tlatools/test/tlc2/value/impl/SubsetValueTest.java index 144ff10f5805fbdca8ad91c42c85d662879f3fb3..6270858465f43a5dd32ee7ac2d4f1c5ff672e0ed 100644 --- a/tlatools/test/tlc2/value/SubsetValueTest.java +++ b/tlatools/test/tlc2/value/impl/SubsetValueTest.java @@ -23,7 +23,7 @@ * Contributors: * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.value; +package tlc2.value.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -42,10 +42,11 @@ import org.junit.BeforeClass; import org.junit.Test; import tlc2.util.FP64; -import tlc2.value.SubsetValue.CoinTossingSubsetEnumerator; -import tlc2.value.SubsetValue.KElementEnumerator; -import tlc2.value.SubsetValue.SubsetEnumerator; -import tlc2.value.SubsetValue.Unrank; +import tlc2.value.RandomEnumerableValues; +import tlc2.value.impl.SubsetValue.CoinTossingSubsetEnumerator; +import tlc2.value.impl.SubsetValue.KElementEnumerator; +import tlc2.value.impl.SubsetValue.SubsetEnumerator; +import tlc2.value.impl.SubsetValue.Unrank; import util.Assert; public class SubsetValueTest { @@ -62,7 +63,7 @@ public class SubsetValueTest { @BeforeClass public static void setup() { // Make test repeatable by setting random seed always to same value. - EnumerableValue.setRandom(15041980L); + RandomEnumerableValues.setSeed(15041980L); // Needed to insert elements into java.util.Set (because of hashcode) later to // detect duplicates. FP64.Init(); @@ -516,4 +517,36 @@ public class SubsetValueTest { setOfSubsets.normalize(); assertEquals(k, setOfSubsets.size()); } + + @Test + public void testSubsetNeedsNormalization() { + final IntervalValue inner = new IntervalValue(1, 5); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vec = new ValueVec(subset.size()); + for (int i = 0; i <= inner.size(); i++) { + List<Value> kElements = subset.kElements(i).all(); + kElements.forEach(e -> vec.addElement(e)); + } + final Value unnormalized = new SetEnumValue(vec, false); + + final Value normalized = subset.toSetEnum().normalize(); + + assertEquals(normalized, unnormalized); + } + + @Test + public void testSubsetNeedsNormalization2() { + final IntervalValue inner = new IntervalValue(1, 6); + final SubsetValue subset = new SubsetValue(inner); + + final ValueVec vec = new ValueVec(subset.size()); + final ValueEnumeration bElements = subset.elementsNormalized(); + bElements.forEach(e -> vec.addElement(e)); + final Value unnormalized = new SetEnumValue(vec, true); + + final Value normalized = subset.toSetEnum().normalize(); + + assertEquals(normalized, unnormalized); + } } diff --git a/tlatools/test/util/ExecutionStatisticsCollectorTest.java b/tlatools/test/util/ExecutionStatisticsCollectorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2c991bb67183820c6266be2b1605bd0287f57b13 --- /dev/null +++ b/tlatools/test/util/ExecutionStatisticsCollectorTest.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import org.junit.Test; + +public class ExecutionStatisticsCollectorTest { + + // Opt-out + + @Test + public void testOptOutNoFile() throws IOException { + final String tmpdir = System.getProperty("java.io.tmpdir"); + final File tempFile = new File(tmpdir + File.separator + "esc" + System.currentTimeMillis() + ".txt"); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + final String identifierA = esc.getIdentifier(); + assertNotNull(identifierA); + assertNotNull(esc.getIdentifier()); + assertEquals(identifierA, esc.getIdentifier()); + } + + @Test + public void testOptOutUnreadableFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + tempFile.setReadable(false); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + assertNull(esc.getIdentifier()); + } + + @Test + public void testOptOutEmptyFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + assertNull(esc.getIdentifier()); + } + + @Test + public void testOptOutNoESCFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), (" " + ExecutionStatisticsCollector.Selection.NO_ESC.toString() + " ").getBytes()); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + assertNull(esc.getIdentifier()); + } + + @Test + public void testOptOutRandomIdFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), (" " + ExecutionStatisticsCollector.Selection.RANDOM_IDENTIFIER.toString() + " ").getBytes()); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + final String identifierA = esc.getIdentifier(); + assertNotNull(identifierA); + final String identifierB = esc.getIdentifier(); + assertNotNull(identifierB); + assertNotEquals(identifierA, identifierB); + } + + @Test + public void testOptOutUserDefinedIdFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), " 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ".getBytes()); + tempFile.deleteOnExit(); + + final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(true, tempFile.getAbsolutePath()); + + assertEquals("123456789ABCDEFGHIJKLMNOPQRSTUVW", esc.getIdentifier()); + } + + // Opt-In + + @Test + public void testNoFile() { + assertNull(new ExecutionStatisticsCollector("/path/does/not/exist").getIdentifier()); + } + + @Test + public void testUnreadableFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + tempFile.setReadable(false); + tempFile.deleteOnExit(); + + assertNull(new ExecutionStatisticsCollector(tempFile.getAbsolutePath()).getIdentifier()); + } + + @Test + public void testEmptyFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + tempFile.deleteOnExit(); + + assertNull(new ExecutionStatisticsCollector(tempFile.getAbsolutePath()).getIdentifier()); + } + + @Test + public void testNoESCFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), (" " + ExecutionStatisticsCollector.Selection.NO_ESC.toString() + " ").getBytes()); + tempFile.deleteOnExit(); + + assertNull(new ExecutionStatisticsCollector(tempFile.getAbsolutePath()).getIdentifier()); + } + + @Test + public void testRandomIdFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), (" " + ExecutionStatisticsCollector.Selection.RANDOM_IDENTIFIER.toString() + " ").getBytes()); + tempFile.deleteOnExit(); + + ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector(tempFile.getAbsolutePath()); + + final String identifierA = esc.getIdentifier(); + assertNotNull(identifierA); + final String identifierB = esc.getIdentifier(); + assertNotNull(identifierB); + assertNotEquals(identifierA, identifierB); + } + + @Test + public void testUserDefinedIdFile() throws IOException { + File tempFile = File.createTempFile("esc", "txt"); + Files.write(tempFile.toPath(), " 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ".getBytes()); + tempFile.deleteOnExit(); + + assertEquals("123456789ABCDEFGHIJKLMNOPQRSTUVW", new ExecutionStatisticsCollector(tempFile.getAbsolutePath()).getIdentifier()); + } +} diff --git a/tlatools/test/util/IsolatedTestCaseRunner.java b/tlatools/test/util/IsolatedTestCaseRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..05c44d4a1e4e85006c5a00146da232f12157fefe --- /dev/null +++ b/tlatools/test/util/IsolatedTestCaseRunner.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import java.lang.reflect.InvocationTargetException; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.JUnit4; +import org.junit.runners.model.InitializationError; + +public class IsolatedTestCaseRunner extends Runner { + + private final JUnit4 delegate; + + public IsolatedTestCaseRunner(final Class<?> testFileClass) + throws InitializationError, ClassNotFoundException, InstantiationException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { + + // Since IsolatedTestCaseRunner runs several isolated tests in a single VM, it + // is good practice to clean resources before each new test. + System.gc(); + + ClassLoader classLoader = IsolatedTestCaseRunner.class.getClassLoader(); + if (classLoader instanceof URLClassLoader) { + // When run within e.g. Eclipse, the classloader might not be of instance + // URLClassLoader. In this case, just use the provided class loader which won't + // isolate tests. A set of tests can thus only be run in a single VM from ant + // or maven which pass a URLClassLoader. + classLoader = new IsolatedTestCaseClassLoader((URLClassLoader) classLoader); + } + delegate = new JUnit4(classLoader.loadClass(testFileClass.getName())); + } + + @Override + public Description getDescription() { + return delegate.getDescription(); + } + + @Override + public void run(RunNotifier notifier) { + delegate.run(notifier); + } + + private class IsolatedTestCaseClassLoader extends URLClassLoader { + + private final Map<String, Class<?>> cache = new HashMap<>(); + private final Set<String> packages = new HashSet<>(); + + public IsolatedTestCaseClassLoader(URLClassLoader classLoader) { + super(classLoader.getURLs()); + + // All of TLC's java packages. + packages.add("tla2sany"); + packages.add("pcal"); + packages.add("util"); + packages.add("tla2tex"); + packages.add("tlc2"); + } + + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + if (cache.containsKey(name)) { + // Cache to not load classes twice for a single test case which results in a + // LinkageError. + return cache.get(name); + } + for (final String pkg : packages) { + if (name.startsWith(pkg)) { + final Class<?> findClass = findClass(name); + cache.put(name, findClass); + return findClass; + } + } + return super.loadClass(name); + } + } +} diff --git a/tlatools/test/util/SimpleFilenameToStreamTest.java b/tlatools/test/util/SimpleFilenameToStreamTest.java index 2ae4c61e0bd61b167918bce89c1e4584ca42cf20..815e8db3429dd7f35de3e25e7bb9b63971bea5b1 100644 --- a/tlatools/test/util/SimpleFilenameToStreamTest.java +++ b/tlatools/test/util/SimpleFilenameToStreamTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; + import org.junit.Test; public class SimpleFilenameToStreamTest { diff --git a/tlatools/test/util/TLCRuntimeTest.java b/tlatools/test/util/TLCRuntimeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4853b42a8d12cd5f6e6f65ccc78b7c32bd157167 --- /dev/null +++ b/tlatools/test/util/TLCRuntimeTest.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2019 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * 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. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package util; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class TLCRuntimeTest { + + @Test + public void testIsThroughputOptimized() { + // customBuild.xml executes the tests with UseParallelGC set. This should thus + // pass. It will pass without UseParallelGC set on a pre Java 9 VM where + // parallel GC used to be the default. + assertTrue(TLCRuntime.getInstance().isThroughputOptimizedGC()); + } +} diff --git a/tlatools/test/util/TestPrintStream.java b/tlatools/test/util/TestPrintStream.java index fc362d0bd6c7066a15136076f62528d34df2ce71..df6400f37613cff591c72c802319082bd94e3ece 100644 --- a/tlatools/test/util/TestPrintStream.java +++ b/tlatools/test/util/TestPrintStream.java @@ -25,6 +25,7 @@ ******************************************************************************/ package util; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.PipedOutputStream; @@ -34,6 +35,7 @@ import java.util.List; public class TestPrintStream extends PrintStream { + private final StringBuffer buf = new StringBuffer(); private final List<String> strings = new ArrayList<String>(); public TestPrintStream() { @@ -45,10 +47,19 @@ public class TestPrintStream extends PrintStream { */ public void println(String x) { strings.add(x); + buf.append(x + "\n"); System.out.println(x); super.println(x); } + public void assertEmpty() { + assertTrue(this.strings.isEmpty()); + } + + public void assertContains(final String seq) { + assertTrue(buf.toString().contains(seq)); + } + public void assertSubstring(String substring) { for (String string : strings) { if (string.contains(substring)) {