diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
new file mode 100644
index 00000000000..0f439c1fba1
--- /dev/null
+++ b/RELEASE-NOTES.md
@@ -0,0 +1,303 @@
+
+## Release 0.28.1 - December 2022
+
+* vis::Charts, vis::Graphs and vis::Text were added to the standard library for visualizing charts, graphs and pretty textual values.
+* for Eclipse, several older issues and newer issues were fixed in the run-time of the Figure library
+* in Eclipse and VScode the new logo was applied, as well as on http://www.rascal-mpl.org
+* util::Validator was added to the standard library: a generic validation module for loading node values produced by reading in XML, JSON or YAML (for example) as verified constructors of algebraic data-types.
+* In lang::json::IO the writing of Rascal values to JSON streams was simplified and rationalized. Now every constructor application corresponds to one object, and the fields of Rascal constructors and nodes (keyword fields as well as positional) are always mapped one-to-one to JSON fields by name. Mapping back from JSON values to Rascal can be hard if there are more than one constructors for a data type. In this case have a look at util::Validator.
+* Most documentation was moved from the rascal project to the rascal-website project; this will make it easier and faster to contribute to (fixes in) the Rascal documentation.
+* Rascal-tutor compiler was improved in many dimensions: screenshots of visuals were added and the compiler is incremental now per Markdown/Rascal file.
+
+
+## Release 0.26.5 - November 8, 2022
+
+* the documentation compiler, a.k.a. course compiler, a.k.a. tutor, was separated into its own top-level project called [rascal-tutor](https://www.github.com/usethesource/rascal-tutor)
+* 80% of the documentation was reviewed and fixed
+ * ported from asciidoctor to Docusaurus markdown
+ * using new features of the new tutor compiler
+ * all code examples run again
+ * all broken links fixed
+ * broken rascal-eclipse library documentation moved to the rascal-eclipse project
+* in `util::Benchmark` several overloaded functions were renamed to fix static typing issues.
+* in `IO` read and write functions with positional encoding parameters were made `@deprecated` in favor of their simpler counterparts with keywordparameters for the encoding.
+* rascal no longer depends on jruby or asciidoctor
+* `Node::unsetRec` was optimized which led to a large speed improvement of the parser generator
+* added `PATH:///` logical file resolver which works well in combination with `util::ShellExec` for finding executables in the system `PATH` variable to run.
+* `util::ShellExec` can now deal with `loc` values anywhere the API expects a file location. This goes also for file parameters to executables. Before they are passed to the executable, Rascal finds or creates and absolute file system path with the contents of the file.
+
+## Release 0.25.x
+
+Release 0.25.x were intermediate releases required to eliminate the old tutor from the rascal package. They never made it into an IDE like VScode or Eclipse and no stable commandline release was distributed either.
+
+## Release 0.24.0 - June 21, 2022
+
+Release 24.x is a maintenance release. A lot of changes happened between 0.17.0 and 0.23.x, so if you have not looked here for a while, go to the [release notes for 0.23.x](/release-notes/rascal-0-23-x-release-notes)
+
+* ParseTree::parser and ParseTree::parsers now generate parsing closures that do not need a JVM lock to synchronize on the Evaluator anymore.
+* Also both functions now capture the generated Class> instance instead of a handle to the grammar, for efficiency's sake
+* The interpreter's implementation of concrete syntax does not do its own parser caching anymore. Instead it relies on the aforementioned
+parsing closures. This saves memory (fewer hash-tables) and also more sharing is possible between parsers for different modules that happen to have the same grammar.
+* Issue #1615 was solved
+* Issue #1614 was solved
+* Issue #1613 was solved by providing `loc` based interfaces to files and programs passed to util::ShellExec. The old `str` based interfaces are now deprecated.
+
+## Release 0.23.0 - April 10th, 2022
+
+The 0.23.0 release marks the end of the migration of all Rascal supporting libraries (vallang, capsule) and the Rascal interpreter to **Java 11**. The contributors include Paul Klint, Jouke Stoel, Mauricio Verano Merino, Tijs van der Storm, Rodin Aarssen, Arnold Lankamp, Davy Landman, Pieter Olivier and Jurgen Vinju.
+
+We report on intermediate releases 0.18.x, 0.19.x, 0.20.x, 0.21.x and 0.22.x as well, as these had not lead to a release of the Rascal Eclipse plugins or a stable release of the commandline version.
+
+**Generating Eclipse and VScode Plugins**
+
+This port to Java 11 implies that the current [stable release of the Rascal Eclipse plugin](https://update.rascal-mpl.org/stable/) works again with the latest releases of Eclipse from 2021 and 2022. In the meantime
+releases of the [rascal-language-server extension](https://marketplace.visualstudio.com/items?itemName=usethesource.rascalmpl) for VScode have been developed.
+
+Porting Rascal's IDE generator features to VScode has had minor impact on the modules in the standard library concerning interaction with DSLs and interactions with the IDE (`util::IDEServices`, `util::Monitor` and `util::IDE`). The old API still works and it is backward compatible in Eclipse. However, if you want to port your DSL to VScode, there are minor changes in how to wrap your extension and new interaction possibilities with the IDE which are not present in Eclipse. Not all new IDE API is available in Eclipse yet either. Both directions of consolidation (VScode <-> Eclipse) are interesting directions of future work.
+
+This release works best with Java 11, but not with higher versions. There are still illegal uses of reflective access which need to be resolved before Rascal runs correctly on Java 13 and higher.
+
+**Hosting Releases and Continuous Integration**
+
+* http://releases.usethesource.io is the current place for all Rascal related releases.
+* The Eclipse stable update site is still at https://update.rascal-mpl.org/stable/.
+* http://nexus.usethesource.io/ is still functional but officially deprecated.
+* If you want to test release candidates, then the URL is https://update.rascal-mpl.org/release, but we must warn you that regressing to an earlier version is not supported, so you'd have to reinstall Eclipse from scratch for that.
+* We migrated our continuous integration scripts to GitHub actions. Thanks to Jenkins for the many years of service and the support from CWI staff and management to keep our servers funded, safe and sound.
+
+**Sponsoring**
+
+It has become possible to [sponsor](https://github.com/sponsors/usethesource) the Rascal project. If you are considering, please do not hesitate to contact us.
+
+**Other changes**
+
+* the `private` access modifier is now idempotent for a name of a function, data-type or syntax non-terminal within single module: in other words, if one of the alternatives is marked private, then all of them are private.
+* caching using the @memo tag is done smarter (faster and cleaner cache clearing)
+* run-time bugs around type-parametrized ADTs were fixed
+* support for constructing the right classpaths by calling `mvn` if pom.xml files are present. This affects the JUnit test runners, the REPL shell, the compiler and type-checker configurations, the setup for terminals in Eclipse projects.
+* added functions for inspecting current memory availability and usage
+* fixed bugs around prefix matching on concrete trees, simplified its implementation by removing code clones.
+* fixed serious bug with prefix shared nullable rules in the parser implementation.
+* fixed race conditions around parser generation for asynchronous usage by the language server protocol
+* backtracking over `<==>` and `==>` and `<==` boolean operators is now limited (as limited as backtracking over the `!` boolean operator)
+* case insensitive literals in grammars, such as `'if' Exp 'then' Stat;` are supported better now, also as follow/precede restrictions and keyword reservations (like `Id !>> 'if'`, `Id \ 'if'`) for which an implementation was missing are now supported.
+* many regression tests were added as side-effect of the development on the Rascal compiler in the rascal-core project.
+* added file watch feature in `IO` module
+* added the `lib://libName` scheme for use in `Required-Libraries` in `META-INF/RASCAL.MF` and other places (pathConfig). It resolves to open `project://libName/target/classes` locations or otherwise the jar file that the library is released in and on the classpath.
+* added features for recursive copy and recursive move in `IO`
+* added lenient option to the JSON parser in `lang::json::IO`
+* added utility functions to `util::SystemExec` for easy process creation and termination.
+* parse tree filter functions are not called implicitly anymore by the generated parser when building up the tree. Instead a `filter` function is passed to the generated `parse` function where the user can provide filter functions by composing them with `+`. This removes the need for the generated parser function to learn from the current calling scope which functions are available for filtering, and makes the entire parser generator independent of the internals of the interpreter. The new `parser` generator functions work both in the compiled and the interpreted context. Of course, under the hood the implementation reuses the interpreter, until we have bootstrapped the parser generator using the new compiler.
+* all Rascal REPLS now support HTML output next to normal string output. Each REPL also serves as a web application host. When a value of type `Content` is the result of evaluation, then the REPL hosts that (Response (Request)) callback until 30 minutes of inactivity. The UI context of the REPL decides how/when and where to show the client side.
+* many fixes around higher-order and type-parametrized functions
+* moved from the interpreter-specific ICalleableValue to the more abstract IFunction interface to run-time function values.
+* rewrote all builtin functions in the standard library to become independent of the interpreter's internals. This is done via constructor arguments of the `@javaClass` implementation classes. These can receive `TypeStore`, `PrintStream` and `IValueFactory` parameters to configure themselves with necessary context of the Rascal runtime.
+* `@reflect` is not used anymore by standard library modules. It is deprecated but still supported for now. If you want to make your code robust against compilation by the Rascal compiler, you have to rewrite uses of `@reflect` and receive arguments in your `@javaClass` class constructor.
+* All Rascal REPLS print the current release version of the Rascal run-time before anything else.
+* Added SourceLocationClassLoader which can construct a JVM classloader instance from references encoded as source location URI. It tries to group file URIs to jar files and forward to URLClassLoader for efficiency's sake. Only ISourceLocationInputResolver schemes which also implement IClassLoaderResolver are supported. We added implementations for all the standard resolvers on the commandline and the necessary ones in the Eclipse context.
+* All static errors produced by the new typechecker were fixed in the standard library
+* Cleaned up error messages and exceptions in standard library modules (issues largely detected by the typechecker)
+* REPLs refactored for use within Bacata (http://github.com/cwi-swat/bacata)
+
+## Release 0.17.0 - March 16th, 2020
+
+The 0.15.x releases served as daily pre-releases for 0.17.0, while 0.16.x was a stable release which included all patches since 0.10.0. The releases between 0.10.0 and 0.16.0 have mainly been concerned with bootstrapping and minor bugfixes.
+
+The current release 0.17.x is a step towards bootstrapping the Rascal compiler and making the new static checker (type checker) available.
+
+The static checker:
+
+* checks all features of Rascal
+* is written in Rascal using the [TypePal framework](https://github.com/usethesource/typepal)
+* is activated on "project clean" and "file save"
+* runs for now in the Rascal interpreter and may be slow on bigger projects (this is transitional, so bear with us)
+* enables editor features such as hover-help and jump-to-definition in Eclipse, based on the state of the file after the last "save"
+* using the Eclipse Preferences: Eclipse > Preferences > Rascal > Enable Rascal Compiler, type checking can be turned on or off
+
+Also in this release significant steps have been made towards Rascal project deployment:
+
+* In RASCAL.MF, Use `Required-Libraries: |lib://myDependency|` to declare projects you depend on
+* Declare a project using `Project-Name: projectName` in RASCAL.MF
+* The `|lib://name|` scheme always resolves to the root of a jar or target folder for a project with that name
+* Eclipse, maven and Junit use the above information to configure interpreter and compiler search paths correctly
+* The starting point is the JVM classpath: every RASCAL.MF file found on this path leads to a loadable library
+* IDEs such as Eclipse dynamically resolve `lib://` references to respective project's target folders if so required
+
+Other notable changes:
+
+* all static errors and warnings in the standard library have been resolved
+* general code cleanup
+* resolved many issues (thanks all for reporting!)
+* various performance improvements
+
+# Releases 0.9.x
+
+In this post we report on the Rascal release 0.9.0, which includes all changes since the 0.7.x releases. We have not written release notes for the 0.8.x series (the details are included here). We expect a number of patch releases for 0.9.x, which we report on by updating this post (at its end) when necessary until we move on to 0.10.x.
+
+The Rascal release 0.9.x includes the following main components:
+
+* Parser and interpreter: parsing and running Rascal programs
+* Parser generator: generating parsers for programming languages and domain specific languages
+* Eclipse plugin: an IDE for Rascal, partially supported by the new type checker and compiler
+* Eclipse plugin generator for DSLs: an IDE generator based on Rascal programs
+* Rascal commandline shell: to run Rascal independently from Eclipse
+* Standard library: utilities for programming in Rascal, including several (stable) programming language front-ends and general analysis facilities.
+* Rascal compiler: the experimental compiler for Rascal
+* Rascal type checker: the experimental type checker for Rascal
+* TypePal: experimental generic name and type analysis framework
+* Salix: a html5-based GUI interaction framework for Rascal
+* Shapes: a html5 back-end for the Figure library
+* Capsule: the hash-trie set, map and multimap Java library supporting the implementation of Rascal's maps, sets and relations
+* Clair: a C++ analysis framework based on the CDT parser
+* Split main Rascal Eclipse plugin release from a number of additional libraries, located at a new update site:
+
+The 0.9 release is a landmark release, including a big number of bug fixes and mainly preparations towards releasing a compiled version of Rascal.
+
+* The most notable new features are:
+ 1. Rascal type checker
+ 2. Experimental Rascal compiler
+ 3. Faster and leaner implementations of maps and relations under-the-hood, based on hash-tries (unfinished)
+ 4. Fully lazy and streaming string templates
+ 5. TypePal: a powerful generic type and name analysis framework
+ 6. Re-implementation of the M3 java Jar extractor
+ 7. Very fast streamed binary value (de)serialization
+ 8. Full re-implementation of the tutor documentation generator based on asciidoctor (unfinished)
+ 9. Typed import/export of JSON data
+ 10. New "common keyword parameters" support; `data X(int x = 0)` where the field `x` with default `0` is made available to all constructors of the data-type `X` in the current scope.
+ 11. Calling compiled Rascal functions from Java code using simple Java interface proxy.
+ 12. M3 models now use keyword fields instead of annotations
+
+* Temporarily disabled features:
+ 1. syntax highlighting of concrete syntax fragments in the Eclipse Rascal editor is currently turned off
+
+* Deprecated features:
+ 1. annotations as in `anno int X@name;` and their usage `x()@name` is deprecated. Please start using keyword parameters as in: `data X(str name = "")` and `x.name`
+ 2. asType: `[Type] "string"` in patterns and expressions. Please use the `parse` function for now.
+
+
+* Other things that were added, improved or fixed:
+ 1. subscript on lrels added
+ 2. many, many tests added
+ 3. refactoring of the REPL api to enable reuse in notebook implementations (see Bacata)
+ 4. windows compatibility improved
+ 5. Pattern matchin a bound variable now ignores keyword fields of constructors unless explicitly mentioned
+ 5. steps towards less dependency on the annotation feature
+ 6. several bugs around the annotion feature and map indexing fixed
+ 7. faster field access in the interpreter
+ 8. compiler is automatically and continuously bootstrapped and validated (no binary code needs committing in the repository)
+ 9. rationalization and consistency improvement of all the input and output parameters of the compiler and the interpreter via the PathConfig data-type.
+ 10. quickcheck random value generator also simplified and made consistent and reusable
+ 11. clear separation of REPL functionalities and reuse of Eclipse tm.terminal
+ 12. clarified and fixed UTF8 encoding details in I/O functions
+ 13. clarified and fixed URI encoding details in I/O functions
+ 14. optimized reading from (nested) jar files
+ 15. much improved efficiency of function calling by the Rascal compiler
+ 16. additional API for managing external processes
+ 17. compiler and type-checker support incremental compilation
+ 18. much faster comparison of source locations
+ 19. rename of rascal.values (used to be pdb.values) to independent project called "vallang"
+ 20. support for Java NIO File Channels for (some of the) location schemes.
+ 21. modular re-implementation of type reification
+ 22. new modular subsystem to generate classloader instances from URI source locations, e.g. `|system:///|`, `|classpath:///|` and `|file:///path/to/jarFile.jar|` and `|file:///path/to/classFolder|`
+ 23. interpreter and compiler made maximally code-independent
+ 24. all projects fully "mavenized"
+ 25. advanced interactive debugging features of compiled Rascal
+ 26. REPL and IDE features based on compiled Rascal
+ 27. integrated compiled Rascal modules as JUnit test runners.
+ 28. several fixes in datetime behavior
+ 29. full implementation of JVM bytecode generation by compiler
+ 30. parsing ambiguity is now by default an "error" (an exception is raised by the parse function). Using the `allowAmbiguity=true` flag an ambiguous parse forest can still be produced.
+ 31. added syntax highlighting of parsed source code fragments in the REPL
+ 32. a `jar+:///path/to/jar!/path/in/jar` scheme supports files in jars.
+
+### Contributors to the 0.8.x and 0.9.x releases
+
+Thanks! In no particular order the following people have contributed to the 0.9.x releases of Rascal and its supporting libraries or the libraries it supports:
+
+* Paul Klint
+* Davy Landman
+* Bert Lisser
+* Michael Steindorfer
+* Mark Hills
+* Jurgen Vinju
+* Ferry Rietveld
+* Tijs van der Storm
+* Thomas Degueule
+* Lina Maria Ochoa Venegas
+* Mauricio Verano
+* Rodin Aarssen
+* Anya Helene Bagge
+* Tim Soethout
+* Aiko Yamashita
+* Nick Lodewijks
+* Jouke Stoel
+* Rodrigo Bonifacio
+* Yoan-Alexander Grigorov
+* Vadim Zaytsev
+* Mats Stijlaart
+* Magiel Bruntink
+* Kevin van der Vlist
+
+Also thanks to all the people who have (clearly) reported bugs and provided smaller pull requests! Your help is much appreciated.
+
+### Patch releases
+
+* Patch 0.9.1. bootstrap release to introduce new pattern match semantics for `var1 := var2`
+* Patch 0.9.2. bootstrap release to fix version number reporting in generated kernels
+
+## Release 0.27.2 - November 23, 2022
+
+* the tutor compiler now takes screenshots if an interactive visual is generated in a rascal-shell code block.
+* the JSON serializer maps objects to constructors one-to-one now. Only [AlgebraicDataTypes](/docs/rascalopedia/algebraicdatatype/) with single constructors are allowed, or lists of nullary constructors (for enums).
+* added vis::Chart with 8 basic chart styles based on chart.js
+* added util::Validator which can validate any `node` instances against an [AlgebraicDataType](/docs/rascalopedia/algebraicdatatype/) using matching and memoized backtracking. Useful for reading in complex XML, JSON or YAML data.
+* issue with variablescope leakage in the visit statement was fixed.
+
+## Release 0.7.0
+
+In this post we report on the Rascal release 0.7.0. We expect a number of patch releases as well, which we report on by updating this post (at its end) when necessary. The Rascal release includes the following main components:
+
+* Parser and interpreter: parsing and running Rascal programs
+* Parser generator: generating parsers for programming languages and domain specific languages
+* Eclipse plugin: an IDE for Rascal
+* Eclipse plugin generator for DSLs: an IDE generator based on Rascal programs
+* Rascal commandline shell: to run Rascal independently from Eclipse
+* Standard library: utilities for programming in Rascal, including several (stable) programming language front-ends and general analysis facilities.
+
+Compared to 0.6.x the 0.7 release is mainly a bug fix release, with a number of extensions to the libraries and one new language feature.
+
+* The new language feature is keyword parameters for both functions and data constructors.
+* In terms of library funcionality the big new things is *M3*, a common intermediate format for facts about source code. This includes a standard set of relations (containment, def/use, etc.) and a preferred way of modeling abstract syntax trees.
+
+### M3
+
+### Keyword parameters
+
+### Looking forward to the 0.8.x, 0.9.x and 1.0 releases
+
+The 0.8 release is planned with:
+
+* Re-implemented general top-down parsing algorithm with on-demand lexing
+* Fast regular expressions and better language integrated pattern matching
+* Concrete syntax features completed and streamlined due to new parser integration
+* Standard library component for communicating with SMT solvers easily
+
+The 0.9 release is planned with:
+
+* Keyword parameters replacing annotations completely
+* New Figure library based on javascript
+
+The 1.0 release is a big bang release which includes the following new components which have been developed over the last two years:
+
+* The Rascal type checker
+* Rascal compiler to RVM
+* RVM interpreter
+
+In 1.0 the old Rascal interpreter will still be included, but from here on its usage will be deprecated. We will be working to switch the IDE support to using the new infra-structure for a while and when this is finished the interpreter will not be released any longer. Note that this does not mean that we will not have a REPL for Rascal anymore. We will always have a REPL.
+
+### Patch releases
+
+* Patch 0.7.1. includes an update to the documentation on M3
+* Patch 0.7.2. bug fixes
+* Patch 0.7.3. bug fixes and memory optimizations (more than 50%)
+
diff --git a/src/org/rascalmpl/ast/IASTVisitor.java b/src/org/rascalmpl/ast/IASTVisitor.java
index c27d97ae216..a7b963594b0 100644
--- a/src/org/rascalmpl/ast/IASTVisitor.java
+++ b/src/org/rascalmpl/ast/IASTVisitor.java
@@ -699,6 +699,16 @@ public interface IASTVisitor {
public T visitSyntaxDefinitionLexical(SyntaxDefinition.Lexical x);
+ public T visitSyntaxRoleModifierData(SyntaxRoleModifier.Data x);
+
+ public T visitSyntaxRoleModifierKeyword(SyntaxRoleModifier.Keyword x);
+
+ public T visitSyntaxRoleModifierLayout(SyntaxRoleModifier.Layout x);
+
+ public T visitSyntaxRoleModifierLexical(SyntaxRoleModifier.Lexical x);
+
+ public T visitSyntaxRoleModifierSyntax(SyntaxRoleModifier.Syntax x);
+
public T visitTagDefault(Tag.Default x);
public T visitTagEmpty(Tag.Empty x);
@@ -719,6 +729,8 @@ public interface IASTVisitor {
public T visitTypeFunction(Type.Function x);
+ public T visitTypeModifier(Type.Modifier x);
+
public T visitTypeSelector(Type.Selector x);
public T visitTypeStructured(Type.Structured x);
diff --git a/src/org/rascalmpl/ast/NullASTVisitor.java b/src/org/rascalmpl/ast/NullASTVisitor.java
index c35f0657179..f6354e6f662 100644
--- a/src/org/rascalmpl/ast/NullASTVisitor.java
+++ b/src/org/rascalmpl/ast/NullASTVisitor.java
@@ -1381,6 +1381,26 @@ public T visitSyntaxDefinitionLexical(SyntaxDefinition.Lexical x) {
return null;
}
+ public T visitSyntaxRoleModifierData(SyntaxRoleModifier.Data x) {
+ return null;
+ }
+
+ public T visitSyntaxRoleModifierKeyword(SyntaxRoleModifier.Keyword x) {
+ return null;
+ }
+
+ public T visitSyntaxRoleModifierLayout(SyntaxRoleModifier.Layout x) {
+ return null;
+ }
+
+ public T visitSyntaxRoleModifierLexical(SyntaxRoleModifier.Lexical x) {
+ return null;
+ }
+
+ public T visitSyntaxRoleModifierSyntax(SyntaxRoleModifier.Syntax x) {
+ return null;
+ }
+
public T visitTagDefault(Tag.Default x) {
return null;
}
@@ -1421,6 +1441,10 @@ public T visitTypeFunction(Type.Function x) {
return null;
}
+ public T visitTypeModifier(Type.Modifier x) {
+ return null;
+ }
+
public T visitTypeSelector(Type.Selector x) {
return null;
}
diff --git a/src/org/rascalmpl/ast/SyntaxRoleModifier.java b/src/org/rascalmpl/ast/SyntaxRoleModifier.java
new file mode 100644
index 00000000000..ee6b65db471
--- /dev/null
+++ b/src/org/rascalmpl/ast/SyntaxRoleModifier.java
@@ -0,0 +1,410 @@
+/*******************************************************************************
+ * Copyright (c) 2009-2015 CWI
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
+ * * Tijs van der Storm - Tijs.van.der.Storm@cwi.nl
+ * * Paul Klint - Paul.Klint@cwi.nl - CWI
+ * * Mark Hills - Mark.Hills@cwi.nl (CWI)
+ * * Arnold Lankamp - Arnold.Lankamp@cwi.nl
+ * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
+ *******************************************************************************/
+package org.rascalmpl.ast;
+
+
+import io.usethesource.vallang.IConstructor;
+import io.usethesource.vallang.ISourceLocation;
+
+@SuppressWarnings(value = {"unused"})
+public abstract class SyntaxRoleModifier extends AbstractAST {
+ public SyntaxRoleModifier(ISourceLocation src, IConstructor node) {
+ super(src /* we forget node on purpose */);
+ }
+
+
+ public boolean hasArg() {
+ return false;
+ }
+
+ public org.rascalmpl.ast.TypeArg getArg() {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+
+ public boolean isData() {
+ return false;
+ }
+
+ static public class Data extends SyntaxRoleModifier {
+ // Production: sig("Data",[arg("org.rascalmpl.ast.TypeArg","arg")],breakable=false)
+
+
+ private final org.rascalmpl.ast.TypeArg arg;
+
+ public Data(ISourceLocation src, IConstructor node , org.rascalmpl.ast.TypeArg arg) {
+ super(src, node);
+
+ this.arg = arg;
+ }
+
+ @Override
+ public boolean isData() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitSyntaxRoleModifierData(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = arg.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ arg.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Data)) {
+ return false;
+ }
+ Data tmp = (Data) o;
+ return true && tmp.arg.equals(this.arg) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 509 + 563 * arg.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.TypeArg getArg() {
+ return this.arg;
+ }
+
+ @Override
+ public boolean hasArg() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(arg));
+ }
+
+ }
+ public boolean isKeyword() {
+ return false;
+ }
+
+ static public class Keyword extends SyntaxRoleModifier {
+ // Production: sig("Keyword",[arg("org.rascalmpl.ast.TypeArg","arg")],breakable=false)
+
+
+ private final org.rascalmpl.ast.TypeArg arg;
+
+ public Keyword(ISourceLocation src, IConstructor node , org.rascalmpl.ast.TypeArg arg) {
+ super(src, node);
+
+ this.arg = arg;
+ }
+
+ @Override
+ public boolean isKeyword() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitSyntaxRoleModifierKeyword(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = arg.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ arg.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Keyword)) {
+ return false;
+ }
+ Keyword tmp = (Keyword) o;
+ return true && tmp.arg.equals(this.arg) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 149 + 431 * arg.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.TypeArg getArg() {
+ return this.arg;
+ }
+
+ @Override
+ public boolean hasArg() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(arg));
+ }
+
+ }
+ public boolean isLayout() {
+ return false;
+ }
+
+ static public class Layout extends SyntaxRoleModifier {
+ // Production: sig("Layout",[arg("org.rascalmpl.ast.TypeArg","arg")],breakable=false)
+
+
+ private final org.rascalmpl.ast.TypeArg arg;
+
+ public Layout(ISourceLocation src, IConstructor node , org.rascalmpl.ast.TypeArg arg) {
+ super(src, node);
+
+ this.arg = arg;
+ }
+
+ @Override
+ public boolean isLayout() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitSyntaxRoleModifierLayout(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = arg.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ arg.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Layout)) {
+ return false;
+ }
+ Layout tmp = (Layout) o;
+ return true && tmp.arg.equals(this.arg) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 67 + 19 * arg.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.TypeArg getArg() {
+ return this.arg;
+ }
+
+ @Override
+ public boolean hasArg() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(arg));
+ }
+
+ }
+ public boolean isLexical() {
+ return false;
+ }
+
+ static public class Lexical extends SyntaxRoleModifier {
+ // Production: sig("Lexical",[arg("org.rascalmpl.ast.TypeArg","arg")],breakable=false)
+
+
+ private final org.rascalmpl.ast.TypeArg arg;
+
+ public Lexical(ISourceLocation src, IConstructor node , org.rascalmpl.ast.TypeArg arg) {
+ super(src, node);
+
+ this.arg = arg;
+ }
+
+ @Override
+ public boolean isLexical() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitSyntaxRoleModifierLexical(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = arg.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ arg.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Lexical)) {
+ return false;
+ }
+ Lexical tmp = (Lexical) o;
+ return true && tmp.arg.equals(this.arg) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 181 + 599 * arg.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.TypeArg getArg() {
+ return this.arg;
+ }
+
+ @Override
+ public boolean hasArg() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(arg));
+ }
+
+ }
+ public boolean isSyntax() {
+ return false;
+ }
+
+ static public class Syntax extends SyntaxRoleModifier {
+ // Production: sig("Syntax",[arg("org.rascalmpl.ast.TypeArg","arg")],breakable=false)
+
+
+ private final org.rascalmpl.ast.TypeArg arg;
+
+ public Syntax(ISourceLocation src, IConstructor node , org.rascalmpl.ast.TypeArg arg) {
+ super(src, node);
+
+ this.arg = arg;
+ }
+
+ @Override
+ public boolean isSyntax() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitSyntaxRoleModifierSyntax(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = arg.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ arg.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Syntax)) {
+ return false;
+ }
+ Syntax tmp = (Syntax) o;
+ return true && tmp.arg.equals(this.arg) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 101 + 421 * arg.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.TypeArg getArg() {
+ return this.arg;
+ }
+
+ @Override
+ public boolean hasArg() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(arg));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/org/rascalmpl/ast/Tag.java b/src/org/rascalmpl/ast/Tag.java
index 905591d829d..df6bfc07973 100644
--- a/src/org/rascalmpl/ast/Tag.java
+++ b/src/org/rascalmpl/ast/Tag.java
@@ -115,7 +115,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 509 + 563 * name.hashCode() + 149 * contents.hashCode() ;
+ return 277 + 487 * name.hashCode() + 797 * contents.hashCode() ;
}
@@ -198,7 +198,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 431 + 67 * name.hashCode() ;
+ return 787 + 397 * name.hashCode() ;
}
@@ -282,7 +282,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 19 + 181 * name.hashCode() + 599 * expression.hashCode() ;
+ return 191 + 977 * name.hashCode() + 173 * expression.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Tags.java b/src/org/rascalmpl/ast/Tags.java
index d9ddbffdbb5..c72fdb05ef3 100644
--- a/src/org/rascalmpl/ast/Tags.java
+++ b/src/org/rascalmpl/ast/Tags.java
@@ -93,7 +93,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 101 + 421 * tags.hashCode() ;
+ return 541 + 491 * tags.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Target.java b/src/org/rascalmpl/ast/Target.java
index f9b0bc91778..51eda667db0 100644
--- a/src/org/rascalmpl/ast/Target.java
+++ b/src/org/rascalmpl/ast/Target.java
@@ -81,7 +81,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 277 ;
+ return 331 ;
}
@@ -146,7 +146,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 487 + 797 * name.hashCode() ;
+ return 167 + 809 * name.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Toplevel.java b/src/org/rascalmpl/ast/Toplevel.java
index a7fa0d0f3d1..f8e0f315ae3 100644
--- a/src/org/rascalmpl/ast/Toplevel.java
+++ b/src/org/rascalmpl/ast/Toplevel.java
@@ -91,7 +91,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 787 + 397 * declaration.hashCode() ;
+ return 109 + 373 * declaration.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Type.java b/src/org/rascalmpl/ast/Type.java
index f71debeb4a4..2828b1fad51 100644
--- a/src/org/rascalmpl/ast/Type.java
+++ b/src/org/rascalmpl/ast/Type.java
@@ -61,6 +61,13 @@ public boolean hasSymbol() {
public org.rascalmpl.ast.Sym getSymbol() {
throw new UnsupportedOperationException();
}
+ public boolean hasModifier() {
+ return false;
+ }
+
+ public org.rascalmpl.ast.SyntaxRoleModifier getModifier() {
+ throw new UnsupportedOperationException();
+ }
public boolean hasType() {
return false;
}
@@ -140,7 +147,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 191 + 977 * basic.hashCode() ;
+ return 449 + 571 * basic.hashCode() ;
}
@@ -214,7 +221,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 173 + 541 * type.hashCode() ;
+ return 467 + 691 * type.hashCode() ;
}
@@ -288,7 +295,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 491 + 331 * function.hashCode() ;
+ return 701 + 19 * function.hashCode() ;
}
@@ -307,6 +314,80 @@ public Object clone() {
return newInstance(getClass(), src, (IConstructor) null , clone(function));
}
+ }
+ public boolean isModifier() {
+ return false;
+ }
+
+ static public class Modifier extends Type {
+ // Production: sig("Modifier",[arg("org.rascalmpl.ast.SyntaxRoleModifier","modifier")],breakable=false)
+
+
+ private final org.rascalmpl.ast.SyntaxRoleModifier modifier;
+
+ public Modifier(ISourceLocation src, IConstructor node , org.rascalmpl.ast.SyntaxRoleModifier modifier) {
+ super(src, node);
+
+ this.modifier = modifier;
+ }
+
+ @Override
+ public boolean isModifier() {
+ return true;
+ }
+
+ @Override
+ public T accept(IASTVisitor visitor) {
+ return visitor.visitTypeModifier(this);
+ }
+
+ @Override
+ protected void addForLineNumber(int $line, java.util.List $result) {
+ if (getLocation().getBeginLine() == $line) {
+ $result.add(this);
+ }
+ ISourceLocation $l;
+
+ $l = modifier.getLocation();
+ if ($l.hasLineColumn() && $l.getBeginLine() <= $line && $l.getEndLine() >= $line) {
+ modifier.addForLineNumber($line, $result);
+ }
+ if ($l.getBeginLine() > $line) {
+ return;
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Modifier)) {
+ return false;
+ }
+ Modifier tmp = (Modifier) o;
+ return true && tmp.modifier.equals(this.modifier) ;
+ }
+
+ @Override
+ public int hashCode() {
+ return 137 + 907 * modifier.hashCode() ;
+ }
+
+
+ @Override
+ public org.rascalmpl.ast.SyntaxRoleModifier getModifier() {
+ return this.modifier;
+ }
+
+ @Override
+ public boolean hasModifier() {
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ return newInstance(getClass(), src, (IConstructor) null , clone(modifier));
+ }
+
}
public boolean isSelector() {
return false;
@@ -362,7 +443,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 167 + 809 * selector.hashCode() ;
+ return 41 + 59 * selector.hashCode() ;
}
@@ -436,7 +517,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 109 + 373 * structured.hashCode() ;
+ return 823 + 139 * structured.hashCode() ;
}
@@ -510,7 +591,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 449 + 571 * symbol.hashCode() ;
+ return 293 + 773 * symbol.hashCode() ;
}
@@ -584,7 +665,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 467 + 691 * user.hashCode() ;
+ return 293 + 421 * user.hashCode() ;
}
@@ -658,7 +739,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 701 + 19 * typeVar.hashCode() ;
+ return 467 + 181 * typeVar.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/TypeArg.java b/src/org/rascalmpl/ast/TypeArg.java
index 198af6e5e41..9ee53d95b12 100644
--- a/src/org/rascalmpl/ast/TypeArg.java
+++ b/src/org/rascalmpl/ast/TypeArg.java
@@ -98,7 +98,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 137 + 907 * type.hashCode() ;
+ return 383 + 263 * type.hashCode() ;
}
@@ -182,7 +182,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 41 + 59 * type.hashCode() + 823 * name.hashCode() ;
+ return 463 + 223 * type.hashCode() + 139 * name.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/TypeVar.java b/src/org/rascalmpl/ast/TypeVar.java
index ba3d636a1b1..7c27b3422b2 100644
--- a/src/org/rascalmpl/ast/TypeVar.java
+++ b/src/org/rascalmpl/ast/TypeVar.java
@@ -108,7 +108,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 139 + 293 * name.hashCode() + 773 * bound.hashCode() ;
+ return 347 + 557 * name.hashCode() + 131 * bound.hashCode() ;
}
@@ -191,7 +191,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 293 + 421 * name.hashCode() ;
+ return 797 + 149 * name.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/UserType.java b/src/org/rascalmpl/ast/UserType.java
index a884b8839d0..e5b3590a8ea 100644
--- a/src/org/rascalmpl/ast/UserType.java
+++ b/src/org/rascalmpl/ast/UserType.java
@@ -98,7 +98,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 467 + 181 * name.hashCode() ;
+ return 877 + 401 * name.hashCode() ;
}
@@ -184,7 +184,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 383 + 263 * name.hashCode() + 463 * parameters.hashCode() ;
+ return 787 + 239 * name.hashCode() + 997 * parameters.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Variable.java b/src/org/rascalmpl/ast/Variable.java
index 7ead41f1d2d..43a719680e7 100644
--- a/src/org/rascalmpl/ast/Variable.java
+++ b/src/org/rascalmpl/ast/Variable.java
@@ -108,7 +108,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 223 + 139 * name.hashCode() + 347 * initial.hashCode() ;
+ return 641 + 701 * name.hashCode() + 13 * initial.hashCode() ;
}
@@ -191,7 +191,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 557 + 131 * name.hashCode() ;
+ return 179 + 797 * name.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Variant.java b/src/org/rascalmpl/ast/Variant.java
index a3e0547990b..b1cd415e07a 100644
--- a/src/org/rascalmpl/ast/Variant.java
+++ b/src/org/rascalmpl/ast/Variant.java
@@ -127,7 +127,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 797 + 149 * name.hashCode() + 877 * arguments.hashCode() + 401 * keywordArguments.hashCode() ;
+ return 101 + 17 * name.hashCode() + 797 * arguments.hashCode() + 499 * keywordArguments.hashCode() ;
}
diff --git a/src/org/rascalmpl/ast/Visibility.java b/src/org/rascalmpl/ast/Visibility.java
index f94f8f1c211..18b6cd051da 100644
--- a/src/org/rascalmpl/ast/Visibility.java
+++ b/src/org/rascalmpl/ast/Visibility.java
@@ -74,7 +74,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 787 ;
+ return 347 ;
}
@@ -129,7 +129,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 239 ;
+ return 947 ;
}
@@ -184,7 +184,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 997 ;
+ return 571 ;
}
diff --git a/src/org/rascalmpl/ast/Visit.java b/src/org/rascalmpl/ast/Visit.java
index 3b80055dee1..59bf504ef15 100644
--- a/src/org/rascalmpl/ast/Visit.java
+++ b/src/org/rascalmpl/ast/Visit.java
@@ -117,7 +117,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 641 + 701 * subject.hashCode() + 13 * cases.hashCode() ;
+ return 907 + 173 * subject.hashCode() + 269 * cases.hashCode() ;
}
@@ -222,7 +222,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- return 179 + 797 * strategy.hashCode() + 101 * subject.hashCode() + 17 * cases.hashCode() ;
+ return 349 + 251 * strategy.hashCode() + 487 * subject.hashCode() + 421 * cases.hashCode() ;
}
diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc
index 22ff2fe7fd5..69c6d20f95d 100644
--- a/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc
+++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc
@@ -196,6 +196,18 @@ bool asubtype(adt:aadt(str n, list[AType] l, SyntaxRole sr), AType b){
fail;
}
+// Open modifiers are sub-types of the kinds that they modify _to_.
+// It's good to remember that _closed_ syntax role modifiers are already rewritten
+// to the type they modify to in ATypeBase
+bool asubtype(\asyntaxRoleModifier(SyntaxRole role, \aparameter(_,_)), aadt(_, _, role)) = true;
+
+// All open syntax role modifiers are sub-types of `node`
+bool asubtype(\asyntaxRoleModifier(SyntaxRole role, \aparameter(_,_)), anode(_)) = true;
+
+// All context-free grammar-related syntax roles are sub-types of `Tree`
+bool asubtype(\asyntaxRoleModifier(SyntaxRole role, \aparameter(_,_)), aadt("Tree", [], dataSyntax())) = true
+ when role in {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
bool asubtype(\start(AType a), AType b) = asubtype(a, b);
bool asubtype(i:\iter(AType s), AType b){
@@ -513,6 +525,11 @@ bool outerComparable1(aparameter(str pname1, AType bound1), aparameter(str pname
bool outerComparable1(aadt(str adtName1, list[AType] parameters1, SyntaxRole syntaxRole1), areified(_)) = true;
+// syntax role with incomparable roles are not outer comparable, but otherwise they act like aadt's:
+// JV: commented out until I understand the use of outerComparable1 better.
+// bool outerComparable1(asyntaxRoleModifier(SyntaxRole role, aparameter(_,_)), asyntaxRoleModifier(role, aparameter(_,_))) = true;
+// bool outerComparable1(asyntaxRoleModifier(SyntaxRole role, aparameter(_,_)), aadt(_,_,role)) = true;
+// bool outerComparable1(aadt(_,_,role), asyntaxRoleModifier(SyntaxRole role, aparameter(_,_))) = true;
default bool outerComparable1(AType l, AType r) {
return comparable(l, r);
@@ -639,6 +656,7 @@ AType addADTLabel(AType a1, AType a2, AType adt){
return adt;
}
+
//AType alub(acons(AType la, list[AType] _, list[Keyword] _), acons(AType ra, list[AType] _, list[Keyword] _)) = alub(la,ra);
AType alub(acons(AType lr, list[AType] lp, list[Keyword] lkw), acons(AType rr, list[AType] rp, list[Keyword] rkw)) {
if(size(lp) == size(rp)){
@@ -685,6 +703,32 @@ AType alub(AType l, p:aparameter(n, b, closed=true)) = lb == b ? p : lb when !(
AType alub(areified(AType l), areified(AType r)) = areified(alub(l,r));
AType alub(areified(AType l), anode(_)) = anode([]);
+AType alub(\asyntaxRoleModifier(SyntaxRole role, \aparameter(_,_)), a:aadt(_, _, role)) = a;
+AType alub(a:aadt(_, _, role), \asyntaxRoleModifier(SyntaxRole role, \aparameter(_,_))) = a;
+
+AType alub(\asyntaxRoleModifier(_, \aparameter(_, _)), anode(l)) = \anode(l);
+AType alub(\anode(l), \asyntaxRoleModifier(_, \aparameter(_, _))) = \anode(l);
+
+AType alub(\asyntaxRoleModifier(SyntaxRole role, \aparameter(_, _)), aadt("Tree",[], dataSyntax()))
+ = aadt("Tree",[], dataSyntax())
+ when role in {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
+AType alub(aadt("Tree",[], dataSyntax()), \asyntaxRoleModifier(SyntaxRole role, \aparameter(_, _)))
+ = aadt("Tree",[], dataSyntax())
+ when role in {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
+// ---
+
+AType alub(\asyntaxRoleModifier(dataSyntax(), \aparameter(x, _)),
+ \asyntaxRoleModifier(SyntaxRole _, \aparameter(y, _))) = anode([]) when x != y;
+
+AType alub(\asyntaxRoleModifier(SyntaxRole _, \aparameter(x, _)),
+ \asyntaxRoleModifier(dataSyntax(), \aparameter(y, _))) = anode([]) when x != y;
+
+AType alub(\asyntaxRoleModifier(SyntaxRole a, \aparameter(x, _)),
+ \asyntaxRoleModifier(SyntaxRole b, \aparameter(y, _))) = aadt("Tree",[], dataSyntax())
+ when x != y, {a,b} < {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
AType alub(l:\achar-class(_), r:\achar-class(_)) = union(l, r);
AType alub(\iter(AType l), \iter(AType r)) = aadt("Tree", [], dataSyntax());
@@ -850,5 +894,18 @@ public AType aglb(afunc(AType lr, list[AType] lp, list[Keyword] kwl), afunc(ATyp
return avalue();
}
+AType aglb(asyntaxRoleModifier(SyntaxRole role, p1:aparameter(_,_)),
+ asyntaxRoleModifier( role, p2:aparameter(_,_)))
+ = asyntaxRoleModifier(r, glb(p1, p2)) when p1 != p2;
+
+AType aglb(a:asyntaxRoleModifier(SyntaxRole _, aparameter(_,_)), \anode(_)) = a;
+AType aglb(\anode(_), a:asyntaxRoleModifier(SyntaxRole _, aparameter(_,_))) = a;
+
+AType aglb(a:asyntaxRoleModifier(SyntaxRole role, aparameter(_,_)), aadt("Tree", [], dataSyntax())) = a
+ when role in {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
+AType aglb(aadt("Tree", [], dataSyntax()), a:asyntaxRoleModifier(SyntaxRole role, aparameter(_,_))) = a
+ when role in {contextFreeSyntax(), lexicalSyntax(), keywordSyntax(), layoutSyntax()};
+
public list[AType] aglbList(list[AType] l, list[AType] r) = [aglb(l[idx],r[idx]) | idx <- index(l)] when size(l) == size(r);
public default list[AType] aglbList(list[AType] l, list[AType] r) = [avalue()];
diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc
index 4fbe21fdc93..3baeae3b988 100644
--- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc
+++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc
@@ -337,6 +337,16 @@ data AType
| \start(AType atype)
;
+@synopsis{These are the syntax role modifier constructors}
+data AType = \asyntaxRoleModifier(SyntaxRole role, AType modified);
+
+@synopsis{this is the core modifier feature: force the "role", keep the rest}
+AType asyntaxRoleModifier(SyntaxRole newRole, aadt(n, ps, SyntaxRole _oldRole)) = aadt(n, ps, newRole);
+
+@synopsis{The outermost modifier eventually always wins, even on open modified types.}
+AType asyntaxRoleModifier(SyntaxRole role, asyntaxRoleModifier(_, AType s))
+ = asyntaxRoleModifier(role, s);
+
//public AType \iter-seps(AType atype, []) = \iter(atype);
//public AType \iter-star-seps(AType atype, []) = \iter-star(atype);
diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc
index 557defab372..079776fd342 100644
--- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc
+++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc
@@ -942,7 +942,37 @@ void collect(current: (TypeVar) `& \<: `, Collector c){
collect(tp, c);
}
-@doc{A parsing function, useful for generating test cases.}
+// syntax type modifiers
+
+void collect(current: (Type) `data[]`, Collector c)
+ = collectSyntaxRoleModifiers(dataSyntax(), current, tp, c);
+
+void collect(current: (Type) `syntax[]`, Collector c)
+ = collectSyntaxRoleModifiers(contextFreeSyntax(), current, tp, c);
+
+void collect(current: (Type) `lexical[]`, Collector c)
+ = collectSyntaxRoleModifiers(lexicalSyntax(), current, tp, c);
+
+void collect(current: (Type) `keyword[]`, Collector c)
+ = collectSyntaxRoleModifiers(keywordSyntax(), current, tp, c);
+
+void collect(current: (Type) `layout[]`, Collector c)
+ = collectSyntaxRoleModifiers(layoutSyntax(), current, tp, c);
+
+private void collectSyntaxRoleModifiers(SyntaxRole role, Type current, Type tp, Collector c) {
+ collect(tp, c);
+ par = c.getType(tp);
+
+ if(!par is aparameter && !par is aadt && !par is asyntaxRoleModifier) {
+ c.report(error(current, "Unable to handle the parameter kind in ``; only type parameters like `&T`, or data, syntax, lexical, layout or keyword names like `Stat` are understood."));
+ }
+ else {
+ c.fact(current, asyntaxRoleModifier(role, c.getType(tp)));
+ }
+}
+
+
+@synopsis{A parsing function, useful for generating test cases.}
public Type parseType(str s) {
return parse(#Type, s);
}
diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/JGenie.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/JGenie.rsc
index 842fab03c76..f29ad1d6211 100644
--- a/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/JGenie.rsc
+++ b/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/JGenie.rsc
@@ -653,7 +653,24 @@ JGenie makeJGenie(MuModule m,
kwpTypeDecls += "$TS.declareKeywordParameter(,\"\", <_getATypeAccessor(kwpField.fieldType)>);\n";
}
}
- } else {
+ }
+ else if (asyntaxRoleModifier(SyntaxRole role, p:aparameter(_,_)) := s) {
+ // all other cases of this constructor have been rewritten to aadt(...) instances,
+ // or caused a fatal error in the type-checker.
+ isLocal = isEmpty(_getATypeAccessor(s));
+ if (isLocal) {
+ switch (role) {
+ case contextFreeSyntax() : r = "Syntax";
+ case lexicalSyntax() : r = "Lexical";
+ case keywordSyntax() : r = "Keyword";
+ case layoutSyntax() : r = "Layout";
+ case dataSyntax() : r = "Data";
+ }
+
+ return "$modifyTo()";
+ }
+ }
+ else {
tdecls += "public final io.usethesource.vallang.type.Type ;\t/**/\n";
tinits += " = ;\n";
}
diff --git a/src/org/rascalmpl/library/ParseTree.rsc b/src/org/rascalmpl/library/ParseTree.rsc
index 7ab0a0da50b..c1b82aa7ed1 100644
--- a/src/org/rascalmpl/library/ParseTree.rsc
+++ b/src/org/rascalmpl/library/ParseTree.rsc
@@ -139,9 +139,10 @@ run-time already uses `.src` while the source code still uses `@\loc`.
module ParseTree
-extend Type;
-extend Message;
extend List;
+extend Message;
+extend Type;
+
@synopsis{The Tree data type as produced by the parser.}
@description{
@@ -307,7 +308,99 @@ data Symbol
data Symbol // <19>
= \conditional(Symbol symbol, set[Condition] conditions);
-bool subtype(Symbol::\sort(_), Symbol::\adt("Tree", _)) = true;
+data Symbol
+ = \syntax(Symbol modified)
+ | \lexical(Symbol modified)
+ | \keyword(Symbol modified)
+ | \layout(Symbol modified)
+ ;
+
+Symbol \data(\syntax(Symbol s)) = \data(s);
+Symbol \data(\lexical(Symbol s)) = \data(s);
+Symbol \data(\keyword(Symbol s)) = \data(s);
+Symbol \data(\layout(Symbol s)) = \data(s);
+
+Symbol \data(a:adt(n, ps)) = a;
+Symbol \data(sort(n)) = \adt(n, []);
+Symbol \data(\parameterized-sort(n, ps)) = \adt(n, ps);
+Symbol \data(lex(n)) = \adt(n, []);
+Symbol \data(\parameterized-lex(n, ps)) = \adt(n, ps);
+Symbol \data(\keywords(n)) = \adt(n, []);
+Symbol \data(\layouts(n)) = \adt(n, []);
+
+Symbol \syntax(\data(Symbol s)) = \syntax(s);
+Symbol \syntax(\syntax(Symbol s)) = \syntax(s);
+Symbol \syntax(\lexical(Symbol s)) = \syntax(s);
+Symbol \syntax(\keyword(Symbol s)) = \syntax(s);
+Symbol \syntax(\layout(Symbol s)) = \syntax(s);
+
+Symbol \syntax(adt(n, [])) = sort(n);
+Symbol \syntax(adt(n, [p, *ps])) = \parameterized-sort(n, [p, *ps]);
+Symbol \syntax(lex(n)) = sort(n);
+Symbol \syntax(\parameterized-lex(n,ps)) = \parameterized-sort(n,ps);
+Symbol \syntax(sort(n)) = sort(n);
+Symbol \syntax(\parameterized-sort(n,ps))= \parameterized-sort(n,ps);
+Symbol \syntax(\keywords(n)) = sort(n);
+Symbol \syntax(\layouts(n)) = sort(n);
+
+Symbol \lexical(\data(Symbol s)) = \lexical(s);
+Symbol \lexical(\syntax(Symbol s)) = \lexical(s);
+Symbol \lexical(\lexical(Symbol s)) = \lexical(s);
+Symbol \lexical(\keyword(Symbol s)) = \lexical(s);
+Symbol \lexical(\layout(Symbol s)) = \lexical(s);
+
+Symbol \lexical(adt(n, [])) = lex(n);
+Symbol \lexical(adt(n, [p, *ps])) = \parameterized-lex(n, [p, *ps]);
+Symbol \lexical(lex(n)) = lex(n);
+Symbol \lexical(\parameterized-lex(n,ps)) = \parameterized-lex(n,ps);
+Symbol \lexical(sort(n)) = lex(n);
+Symbol \lexical(\parameterized-sort(n,ps))= \parameterized-lex(n,ps);
+Symbol \lexical(\keywords(n)) = lex(n);
+Symbol \lexical(\layouts(n)) = lex(n);
+
+Symbol \keyword(\data(Symbol s)) = \keyword(s);
+Symbol \keyword(\syntax(Symbol s)) = \keyword(s);
+Symbol \keyword(\lexical(Symbol s)) = \keyword(s);
+Symbol \keyword(\keyword(Symbol s)) = \keyword(s);
+Symbol \keyword(\layout(Symbol s)) = \keyword(s);
+
+Symbol \keyword(adt(n, [])) = keywords(n);
+Symbol \keyword(lex(n)) = keywords(n);
+Symbol \keyword(sort(n)) = keywords(n);
+Symbol \keyword(\keywords(n)) = keywords(n);
+Symbol \keyword(\layouts(n)) = keywords(n);
+
+Symbol \layout(\data(Symbol s)) = \layout(s);
+Symbol \layout(\syntax(Symbol s)) = \layout(s);
+Symbol \layout(\lexical(Symbol s)) = \layout(s);
+Symbol \layout(\keyword(Symbol s)) = \layout(s);
+Symbol \layout(\layout(Symbol s)) = \layout(s);
+
+Symbol \layout(adt(n, [])) = layouts(n);
+Symbol \layout(lex(n)) = layouts(n);
+Symbol \layout(sort(n)) = layouts(n);
+Symbol \layout(\keywords(n)) = layouts(n);
+Symbol \layout(\layouts(n)) = layouts(n);
+
+
+bool subtype(Symbol::\sort(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(Symbol::\parameterized-sort(_,_), Symbol::\adt("Tree", [])) = true;
+bool subtype(Symbol::\lex(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(Symbol::\parameterized-lex(_,_), Symbol::\adt("Tree", [])) = true;
+bool subtype(Symbol::\layouts(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(Symbol::\keywords(_), Symbol::\adt("Tree", [])) = true;
+
+bool subtype(\syntax(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(\lexical(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(\layout(_), Symbol::\adt("Tree", [])) = true;
+bool subtype(\keyword(_), Symbol::\adt("Tree", [])) = true;
+
+bool subtype(\syntax(parameter(_,_)), sort(_)) = true;
+bool subtype(\syntax(parameter(_,_)), \parameterized-sort(_,_)) = true;
+bool subtype(\lexical(parameter(_,_)), lex(_)) = true;
+bool subtype(\lexical(parameter(_,_)), \parameterized-lex(_,_)) = true;
+bool subtype(\keyword(parameter(_,_)), keywords(_)) = true;
+bool subtype(\layout(parameter(_,_)), layouts(_)) = true;
@synopsis{Datatype for declaring preconditions and postconditions on symbols}
@@ -738,7 +831,6 @@ data Exp = add(Exp, Exp);
}
java &T<:value implode(type[&T<:value] t, Tree tree);
-
@synopsis{Annotate a parse tree node with an (error) message.}
anno Message Tree@message;
diff --git a/src/org/rascalmpl/library/Type.java b/src/org/rascalmpl/library/Type.java
index 8669f57199d..55d2e6ae9fc 100644
--- a/src/org/rascalmpl/library/Type.java
+++ b/src/org/rascalmpl/library/Type.java
@@ -11,33 +11,33 @@
*******************************************************************************/
package org.rascalmpl.library;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.HashSet;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.stream.Collectors;
import org.rascalmpl.exceptions.RuntimeExceptionFactory;
import org.rascalmpl.types.TypeReifier;
+import org.rascalmpl.values.IRascalValueFactory;
+import org.rascalmpl.values.RascalValueFactory;
import io.usethesource.vallang.IBool;
import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IList;
import io.usethesource.vallang.IMap;
+import io.usethesource.vallang.INode;
+import io.usethesource.vallang.ISetWriter;
import io.usethesource.vallang.IString;
+import io.usethesource.vallang.ITuple;
import io.usethesource.vallang.IValue;
-import io.usethesource.vallang.IValueFactory;
import io.usethesource.vallang.exceptions.FactTypeUseException;
import io.usethesource.vallang.type.TypeFactory;
import io.usethesource.vallang.type.TypeStore;
public class Type {
- private final IValueFactory vf;
- private final IMap emptyMap;
+ private final IRascalValueFactory vf;
- public Type(IValueFactory vf) {
+ public Type(IRascalValueFactory vf, TypeFactory tf) {
this.vf = vf;
- emptyMap = vf.mapWriter().done();
}
public IValue typeOf(IValue v) {
@@ -48,39 +48,44 @@ public IValue typeOf(IValue v) {
).get("symbol");
}
+ public IValue getConstructor(INode v) {
+ assert v.getType().isAbstractData();
+ io.usethesource.vallang.type.Type constructor = ((IConstructor) v).getUninstantiatedConstructorType();
+
+ TypeStore store = new TypeStore();
+ store.declareAbstractDataType(v.getType());
+ store.declareConstructor(constructor);
+
+ ISetWriter grammar = vf.setWriter();
+
+ new TypeReifier(vf).typeToValue(constructor, store, vf.map());
+
+ constructor.asProductions(vf, store, grammar, new HashSet<>());
+
+ return grammar.done().stream().map(t -> ((ITuple) t).get(1)).findFirst().get();
+ }
+
public IBool eq(IValue x, IValue y) {
return vf.bool(x.equals(y));
}
public IValue make(IValue type, IString name, IList args) {
- return make(type, name, args, emptyMap);
+ return make(type, name, args, vf.map());
}
public IValue make(IValue type, IString name, IList args, IMap keywordParameters) {
- TypeStore store = new TypeStore();
- io.usethesource.vallang.type.Type t = new TypeReifier(vf).valueToType((IConstructor) type, store);
-
- IValue[] children = new IValue[args.length()];
- io.usethesource.vallang.type.Type[] argsTypes = new io.usethesource.vallang.type.Type[args.length()];
+ Map kwMap = keywordParameters
+ .stream()
+ .map(v -> (ITuple) v)
+ .collect(Collectors.toMap(t -> ((IString) t.get(0)).getValue(), t -> t.get(1)));
- for (int i = 0; i < args.length(); i++) {
- children[i] = args.get(i);
- argsTypes[i] = children[i].getType();
- }
+ IValue[] children = args.stream().toArray(IValue[]::new);
- Map kwmap;
-
- if(keywordParameters.size() == 0){
- kwmap = Collections.emptyMap();
- } else {
-
- Iterator> iter = keywordParameters.entryIterator();
- kwmap = new HashMap();
- while(iter.hasNext()){
- Entry entry = iter.next();
- kwmap.put(((IString) entry.getKey()).getValue(), entry.getValue());
- }
- }
+ io.usethesource.vallang.type.Type[] argsTypes
+ = args.stream().map(v -> v.getType()).toArray(io.usethesource.vallang.type.Type[]::new);
+
+ TypeStore store = new TypeStore();
+ io.usethesource.vallang.type.Type t = new TypeReifier(vf).valueToType((IConstructor) type, store);
try {
@@ -88,15 +93,40 @@ public IValue make(IValue type, IString name, IList args, IMap keywordParameters
= store.lookupConstructor(t, name.getValue(), TypeFactory.getInstance().tupleType(argsTypes));
if (constructor == null) {
- // TODO: improve error messaging, using specialized exception
- throw RuntimeExceptionFactory.illegalArgument(type, null, null);
+ throw RuntimeExceptionFactory.illegalArgument(type, vf.string("one of the parameters of the constructor did not fit its declaration."));
}
- return vf.constructor(constructor, children, kwmap);
+
+ return vf.constructor(constructor, children, kwMap);
+
+ }
+ catch (FactTypeUseException e) {
+ throw RuntimeExceptionFactory.illegalArgument(type, vf.string("one of the (keyword) parameters of the constructor did not fit its declaration."));
+ }
+ }
+ public IValue make(IConstructor cons, IList args, IMap keywordParameters) {
+ Map kwMap = keywordParameters
+ .stream()
+ .map(v -> (ITuple) v)
+ .collect(Collectors.toMap(t -> ((IString) t.get(0)).getValue(), t -> t.get(1)));
+
+ if (cons.getConstructorType() == RascalValueFactory.Production_Default) {
+ // this is a parse tree production. We can just return the tree, and add the keyword parameters
+ return vf.appl(cons, args).asWithKeywordParameters().setParameters(kwMap);
+ }
+
+ if (cons.getConstructorType() != RascalValueFactory.Production_Cons) {
+ throw RuntimeExceptionFactory.illegalArgument(cons, "must be a cons or a prod rule.");
+ }
+
+ io.usethesource.vallang.type.Type constructor = new TypeReifier(vf).productionToConstructorType(cons);
+
+ try {
+ IValue[] children = args.stream().toArray(IValue[]::new);
+ return vf.constructor(constructor, children, kwMap);
}
catch (FactTypeUseException e) {
- // TODO: improve error messaging, using specialized exception
- throw RuntimeExceptionFactory.illegalArgument(type, null, null);
+ throw RuntimeExceptionFactory.illegalArgument(cons, vf.string("one of the parameters of the constructor did not fit its declaration."));
}
}
diff --git a/src/org/rascalmpl/library/Type.rsc b/src/org/rascalmpl/library/Type.rsc
index 3ccc265062c..28c71ee72c7 100644
--- a/src/org/rascalmpl/library/Type.rsc
+++ b/src/org/rascalmpl/library/Type.rsc
@@ -93,6 +93,14 @@ data Symbol // <4>
= \parameter(str name, Symbol bound)
;
+data Symbol = \data(Symbol modified); // to-data modifier
+
+Symbol \data(\data(Symbol s)) = \data(s);
+Symbol \data(adt(n, ps)) = adt(n, ps);
+
+bool subtype(\data(Symbol s), \node()) = true;
+bool subtype(\data(parameter(_,_)), adt(_,_)) = true;
+
@synopsis{A production in a grammar or constructor in a data type.}
@description{
Productions represent abstract (recursive) definitions of abstract data type constructors and functions:
@@ -499,7 +507,30 @@ public java &T make(type[&T] typ, str name, list[value] args);
@javaClass{org.rascalmpl.library.Type}
public java &T make(type[&T] typ, str name, list[value] args, map[str,value] keywordArgs);
-
+
+@javaClass{org.rascalmpl.library.Type}
+@synopsis{Instantiate a constructor value by first declaring the given constructor and then applying it to the given parameters.}
+@description{
+The grammar rules for data constructors in a reified type can inversely be applied
+again to construct constructor instances, dynamically.
+
+This "reflection" feature is dynamically typed, so we don't know statically which type
+of ADT will come out.
+}
+@examples{
+This is the value-ified represention of `data Exp = constant(int n)`:
+```rascal-shell
+import Type;
+rule = cons(label("constant",adt("Exp",[])),[label("n",\int())],[],{});
+// we can use it to instantiate a constructor value that uses that rule:
+example = make(rule, [1]);
+// to illustrate we now construct it the normal way and test for equivalence:
+data Exp = constant(int n);
+example == constant(1);
+```
+}
+public java node make(Production cons, list[value] args, map[str,value] keywordArgs=());
+
@synopsis{Returns the dynamic type of a value as a ((Type-Symbol)).}
@description{
As opposed to the # operator, which produces the type of a value statically, this
@@ -525,6 +556,9 @@ reify operator `#` does, since values may escape the scope in which they've been
@javaClass{org.rascalmpl.library.Type}
public java Symbol typeOf(value v);
+@javaClass{org.rascalmpl.library.Type}
+public java Production getConstructor(&A <: node constructor);
+
@synopsis{Determine if the given type is an int.}
public bool isIntType(Symbol::\alias(_,_,Symbol at)) = isIntType(at);
public bool isIntType(Symbol::\parameter(_,Symbol tvb)) = isIntType(tvb);
diff --git a/src/org/rascalmpl/library/lang/paths/Windows.rsc b/src/org/rascalmpl/library/lang/paths/Windows.rsc
index 2aa288ba59e..d1177e6f089 100644
--- a/src/org/rascalmpl/library/lang/paths/Windows.rsc
+++ b/src/org/rascalmpl/library/lang/paths/Windows.rsc
@@ -10,7 +10,7 @@ The main function of this module, ((parseWindowsPath)):
* throws a ParseError if the path does not comply. Typically file names ending in spaces do not comply.
* ensures that if the file exists on system A, then the `loc` representation
resolves to the same file on system A via any ((Library:module:IO)) function.
-* and nothing more. No normalization, no interpretatioon of `.` and `..`, no changing of cases.
+* and nothing more. No normalization, no interpretation of `.` and `..`, no changing of cases.
This is left to downstream processors of `loc` values, if necessary. The current transformation
is purely syntactical, and tries to preserve the semantics of the path as much as possible.
}
diff --git a/src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc
index 4b3e603d081..006cac1d7df 100644
--- a/src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc
+++ b/src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc
@@ -157,10 +157,10 @@ lexical Name
;
syntax SyntaxDefinition
- = @Foldable \layout : Visibility vis "layout" Sym defined "=" Prod production ";"
- | @Foldable \lexical : "lexical" Sym defined "=" Prod production ";"
- | @Foldable \keyword : "keyword" Sym defined "=" Prod production ";"
- | @Foldable language: Start start "syntax" Sym defined "=" Prod production ";" ;
+ = @Foldable \layout : Visibility vis "layout" Sym!characterClass defined "=" Prod production ";"
+ | @Foldable \lexical : "lexical" Sym!characterClass defined "=" Prod production ";"
+ | @Foldable \keyword : "keyword" Sym!characterClass defined "=" Prod production ";"
+ | @Foldable language: Start start "syntax" Sym!characterClass defined "=" Prod production ";" ;
syntax Kind
= function: "function"
@@ -739,6 +739,15 @@ syntax Type
| selector: DataTypeSelector selector
| variable: TypeVar typeVar
| symbol: Sym!nonterminal!labeled!parametrized!parameter symbol
+ | modifier: SyntaxRoleModifier modifier
+ ;
+
+syntax SyntaxRoleModifier // TODO @rodin zegt dat dit Type moet zijn en niet TypeArg
+ = \syntax: "syntax" "[" TypeArg arg "]"
+ | \lexical: "lexical" "[" TypeArg arg "]"
+ | \layout: "layout" "[" TypeArg arg "]"
+ | \keyword: "keyword" "[" TypeArg arg "]"
+ | \data: "data" "[" TypeArg arg "]"
;
syntax Declaration
diff --git a/src/org/rascalmpl/library/lang/rascal/tests/functionality/SyntaxRoleModifiers1.rsc b/src/org/rascalmpl/library/lang/rascal/tests/functionality/SyntaxRoleModifiers1.rsc
new file mode 100644
index 00000000000..78eb587e0e2
--- /dev/null
+++ b/src/org/rascalmpl/library/lang/rascal/tests/functionality/SyntaxRoleModifiers1.rsc
@@ -0,0 +1,99 @@
+module lang::rascal::tests::functionality::SyntaxRoleModifiers1
+
+import Type;
+
+lexical Z = [a-z]+;
+
+syntax A = "a" | "b" "b";
+
+layout L = [\ ]*;
+
+data A = a();
+
+test bool useOfDifferentModifierTypesWithinASingleScope() {
+ data[A] anExample = a();
+ syntax[A] anotherExample = [syntax[A]] "a";
+ return anExample != anotherExample
+ && anotherExample := (A) `a`;
+}
+
+test bool dispatchingOnSyntaxRole() {
+ int f(lexical[&T] _) = 1;
+ int f(syntax[&T] _) = 2;
+ default int f(data[&T] _) = 4;
+
+ return f(a()) == 4
+ && f([lexical[Z]] "z") == 1
+ && f([syntax[A]] "a") == 2;
+}
+
+test bool canNestSyntaxModifiers() {
+ data[data[A]] v1 = a();
+ data[syntax[A]] v2 = a();
+ data[lexical[A]] v3 = a();
+ data[layout[A]] v4 = a();
+ syntax[syntax[A]] v5 = [syntax[A]] "a";
+ syntax[data[A]] v6 = [syntax[A]] "a";
+ syntax[keyword[A]] v7 = [syntax[A]] "a";
+ syntax[layout[A]] v8 = [syntax[A]] "a";
+ syntax[lexical[A]] v9 = [syntax[A]] "a";
+
+ // nothing crashed so far and the values remain equal:
+ return {a()} == {v1,v2,v3,v4}
+ && {[syntax[A]] "a"} == {v5,v6,v7,v8,v9};
+}
+
+test bool namePreservation1() {
+ // this is a simple ad-hoc mock for the real implode function:
+ data[&T] implode(syntax[&T] t:appl(prod(sort("A"),_,_),_)) = a();
+
+ // the type signature of `implode` guarantees name preservation,
+ // so implode of a syntax A will produce a data A without a type-checking error:
+ data[A] x = implode([syntax[A]] "a");
+
+ // this is not the real test. Of course the dynamic type would be data[A].
+ // the real test was the above assignment, where the static type system for
+ // assignment and function return types would fail if we had a bug here.
+ return adt("A",[]) == typeOf(x);
+}
+
+test bool namePreservation2() {
+ // this is a simple ad-hoc mock for the real explode function:
+ syntax[&T] explode(data[&T] t:a()) = [syntax[A]] "a";
+
+ // the type signature of `implode` guarantees name preservation,
+ // so explode of a data A will produce a syntax A without a type-checking error:
+ syntax[A] x = explode(a());
+
+ // this is not the real test. Of course the dynamic type would be data[A].
+ // the real test was the above assignment, where the static type system for
+ // assignment and function return types would fail if we had a bug here.
+ return sort("A") == typeOf(x);
+}
+
+test bool dataMatchesSyntaxTreesToo1() {
+ return data[Tree] _ := [syntax[A]] "a";
+}
+
+@expected{UnexpectedType}
+test bool dataMatchesSyntaxTreesToo2() {
+ // even though this is a type-preserving function,
+ // it will up-cast &T to Tree if called with a non-terminal
+ data[&T] castIt(data[&T] i) = i;
+
+ // here &T should be bound to adt("Tree",[]) and not to sort("A"), statically.
+ // but I can't write a negative test for the type-checker here I think..
+ syntax[A] shouldNotAssignStatically = castIt([syntax[A]] "a");
+
+ // we are never supposed to end up here
+ return false;
+}
+
+data X = x();
+
+test bool dataIsANodeToo() {
+ data[&T] washGeneric(data[&T] x) = x;
+
+ // this would fail the type-checker if `data[&T] `is not sub-type of `node`
+ return washGeneric(x()) == x();
+}
\ No newline at end of file
diff --git a/src/org/rascalmpl/library/util/Explode.rsc b/src/org/rascalmpl/library/util/Explode.rsc
new file mode 100644
index 00000000000..cde39964688
--- /dev/null
+++ b/src/org/rascalmpl/library/util/Explode.rsc
@@ -0,0 +1,184 @@
+@licence{
+Copyright (c) 2023, NWO-I Centrum Wiskunde & Informatica (CWI)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+}
+@contributor{Jurgen J. Vinju - Jurgen.Vinju@cwi.nl}
+@synopsis{Explode lifts abstract syntax trees to parse trees}
+@description{
+The explode function is used to lift abstract syntax trees to concrete syntax trees.
+The main difference is that all whitespace and comments are retrieved from the original
+files and placed inside of the parse tree.
+}
+@benefits{
+* when analyzing a parse tree all information including layout and comments is preservation
+* when transforming parse trees, the original layout and comments are transformed along; moroever things that remain the same, remain the same.
+* unparsing a parse tree returns the exact original input file
+* using the `explode` function we can reuse an external parser that produces ASTs, and still have Hi-fidelity source code analyses and transformations.
+* the explode function is "type name preserving", such that a data-type named "Expression" becomes a concrete syntax tree type named "Expression"
+}
+@pitfalls{
+* exploding only works correctly if the AST implements the AST specification from analysis::m3::AST.
+* exploding takes about as much time as parsing a file
+}
+module util::Explode
+
+extend ParseTree;
+import IO;
+import Node;
+import List;
+import Location;
+
+@synopsis{Turn an AST into a ParseTree, while preserving the name of the type.}
+syntax[&T] explode(data[&T] ast) {
+ assert ast.src?;
+ assert readFile(ast.src.top) == readFile(ast.src);
+ assert astNodeSpecification(ast);
+
+ if (syntax[&T] r := explode(ast, readFile(ast.src.top), ast.src.offset, ast.src.length)) {
+ return r;
+ }
+
+ throw "unexpected problem while exploding ";
+}r
+
+// singleton str nodes are lexicals (identifiers and constants)
+Tree explode(data[&T] ast:str label(str identifier), str contents, int offset, int length) {
+ return appl(prod(lex("*identifiers*"),[\iter-star(\char-class([range(1,1114111)]))],{}),
+ [
+ appl(regular(\iter-star(\char-class([range(1,1114111)]))),
+ [char(ch) | ch <- chars(contents[offset..offset+length])])
+ ]);
+}
+
+// lists get separator too. pretty sure the first and last separators will always be empty...
+list[Tree] explodeList(list[data[&T]] lst, Symbol s, str contents, int offset, int length) {
+ children = [
+ *[
+ separatorTree(contents, offset, c.src.offset),
+ explode(c, contents, c.src.offset, c.src.length) | c <- children
+ ],
+ separatorTree(contents, last.src.offset + last.src.length, offset + length) | last <- children[-1..]
+ ];
+
+ return appl(regular(s), children);
+}
+
+// we do not further explode parse trees
+Tree explode(Tree t, str _, int _, int _) = t;
+
+// this is the main workhorse
+default Tree explode(data[&T] ast, str contents, int offset, int length) {
+ children = getChildren(ast);
+ pox = positions(ast.src, children);
+ cons = getConstructor(ast);
+ symbols = cons.symbols;
+
+ // Here we generate a quasi syntax rule on-the-fly that has the structure and the types
+ // of the exploded children. Each rule starts with separators, has separators
+ // in between every child, and ends with separators. Each child node is modified
+ // to a syntax node. Lists become iter-star symbols.
+ rule = prod(\syntax(cons.def), [
+ layouts("*separators*"),
+ *[\syntax(c), layouts("*separators*") | Symbol c <- symbols]
+ ],
+ {});
+
+ children = [
+ *[
+ separatorTree(contents, offset, c.src.offset),
+ // there are 3 cases, mutually exclusive:
+ *[explode(c, contents, c.src.offset, c.src.length)[src=p] | node _ := c], // a node
+ *[emptyList(s, p) | [] := c], // an empty list
+ *[explodeList(c, \syntax(s), contents, c.src.offset, c.src.length)[src=p] | [_,*_] := c] // a non-empty list
+ | <- zip3(children, symbols, pox)
+ ],
+ separatorTree(contents, last.src.offset + last.src.length, offset + length) | last <- children[-1..]
+ ];
+
+ return appl(rule, children, src=ast.src);
+}
+
+Tree emptyList(Symbol s, loc src) = appl(regular(s), [], src=src);
+
+Tree separatorTree(str contents, int \start, int end)
+ = appl(prod(layouts("*separators*"),[\iter-star(\char-class([range(1,1114111)]))],{}),
+ [
+ appl(regular(\iter-star(\char-class([range(1,1114111)]))),
+ [char(ch) | int ch <- chars(contents[\start..end])])
+ ]);
+
+@synopsis{Helper function to convert AST notions to their ParseTree equivalent.}
+@description{
+* argument labels are kept for field access purposes later
+* string constants represent (flat) lexical syntax
+* abstract lists become concrete layout-separated nullable lists.
+}
+Symbol \syntax(label(str x, Symbol s)) = label(x, \syntax(s));
+Symbol \syntax(\str()) = \lex("*lexical*");
+Symbol \syntax(\list(Symbol s)) = \iter-star-seps(\syntax(s),[layouts("*separators*")]);
+
+private Symbol unlabel(label(str _, Symbol s)) = unlabel(s);
+private Symbol unlabel(conditional(Symbol s, set[Condition] _)) = unlabel(s);
+private default Symbol unlabel(Symbol s) = s;
+
+@synopsis{Give every element an exact and true location for later processing.}
+@description{
+For every AST element in a list, the function returns a list of the same length,
+with each inferred fully-specified location in the place of the respective AST element.
+
+There are strings, nodes, empty lists and non-empty lists to consider. Only nodes have
+a `.src` field. For the other values a `loc` value is computed from the surrounding
+siblings and the parent span.
+
+This algorithm runs in 2 steps:
+1. `pos` first positions every type of possible abstract element
+ * for lexical strings it becomes the entire span
+ * empty lists are not resolvable in this stage, deferred with `empty:///`
+ * nodes with src annotations; that is used
+ * non-empty lists take the cover of the first and last element.
+2. The second step is a fixed-point computation that incrementally replaces `empty:///` instances
+by using the information of the already resolved siblings, until all `empty:///` spots have been resolved.
+ * `empty:///` at the start means we can use the parent span for the left border.
+ * `empty:///` at the end means we can use the parent span for the right border.
+ * `empty:///` after a resolved location can take over the right border of that sibling.
+ * `empty:///` before a resolved location can take over the left border of that sibling.
+
+Due to the semantics of list matching, the algorithm typically replaces `empty:///` in the list
+going from left to right to find instances of the above cases.
+}
+private list[loc] positions(loc span, list[value] l) = infer(span, [pos(span, x) | x <- l]);
+
+@synopsis{Replaces all |empty:///| with a correct loc inferred from the surroundings}
+private list[loc] infer(loc span, [loc l, *loc rest]) = infer(span, [span[length=0], *rest]) when l == |empty:///|;
+private list[loc] infer(loc span, [*loc rest, loc l]) = infer(span, [*rest, span[offset=span.offset+span.length-1][length=0]]) when l == |empty:///|;
+private list[loc] infer(loc span, [*loc pre, loc before, loc l, *loc post]) = infer(span, [*pre, before, before[offset=before.offset+before.length][length = 0], *post]) when l == |empty:///|;
+private list[loc] infer(loc span, [*loc pre, loc l, loc after, *loc post]) = infer(span, [*pre, after[offset=after.offset][length = 0], after, *post]) when l == |empty:///|;
+private default list[loc] infer(loc _span, list[loc] done) = done;
+
+@synsopsis{An element either knows its position, or it does not.}
+@description{
+This function applies the `span` and any directly available `.src` fields
+to do a first estimate at solving the location of an AST element.
+In particular it fails to do so for empty lists `[]`, which is left for
+the later `infer` stage.
+}
+@pitfalls{
+* This is where we have to assume that `str` fields are always singletons, otherwise we could not
+put the entire `span` around them.
+}
+private loc pos(loc span, str _) = span;
+private loc pos(loc _span, []) = |empty:///|;
+private loc pos(loc _span, node n) = \loc(n);
+private loc pos(loc _span, [node n]) = \loc(n);
+private loc pos(loc _span, [node a, *_, node b]) = cover([\loc(a), \loc(b)]);
+
+@synopsis{Waiting for `node.src` to be available in Rascal for good...}
+private loc \loc(node n) = l when loc l := n.src;
\ No newline at end of file
diff --git a/src/org/rascalmpl/runtime/$RascalModule.java b/src/org/rascalmpl/runtime/$RascalModule.java
index cf8bb3c0316..5d74655b67d 100644
--- a/src/org/rascalmpl/runtime/$RascalModule.java
+++ b/src/org/rascalmpl/runtime/$RascalModule.java
@@ -253,41 +253,6 @@ public Set findResources(String fileName) {
}
}
- private static void $usage(String module, String error, Type kwargs) {
- PrintWriter $ERR = new PrintWriter(System.err);
-
- if (!error.isEmpty() && !error.equals("help")) {
- $ERR.println(error);
- }
-
- $ERR.println("Usage: ");
- $ERR.println("java -cp ... " + module + " ");
-
- if (kwargs.getArity() > 0) {
- $ERR.println(" [options]\n\nOptions:\n");
-
- for (String param : kwargs.getFieldNames()) {
- $ERR.print("\t-");
- $ERR.print(param);
- if (kwargs.getFieldType(param).isSubtypeOf(TypeFactory.getInstance().boolType())) {
- $ERR.println("\t[arg]: one of nothing (true), \'1\', \'0\', \'true\' or \'false\';");
- }
- else {
- $ERR.println("\t[arg]: " + kwargs.getFieldType(param) + " argument;");
- }
- }
- }
- else {
- $ERR.println('\n');
- }
-
- $ERR.flush();
-
- if (!error.equals("help")) {
- throw new IllegalArgumentException();
- }
- }
-
protected static Map $parseCommandlineParameters(String module, String[] commandline, Type kwTypes) {
// reusing the same commandline parameter parser that the interpreter uses, based on the keyword parameter types
// of the function type of the `main` function.
@@ -358,6 +323,26 @@ public Set findResources(String fileName) {
//$TS.declareAbstractDataType(adtType);
return adtType;
}
+
+ public io.usethesource.vallang.type.Type $modifyToData(Type arg) {
+ return $RTF.modifyToData(arg);
+ }
+
+ public io.usethesource.vallang.type.Type $modifyToSyntax(Type arg) {
+ return $RTF.modifyToSyntax(arg);
+ }
+
+ public io.usethesource.vallang.type.Type $modifyToLexical(Type arg) {
+ return $RTF.modifyToLexical(arg);
+ }
+
+ public io.usethesource.vallang.type.Type $modifyToKeyword(Type arg) {
+ return $RTF.modifyToKeyword(arg);
+ }
+
+ public io.usethesource.vallang.type.Type $modifyToLayout(Type arg) {
+ return $RTF.modifyToLayout(arg);
+ }
public io.usethesource.vallang.type.Type $sort(String adtName){
Type adtType = $TF.abstractDataType($TS, adtName);
diff --git a/src/org/rascalmpl/semantics/dynamic/SyntaxRoleModifier.java b/src/org/rascalmpl/semantics/dynamic/SyntaxRoleModifier.java
new file mode 100644
index 00000000000..bb7ee3cb53d
--- /dev/null
+++ b/src/org/rascalmpl/semantics/dynamic/SyntaxRoleModifier.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2009-2013 CWI
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+
+ * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
+ * * Mark Hills - Mark.Hills@cwi.nl (CWI)
+*******************************************************************************/
+package org.rascalmpl.semantics.dynamic;
+
+import org.rascalmpl.interpreter.IEvaluator;
+import org.rascalmpl.interpreter.env.Environment;
+import org.rascalmpl.interpreter.result.Result;
+import org.rascalmpl.interpreter.staticErrors.NonWellformedType;
+
+import io.usethesource.vallang.IConstructor;
+import io.usethesource.vallang.ISourceLocation;
+import io.usethesource.vallang.IValue;
+import io.usethesource.vallang.type.Type;
+
+public abstract class SyntaxRoleModifier extends org.rascalmpl.ast.SyntaxRoleModifier {
+
+ static public class Syntax extends org.rascalmpl.ast.SyntaxRoleModifier.Syntax {
+ public Syntax(ISourceLocation __param1, IConstructor tree, org.rascalmpl.ast.TypeArg __param2) {
+ super(__param1, tree, __param2);
+ }
+
+ @Override
+ public Type typeOf(Environment __eval, IEvaluator> eval, boolean instantiateTypeParameters) {
+ try {
+ return RTF.modifyToSyntax(getArg().typeOf(__eval, eval, instantiateTypeParameters));
+ }
+ catch (IllegalArgumentException e) {
+ throw new NonWellformedType(e.getMessage(), eval.getCurrentAST());
+ }
+ }
+ }
+
+ static public class Lexical extends org.rascalmpl.ast.SyntaxRoleModifier.Lexical {
+ public Lexical(ISourceLocation __param1, IConstructor tree, org.rascalmpl.ast.TypeArg __param2) {
+ super(__param1, tree, __param2);
+ }
+
+ @Override
+ public Type typeOf(Environment __eval, IEvaluator> eval, boolean instantiateTypeParameters) {
+ try {
+ return RTF.modifyToLexical(getArg().typeOf(__eval, eval, instantiateTypeParameters));
+ }
+ catch (IllegalArgumentException e) {
+ throw new NonWellformedType(e.getMessage(), eval.getCurrentAST());
+ }
+ }
+ }
+
+ static public class Layout extends org.rascalmpl.ast.SyntaxRoleModifier.Layout {
+ public Layout(ISourceLocation __param1, IConstructor tree, org.rascalmpl.ast.TypeArg __param2) {
+ super(__param1, tree, __param2);
+ }
+
+ @Override
+ public Type typeOf(Environment __eval, IEvaluator> eval, boolean instantiateTypeParameters) {
+ try {
+ return RTF.modifyToLayout(getArg().typeOf(__eval, eval, instantiateTypeParameters));
+ }
+ catch (IllegalArgumentException e) {
+ throw new NonWellformedType(e.getMessage(), eval.getCurrentAST());
+ }
+ }
+ }
+
+ static public class Keyword extends org.rascalmpl.ast.SyntaxRoleModifier.Keyword {
+ public Keyword(ISourceLocation __param1, IConstructor tree, org.rascalmpl.ast.TypeArg __param2) {
+ super(__param1, tree, __param2);
+ }
+
+ @Override
+ public Type typeOf(Environment __eval, IEvaluator> eval, boolean instantiateTypeParameters) {
+ try {
+ return RTF.modifyToKeyword(getArg().typeOf(__eval, eval, instantiateTypeParameters));
+ }
+ catch (IllegalArgumentException e) {
+ throw new NonWellformedType(e.getMessage(), eval.getCurrentAST());
+ }
+ }
+ }
+
+ static public class Data extends org.rascalmpl.ast.SyntaxRoleModifier.Data {
+ public Data(ISourceLocation __param1, IConstructor tree, org.rascalmpl.ast.TypeArg __param2) {
+ super(__param1, tree, __param2);
+ }
+
+ @Override
+ public Type typeOf(Environment __eval, IEvaluator> eval, boolean instantiateTypeParameters) {
+ try {
+ return RTF.modifyToData(getArg().typeOf(__eval, eval, instantiateTypeParameters));
+ }
+ catch (IllegalArgumentException e) {
+ throw new NonWellformedType(e.getMessage(), eval.getCurrentAST());
+ }
+ }
+ }
+
+
+
+ public SyntaxRoleModifier(ISourceLocation __param1, IConstructor tree) {
+ super(__param1, tree);
+ }
+}
diff --git a/src/org/rascalmpl/semantics/dynamic/Type.java b/src/org/rascalmpl/semantics/dynamic/Type.java
index bfa8fa3148d..3f7b9efd6cb 100644
--- a/src/org/rascalmpl/semantics/dynamic/Type.java
+++ b/src/org/rascalmpl/semantics/dynamic/Type.java
@@ -18,6 +18,7 @@
import org.rascalmpl.ast.FunctionType;
import org.rascalmpl.ast.StructuredType;
import org.rascalmpl.ast.Sym;
+import org.rascalmpl.ast.SyntaxRoleModifier;
import org.rascalmpl.ast.TypeVar;
import org.rascalmpl.ast.UserType;
import org.rascalmpl.interpreter.IEvaluator;
@@ -105,7 +106,7 @@ public io.usethesource.vallang.type.Type typeOf(Environment env, IEvaluator> eval, boolean instantiateTypeParameters) {
+ return getModifier().typeOf(env, eval, instantiateTypeParameters);
+ }
+ }
+
public Type(ISourceLocation __param1, IConstructor tree) {
super(__param1, tree);
}
diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java
index 494767ac9b2..8e9ee211423 100644
--- a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java
+++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java
@@ -260,7 +260,7 @@ private void processModules() {
// register a failing module to make sure we report failure later on.
- Description testDesc = Description.createTestDescription(getClass(), module, new CompilationFailed() {
+ Description testDesc = Description.createTestDescription(module, module, new CompilationFailed() {
@Override
public Class extends Annotation> annotationType() {
return getClass();
@@ -277,7 +277,7 @@ public Class extends Annotation> annotationType() {
if (!moduleEnv.getTests().isEmpty()) {
Description modDesc = Description.createSuiteDescription(module);
for (AbstractFunction f : moduleEnv.getTests()) {
- modDesc.addChild(Description.createTestDescription(getClass(), RascalJUnitTestRunner.computeTestName(f.getName(), f.getAst().getLocation())));
+ modDesc.addChild(Description.createTestDescription(module, RascalJUnitTestRunner.computeTestName(f.getName(), f.getAst().getLocation())));
}
descriptions.add(modDesc);
testModules.add(modDesc);
diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java
index 6afe55280cd..bdb819a21e9 100644
--- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java
+++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java
@@ -171,13 +171,13 @@ public Description getDescription() {
// the order of the tests aren't decided by this list so no need to randomly order them.
for (AbstractFunction f : tests) {
- modDesc.addChild(Description.createTestDescription(clazz, computeTestName(f.getName(), f.getAst().getLocation())));
+ modDesc.addChild(Description.createTestDescription(name, computeTestName(f.getName(), f.getAst().getLocation())));
}
}
catch (Throwable e) {
desc.addChild(modDesc);
- Description testDesc = Description.createTestDescription(clazz, name + " compilation failed", new CompilationFailed() {
+ Description testDesc = Description.createTestDescription(name, name + " compilation failed", new CompilationFailed() {
@Override
public Class extends Annotation> annotationType() {
return getClass();
@@ -190,7 +190,7 @@ public Class extends Annotation> annotationType() {
return true;
} catch (IOException e) {
- Description testDesc = Description.createTestDescription(clazz, prefix + " compilation failed: " + e.getMessage(), new CompilationFailed() {
+ Description testDesc = Description.createTestDescription(prefix, prefix + " compilation failed: " + e.getMessage(), new CompilationFailed() {
@Override
public Class extends Annotation> annotationType() {
return getClass();
diff --git a/src/org/rascalmpl/types/DefaultRascalTypeVisitor.java b/src/org/rascalmpl/types/DefaultRascalTypeVisitor.java
index e93f772dba1..a80532700ec 100644
--- a/src/org/rascalmpl/types/DefaultRascalTypeVisitor.java
+++ b/src/org/rascalmpl/types/DefaultRascalTypeVisitor.java
@@ -24,4 +24,9 @@ public T visitReified(RascalType type) throws E {
public T visitNonTerminal(RascalType type) throws E {
return def;
}
+
+ @Override
+ public T visitRoleModifier(RascalType type) throws E {
+ return def;
+ }
}
diff --git a/src/org/rascalmpl/types/IRascalTypeVisitor.java b/src/org/rascalmpl/types/IRascalTypeVisitor.java
index 0e05e290550..11d19c65521 100644
--- a/src/org/rascalmpl/types/IRascalTypeVisitor.java
+++ b/src/org/rascalmpl/types/IRascalTypeVisitor.java
@@ -3,6 +3,7 @@
import io.usethesource.vallang.type.ITypeVisitor;
public interface IRascalTypeVisitor extends ITypeVisitor {
- T visitReified(RascalType type) throws E;
- T visitNonTerminal(RascalType type) throws E;
+ T visitReified(RascalType THIS) throws E;
+ T visitNonTerminal(RascalType THIS) throws E;
+ T visitRoleModifier(RascalType THIS) throws E;
}
diff --git a/src/org/rascalmpl/types/ModifySyntaxRole.java b/src/org/rascalmpl/types/ModifySyntaxRole.java
new file mode 100644
index 00000000000..1b1e2007b1c
--- /dev/null
+++ b/src/org/rascalmpl/types/ModifySyntaxRole.java
@@ -0,0 +1,953 @@
+package org.rascalmpl.types;
+
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isKeyword;
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isLayouts;
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isLex;
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isParameterizedLex;
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isParameterizedSort;
+import static org.rascalmpl.values.parsetrees.SymbolAdapter.isSort;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.StreamSupport;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.rascalmpl.values.RascalValueFactory;
+import org.rascalmpl.values.parsetrees.SymbolAdapter;
+import io.usethesource.vallang.IConstructor;
+import io.usethesource.vallang.ISetWriter;
+import io.usethesource.vallang.IValue;
+import io.usethesource.vallang.IValueFactory;
+import io.usethesource.vallang.exceptions.FactTypeUseException;
+import io.usethesource.vallang.type.Type;
+import io.usethesource.vallang.type.TypeFactory;
+import io.usethesource.vallang.type.TypeStore;
+import io.usethesource.vallang.type.TypeFactory.RandomTypesConfig;
+
+/**
+ * A ModifySyntaxRole is a lazy modification operation on a Type that
+ * preserves its name, but not its syntax role. The lazyness is of essence
+ * due to type parameters: for `syntax[&T]` we must remember to modify
+ * to the `syntax` role until after the substitution of the type parameter.
+ * A lazy role has an effect during pattern matching, where it filters for
+ * types that have a certain role (e.g. `syntax[&T] _` only matches non-terminals
+ * that are not lexical, layout or keywords).
+ *
+ * However, once a type parameter is made concrete, then ModifySyntaxRole
+ * should be `apply`ed. The canonical form of a ModifySyntaxRole for non-open
+ * types is the actually modified type representation. So a NonterminalType
+ * or an AbstractDatatype, etc. It is absolutely essential that the _apply_
+ * method is executed by the RascalTypeFactory and by the `Type.instantiate`
+ * implementations below to guarantee the canonical forms.
+ */
+public abstract class ModifySyntaxRole extends RascalType {
+ private final static RascalTypeFactory TF = RascalTypeFactory.getInstance();
+ private final static TypeFactory tf = TypeFactory.getInstance();
+
+ /**
+ * This is the type to be modified.
+ */
+ protected final Type arg;
+
+ public ModifySyntaxRole(Type param) {
+ assert param != null : "syntax role modifier must have non-null parameter";
+ this.arg = param;
+ }
+
+ /**
+ * `apply` modifies the parameter type to "become" a type that is indicated
+ * by the modifier class. This happens at construction time, when the
+ * type is made: syntax[data[X]] => syntax[X], and also after type-parameter
+ * substitution.
+ *
+ * Because there is a case distinction on both the receiver and the parameter
+ * type, we use the "double dispatch" design pattern to quickly reduce any
+ * combination of modifier and type kinds to the right result.
+ *
+ * Typically `apply` guarantees "name preservation". So the name of the
+ * resulting type is equal to the name of the parameter type.
+ */
+ public Type apply() {
+ if (arg.isParameter()) {
+ return this;
+ }
+ else if (arg instanceof ModifySyntaxRole) {
+ return applyToRole((ModifySyntaxRole) arg);
+ }
+ else if (arg instanceof NonTerminalType) {
+ IConstructor symbol = ((NonTerminalType) arg).getSymbol();
+
+ if (isSort(symbol) || isParameterizedSort(symbol)) {
+ return applyToSyntax((NonTerminalType) arg);
+ }
+ else if (isLex(symbol) || isParameterizedLex(symbol)) {
+ return applyToLexical((NonTerminalType) arg);
+ }
+ else if (isLayouts(symbol)) {
+ return applyToLayout((NonTerminalType) arg);
+ }
+ else if (isKeyword(symbol)) {
+ return applyToKeyword((NonTerminalType) arg);
+ }
+ }
+ else if (arg.isAbstractData()) {
+ return applyToData(arg);
+ }
+
+ throw new IllegalArgumentException("Do not know how to apply the " + getClass().getSimpleName() + " syntax role modifier to " + arg);
+ }
+
+ protected abstract Type applyToRole(ModifySyntaxRole role);
+ protected abstract Type applyToSyntax(NonTerminalType role);
+ protected abstract Type applyToLexical(NonTerminalType role);
+ protected abstract Type applyToLayout(NonTerminalType role);
+ protected abstract Type applyToKeyword(NonTerminalType role);
+ protected abstract Type applyToData(Type role);
+
+ /** this represents `syntax[&T]` */
+ public static class Syntax extends ModifySyntaxRole {
+ public Syntax(Type arg) {
+ super(arg);
+ }
+
+ @Override
+ public String toString() {
+ return "syntax[" + arg.toString() + "]";
+ }
+
+ @Override
+ public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) {
+ return vf.constructor(RascalValueFactory.Symbol_SyntaxModifier, arg.asSymbol(vf, store, grammar, done));
+ }
+
+ @Override
+ protected Type lubWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return TF.modifyToSyntax(((ModifySyntaxRole) type).arg.lub(arg));
+ }
+ else if (type instanceof Lexical) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Layout) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Keyword) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Data) {
+ return tf.nodeType();
+ }
+
+ return tf.nodeType();
+ }
+
+ @Override
+ protected Type glbWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return TF.modifyToSyntax(((ModifySyntaxRole) type).arg.glb(arg));
+ }
+
+ return tf.voidType();
+ }
+
+ @Override
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ assert isOpen();
+ return type instanceof Syntax;
+ }
+
+ @Override
+ protected boolean isSupertypeOf(RascalType type) {
+ assert isOpen();
+
+ if (type instanceof NonTerminalType) {
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isSort(sym) || SymbolAdapter.isParameterizedSort(sym);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isSubtypeOfNonTerminal(RascalType type) {
+ assert isOpen(); // otherwise we wouldn't be here
+
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isSort(sym) || SymbolAdapter.isParameterizedSort(sym);
+ }
+
+ @Override
+ public boolean match(Type matched, Map bindings) throws FactTypeUseException {
+ if (matched instanceof NonTerminalType) {
+ IConstructor sym = ((NonTerminalType) matched).getSymbol();
+
+ if (SymbolAdapter.isSort(sym) || SymbolAdapter.isParameterizedSort(sym)) {
+ return arg.match(matched, bindings);
+ }
+ }
+ else if (matched.isBottom()) {
+ return arg.match(matched, bindings);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Type instantiate(Map bindings) {
+ return TF.modifyToSyntax(arg.instantiate(bindings));
+ }
+
+ @Override
+ protected boolean isSubtypeOfAbstractData(Type type) {
+ // syntax[T] <: Tree
+ return type == RascalValueFactory.Tree;
+ }
+
+ @Override
+ protected Type applyToRole(ModifySyntaxRole role) {
+ return TF.modifyToSyntax(role.arg);
+ }
+
+ @Override
+ public Type applyToSyntax(NonTerminalType arg) {
+ return arg;
+ }
+
+ @Override
+ public Type applyToLexical(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ if (arg.isParameterized()) {
+ return TF.syntaxType(name, SymbolAdapter.getParameters(arg.getSymbol()));
+ }
+ else {
+ return TF.syntaxType(name);
+ }
+ }
+
+ @Override
+ public Type applyToKeyword(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.syntaxType(name);
+ }
+
+ @Override
+ public Type applyToLayout(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.syntaxType(name);
+ }
+
+ @Override
+ public Type applyToData(Type arg) {
+ String name = arg.getName();
+
+ if (arg.isParameterized()) {
+ return TF.syntaxType(name, StreamSupport.stream(arg.getTypeParameters().spliterator(), false).toArray(Type[]::new));
+ }
+ else {
+ return TF.syntaxType(name);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return SymbolAdapter.getName(((NonTerminalType) arg).getSymbol());
+ }
+ }
+
+ /** this represents `lexical[&T]` */
+ public static class Lexical extends ModifySyntaxRole {
+ public Lexical(Type arg) {
+ super(arg);
+ }
+
+ @Override
+ public String toString() {
+ return "lexical[" + arg.toString() + "]";
+ }
+
+ @Override
+ protected boolean isSupertypeOf(RascalType type) {
+ assert isOpen();
+
+ if (type instanceof NonTerminalType) {
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isLex(sym) || SymbolAdapter.isParameterizedLex(sym);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ assert isOpen();
+ return type instanceof Lexical;
+ }
+
+ @Override
+ public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) {
+ return vf.constructor(RascalValueFactory.Symbol_LexicalModifier, arg.asSymbol(vf, store, grammar, done));
+ }
+
+ @Override
+ protected Type lubWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Lexical) {
+ return TF.modifyToLexical(((ModifySyntaxRole) type).arg.lub(arg));
+ }
+ else if (type instanceof Layout) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Keyword) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Data) {
+ return tf.nodeType();
+ }
+
+ return tf.nodeType();
+ }
+
+ @Override
+ protected Type glbWithModifySyntax(RascalType type) {
+ if (type instanceof Lexical) {
+ return TF.modifyToLexical(((ModifySyntaxRole) type).arg.glb(arg));
+ }
+
+ return tf.voidType();
+ }
+
+ @Override
+ public boolean isSubtypeOfNonTerminal(RascalType type) {
+ assert isOpen(); // otherwise we wouldn't be here
+
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isLex(sym) || SymbolAdapter.isParameterizedLex(sym);
+ }
+
+ @Override
+ protected boolean isSubtypeOfAbstractData(Type type) {
+ // syntax[T] <: Tree
+ return type == RascalValueFactory.Tree;
+ }
+
+ @Override
+ public boolean match(Type matched, Map bindings) throws FactTypeUseException {
+ if (matched instanceof NonTerminalType) {
+ IConstructor sym = ((NonTerminalType) matched).getSymbol();
+
+ if (SymbolAdapter.isLex(sym) || SymbolAdapter.isParameterizedLex(sym)) {
+ return arg.match(matched, bindings);
+ }
+ }
+ else if (matched.isBottom()) {
+ return arg.match(matched, bindings);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Type instantiate(Map bindings) {
+ return TF.modifyToLexical(arg.instantiate(bindings));
+ }
+
+ @Override
+ protected Type applyToRole(ModifySyntaxRole role) {
+ return TF.modifyToLexical(role.arg);
+ }
+
+ @Override
+ public Type applyToLexical(NonTerminalType arg) {
+ return arg;
+ }
+
+ @Override
+ public Type applyToSyntax(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ if (arg.isParameterized()) {
+ return TF.lexicalType(name, SymbolAdapter.getParameters(arg.getSymbol()));
+ }
+ else {
+ return TF.lexicalType(name);
+ }
+ }
+
+ @Override
+ public Type applyToKeyword(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.lexicalType(name);
+ }
+
+ @Override
+ public Type applyToLayout(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.lexicalType(name);
+ }
+
+ @Override
+ public Type applyToData(Type arg) {
+ String name = arg.getName();
+
+ if (arg.isParameterized()) {
+ return TF.lexicalType(name, StreamSupport.stream(arg.getTypeParameters().spliterator(), false).toArray(Type[]::new));
+ }
+ else {
+ return TF.lexicalType(name);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return SymbolAdapter.getName(((NonTerminalType) arg).getSymbol());
+ }
+ }
+ public static class Layout extends ModifySyntaxRole {
+ public Layout(Type arg) {
+ super(arg);
+ }
+
+ @Override
+ public String toString() {
+ return "layout[" + arg.toString() + "]";
+ }
+
+ @Override
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ assert isOpen();
+ return type instanceof Layout;
+ }
+
+ @Override
+ protected boolean isSupertypeOf(RascalType type) {
+ assert isOpen();
+
+ if (type instanceof NonTerminalType) {
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isLayouts(sym);
+ }
+
+ return false;
+ }
+
+
+ @Override
+ protected Type lubWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Lexical) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Layout) {
+ return TF.modifyToLayout(((ModifySyntaxRole) type).arg.lub(arg));
+ }
+ else if (type instanceof Keyword) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Data) {
+ return tf.nodeType();
+ }
+
+ return tf.nodeType();
+ }
+
+ @Override
+ protected Type glbWithModifySyntax(RascalType type) {
+ if (type instanceof Layout) {
+ return TF.modifyToLayout(((ModifySyntaxRole) type).arg.glb(arg));
+ }
+
+ return tf.voidType();
+ }
+
+
+ @Override
+ public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) {
+ return vf.constructor(RascalValueFactory.Symbol_LayoutModifier, arg.asSymbol(vf, store, grammar, done));
+ }
+
+ @Override
+ public boolean isSubtypeOfNonTerminal(RascalType type) {
+ assert isOpen(); // otherwise we wouldn't be here
+
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isLayouts(sym);
+ }
+
+ @Override
+ protected boolean isSubtypeOfAbstractData(Type type) {
+ // syntax[T] <: Tree
+ return type == RascalValueFactory.Tree;
+ }
+
+ @Override
+ public boolean match(Type matched, Map bindings) throws FactTypeUseException {
+ if (matched instanceof NonTerminalType) {
+ IConstructor sym = ((NonTerminalType) matched).getSymbol();
+
+ if (SymbolAdapter.isLayouts(sym)) {
+ return arg.match(matched, bindings);
+ }
+ }
+ else if (matched.isBottom()) {
+ return arg.match(matched, bindings);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Type instantiate(Map bindings) {
+ return TF.modifyToLayout(arg.instantiate(bindings));
+ }
+
+ @Override
+ protected Type applyToRole(ModifySyntaxRole role) {
+ return TF.modifyToLayout(role.arg);
+ }
+
+ @Override
+ public Type applyToSyntax(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ assert !arg.isParameterized() : "layout is never parameterized";
+
+ return TF.layoutType(name);
+ }
+
+ @Override
+ public Type applyToLexical(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ assert !arg.isParameterized() : "layout is never parameterized";
+
+ return TF.layoutType(name);
+ }
+
+ @Override
+ public Type applyToKeyword(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.layoutType(name);
+ }
+
+ @Override
+ public Type applyToLayout(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.layoutType(name);
+ }
+
+ @Override
+ public Type applyToData(Type arg) {
+ String name = arg.getName();
+
+ assert !arg.isParameterized() : "layout is never parameterized";
+
+ return TF.layoutType(name);
+ }
+
+ @Override
+ public String getName() {
+ return SymbolAdapter.getName(((NonTerminalType) arg).getSymbol());
+ }
+ }
+ public static class Keyword extends ModifySyntaxRole {
+ public Keyword(Type arg) {
+ super(arg);
+ }
+
+ @Override
+ public String toString() {
+ return "keyword[" + arg.toString() + "]";
+ }
+
+ @Override
+ public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) {
+ return vf.constructor(RascalValueFactory.Symbol_KeywordModifier, arg.asSymbol(vf, store, grammar, done));
+ }
+
+ @Override
+ protected Type lubWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Lexical) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Layout) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Keyword) {
+ return TF.modifyToKeyword(((ModifySyntaxRole) type).arg.lub(arg));
+ }
+ else if (type instanceof Data) {
+ return tf.nodeType();
+ }
+
+ return tf.nodeType();
+ }
+
+ @Override
+ protected Type glbWithModifySyntax(RascalType type) {
+ if (type instanceof Keyword) {
+ return TF.modifyToKeyword(((ModifySyntaxRole) type).arg.glb(arg));
+ }
+
+
+ return tf.voidType();
+ }
+
+ @Override
+ protected boolean isSupertypeOf(RascalType type) {
+ if (type instanceof NonTerminalType) {
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isKeyword(sym);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ assert isOpen();
+ return type instanceof Keyword;
+ }
+
+ @Override
+ public boolean isSubtypeOfNonTerminal(RascalType type) {
+ assert isOpen(); // otherwise we wouldn't be here
+
+ NonTerminalType nt = (NonTerminalType) type;
+ IConstructor sym = nt.getSymbol();
+
+ return SymbolAdapter.isKeyword(sym);
+ }
+
+ @Override
+ protected boolean isSubtypeOfAbstractData(Type type) {
+ // syntax[T] <: Tree
+ return type == RascalValueFactory.Tree;
+ }
+
+ @Override
+ public boolean match(Type matched, Map bindings) throws FactTypeUseException {
+ if (matched instanceof NonTerminalType) {
+ IConstructor sym = ((NonTerminalType) matched).getSymbol();
+
+ if (SymbolAdapter.isKeyword(sym)) {
+ return arg.match(matched, bindings);
+ }
+ }
+ else if (matched.isBottom()) {
+ return arg.match(matched, bindings);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Type instantiate(Map bindings) {
+ return TF.modifyToKeyword(arg.instantiate(bindings));
+ }
+
+ @Override
+ protected Type applyToRole(ModifySyntaxRole role) {
+ return TF.modifyToKeyword(role.arg);
+ }
+
+ @Override
+ public Type applyToSyntax(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ assert !arg.isParameterized() : "keyword is never parameterized";
+
+ return TF.keywordType(name);
+ }
+
+ @Override
+ public Type applyToLexical(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ assert !arg.isParameterized() : "keyword is never parameterized";
+
+ return TF.keywordType(name);
+ }
+
+ @Override
+ public Type applyToKeyword(NonTerminalType arg) {
+ return arg;
+ }
+
+ @Override
+ public Type applyToLayout(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.keywordType(name);
+ }
+
+ @Override
+ public Type applyToData(Type arg) {
+ String name = arg.getName();
+
+ assert !arg.isParameterized() : "keyword is never parameterized";
+
+ return TF.keywordType(name);
+ }
+ }
+ public static class Data extends ModifySyntaxRole {
+ public Data(Type arg) {
+ super(arg);
+ }
+
+ @Override
+ public String toString() {
+ return "data[" + arg.toString() + "]";
+ }
+
+ @Override
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ assert isOpen();
+ return type instanceof Data;
+ }
+
+ @Override
+ protected boolean isSupertypeOf(RascalType type) {
+ assert isOpen();
+ // Here is it essential that {@link NonTerminalType#isAbstractData()} returns true.
+ return type.isAbstractData();
+ }
+
+ @Override
+ protected Type lubWithModifySyntax(RascalType type) {
+ if (type instanceof Syntax) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Lexical) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Layout) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Keyword) {
+ return RascalValueFactory.Tree;
+ }
+ else if (type instanceof Data) {
+ return this;
+ }
+
+ return tf.nodeType();
+ }
+
+ @Override
+ protected Type glbWithModifySyntax(RascalType type) {
+ if (type instanceof Data) {
+ return this;
+ }
+
+ return tf.voidType();
+ }
+
+ @Override
+ protected boolean isSupertypeOf(Type type) {
+ assert isOpen();
+ return type.isBottom() || type.isAbstractData();
+ }
+
+ @Override
+ public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) {
+ return vf.constructor(RascalValueFactory.Symbol_DataModifier, arg.asSymbol(vf, store, grammar, done));
+ }
+
+
+ @Override
+ protected Type applyToRole(ModifySyntaxRole role) {
+ return TF.modifyToData(role.arg);
+ }
+
+ @Override
+ protected boolean isSubtypeOfAbstractData(Type type) {
+ assert isOpen();
+ return true;
+ }
+
+ @Override
+ public boolean match(Type matched, Map bindings) throws FactTypeUseException {
+ if (matched instanceof NonTerminalType) {
+ // here a `syntax` or `lexical` or `keyword` or `layout` would match against a
+ // literal data[&T], and we need the &T to bind with `Tree` and not `Statement` or
+ // some non-terminal name. Note that this is correct because `Tree` is an
+ // algebraic `data` type.
+ return arg.match(RascalValueFactory.Tree, bindings);
+ }
+ else if (matched.isAbstractData() || matched.isBottom()) {
+ return arg.match(matched, bindings);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Type instantiate(Map bindings) {
+ return TF.modifyToData(arg.instantiate(bindings));
+ }
+
+ @Override
+ public Type applyToSyntax(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+
+ if (arg.isParameterized()) {
+ Type[] params = SymbolAdapter.getParameters(arg.getSymbol()).stream().map(c -> TF.nonTerminalType((IConstructor) c)).toArray(Type[]::new);
+ return tf.abstractDataType(new TypeStore(), name, params);
+ }
+ else {
+ return tf.abstractDataType(new TypeStore(), name);
+ }
+ }
+
+ @Override
+ public Type applyToLexical(NonTerminalType arg) {
+ return applyToSyntax(arg);
+ }
+
+ @Override
+ public Type applyToKeyword(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return TF.syntaxType(name);
+ }
+
+ @Override
+ public Type applyToLayout(NonTerminalType arg) {
+ String name = SymbolAdapter.getName(arg.getSymbol());
+ return tf.abstractDataType(new TypeStore(), name);
+ }
+
+ @Override
+ public Type applyToData(Type arg) {
+ return arg;
+ }
+
+ @Override
+ protected Type lubWithAbstractData(Type type) {
+ return type.lub(arg);
+ }
+
+ @Override
+ protected Type glbWithAbstractData(Type type) {
+ return type.glb(arg);
+ }
+ }
+
+ @Override
+ public boolean isOpen() {
+ return arg.isOpen();
+ }
+
+ @Override
+ protected Type lubWithAbstractData(Type type) {
+ // this is for all the syntax roles that are not data. Data overrides this
+ if (type == RascalValueFactory.Tree) {
+ return type;
+ }
+
+ return tf.valueType();
+ }
+
+ @Override
+ protected Type glbWithAbstractData(Type type) {
+ // this is for all the syntax roles that are not data. Data overrides this
+ return type == RascalValueFactory.Tree ? this : tf.voidType();
+ }
+
+ @Override
+ abstract protected boolean isSupertypeOf(RascalType type);
+
+ @Override
+ protected boolean isSubtypeOfNode(Type type) {
+ // all syntax roles are sub-type of node
+ return true;
+ }
+
+ @Override
+ protected Type lub(RascalType type) {
+ return type.lubWithModifySyntax(this);
+ }
+
+ @Override
+ protected Type glb(RascalType type) {
+ return type.glbWithModifySyntax(this);
+ }
+
+ @Override
+ abstract protected Type glbWithModifySyntax(RascalType type);
+
+ @Override
+ protected boolean intersects(RascalType type) {
+ return type.intersectsWithModifySyntax(this);
+ }
+
+ @Override
+ protected boolean intersectsWithModifySyntax(RascalType type) {
+ // since we have only one parameter, intersection coincides with subtype comparability
+ return this.comparable(type);
+ }
+
+ @Override
+ public Type asAbstractDataType() {
+ return RascalValueFactory.Symbol;
+ }
+
+ @Override
+ abstract public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done);
+
+ @Override
+ abstract public Type instantiate(Map bindings);
+
+ @Override
+ abstract public boolean match(Type matched, Map bindings) throws FactTypeUseException;
+
+ @Override
+ abstract public String toString();
+
+ @Override
+ public IValue randomValue(Random random, RandomTypesConfig cfg, IValueFactory vf, TypeStore store, Map typeParameters,
+ int maxDepth, int maxBreadth) {
+ return arg.randomValue(random, cfg, vf, store, typeParameters, maxDepth, maxBreadth);
+ }
+
+ @Override
+ public T accept(IRascalTypeVisitor v) throws E {
+ return v.visitRoleModifier(this);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null) {
+ return false;
+ }
+
+ // implementing this for several sub-classes at the same time.
+ return o.getClass() == getClass() && ((ModifySyntaxRole) o).arg == arg;
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().getCanonicalName().hashCode() + 23 * arg.hashCode();
+ }
+}
diff --git a/src/org/rascalmpl/types/NonTerminalType.java b/src/org/rascalmpl/types/NonTerminalType.java
index 761221a1ccf..e38c6b1fa3f 100644
--- a/src/org/rascalmpl/types/NonTerminalType.java
+++ b/src/org/rascalmpl/types/NonTerminalType.java
@@ -228,6 +228,16 @@ public Type asAbstractDataType() {
return RascalValueFactory.Tree;
}
+ @Override
+ public boolean isParameterized() {
+ return SymbolAdapter.isParameterizedLex(symbol) || SymbolAdapter.isParameterizedSort(symbol);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return isParameterized() && SymbolAdapter.getParameters(symbol).stream().anyMatch(v -> SymbolAdapter.isParameter((IConstructor) v));
+ }
+
public IConstructor getSymbol() {
return symbol;
}
@@ -454,6 +464,8 @@ else if (SymbolAdapter.isCharClass(symbol) && SymbolAdapter.isCharClass(otherSym
protected Type lubWithNonTerminal(RascalType other) {
IConstructor otherSym = ((NonTerminalType)other).symbol;
+ // TODO: this code does not cater for type parameters!
+
// * eats +
if (SymbolAdapter.isIterPlus(symbol) && SymbolAdapter.isIterStar(otherSym)) {
return other;
@@ -478,6 +490,8 @@ else if (SymbolAdapter.isCharClass(symbol) && SymbolAdapter.isCharClass(otherSym
protected Type glbWithNonTerminal(RascalType other) {
IConstructor otherSym = ((NonTerminalType)other).symbol;
+ // TODO: this code does not cater for type parameters!
+
if (SymbolAdapter.isIterPlus(symbol) && SymbolAdapter.isIterStar(otherSym)) {
return this;
}
diff --git a/src/org/rascalmpl/types/RascalType.java b/src/org/rascalmpl/types/RascalType.java
index 2dac9fd2983..dedf1f98998 100644
--- a/src/org/rascalmpl/types/RascalType.java
+++ b/src/org/rascalmpl/types/RascalType.java
@@ -22,7 +22,6 @@ protected Type glbWithExternal(Type type) {
@Override
protected boolean intersectsWithExternal(Type type) {
assert type instanceof RascalType;
- System.err.println(this.toString() + "Intersects with " + type);
return intersects((RascalType) type);
}
@@ -42,6 +41,10 @@ public boolean isSubtypeOfNonTerminal(RascalType type) {
return false;
}
+ public boolean isSubtypeOfSyntaxModifier(RascalType type) {
+ return false;
+ }
+
protected boolean isSubtypeOfFunction(RascalType type) {
return false;
}
@@ -62,6 +65,10 @@ protected Type lubWithReified(RascalType type) {
return TF.valueType();
}
+ protected Type lubWithModifySyntax(RascalType type) {
+ return TF.valueType();
+ }
+
protected Type glbWithNonTerminal(RascalType type) {
return TF.voidType();
}
@@ -74,6 +81,9 @@ protected Type glbWithReified(RascalType type) {
return TF.voidType();
}
+ protected Type glbWithModifySyntax(RascalType type) {
+ return TF.voidType();
+ }
protected boolean intersectsWithNonTerminal(RascalType type) {
return false;
@@ -86,6 +96,10 @@ protected boolean intersectsWithFunction(RascalType type) {
protected boolean intersectsWithReified(RascalType type) {
return false;
}
+
+ protected boolean intersectsWithModifySyntax(RascalType type) {
+ return false;
+ }
public boolean isNonterminal() {
return false;
@@ -99,6 +113,10 @@ public boolean isReified() {
return false;
}
+ public boolean isRoleModifier() {
+ return false;
+ }
+
public static boolean isNonterminal(Type type) {
return type.isExternalType() && ((RascalType) type).isNonterminal();
}
@@ -110,4 +128,9 @@ public static boolean isReified(Type type) {
public static boolean isFunction(Type type) {
return type.isExternalType() && ((RascalType) type).isFunction();
}
+
+ public static boolean isRoleModifier(Type type) {
+ return type.isExternalType() && ((RascalType) type).isRoleModifier();
+ }
+
}
diff --git a/src/org/rascalmpl/types/RascalTypeFactory.java b/src/org/rascalmpl/types/RascalTypeFactory.java
index 748fd174c9a..994816d119f 100644
--- a/src/org/rascalmpl/types/RascalTypeFactory.java
+++ b/src/org/rascalmpl/types/RascalTypeFactory.java
@@ -11,15 +11,19 @@
*******************************************************************************/
package org.rascalmpl.types;
+import java.util.Arrays;
+import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.parsetrees.SymbolAdapter;
+import org.rascalmpl.values.parsetrees.SymbolFactory;
import io.usethesource.vallang.IConstructor;
+import io.usethesource.vallang.IList;
import io.usethesource.vallang.type.Type;
import io.usethesource.vallang.type.TypeFactory;
-import io.usethesource.vallang.type.TypeStore;
public class RascalTypeFactory {
private TypeFactory tf = TypeFactory.getInstance();
+ private IRascalValueFactory vf = IRascalValueFactory.getInstance();
private static class InstanceHolder {
public static final RascalTypeFactory sInstance = new RascalTypeFactory();
@@ -30,12 +34,8 @@ public static RascalTypeFactory getInstance() {
}
public Type nonTerminalType(IConstructor cons) {
- if (SymbolAdapter.isADT(cons)) {
- // TODO: what if the ADT has parameters?
- return TypeFactory.getInstance().abstractDataType(
- new TypeStore(),
- SymbolAdapter.getName(cons));
- }
+ assert !SymbolAdapter.isADT(cons) && !SymbolAdapter.isParameter(cons);
+
return tf.externalType(new NonTerminalType(cons));
}
@@ -46,4 +46,119 @@ public Type nonTerminalType(org.rascalmpl.ast.Type symbol, boolean lex, String l
public Type reifiedType(Type arg) {
return tf.externalType(new ReifiedType(arg));
}
+
+ public Type syntaxType(String name, Type[] parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeSort(name,
+ Arrays.stream(parameters)
+ .map(p -> ((NonTerminalType) p).getSymbol())
+ .collect(vf.listWriter()))
+ ));
+ }
+
+ public Type syntaxType(String name, IList parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeSort(name, parameters)));
+ }
+
+ public Type syntaxType(String name) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeSort(name)));
+ }
+
+ public Type lexicalType(String name, Type[] parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLex(name,
+ Arrays.stream(parameters)
+ .map(p -> ((NonTerminalType) p).getSymbol())
+ .collect(vf.listWriter()))
+ ));
+ }
+
+ public Type lexicalType(String name) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLex(name)));
+ }
+
+ public Type lexicalType(String name, IList parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLex(name, parameters)));
+ }
+
+ public Type keywordType(String name) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeKeyword(name, vf.list())));
+ }
+
+ public Type layoutType(String name, Type[] parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLayout(name, vf.list())));
+ }
+
+ public Type layoutType(String name, IList parameters) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLayout(name, parameters)));
+ }
+
+ public Type layoutType(String name) {
+ return tf.externalType(new NonTerminalType(SymbolFactory.makeLayout(name)));
+ }
+
+ /**
+ * Changes a data-type, a lexical, a syntax or a layout type to a keyword type.
+ * Because keyword types do not support parameters, this method throws exceptions
+ * for unsupported cases. It is the task of the type-checker to make sure these
+ * will be caught before running.
+ *
+ * @param arg a data-type, lexical or syntax or layout sort to be modified
+ * @return a keyword type with the same name as the input type, but mofied to a keyword non-terminal.
+ */
+ public Type modifyToKeyword(Type arg) {
+ return tf.externalType(new ModifySyntaxRole.Keyword(arg).apply());
+ }
+
+ /**
+ * Changes a keyword, a lexical, a data type or a layout type to a syntax type.
+ * When the modified type is not a named entity type like a syntax or lexical sort,
+ * and adt or a keyword non-terminal, then this method throws an exception.
+ *
+ * @param arg a data-type, lexical or syntax or layout sort to be modified
+ * @return a syntax type with the same name as the input type, but modified to a syntax non-terminal,
+ * or a still open modifier type for lazy instantation.
+ */
+ public Type modifyToSyntax(Type arg) {
+ return tf.externalType(new ModifySyntaxRole.Syntax(arg).apply());
+ }
+
+ /**
+ * Changes a keyword, a syntax, a data type or a layout type to a lexical type.
+ * When the modified type is not a named entity type like a syntax or lexical sort,
+ * and adt or a keyword non-terminal, then this method throws an exception.
+ *
+ * @param arg a data-type, lexical or syntax or layout sort to be modified
+ * @return a syntax type with the same name as the input type, but modified to a syntax non-terminal,
+ * or a still open modifier type for lazy instantation.
+ */
+ public Type modifyToLexical(Type arg) {
+ return tf.externalType(new ModifySyntaxRole.Lexical(arg).apply());
+ }
+
+
+ /**
+ * Changes a keyword, a lexical, a syntax or a layout type to a data type.
+ * When the modified type is not a named entity type like a syntax or lexical sort,
+ * and adt or a keyword non-terminal, then this method throws an exception.
+ *
+ * @param arg a data-type, lexical or syntax or layout sort to be modified
+ * @return a data type with the same name as the input type, but modified to a data non-terminal,
+ * or a still open modifier type for lazy instantation.
+ */
+ public Type modifyToData(Type arg) {
+ return tf.externalType(new ModifySyntaxRole.Data(arg).apply());
+ }
+
+ /**
+ * Changes a syntax, a lexical, a syntax or a data type to a layout type.
+ * When the modified type is not a named entity type like a syntax or lexical sort,
+ * and adt or a keyword non-terminal, then this method throws an exception.
+ *
+ * @param arg a data-type, lexical or syntax or layout sort to be modified
+ * @return a data type with the same name as the input type, but modified to a data non-terminal,
+ * or a still open modifier type for lazy instantation.
+ */
+ public Type modifyToLayout(Type arg) {
+ return tf.externalType(new ModifySyntaxRole.Layout(arg).apply());
+ }
+
}
diff --git a/src/org/rascalmpl/types/TypeReifier.java b/src/org/rascalmpl/types/TypeReifier.java
index 75b33221aec..b075429e001 100644
--- a/src/org/rascalmpl/types/TypeReifier.java
+++ b/src/org/rascalmpl/types/TypeReifier.java
@@ -119,12 +119,18 @@ public Type valueToType(IConstructor typeValue, TypeStore store) {
*/
public Type productionToConstructorType(IConstructor prod) {
if (prod.getConstructorType() == RascalValueFactory.Symbol_Prod) {
+ // this is due to the type-checker accidentally representing productions as Symbols
return productionToConstructorType(convertSymbolProdToProduction(prod));
}
- // TODO remove check after bootstrap suc6
- IConstructor adt = (IConstructor) (prod.has("adt") ? prod.get("adt") : prod.get("def"));
- return TypeFactory.getInstance().fromSymbol(prod, new TypeStore(), x -> x == adt ? Collections.singleton(prod) : Collections.emptySet());
+ // this conditional is not needed; used to be for bad bootstrap in the RVM
+ IConstructor adt = SymbolAdapter.delabel((IConstructor) (prod.has("adt") ? prod.get("adt") : prod.get("def")));
+ TypeStore store = new TypeStore();
+
+ // we store the rule in a grammar lookup function such that it can be added to the store as "side-effect"
+ Type sym = TypeFactory.getInstance().fromSymbol(adt, store, x -> x == adt ? Collections.singleton(prod) : Collections.emptySet());
+ // return the single rule that was defined into the store for this symbol:
+ return store.lookupAlternatives(sym).iterator().next();
}
/**
diff --git a/src/org/rascalmpl/values/RascalValueFactory.java b/src/org/rascalmpl/values/RascalValueFactory.java
index 3c4a7218b5d..8256bab2a2d 100644
--- a/src/org/rascalmpl/values/RascalValueFactory.java
+++ b/src/org/rascalmpl/values/RascalValueFactory.java
@@ -226,6 +226,14 @@ public class RascalValueFactory extends AbstractValueFactoryAdapter implements I
public static final Type Symbol_Alias = tf.constructor(uptr, Symbol, "alias", str, "name", tf.listType(Symbol), "parameters", Symbol, "aliased");
public static final Type Symbol_Cons = tf.constructor(uptr, Symbol, "cons", Symbol, "adt", str, "name", tf.listType(Symbol), "parameters");
+ /* Modifiers */
+ public static final Type Symbol_DataModifier = tf.constructor(uptr, Symbol, "data", Symbol, "modified");
+ public static final Type Symbol_SyntaxModifier = tf.constructor(uptr, Symbol, "syntax", Symbol, "modified");
+ public static final Type Symbol_LexicalModifier = tf.constructor(uptr, Symbol, "lexical", Symbol, "modified");
+ public static final Type Symbol_KeywordModifier = tf.constructor(uptr, Symbol, "keyword", Symbol, "modified");
+ public static final Type Symbol_LayoutModifier = tf.constructor(uptr, Symbol, "layout", Symbol, "modified");
+
+
/* Internally (type checker) used constructors for Symbol: */
public static final Type Symbol_Overloaded = tf.constructor(uptr, Symbol, "overloaded", tf.setType(Symbol), "overloads", tf.setType(Symbol), "defaults");
public static final Type Symbol_Prod = tf.constructor(uptr, Symbol, "prod", Symbol, "sort", str, "name", tf.listType(Symbol), "parameters", tf.setType(Attr), "attributes");
diff --git a/src/org/rascalmpl/values/parsetrees/SymbolAdapter.java b/src/org/rascalmpl/values/parsetrees/SymbolAdapter.java
index 5d147f453f6..512f4671f0e 100644
--- a/src/org/rascalmpl/values/parsetrees/SymbolAdapter.java
+++ b/src/org/rascalmpl/values/parsetrees/SymbolAdapter.java
@@ -138,12 +138,7 @@ public static boolean isStartSort(IConstructor tree) {
tree = delabel(tree);
return tree.getConstructorType() == Symbol_Start;
}
-
-// public static boolean isStart(IConstructor tree) {
-// tree = delabel(tree);
-// return tree.getConstructorType() == Factory.Symbol_START;
-// }
-
+
public static IConstructor getStart(IConstructor tree) {
if (isStartSort(tree)) {
tree = delabel(tree);
diff --git a/src/org/rascalmpl/values/parsetrees/SymbolFactory.java b/src/org/rascalmpl/values/parsetrees/SymbolFactory.java
index 3533d194343..499c1c8f8c9 100644
--- a/src/org/rascalmpl/values/parsetrees/SymbolFactory.java
+++ b/src/org/rascalmpl/values/parsetrees/SymbolFactory.java
@@ -40,6 +40,7 @@
import io.usethesource.vallang.exceptions.FactTypeUseException;
import io.usethesource.vallang.io.StandardTextReader;
+import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.RascalValueFactory;
import org.rascalmpl.values.ValueFactoryFactory;
@@ -544,4 +545,58 @@ private static int rangeBegin(IConstructor range) {
private static int rangeEnd(IConstructor range) {
return ((IInteger) range.get("end")).intValue();
}
+
+ private static final IRascalValueFactory VF = IRascalValueFactory.getInstance();
+
+ public static IConstructor makeSort(String name) {
+ return VF.constructor(RascalValueFactory.Symbol_Sort, VF.string(name));
+ }
+
+ public static IConstructor makeSort(String name, IList parameters) {
+ if (parameters.length() != 0) {
+ return VF.constructor(RascalValueFactory.Symbol_ParameterizedSort, VF.string(name), parameters);
+ }
+ else {
+ return makeSort(name);
+ }
+ }
+
+ public static IConstructor makeLex(String name) {
+ return VF.constructor(RascalValueFactory.Symbol_Lex, VF.string(name));
+ }
+
+ public static IConstructor makeLex(String name, IList parameters) {
+ if (parameters.length() != 0) {
+ return VF.constructor(RascalValueFactory.Symbol_ParameterizedLex, VF.string(name), parameters);
+ }
+ else {
+ return makeSort(name);
+ }
+ }
+
+ public static IConstructor makeKeyword(String name) {
+ return VF.constructor(RascalValueFactory.Symbol_Keywords, VF.string(name));
+ }
+
+ public static IConstructor makeKeyword(String name, IList parameters) {
+ if (parameters.length() != 0) {
+ throw new IllegalArgumentException("keyword types can not have parameters");
+ }
+ else {
+ return makeKeyword(name);
+ }
+ }
+
+ public static IConstructor makeLayout(String name) {
+ return VF.constructor(RascalValueFactory.Symbol_Layouts, VF.string(name));
+ }
+
+ public static IConstructor makeLayout(String name, IList parameters) {
+ if (parameters.length() != 0) {
+ throw new IllegalArgumentException("layout types can not have parameters");
+ }
+ else {
+ return makeLayout(name);
+ }
+ }
}