diff --git a/ChangeLog b/ChangeLog index 3ce0d883927bad3f95e80a305d3ddff8fb3b65c3..ac56606ae1ea498563c0680888270da5ab8abddf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2019-03-18 Jesper Öqvist <jesper.oqvist@cs.lth.se> + + * Allow implicit root type for collection attributes in grammars with + multiple root types. + 2018-06-14 Jesper Öqvist <jesper.oqvist@cs.lth.se> * Removed generation of the is$Equal method. The method was unused. diff --git a/src/jastadd/ast/ASTErrors.jrag b/src/jastadd/ast/ASTErrors.jrag index a2109f3d9ba1bda8e777e1ecaa78f06620341db0..96a8f4481e4ebfee390ade81065441e25dd14445 100644 --- a/src/jastadd/ast/ASTErrors.jrag +++ b/src/jastadd/ast/ASTErrors.jrag @@ -43,15 +43,6 @@ aspect ASTErrors { [new LinkedList<Problem>()] root Grammar; - syn boolean TypeDecl.isRootNode() = false; - - eq ASTDecl.isRootNode() = isPotentialRootNode() && parents().isEmpty(); - - syn boolean TypeDecl.isPotentialRootNode() = false; - - eq ASTDecl.isPotentialRootNode() = - !hasAbstract() && !isASTNodeDecl() && !isOptSubtype() && !isListSubtype(); - Grammar contributes Problem.builder() .message("there is no root node in the grammar!") .buildWarning() diff --git a/src/jastadd/ast/AttributeProblems.jrag b/src/jastadd/ast/AttributeProblems.jrag index de7fa1df46794143073a65080f76668e36772065..aa5e9ae6b3997e6388f68b347cd955f96f267934 100644 --- a/src/jastadd/ast/AttributeProblems.jrag +++ b/src/jastadd/ast/AttributeProblems.jrag @@ -461,22 +461,6 @@ aspect AttributeProblems { return error(msg); } - CollDecl contributes multipleRootsProblem() - when hasMultipleRootsProblem() - to TypeDecl.attributeProblems() - for hostClass(); - - syn boolean CollDecl.hasMultipleRootsProblem() = root == null && grammar().roots().size() > 1; - - syn Problem CollDecl.multipleRootsProblem() { - StringBuilder buf = new StringBuilder(); - buf.append("multiple tree roots to search for contributions. Please explicitly select one of"); - for (ASTDecl decl : grammar().roots()) { - buf.append(" " + decl.name()); - } - return error(buf.toString()); - } - CollDecl contributes error("No tree roots to search for contributions. " + "Please declare an explicit root node.") when hasNoRootProblem() diff --git a/src/jastadd/ast/CollectionAttributes.jrag b/src/jastadd/ast/CollectionAttributes.jrag index c4ca0f82ac98782293ffdf89c664fe86044d9a2a..28ba15e93bc9f79823243cf6186815b421aef09b 100644 --- a/src/jastadd/ast/CollectionAttributes.jrag +++ b/src/jastadd/ast/CollectionAttributes.jrag @@ -1,4 +1,4 @@ -/* Copyright (c) 2005-2016, The JastAdd Team +/* Copyright (c) 2005-2019, The JastAdd Team * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,6 +39,9 @@ aspect CollectionAttributes { /** @return the type name of the collection root node */ syn String CollDecl.rootType() = root().name(); + /** Returns {@code true} if the declaration does not have an explicit root type. */ + syn boolean CollDecl.implicitRoot() = root == null; + /** @return the type name of the collection root node */ syn String CollEq.rootType() = decl().rootType(); @@ -134,9 +137,18 @@ aspect CollectionAttributes { } } - syn TypeDecl AttrDecl.root() = grammar().root(); - - eq CollDecl.root() = root != null ? grammar().lookup(root) : super.root(); + syn TypeDecl CollDecl.root() { + if (root != null) { + return grammar().lookup(root); + } else { + Collection<ASTDecl> roots = grammar().roots(); + if (roots.size() == 1) { + return roots.iterator().next(); + } else { + return grammar().lookup(config().astNodeType()); + } + } + } // Only used by circular collection attributes. public void AttrDecl.emitCircularCollectionEval(PrintStream out) { @@ -428,6 +440,10 @@ aspect CollectionAttributes { return s.toString(); } + /** + * Finds all roots in the grammar. + * A root is not a child of any other node. + */ syn lazy Collection<ASTDecl> Grammar.roots() { Collection<ASTDecl> roots = new HashSet<ASTDecl>(); for (TypeDecl decl : getTypeDeclList()) { @@ -438,7 +454,18 @@ aspect CollectionAttributes { return roots; } - syn ASTDecl Grammar.root() = roots().isEmpty() ? null : roots().iterator().next(); + /** + * Returns {@code true} if this type is a root in the abstract grammar. + * A root is not abstract and not a child of any other type in the grammar. + */ + syn boolean TypeDecl.isRootNode() = false; + + eq ASTDecl.isRootNode() = isPotentialRootNode() && parents().isEmpty(); + + syn boolean TypeDecl.isPotentialRootNode() = false; + + eq ASTDecl.isPotentialRootNode() = + !hasAbstract() && !isASTNodeDecl() && !isOptSubtype() && !isListSubtype(); eq ASTDecl.getCollDecl().hostClass() = this; diff --git a/src/template/ast/Collections.tt b/src/template/ast/Collections.tt index 660efeced6f71c5cbd3eae21475fb79d9b1287bb..d5c16669fb4e9985c4b82ccfa078328b9502e7ff 100644 --- a/src/template/ast/Collections.tt +++ b/src/template/ast/Collections.tt @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2015, The JastAdd Team +# Copyright (c) 2013-2019, The JastAdd Team # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,6 +25,22 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +CollDecl.findRoot [[ +$if(#implicitRoot) +$ASTNode node = this; +while (node.getParent() != null) { + node = node.getParent(); +} +$else +$ASTNode node = this; +while (node != null && !(node instanceof #rootType)) { + node = node.getParent(); +} +$endif +$include(CollDecl.collDebugCheck) +#rootType root = (#rootType) node; +]] + CollDecl.collDebugCheck [[ $if(DebugMode) if (node == null) { @@ -37,12 +53,7 @@ $endif CollDecl.computeMethod:onePhase [[ /** @apilevel internal */ private #getType #(name)_compute() { - $ASTNode node = this; - while (node != null && !(node instanceof #rootType)) { - node = node.getParent(); - } - $include(CollDecl.collDebugCheck) - #rootType root = (#rootType) node; + $include(CollDecl.findRoot) root.survey_#collectionId(); if (#(signature)_value == null) { #(signature)_value = $BottomValue; @@ -54,12 +65,7 @@ CollDecl.computeMethod:onePhase [[ CollDecl.computeMethod:twoPhase [[ /** @apilevel internal */ private #getType #(name)_compute() { - $ASTNode node = this; - while (node != null && !(node instanceof #rootType)) { - node = node.getParent(); - } - $include(CollDecl.collDebugCheck) - #rootType root = (#rootType) node; + $include(CollDecl.findRoot) root.survey_#collectionId(); #getType _computedValue = $BottomValue; $include(CollDecl.collectContributions) @@ -69,7 +75,7 @@ CollDecl.computeMethod:twoPhase [[ CollDecl.collectContributions [[ if (root.contributorMap_#collectionId.containsKey(this)) { - for ($ASTNode contributor : root.contributorMap_#collectionId.get(this)) { + for ($ASTNode contributor : (java.util.Set<$ASTNode>) root.contributorMap_#collectionId.get(this)) { contributor.contributeTo_#(signature)(_computedValue); } }