diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Layout.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Layout.rsc index 5e46e780b54..6beee402f60 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Layout.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Layout.rsc @@ -34,11 +34,10 @@ import lang::rascalcore::check::ATypeUtils; public AGrammar layouts(AGrammar g, AType l, set[AType] others) { res = top-down-break visit (g) { - case p: prod(\start(aadt(_, list[AType] _, contextFreeSyntax())), [x]) => p[atypes=[l, x, l]] - - case p: prod(aadt(_, list[AType] _, contextFreeSyntax()), list[AType] lhs) => p[atypes=intermix(lhs, l, others)] + case p: prod(aadt(_, list[AType] _, contextFreeSyntax()), list[AType] lhs) => p[atypes=intermix(lhs, l, others)] + case p: prod(\start(AType topSymbol, SyntaxRole _), [topSymbol]) => p[atypes=[l, topSymbol, l]] } - //iprintln(res); + return res; } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Symbols.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Symbols.rsc index a07a75ae2e3..4045c3dbbad 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Symbols.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/agrammar/definition/Symbols.rsc @@ -61,7 +61,7 @@ public AType sym2AType(Sym sym) { case lang::rascal::\syntax::Rascal::nonterminal(Nonterminal n) : return AType::aadt("", [], dataSyntax()); case \start(Nonterminal n) : - return \start(AType::aadt("", [], dataSyntax())); + return \start(AType::aadt("", [], contextFreeSyntax()), contextFreeSyntax()); case literal(StringConstant l): return AType::alit(unescapeLiteral(l)); case caseInsensitiveLiteral(CaseInsensitiveStringConstant l): @@ -124,7 +124,7 @@ public AType defsym2AType(Sym sym, SyntaxRole sr) { return AType::aadt("",separgs2ATypes(syms), sr); case \start(Nonterminal n) : - return \start(AType::aadt("", [], sr)); + return \start(AType::aadt("", [], sr), contextFreeSyntax()); default: { iprintln(sym); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc index 9d75d2d38cf..5e922a734a6 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc @@ -194,20 +194,11 @@ tuple[TModel, ModuleStatus] addGrammar(str qualifiedModuleName, set[str] imports } allStarts = uncloseTypeParams(allStarts); rel[AType,AProduction] allProductions = uncloseTypeParams(definedProductions); - - allProductions = visit(allProductions){ - case p:prod(\start(a:aadt(_,_,_)),defs) => p[def=a] - case \start(a:aadt(_,_,_)) => a - } - set[AType] allLayouts = {}; set[AType] allManualLayouts = {}; map[AType,AProduction] syntaxDefinitions = (); for(AType adtType <- domain(allProductions)){ - if(\start(adtType2) := adtType){ - adtType = adtType2; - } productions = allProductions[adtType]; syntaxDefinitions[adtType] = achoice(adtType, productions); //println("syntaxDefinitions, for add "); @@ -250,7 +241,7 @@ tuple[TModel, ModuleStatus] addGrammar(str qualifiedModuleName, set[str] imports // Add start symbols for(AType adtType <- allStarts){ - syntaxDefinitions[\start(adtType)] = achoice(\start(adtType), { prod(\start(adtType), [definedLayout, adtType[alabel="top"], definedLayout]) }); + syntaxDefinitions[\start(adtType, contextFreeSyntax())] = achoice(\start(adtType, contextFreeSyntax()), { prod(\start(adtType, contextFreeSyntax()), [definedLayout, adtType[alabel="top"], definedLayout]) }); } // Add auxiliary rules for instantiated syntactic ADTs outside the grammar rules @@ -365,7 +356,8 @@ TModel checkKeywords(rel[AType, AProduction] allProductions, TModel tm){ } } } - for(AType adtType <- domain(allProductions), ((\start(t) := adtType) ? t.syntaxRole : adtType.syntaxRole) == keywordSyntax()){ + + for(AType adtType <- domain(allProductions), adtType.syntaxRole == keywordSyntax()){ for(p:prod(AType _, list[AType] asymbols) <- allProductions[adtType]){ if(size(asymbols) != 1){ tm.messages += [warning(size(asymbols) == 0 ? "One symbol needed in keyword declaration, found none" : "Keyword declaration should consist of one symbol", p.src)]; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc index da4e43f2da6..b971e87f154 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc @@ -73,8 +73,6 @@ default bool asubtype(AType l, AType r){ return l is aint || l is areal || l is arat || l is anum; case aalias(str _, list[AType] _, AType aliased): return asubtype(l, aliased); - case \start(AType t): - return asubtype(l, t); case aprod(p): return asubtype(l, p.def); case \iter(AType t): @@ -192,8 +190,6 @@ bool asubtype(ac:acons(AType a, list[AType] ap, list[Keyword] _), AType b){ return true; case afunc(AType b, list[AType] bp, list[Keyword] _): return asubtype(a, b) && comparableList(ap, bp); - case \start(AType t): - return asubtype(ac, t); case avalue(): return true; } @@ -202,10 +198,8 @@ bool asubtype(ac:acons(AType a, list[AType] ap, list[Keyword] _), AType b){ bool asubtype(ap: aprod(AProduction p), AType b){ switch(b){ - case aprod(AProduction q): + case aprod(AProduction q): return asubtype(p.def, q.def); - case \start(AType t): - return asubtype(ap, t); case conditional(AType t, _): return asubtype(ap, t); case AType t: @@ -228,8 +222,6 @@ bool asubtype(adt:aadt(str n, list[AType] l, SyntaxRole sr), AType b){ return asubtypeList(l, r); case aadt("Tree", _, _): if(isConcreteSyntaxRole(sr)) return true; - case \start(AType t): - if(isConcreteSyntaxRole(sr)) return asubtype(adt, t); case avalue(): return true; case p:aparameter(_, AType bnd): @@ -238,7 +230,11 @@ bool asubtype(adt:aadt(str n, list[AType] l, SyntaxRole sr), AType b){ fail; } -bool asubtype(\start(AType a), AType b) = asubtype(a, b); +// start non-terminals behave just like parameterized non-terminals. +// but note that this code is currently unreachable since we can't type `start[&T]` +bool asubtype(\start(AType a, SyntaxRole sr), \start(AType b, sr)) = asubtype(a, b); +bool asubtype(\start(AType a, SyntaxRole _sr), aadt("Tree", [], dataSyntax())) = true; +bool asubtype(\start(AType a, SyntaxRole _sr), anode(_)) = true; bool asubtype(i:\iter(AType s), AType b){ switch(b){ @@ -254,8 +250,6 @@ bool asubtype(i:\iter(AType s), AType b){ return asubtype(s,t) && isEmpty(removeLayout(seps)); case \iter-star-seps(AType t, list[AType] seps): return asubtype(s,t) && isEmpty(removeLayout(seps)); - case \start(AType t): - return asubtype(i, t); case avalue(): return true; } @@ -276,8 +270,6 @@ bool asubtype(i:\iter-seps(AType s, list[AType] seps), AType b){ return asubtype(s,t) && isEmpty(removeLayout(seps)); case \iter-star-seps(AType t, list[AType] seps2): return asubtype(s,t) && asubtypeList(removeLayout(seps), removeLayout(seps2)); - case \start(AType t): - return asubtype(i, t); case avalue(): return true; } @@ -294,8 +286,6 @@ bool asubtype(i:\iter-star(AType s), AType b){ return asubtype(s, t); case \iter-star-seps(AType t, list[AType] seps): return asubtype(s,t) && isEmpty(removeLayout(seps)); - case \start(AType t): - return asubtype(i, t); case avalue(): return true; } @@ -310,8 +300,6 @@ bool asubtype(i:\iter-star-seps(AType s, list[AType] seps), AType b){ return true; case \iter-star-seps(AType t, list[AType] seps2): return asubtype(s,t) && asubtypeList(removeLayout(seps), removeLayout(seps2)); - case \start(AType t): - return asubtype(i, t); case avalue(): return true; } @@ -440,8 +428,6 @@ bool asubtype(a:anode(list[AType] l), AType b){ return true; case anode(list[AType] r): return l <= r; - case \start(t): - return asubtype(a, t); case avalue(): return true; } @@ -464,8 +450,6 @@ bool asubtype(l:\achar-class(_), AType r){ } case aadt("Tree", _, _): return true; // characters are Tree instances - case \start(t): - return asubtype(l, t); case avalue(): return true; } @@ -496,7 +480,7 @@ bool isLayoutAType(aparameter(_,AType tvb)) = isLayoutAType(tvb); bool isLayoutAType(\conditional(AType ss,_)) = isLayoutAType(ss); bool isLayoutAType(t:aadt(adtName,_,SyntaxRole sr)) = sr == layoutSyntax(); -bool isLayoutAType(\start(AType ss)) = isLayoutAType(ss); +bool isLayoutAType(\start(AType _, SyntaxRole _)) = false; bool isLayoutAType(\iter(AType s)) = isLayoutAType(s); bool isLayoutAType(\iter-star(AType s)) = isLayoutAType(s); bool isLayoutAType(\iter-seps(AType s,_)) = isLayoutAType(s); @@ -707,8 +691,11 @@ AType alub(l:aadt("Tree", _, _), AType r) = l AType alub(AType l, r:aadt("Tree", _, _)) = r when l is \achar-class || l is seq || l is opt || l is alt || l is iter || l is \iter-star || l is \iter-seps || l is \iter-star-seps; -AType alub(\start(AType l) , AType r) = alub(l, r); -AType alub(AType l, \start(AType r)) = alub(l, r); +AType alub(\start(AType l, SyntaxRole sr) , \start(AType r, sr)) = \start(alub(l, r), sr); +AType alub(\start(AType l, SyntaxRole _sr) , aadt("Tree", [], dataSyntax())) = aadt("Tree", [], dataSyntax()); +AType alub(aadt("Tree", [], dataSyntax()), \start(AType l, SyntaxRole _sr)) = aadt("Tree", [], dataSyntax()); +AType alub(anode(list[AType] ps), \start(AType l, SyntaxRole _sr)) = anode(ps); +AType alub(\start(AType l, SyntaxRole _sr), anode(list[AType] ps)) = anode(ps); AType alub(conditional(AType l, _), AType r) = alub(l, r); AType alub(AType l, conditional(AType r, _)) = alub(l, r); @@ -781,6 +768,12 @@ public AType aglb(aset(AType s), aset(AType t)) = aset(aglb(s, t)); public AType aglb(aset(AType s), arel(AType t)) = aset(aglb(s,atuple(t))); public AType aglb(arel(AType s), aset(AType t)) = aset(aglb(atuple(s), t)); +AType aglb(\start(AType a, SyntaxRole sr), \start(AType b, sr)) = \start(aglb(a, b), sr); +AType aglb(aadt("Tree", [], dataSyntax()), \start(AType b, SyntaxRole sr)) = \start(b, sr); +AType aglb(\start(AType a, SyntaxRole sr), aadt("Tree", [], dataSyntax())) = \start(a, sr); +AType aglb(\anode(_), \start(AType b, SyntaxRole sr)) = \start(b, sr); +AType aglb(\start(AType a, SyntaxRole sr), \anode(_)) = \start(a, sr); + AType aglb(arel(atypeList(list[AType] l)), arel(atypeList(list[AType] r))) = size(l) == size(r) ? arel(atypeList(aglbList(l, r))) : aset(avalue()); AType aglb(overloadedAType(overloads), AType t2) diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc index 883cce78eb0..58ab10031a4 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeBase.rsc @@ -334,12 +334,9 @@ data AType | \iter-star-seps(AType atype, list[AType] separators, bool isLexical = false) // <16> | \alt(set[AType] alternatives) // <17> | \seq(list[AType] atypes) // <18> - | \start(AType atype) + | \start(AType atype, SyntaxRole syntaxRole) ; -//public AType \iter-seps(AType atype, []) = \iter(atype); -//public AType \iter-star-seps(AType atype, []) = \iter-star(atype); - // flattening rules public AType seq([*AType a, seq(list[AType] b), *AType c]) = AType::seq(a + b + c); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeUtils.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeUtils.rsc index e2d949cc721..eba6062eb87 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeUtils.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ATypeUtils.rsc @@ -127,7 +127,7 @@ str prettyAType(cc: \achar-class(list[ACharRange] ranges)) { return cc == anyCharType ? "![]" : "[-" | r <- ranges ])>]"; } -str prettyAType(\start(AType symbol)) = "start[]"; +str prettyAType(\start(AType symbol, SyntaxRole _)) = "start[]"; // regular symbols str prettyAType(\aempty()) = "()"; @@ -225,8 +225,7 @@ Symbol atype2symbol1(acilit(str string)) = Symbol::\cilit(string); //Symbol atype2symbol1("lit"(str string)) = Symbol::\lit(string); //Symbol atype2symbol1("cilit"(str string)) = Symbol::\cilit(string); Symbol atype2symbol1(\achar-class(list[ACharRange] ranges)) = Symbol::\char-class([range(r.begin, r.end) | r <- ranges ]); - -Symbol atype2symbol1(\start(AType symbol)) = Symbol::\start(atype2symbol(symbol)); +Symbol atype2symbol1(\start(AType symbol, SyntaxRole _)) = Symbol::\start(atype2symbol(symbol)); // regular symbols Symbol atype2symbol1(\aempty()) = Symbol::\empty(); @@ -486,7 +485,7 @@ AType symbol2atype1(Symbol::\seq(list[Symbol] symbols)) = AType::seq(symbol2atype(symbols)); AType symbol2atype1(Symbol::\start(Symbol symbol)) - = AType::\start(symbol2atype1(symbol)); + = AType::\start(symbol2atype1(symbol), contextFreeSyntax()); list[AType] symbol2atype(list[Symbol] symbols) = [ symbol2atype(s) | s <- symbols ]; @@ -1061,7 +1060,7 @@ Determine if the given type is an Abstract Data Type (ADT). bool isADTAType(aparameter(_,AType tvb)) = isADTAType(tvb); bool isADTAType(aadt(_,_,_)) = true; bool isADTAType(areified(_)) = true; -bool isADTAType(\start(AType s)) = isADTAType(s); +bool isADTAType(\start(AType s, SyntaxRole _)) = isADTAType(s); default bool isADTAType(AType _) = false; @doc{Create a new parameterized ADT type with the given type parameters} @@ -1074,7 +1073,7 @@ AType makeADTType(str n) = aadt(n,[], dataSyntax()); str getADTName(AType t) { if (aadt(n,_,_) := unwrapAType(t)) return n; if (acons(a,_,_) := unwrapAType(t)) return getADTName(a); - if (\start(ss) := unwrapAType(t)) return getADTName(ss); + if (\start(ss, _) := unwrapAType(t)) return "start[]"; if (areified(_) := unwrapAType(t)) return "type"; if (aprod(prod(AType def, list[AType] _)) := unwrapAType(t)) return getADTName(def); throw rascalCheckerInternalError("getADTName, invalid type given: "); @@ -1084,7 +1083,7 @@ str getADTName(AType t) { list[AType] getADTTypeParameters(AType t) { if (aadt(_,ps,_) := unwrapAType(t)) return ps; if (acons(a,_,_) := unwrapAType(t)) return getADTTypeParameters(a); - if (\start(ss) := unwrapAType(t)) return getADTTypeParameters(ss); + if (\start(ss, _) := unwrapAType(t)) return [ss]; if (areified(_) := unwrapAType(t)) return []; if (aprod(prod(AType def, list[AType] _)) := unwrapAType(t)) return getADTTypeParameters(def); throw rascalCheckerInternalError("getADTTypeParameters given non-ADT type "); @@ -1342,7 +1341,7 @@ bool isNonTerminalAType(aparameter(_,AType tvb)) = isNonTerminalAType(tvb); bool isNonTerminalAType(AType::\conditional(AType ss,_)) = isNonTerminalAType(ss); bool isNonTerminalAType(t:aadt(adtName,_,SyntaxRole sr)) = isConcreteSyntaxRole(sr); bool isNonTerminalAType(acons(AType adt, list[AType] _, list[Keyword] _)) = isNonTerminalAType(adt); -bool isNonTerminalAType(AType::\start(AType ss)) = isNonTerminalAType(ss); +bool isNonTerminalAType(AType::\start(AType ss, SyntaxRole _)) = true; bool isNonTerminalAType(AType::aprod(AProduction p)) = isNonTerminalAType(p.def); bool isNonTerminalAType(AType::\iter(AType t)) = isNonTerminalAType(t); @@ -1361,11 +1360,11 @@ bool isNonParameterizedNonTerminalType(AType t) = isNonTerminalAType(t) && (t ha // start bool isStartNonTerminalType(aparameter(_,AType tvb)) = isStartNonTerminalType(tvb); -bool isStartNonTerminalType(AType::\start(_)) = true; +bool isStartNonTerminalType(AType::\start(_, _)) = true; default bool isStartNonTerminalType(AType s) = false; AType getStartNonTerminalType(aparameter(_,AType tvb)) = getStartNonTerminalType(tvb); -AType getStartNonTerminalType(AType::\start(AType s)) = s; +AType getStartNonTerminalType(AType::\start(AType s, _)) = s; default AType getStartNonTerminalType(AType s) { throw rascalCheckerInternalError(" is not a start non-terminal type"); } @@ -1376,7 +1375,7 @@ bool isLexicalAType(aparameter(_,AType tvb)) = isLexicalAType(tvb); bool isLexicalAType(AType::\conditional(AType ss,_)) = isLexicalAType(ss); bool isLexicalAType(t:aadt(adtName,_,SyntaxRole sr)) = sr == lexicalSyntax() || sr == layoutSyntax(); bool isLexicalAType(acons(AType adt, list[AType] fields, list[Keyword] kwFields)) = isLexicalAType(adt); -bool isLexicalAType(AType::\start(AType ss)) = isLexicalAType(ss); +bool isLexicalAType(AType::\start(AType ss, _)) = false; bool isLexicalAType(AType:alit(str string)) = true; bool isLexicalAType(AType:acilit(str string)) = true; @@ -1524,13 +1523,9 @@ default list[AType] getSeqTypes(AType t){ //AType getSyntaxType(AType t, Solver _) = t; -AType getSyntaxType(AType t, Solver _) = stripStart(removeConditional(t)); - -AType getSyntaxType(Tree tree, Solver s) = stripStart(removeConditional(s.getType(tree))); - -AType stripStart(AType nt) = isStartNonTerminalType(nt) ? getStartNonTerminalType(nt) : nt; +AType getSyntaxType(AType t, Solver _) = removeConditional(t); -AType stripStart(aprod(AProduction production)) = production.def; +AType getSyntaxType(Tree tree, Solver s) = removeConditional(s.getType(tree)); AType removeConditional(cnd:conditional(AType s, set[ACondition] _)) = cnd.alabel? ? s[alabel=cnd.alabel] : s; default AType removeConditional(AType s) = s; @@ -1561,4 +1556,4 @@ public AType filterOverloads(overloadedAType(rel[loc, IdRole, AType] overloads), if({<_,_,t>} := reduced) return t; return overloadedAType(reduced); } -public default AType filterOverloads(AType t, set[IdRole] roles) = t; \ No newline at end of file +public default AType filterOverloads(AType t, set[IdRole] roles) = t; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectExpression.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectExpression.rsc index 2a458f25d69..299f3929287 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectExpression.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectExpression.rsc @@ -574,6 +574,7 @@ void collect(current: (Expression) ` ( <{Expression ","}* } AType texp = s.getType(expression); + if(isStrAType(texp)){ return computeExpressionNodeType(scope, actuals, keywordArguments, s); } @@ -592,6 +593,7 @@ void collect(current: (Expression) ` ( <{Expression ","}* if(isConstructorAType(texp) && getConstructorResultType(texp).adtName == "Tree" && expression is qualifiedName){ = splitQualifiedName(expression.qualifiedName); + if (base == "char" && (isEmpty(qualifier) || qualifier == "Tree")){ nactuals = size(actuals); if(nactuals != 1){ @@ -671,8 +673,7 @@ void collect(current: (Expression) ` ( <{Expression ","}* return res; } if(acons(ret:aadt(adtName, list[AType] _,_), list[AType] fields, list[Keyword] kwFields) := texp){ - res = computeADTType(expression, adtName, scope, ret, fields, kwFields, actuals, keywordArguments, [true | int _ <- index(fields)], s); - return res; + return computeADTType(expression, adtName, scope, ret, fields, kwFields, actuals, keywordArguments, [true | int _ <- index(fields)], s); } reportCallError(current, expression, actuals, keywordArguments, s); return avalue(); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectStatement.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectStatement.rsc index 8877c85fef6..919fac8b22c 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectStatement.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectStatement.rsc @@ -1007,9 +1007,6 @@ private void requireAssignmentSubType(Tree current, AType a, AType b, FailMessag private AType computeFieldAssignableType(Statement current, AType receiverType, Tree field, str operator, AType rhs, loc scope, Solver s){ //println("computeFieldAssignableType: "); fieldName = unescape(""); - if(isNonTerminalAType(receiverType) && fieldName == "top"){ - return isStartNonTerminalType(receiverType) ? getStartNonTerminalType(receiverType) : receiverType; - } fieldType = s.getTypeInType(receiverType, field, {fieldId(), keywordFieldId()}, scope); updatedFieldType = computeAssignmentRhsType(current, fieldType, operator, rhs, s); requireAssignmentSubType(current, updatedFieldType, fieldType, error(current, "Field %q requires %t, found %t", fieldName, fieldType, updatedFieldType), s); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectSyntaxDeclaration.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectSyntaxDeclaration.rsc index 6a474472b4e..896bc3651aa 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectSyntaxDeclaration.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectSyntaxDeclaration.rsc @@ -62,9 +62,16 @@ void collect (current: (SyntaxDefinition) ` syntax = < public int nalternatives = 0; public int syndefCounter = 0; + void declareSyntax(SyntaxDefinition current, SyntaxRole syntaxRole, IdRole idRole, Collector c, Vis vis=publicVis()){ // println("declareSyntax: "); Sym defined = current.defined; + + if (defined is \start) { + c.report(error(defined, "Can not manually define a start non-terminal, because its syntax rule is already generated automatically.")); + return; + } + Prod production = current.production; nonterminalType = defsym2AType(defined, syntaxRole); @@ -76,7 +83,7 @@ void declareSyntax(SyntaxDefinition current, SyntaxRole syntaxRole, IdRole idRol nonterminalType = nonterminalType[parameters=[ aparameter("", treeType,closed=true)| tp <- typeParameters ]]; } - dt = defType(/*current is language && current.\start is present ? \start(nonterminalType) : */nonterminalType); + dt = defType(nonterminalType); dt.vis = vis; dt.md5 = md5Hash("" : "">"); syndefCounter += 1; @@ -84,6 +91,10 @@ void declareSyntax(SyntaxDefinition current, SyntaxRole syntaxRole, IdRole idRol // Define the syntax symbol itself and all labelled alternatives as constructors c.define(adtName, idRole, current, dt); + if (current is \language && current.\start is present) { + collectStartRule(current.\start, nonterminalType, c); + } + adtParentScope = c.getScope(); c.enterScope(current); beginDefineOrReuseTypeParameters(c,closed=false); @@ -102,6 +113,41 @@ void declareSyntax(SyntaxDefinition current, SyntaxRole syntaxRole, IdRole idRol } } +@synopsis{Declare a `top` field for each `start` rule} +@description{ +For every `start syntax A = ...` which is being collected, we simulate the declaration +of a `top` field of the form `syntax start[A] = A top;`: +* a `start[A]` type +* a production rule `syntax start[A] = A top;` +* a field `A top` of `start[A]` + +We don't include layout before and after the `top` field, because that is added much +later in the compilatiojn pipeline with the other layout non-terminals. +} +void collectStartRule(Start current, AType nonterminalType, Collector c) { + str currentModuleName = str nm := c.top(key_current_module) ? nm : ""; + str md5prefix = "_start_"; + + aStartSym = \start(nonterminalType, contextFreeSyntax()); + st = defType(aStartSym); + st.md5 = md5Hash("_type"); + c.define("", nonterminalId(), current, st); + + c.enterScope(current); + startProd = defType(aprod(prod(aStartSym, [nonterminalType[alabel="top"]]))); + startProd.md5 = md5Hash("_prod"); + sPos = current@\loc.top(current@\loc.offset, 1); + c.define("", productionId(), sPos, startProd); + + tPos = current@\loc.top(current@\loc.offset + 1, 1); + fieldDef = defType(nonterminalType[alabel="top"]); + + fieldDef.md5 = md5Hash("_top"); + + c.define("top", fieldId(), tPos, fieldDef); + c.leaveScope(current); +} + // ---- Prod ------------------------------------------------------------------ AProduction getProd(AType adtType, Tree tree, Solver s){ @@ -195,8 +241,6 @@ void collect(current: (Prod) ` : ")); } else throw "Unexpected type of production: "; })[md5=md5Hash("")]); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc index 3bbdd3d0af9..5fd3ca5e0bf 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc @@ -565,7 +565,7 @@ void collect(current:(Sym) `start [ ]`, Collector c){ AType(Solver s){ adtType = getSyntaxType(n, s); s.requireTrue(isNonTerminalAType(adtType), error(current, "Expected a non-terminal type, found %t", adtType)); - return \start(adtType); + return \start(adtType, contextFreeSyntax()); }); collect(n, c); } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ComputeType.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ComputeType.rsc index a7fd9443c6f..d7d6db8bbe9 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ComputeType.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ComputeType.rsc @@ -245,7 +245,7 @@ AType ternaryOp(str op, AType(Tree, AType, AType, AType, Solver) computeType, Tr } AType computeADTType(Tree current, str adtName, loc scope, AType retType, list[AType] formals, list[Keyword] kwFormals, actuals, keywordArguments, list[bool] identicalFormals, Solver s){ - //println("---- , identicalFormals: "); + // println("---- , identicalFormals: "); requireFullyInstantiated(s, retType); nactuals = size(actuals); nformals = size(formals); if(nactuals != nformals){ @@ -321,6 +321,7 @@ AType computeADTReturnType(Tree current, str adtName, loc scope, list[AType] for } else continue; } + s.requireComparable(aiU, iformalsU[i], error(current, "Argument %v should have type %t, found %t", i, formalTypesU[i], aiU)); } adtType = s.getTypeInScopeFromName(adtName, scope, dataOrSyntaxRoles); @@ -466,9 +467,6 @@ public AType computeFieldTypeWithADT(AType containerType, Tree field, loc scope, containerType = unwrapAType(containerType); requireFullyInstantiated(s, containerType); fieldName = unescape(""); - if(isNonTerminalAType(containerType) && fieldName == "top"){ - return isStartNonTerminalType(containerType) ? getStartNonTerminalType(containerType) : containerType; - } return s.getTypeInType(containerType, field, {fieldId(), keywordFieldId(), annoId()}, scope); // DURING TRANSITION: allow annoIds } @@ -889,8 +887,6 @@ private AType do_computeSubtractionType(Tree current, AType t1, AType t2, Solver return numericArithTypes(t1, t2); } if(isDateTimeAType(t1) && isDateTimeAType(t2)) { - // TODO JV: why are we promoting the type parameter here? - // BTW, the difference between two DateTime's is _NOT_ a datetime but an integer or something that represents a Duration. return isSameTypeParameter(t1, t2) ? t1 : adatetime(); } if(isListAType(t1) && isListAType(t2)){ @@ -899,8 +895,6 @@ private AType do_computeSubtractionType(Tree current, AType t1, AType t2, Solver return t1; } - // TODO JV: this is weird, what if it's a list of lists and you want to subtract something? Then the previous case already - // complains about incomparability... if(isListAType(t1)){ s.requireComparable(getListElementType(t1), t2, error(current, "%v of type %t could never contain elements of type %t", isListRelAType(t1) ? "List Relation" : "List", t1, t2)); return t1; @@ -910,7 +904,6 @@ private AType do_computeSubtractionType(Tree current, AType t1, AType t2, Solver return t1; } - // TODO JV: same issue as with list if(isSetAType(t1)){ s.requireComparable(getSetElementType(t1), t2, error(current, "%v of type %t could never contain elements of type %t", isRelAType(t1) ? "Relation" : "Set", t1, t2)); return t1; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc index 8031643e163..7066a1f0b3f 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc @@ -241,6 +241,10 @@ tuple[list[str] typeNames, set[IdRole] idRoles] rascalGetTypeNamesAndRole(aadt(s return ; } +tuple[list[str] typeNames, set[IdRole] idRoles] rascalGetTypeNamesAndRole(at:\start(AType _adt, SyntaxRole _syntaxRole)){ + return <["", "Tree"], {dataId(), nonterminalId()}>; +} + tuple[list[str] typeNames, set[IdRole] idRoles] rascalGetTypeNamesAndRole(acons(aadt(str adtName, list[AType] parameters, SyntaxRole syntaxRole), _, _)){ return <[adtName], {dataId(), nonterminalId(), lexicalId(), layoutId(), keywordFieldId()}>; } @@ -506,7 +510,7 @@ void reportConstructorOverload(Expression current, overloadedAType(rel[loc def, adtNames = { adtName | <- overloads, acons(ret:aadt(adtName, list[AType] _, _), list[AType] fields, list[Keyword] kwFields) := tp }; qualifyHint = size(adtNames) > 1 ? " you may use as qualifier" : ""; argHint = "make argument type(s) more precise"; - msg = error("Constructor `` is overloaded, maybe", + msg = error("Constructor `` is overloaded, maybe ", current@\loc); s.addMessages([msg]); } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ATypeTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ATypeTests.rsc index 316267ab9d3..5b55667bc33 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ATypeTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ATypeTests.rsc @@ -36,7 +36,6 @@ AType clean(AType t){ case tvar(loc _) => aint() case aparameter(_, AType t) => t case lazyLub(list[AType] lst) => isEmpty(lst) ? avoid() : avalue() - case \start(AType t) => t case overloadedAType(rel[loc, IdRole, AType] overloads): if(isEmpty(overloads)){ insert avoid(); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeAndHashTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeAndHashTests.rsc index 4122d1b3ba0..5b92c2819c7 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeAndHashTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeAndHashTests.rsc @@ -349,9 +349,9 @@ test bool synParameterLayoutChanged() = expectEqualGrammar("syntax A[&T] = &T;", "syntax A[ &T ] = &T ;"); test bool synStartChanged() - // start is no longer included in the type of the nonterminal; - // the grammar itself is therefore not changed - = expectEqualGrammar("syntax A = \"a\";", "start syntax A = \"a\";"); + // start is no longer included as a modifier of the syntax rule, + // so its generated start rule dissappears from the grammar. + = expectNotEqualGrammar("syntax A = \"a\";", "start syntax A = \"a\";"); test bool synStartLayoutChanged() = expectEqualGrammar("start syntax A = \"a\";", "start syntax A = \"a\" ;"); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StatementTCTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StatementTCTests.rsc index 5ae44f94a11..03fb0a2c4be 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StatementTCTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StatementTCTests.rsc @@ -99,11 +99,10 @@ test bool WrongInsert() = unexpectedType("String vs = visit ([1,2,3]) {case 1: i // https://github.com/cwi-swat/rascal/issues/416 -test bool Issue416() = checkModuleOK(" - module Issue416 - data D = d(int i) | d(); - D d(int i) { if (i % 2 == 0) fail d; else return d();} - "); +test bool Issue416() = checkModuleOK( + "module Issue416 + ' data D = d(int i) | d(); + ' D d(int i) { if (i % 2 == 0) fail d; else return d();}"); // https://github.com/cwi-swat/rascal/issues/432 diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/SyntaxDeclarationTCTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/SyntaxDeclarationTCTests.rsc index 132e18b9318..2c62c68c39f 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/SyntaxDeclarationTCTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/SyntaxDeclarationTCTests.rsc @@ -555,6 +555,52 @@ test bool WrongNonterminal2() = unexpectedTypeInModule(" alias ZZZ = int; "); +test bool StartSymbolTop() = checkModuleOK(" + module StartSymbolTop + + start syntax A = \"A\"; + + void main() { + start[A] sa = [start[A]] \"A\"; + A a = sa.top; + } +"); + +test bool TwoStartSymbolsTop() = checkModuleOK(" + module StartSymbolTop + + start syntax A = \"A\"; + start syntax B = \"B\"; + + void main() { + start[A] sa = [start[A]] \"A\"; + start[B] sb = [start[B]] \"B\"; + A a = sa.top; + B b = sb.top; + } +"); + +test bool StartNotSuperType() = unexpectedDeclarationInModule(" + module StartNotSuperType + + start syntax A = \"A\"; + + void main() { + A x = [A] \"A\"; + start[A] a = x; + } +"); + +test bool StartNotSubType() = unexpectedDeclarationInModule(" + module StartNotSubType + + start syntax A = \"A\"; + + void main() { + A a = [start[A]] \"A\"; + } +"); + // https://github.com/cwi-swat/rascal/issues/442 test bool Issue442() = checkModuleOK(" diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalExpression.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalExpression.rsc index 962ad8c0c30..a8f081f3783 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalExpression.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalExpression.rsc @@ -1276,7 +1276,7 @@ private MuExp translateSlice(Expression expression, OptionalExpression optFirst, MuExp translate (e:(Expression) ` . `) { orgtp = getType(expression); - tp = stripStart(orgtp); + tp = orgtp; fieldType = getType(field); ufield = unescape(""); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalPattern.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalPattern.rsc index 01dc7988eb5..32c534018f0 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalPattern.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/RascalPattern.rsc @@ -2375,11 +2375,6 @@ MuExp translatePat(p:(Pattern) `/ `, AType subjectType, MuExp s return code; } -// Strip start if present - -AType stripStart(\start(AType s)) = s; -default AType stripStart(AType s) = s; - // Is a pattern a concretePattern? // Note that a callOrTree pattern always requires a visit of the production to inspect labeled fields and is etherefore // NOT a concrete pattern diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/TypeUtils.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/TypeUtils.rsc index 5b965af1950..e2de1484c15 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/TypeUtils.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/compile/Rascal2muRascal/TypeUtils.rsc @@ -541,11 +541,6 @@ tuple[str moduleName, AType atype, bool isKwp] getConstructorInfo(AType adtType, //println("getConstructorInfo: , , "); assert isADTAType(adtType) : "getConstructorInfo: "; adtType = unsetRec(adtType); - is_start = false; - if(isStartNonTerminalType(adtType)){ - adtType = getStartNonTerminalType(adtType); - is_start = true; - } adtType1 = adtType; // TODO: this is to ensure that adType is a constant inside visit below fieldType = fieldType[alabel=fieldName]; if(adtType1 in domain(getBuiltinFieldMap())){ @@ -603,7 +598,7 @@ tuple[str moduleName, AType atype, bool isKwp] getConstructorInfo(AType adtType, productions = getGrammar().rules[adtType1].alternatives; for(prod(AType _, list[AType] atypes) <- productions){ for(a <- atypes, a.alabel?, a.alabel == fieldName){ - return <"", is_start ? \start(a) : a, false>; + return <"", a, false>; } } } @@ -615,12 +610,12 @@ tuple[str moduleName, AType atype, bool isKwp] getConstructorInfo(AType adtType, //} for(Keyword kw <- adt_common_keyword_fields[treeType] ? []){ if("" == fieldName){ - return ; + return ; } } } - return <"", is_start ? \start(adtType1) : adtType1, false>; + return <"", adtType1, false>; //throw "getConstructorInfo, no constructor found for , , "; } @@ -703,7 +698,7 @@ set[loc] getDefiningScopes(AType root) def := definitions[defLoc], def.idRole in syntaxRoles, dt := getDefType(defLoc), - dt == root || dt == \start(root) + dt == root } & module_scopes; // Get the governing layout rule @@ -736,10 +731,6 @@ map[AType,set[AType]] collectNeededDefs(AType t){ is_start = false; syntax_type = false; base_t = t; - if(\start(AType t2) := base_t){ - is_start = true; - base_t = t2; - } if(isReifiedAType(t)){ base_t = getReifiedType(t); @@ -793,9 +784,6 @@ map[AType,set[AType]] collectNeededDefs(AType t){ definedLayouts = getLayouts(base_t, allADTs); my_definitions += ( adt : {aprod(my_grammar_rules[adt])} | adt <- allADTs, my_grammar_rules[adt]? ); - if(is_start){ - my_definitions += (\start(base_t) : { aprod(achoice(\start(base_t), { prod(\start(base_t), [ definedLayouts, base_t[alabel="top"], definedLayouts]) })) }); - } if(!isEmpty(parameterized_uninstantiated_ADTs)){ // add generic parameter type Tree my_definitions += (treeType : {}); } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/Conversions.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/Conversions.rsc index d0f27132054..6e9a7b0923e 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/Conversions.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/compile/muRascal2Java/Conversions.rsc @@ -84,7 +84,7 @@ str atype2javatype(avoid()) = "void"; str atype2javatype(tvar(_)) = "IValue"; -str atype2javatype(\start(AType t)) = atype2javatype(t); +str atype2javatype(\start(AType t, _)) = "ITree"; str atype2javatype(overloadedAType(rel[loc, IdRole, AType] overloads)) = atype2javatype(lubList(toList(overloads<2>))); @@ -166,7 +166,7 @@ str atype2idpart(\iter-star-seps(AType atype, list[AType] separators)) = "iter_star_seps_"; str atype2idpart(\alt(set[AType] alternatives)) = "alt_"; //TODO str atype2idpart(\seq(list[AType] atypes)) = "seq_"; //TODO -str atype2idpart(\start(AType atype)) = "start_"; +str atype2idpart(\start(AType atype, _)) = "start_"; str atype2idpart(\conditional(AType atype, set[ACondition] conditions)) = atype2idpart(atype); @@ -465,7 +465,7 @@ private str atype2IValue1(AType::\alt(set[AType] alternatives) , map[AType, set[ private str atype2IValue1(AType::\seq(list[AType] symbols) , map[AType, set[AType]] defs) = "$RVF.constructor(RascalValueFactory.Symbol_Seq, )"; -private str atype2IValue1(AType::\start(AType symbol), map[AType, set[AType]] defs) +private str atype2IValue1(AType::\start(AType symbol, _), map[AType, set[AType]] defs) = "$RVF.constructor(RascalValueFactory.Symbol_Start, )"; //private str atype2IValue1(AType::\conditional(AType symbol, set[ACondition] conditions), map[AType, set[AType]] defs) @@ -909,7 +909,7 @@ str atype2vtype(a:aadt(str adtName, list[AType] parameters, lexicalSyntax()), JG } } -str atype2vtype(\start(AType atype), JGenie jg, bool inTest=false) +str atype2vtype(\start(AType atype, _), JGenie jg, bool inTest=false) = atype2vtype(atype, jg, inTest=inTest); str atype2vtype(aadt(str adtName, list[AType] parameters, keywordSyntax()), JGenie jg, bool inTest=false)